32 #ifndef _LIGHTWEIGHT_SERVO_HPP
33 #define _LIGHTWEIGHT_SERVO_HPP
35 #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined (__AVR_ATmega328PB__) || defined(__AVR_ATmega2560__)
50 int sMicrosecondsForServo0Degree = 544;
51 int sMicrosecondsForServo180Degree = 2400;
53 #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined (__AVR_ATmega328PB__)
62 void initLightweightServoPin9And10() {
63 initLightweightServoPins();
73 void initLightweightServoPin9_10(
bool aUsePin9,
bool aUsePin10) {
75 uint8_t tNewTCCR1A = TCCR1A & (_BV(COM1A1) | _BV(COM1B1));
76 tNewTCCR1A |= _BV(WGM11);
80 tNewTCCR1A |= _BV(COM1A1);
85 tNewTCCR1A |= _BV(COM1B1);
89 TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11);
90 ICR1 = ISR_COUNT_FOR_20_MILLIS;
96 void initLightweightServoPin9() {
98 TCCR1A = _BV(WGM11) | _BV(COM1A1);
99 TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11);
100 ICR1 = ISR_COUNT_FOR_20_MILLIS;
106 void initLightweightServoPin10() {
108 TCCR1A = _BV(WGM11) | _BV(COM1B1);
109 TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11);
110 ICR1 = ISR_COUNT_FOR_20_MILLIS;
114 void deinitLightweightServoPin9_10(
bool aUsePin9,
bool aUsePin10) {
116 DDRB &= ~(_BV(DDB1));
117 TCCR1A &= ~(_BV(COM1A1));
120 DDRB &= ~(_BV(DDB2));
121 TCCR1A &= ~(_BV(COM1B1));
131 int writeLightweightServo(
int aDegree,
bool aUsePin9,
bool aUpdateFast) {
132 if (aDegree <= 180) {
133 aDegree = DegreeToMicrosecondsLightweightServo(aDegree);
135 writeMicrosecondsLightweightServo(aDegree, aUsePin9, aUpdateFast);
139 void writeMicrosecondsLightweightServo(
int aMicroseconds,
bool aUsePin9,
bool aUpdateFast) {
140 #if !defined(DISABLE_SERVO_TIMER_AUTO_INITIALIZE)
142 if ((TCCR1B != (_BV(WGM13) | _BV(WGM12) | _BV(CS11))) || (aUsePin9 && ((TCCR1A & ~_BV(COM1B1)) != (_BV(COM1A1) | _BV(WGM11))))
143 || (!aUsePin9 && ((TCCR1A & ~_BV(COM1A1)) != (_BV(COM1B1) | _BV(WGM11))))) {
144 initLightweightServoPin9_10(aUsePin9, !aUsePin9);
148 #if (F_CPU == 16000000L)
150 #elif (F_CPU < 8000000L) // for 8 MHz resolution is exactly 1 microsecond :-)
151 aMicroseconds /= (8000000L / F_CPU);
154 uint16_t tTimerCount = TCNT1;
155 if (tTimerCount > ISR_COUNT_FOR_2_5_MILLIS) {
161 OCR1A = aMicroseconds;
163 OCR1B = aMicroseconds;
170 void write9(
int aDegree,
bool aUpdateFast) {
171 writeLightweightServo(aDegree,
true, aUpdateFast);
174 void writeMicroseconds9(
int aMicroseconds,
bool aUpdateFast) {
175 writeMicrosecondsLightweightServo(aMicroseconds,
true, aUpdateFast);
181 void writeMicroseconds9Direct(
int aMicroseconds) {
182 #if (F_CPU == 16000000L)
184 #elif (F_CPU < 8000000L) // for 8 MHz resolution is exactly 1 microsecond :-)
185 aMicroseconds /= (8000000L / F_CPU);
187 OCR1A = aMicroseconds;
193 void write10(
int aDegree,
bool aUpdateFast) {
194 writeLightweightServo(aDegree,
false, aUpdateFast);
197 void writeMicroseconds10(
int aMicroseconds,
bool aUpdateFast) {
198 writeMicrosecondsLightweightServo(aMicroseconds,
false, aUpdateFast);
204 void writeMicroseconds10Direct(
int aMicroseconds) {
205 #if (F_CPU == 16000000L)
207 #elif (F_CPU < 8000000L) // for 8 MHz resolution is exactly 1 microsecond :-)
208 aMicroseconds /= (8000000L / F_CPU);
210 OCR1B = aMicroseconds;
224 void initLightweightServoPins() {
225 #if defined(__AVR_ATmega2560__)
229 DDRL |= _BV(DDL3) | _BV(DDL4) | _BV(DDL5);
230 TCCR5A = _BV(COM5A1) | _BV(COM5B1) | _BV(COM5C1) | _BV(WGM51);
231 TCCR5B = _BV(WGM53) | _BV(WGM52) | _BV(CS51);
232 ICR5 = ISR_COUNT_FOR_20_MILLIS;
234 DDRB |= _BV(DDB1) | _BV(DDB2);
235 TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM11);
236 TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11);
237 ICR1 = ISR_COUNT_FOR_20_MILLIS;
250 void checkAndInitLightweightServoPin(uint8_t aPin) {
251 bool tPinWasNotInitialized =
false;
253 #if defined(__AVR_ATmega2560__)
254 uint8_t tNewTCCR5A = TCCR5A & (_BV(COM5A1) | _BV(COM5B1) | _BV(COM5C1) | _BV(WGM51));
255 if (aPin == LIGHTWEIGHT_SERVO_CHANNEL_A_PIN && !(TCCR5A & (_BV(COM5A1)))) {
258 tNewTCCR5A |= (_BV(COM5A1)) | _BV(WGM51);
259 tPinWasNotInitialized =
true;
260 }
else if (aPin == LIGHTWEIGHT_SERVO_CHANNEL_B_PIN && !(TCCR5A & (_BV(COM5B1)))) {
263 tNewTCCR5A |= (_BV(COM5B1)) | _BV(WGM51);
264 tPinWasNotInitialized =
true;
265 }
else if (aPin == LIGHTWEIGHT_SERVO_CHANNEL_C_PIN && !(TCCR5A & (_BV(COM5C1)))) {
268 tNewTCCR5A |= (_BV(COM5C1)) | _BV(WGM51);
269 tPinWasNotInitialized =
true;
272 uint8_t tNewTCCR1A = TCCR1A & (_BV(COM1A1) | _BV(COM1B1));
273 if (aPin == LIGHTWEIGHT_SERVO_CHANNEL_A_PIN && !(TCCR1A & (_BV(COM1A1)))) {
276 tNewTCCR1A |= (_BV(COM1A1)) | _BV(WGM11);
277 tPinWasNotInitialized =
true;
278 }
else if (aPin == LIGHTWEIGHT_SERVO_CHANNEL_B_PIN && !(TCCR1A & (_BV(COM1B1)))) {
281 tNewTCCR1A |= (_BV(COM1B1)) | _BV(WGM11);
282 tPinWasNotInitialized =
true;
286 if (tPinWasNotInitialized) {
287 #if defined(LOCAL_DEBUG)
288 Serial.print(F(
"Auto initialize pin "));
290 Serial.print(F(
" TCCR5A=0x"));
291 Serial.println(tNewTCCR5A,HEX);
296 #if defined(__AVR_ATmega2560__)
298 TCCR5B = _BV(WGM53) | _BV(WGM52) | _BV(CS51);
302 ICR5 = ISR_COUNT_FOR_20_MILLIS;
306 TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11);
307 ICR1 = ISR_COUNT_FOR_20_MILLIS;
316 void deinitLightweightServoPin(uint8_t aPin) {
317 #if defined(__AVR_ATmega2560__)
318 if (aPin == LIGHTWEIGHT_SERVO_CHANNEL_A_PIN) {
319 DDRL &= ~(_BV(DDL3));
320 TCCR5A &= ~(_BV(COM5A1));
321 }
else if (aPin == LIGHTWEIGHT_SERVO_CHANNEL_B_PIN) {
322 DDRL &= ~(_BV(DDL4));
323 TCCR5A &= ~(_BV(COM5B1));
325 DDRL &= ~(_BV(DDL5));
326 TCCR5A &= ~(_BV(COM5C1));
329 if (aPin == LIGHTWEIGHT_SERVO_CHANNEL_A_PIN) {
330 DDRB &= ~(_BV(DDB1));
331 TCCR1A &= ~(_BV(COM1A1));
332 }
else if (aPin == LIGHTWEIGHT_SERVO_CHANNEL_B_PIN) {
333 DDRB &= ~(_BV(DDB2));
334 TCCR1A &= ~(_BV(COM1B1));
345 int writeLightweightServoPin(
int aDegree, uint8_t aPin,
bool aUpdateFast) {
346 if (aDegree <= 180) {
347 aDegree = DegreeToMicrosecondsLightweightServo(aDegree);
349 writeMicrosecondsLightweightServoPin(aDegree, aPin, aUpdateFast);
353 void writeMicrosecondsLightweightServoPin(
int aMicroseconds, uint8_t aPin,
bool aUpdateFast,
bool aDoAutoInit) {
354 #if defined(LOCAL_DEBUG)
355 Serial.print(F(
" Micros="));
356 Serial.print(aMicroseconds);
357 Serial.print(F(
" pin="));
358 Serial.println(aPin);
360 #if !defined(DISABLE_SERVO_TIMER_AUTO_INITIALIZE)
362 checkAndInitLightweightServoPin(aPin);
366 #if (F_CPU == 16000000L)
368 #elif (F_CPU < 8000000L) // for 8 MHz resolution is exactly 1 microsecond :-)
369 aMicroseconds /= (8000000L / F_CPU);
371 #if defined(__AVR_ATmega2560__)
373 uint16_t tTimerCount = TCNT5;
374 if (tTimerCount > ISR_COUNT_FOR_2_5_MILLIS) {
379 if (aPin == LIGHTWEIGHT_SERVO_CHANNEL_A_PIN) {
380 OCR5A = aMicroseconds;
381 }
else if (aPin == LIGHTWEIGHT_SERVO_CHANNEL_B_PIN) {
382 OCR5B = aMicroseconds;
384 OCR5C = aMicroseconds;
388 uint16_t tTimerCount = TCNT1;
389 if (tTimerCount > ISR_COUNT_FOR_2_5_MILLIS) {
394 if (aPin == LIGHTWEIGHT_SERVO_CHANNEL_A_PIN) {
395 OCR1A = aMicroseconds;
397 OCR1B = aMicroseconds;
406 void setLightweightServoRefreshRate(
unsigned int aRefreshPeriodMicroseconds) {
407 #if defined(__AVR_ATmega2560__)
408 ICR5 = aRefreshPeriodMicroseconds * 2;
410 ICR1 = aRefreshPeriodMicroseconds * 2;
416 void setLightweightServoPulseMicrosFor0And180Degree(
int aMicrosecondsForServo0Degree,
int aMicrosecondsForServo180Degree) {
417 sMicrosecondsForServo0Degree = aMicrosecondsForServo0Degree;
418 sMicrosecondsForServo180Degree = aMicrosecondsForServo180Degree;
424 int DegreeToMicrosecondsLightweightServo(
int aDegree) {
425 return (map(aDegree, 0, 180, sMicrosecondsForServo0Degree, sMicrosecondsForServo180Degree));
428 int MicrosecondsToDegreeLightweightServo(
int aMicroseconds) {
429 return map(aMicroseconds, sMicrosecondsForServo0Degree, sMicrosecondsForServo180Degree, 0, 180);
435 uint8_t LightweightServo::attach(
int aPin) {
436 LightweightServoPin = aPin;
437 checkAndInitLightweightServoPin(aPin);
444 uint8_t LightweightServo::attach(
int aPin,
int aMicrosecondsForServo0Degree,
int aMicrosecondsForServo180Degree) {
445 LightweightServoPin = aPin;
446 MicrosecondsForServo0Degree = aMicrosecondsForServo0Degree;
447 MicrosecondsForServo180Degree = aMicrosecondsForServo180Degree;
448 checkAndInitLightweightServoPin(aPin);
452 void LightweightServo::detach() {
453 deinitLightweightServoPin(LightweightServoPin);
456 void LightweightServo::write(
int aTargetDegreeOrMicrosecond) {
457 if (aTargetDegreeOrMicrosecond <= 180) {
458 aTargetDegreeOrMicrosecond = (map(aTargetDegreeOrMicrosecond, 0, 180, MicrosecondsForServo0Degree,
459 MicrosecondsForServo180Degree));
462 writeMicrosecondsLightweightServoPin(aTargetDegreeOrMicrosecond, LightweightServoPin,
false,
false);
465 void LightweightServo::writeMicroseconds(
int aTargetMicrosecond) {
467 writeMicrosecondsLightweightServoPin(aTargetMicrosecond, LightweightServoPin,
false,
false);
470 #if defined(LOCAL_DEBUG)
473 #endif // _LIGHTWEIGHT_SERVO_HPP
474 #endif // defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega2560__)