diff --git a/README.md b/README.md index 86a2717..dad0a8c 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,24 @@ # Servo Hardware PWM Library for Arduino Mega -This library allows Arduino/Genuino Mega boards to control up to **6 servos** with the integrated **16-bit hardware PWM timer/counter**. +This library allows Arduino/Genuino Mega boards to control up to **9 servos** with the integrated **16-bit hardware PWM timer/counter**. 16-bit hardware timer/counter (timer3, timer4 and timer5) are used to control the servos. Unlike the original Servo.h library, this library does not use timer1. The advantage here is that when using the Wire.h library no fluctuations in the pulse width occur. In addition, I/O registers are addressed directly and not via the digitalWrite()-function (as in Servo.h). -Possible output pins are **pin 2, 3, 7, 8, 44,** and **45**. +Possible output pins are **pin 2, 3, 5, 6, 7, 8, 44, 45** and **46**. **Only Arduino/Genuino Mega boards are supported!** ### Installation This library can be installed through the Arduino IDE library manager like so: ![](installation.gif) -### Note +### Notes +Starting from version 1.3.0 this Servo-Library supports 9 instead of 6 servos! (usable pins are: 2, 3, 5, 6, 7, 8, 44, 45 and 46) + +--- + Starting from version 1.2.0 this Servo-Library is compatible with all the [original Arduino Servo Library](https://github.com/arduino-libraries/Servo) - commands available. In addition to these "standard"-functions, following commands are added: * ``` attach(int pin, int min, int max, int defaultPos)``` - Besides the ability to set the servo pin and the upper and lower pulse width limit, the starting pulse width of the servo can be set with the defaultPos. This allows the servo to start from a user-defined angle instead of the middle position. * ```detachAll()``` - This feature allows detaching all servos at once. @@ -32,4 +36,5 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file ### Acknowledgments * Inspired by - [original Arduino Servo Library](https://github.com/arduino-libraries/Servo) * Thanks for helping me to improve my library - [per1234](https://github.com/per1234) +* Thanks for helping me to improve my library - [QuadCorei8085](https://github.com/QuadCorei8085) * Screen-GIF recorded with - [ShareX](https://getsharex.com/) diff --git a/examples/Servo_Sweep/Servo_Sweep.ino b/examples/Servo_Sweep/Servo_Sweep.ino index 402e70b..aeb3cd3 100644 --- a/examples/Servo_Sweep/Servo_Sweep.ino +++ b/examples/Servo_Sweep/Servo_Sweep.ino @@ -1,6 +1,6 @@ /* Servo Sweep Created by Daniel Duller, 12. January, 2019. - Changed by Daniel Duller, 11. October, 2019. + Changed by Daniel Duller, 16. November, 2019. This example code is in the public domain. */ @@ -12,39 +12,51 @@ Servo myServo3; Servo myServo4; Servo myServo5; Servo myServo6; +Servo myServo7; +Servo myServo8; +Servo myServo9; unsigned int valueMicros = 0; //variable that contains the microseconds int valueDegrees = 0; //variable that contains the degrees void setup() { - myServo1.attach(2); //attaches the servo to pin 2 - myServo2.attach(3); - myServo3.attach(7); - myServo4.attach(8); - myServo5.attach(44); - myServo6.attach(45); + myServo1.attach(2); //attaches the servo to pin 2 + myServo2.attach(3); + myServo3.attach(5); + myServo4.attach(6); + myServo5.attach(7); + myServo6.attach(8); + myServo7.attach(44); + myServo8.attach(45); + myServo9.attach(46); } void loop() { - //option 1 - using microseconds and the writeMicroseconds-function: - for (valueMicros = 500; valueMicros < 2500; valueMicros++){ //goes from 500us to 2500us (0° to 180°) - myServo1.writeMicroseconds(valueMicros); //writes the value of valueMicros to the servo - myServo2.writeMicroseconds(valueMicros); - myServo3.writeMicroseconds(valueMicros); - myServo4.writeMicroseconds(valueMicros); - myServo5.writeMicroseconds(valueMicros); - myServo6.writeMicroseconds(valueMicros); - delay(1); - } + //option 1 - using microseconds and the writeMicroseconds-function: + for (valueMicros = 500; valueMicros < 2500; valueMicros++){ //goes from 500us to 2500us (0° to 180°) + myServo1.writeMicroseconds(valueMicros); //writes the value of valueMicros to the servo + myServo2.writeMicroseconds(valueMicros); + myServo3.writeMicroseconds(valueMicros); + myServo4.writeMicroseconds(valueMicros); + myServo5.writeMicroseconds(valueMicros); + myServo6.writeMicroseconds(valueMicros); + myServo7.writeMicroseconds(valueMicros); + myServo8.writeMicroseconds(valueMicros); + myServo9.writeMicroseconds(valueMicros); + delay(1); + } - //option 2 - using degrees and the write-function: - for (valueDegrees = 180; valueDegrees > 0; valueDegrees--){ //goes from 180° to 0° (2500us to 500us) - myServo1.write(valueDegrees); //writes the value of valueDegrees to the servo - myServo2.write(valueDegrees); - myServo3.write(valueDegrees); - myServo4.write(valueDegrees); - myServo5.write(valueDegrees); - myServo6.write(valueDegrees); - delay(10); - } + //option 2 - using degrees and the write-function: + for (valueDegrees = 180; valueDegrees > 0; valueDegrees--){ //goes from 180° to 0° (2500us to 500us) + myServo1.write(valueDegrees); //writes the value of valueDegrees to the servo + myServo2.write(valueDegrees); + myServo3.write(valueDegrees); + myServo4.write(valueDegrees); + myServo5.write(valueDegrees); + myServo6.write(valueDegrees); + myServo7.write(valueDegrees); + myServo8.write(valueDegrees); + myServo9.write(valueDegrees); + delay(10); + } } diff --git a/extras/functions_explained.adoc b/extras/functions_explained.adoc index 2255e05..a3cea3c 100644 --- a/extras/functions_explained.adoc +++ b/extras/functions_explained.adoc @@ -1,8 +1,8 @@ The functions of the library are: -**Servo** -- Class for manipulating servo motors connected to Arduino pins. (**max. 6** elements) +**Servo** -- Class for manipulating servo motors connected to Arduino pins. (**max. 9** elements) -**attach(pin)** -- Attaches a servo motor to an i/o pin. (only **pin 2, 3, 7, 8, 44,** and **45**) +**attach(pin)** -- Attaches a servo motor to an i/o pin. (only **pin 2, 3, 5, 6, 7, 8, 44, 45** and **46**) **attach(pin, min, max)** -- Attaches a servo motor to an i/o pin with a custom lower and upper pulse width limit. diff --git a/library.properties b/library.properties index bc2b136..7ac4997 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=Servo Hardware PWM -version=1.2.1 +version=1.3.0 author=Daniel Duller maintainer=Daniel Duller -sentence=Allows Arduino/Genuino Mega boards to control up to 6 servos with the integrated 16-bit hardware PWM timer/counter. -paragraph=
This library uses the 16-bit hardware timer/counter (timer3, timer4 and timer5) to control the servos.
Possible output pins are pin 2, 3, 7, 8, 44, and 45.
Unlike the original Servo.h library, this library does not use Timer1.
The advantage here is that when using the Wire.h library no fluctuations in the pulse width occur.
In addition, I / O registers are addressed directly and not via the digitalWrite()-function (as in Servo.h).
+sentence=Allows Arduino/Genuino Mega boards to control up to 9 servos with the integrated 16-bit hardware PWM timer/counter. +paragraph=
This library uses the 16-bit hardware timer/counter (timer3, timer4 and timer5) to control the servos.
Possible output pins are pin 2, 3, 5, 6, 7, 8, 44, 45 and 46.
Unlike the original Servo.h library, this library does not use Timer1.
The advantage here is that when using the Wire.h library no fluctuations in the pulse width occur.
In addition, I / O registers are addressed directly and not via the digitalWrite()-function (as in Servo.h).
category=Device Control url=https://github.com/dadul96/Arduino-Servo-Hardware-PWM-Library architectures=avr diff --git a/src/Servo_Hardware_PWM.cpp b/src/Servo_Hardware_PWM.cpp index 5b4ebd1..a6062c2 100644 --- a/src/Servo_Hardware_PWM.cpp +++ b/src/Servo_Hardware_PWM.cpp @@ -44,22 +44,23 @@ uint8_t Servo::attach(int pin, int min, int max, int defaultPos) { { if (pin == 2) { - if (pinActive[1] == BOOL_FALSE) + if (pinActive[1] == BOOL_FALSE && pinActive[2] == BOOL_FALSE) { - //resetting the control register A and B: + //resetting the control register A, B, C: TCCR3A = 0x0; TCCR3B = 0x0; - } + TCCR3C = 0x0; - //setting the prescaler to 8 (2MHz): - TCCR3B |= (1 << CS31); + //setting the prescaler to 8 (2MHz): + TCCR3B |= (1 << CS31); - //setting the waveform generation mode to 15: - TCCR3A |= (1 << WGM31) | (1 << WGM30); - TCCR3B |= (1 << WGM32) | (1 << WGM33); + //setting the waveform generation mode to 14: + TCCR3A |= (1 << WGM31) | (0 << WGM30); + TCCR3B |= (1 << WGM32) | (1 << WGM33); - //setting the TOP value: - OCR3A = MAX_TIMER_COUNT; //results in 50Hz at 2MHz Clock + //setting the TOP value: + ICR3 = MAX_TIMER_COUNT; //results in 50Hz at 2MHz Clock + } //setting the output to non inverted: TCCR3A |= (1 << COM3B1); @@ -74,22 +75,23 @@ uint8_t Servo::attach(int pin, int min, int max, int defaultPos) { } else if (pin == 3) { - if (pinActive[0] == BOOL_FALSE) + if (pinActive[0] == BOOL_FALSE && pinActive[2] == BOOL_FALSE) { - //resetting the control register A and B: + //resetting the control register A, B, C: TCCR3A = 0x0; TCCR3B = 0x0; - } + TCCR3C = 0x0; - //setting the prescaler to 8 (2MHz): - TCCR3B |= (1 << CS31); + //setting the prescaler to 8 (2MHz): + TCCR3B |= (1 << CS31); - //setting the waveform generation mode to 15: - TCCR3A |= (1 << WGM31) | (1 << WGM30); - TCCR3B |= (1 << WGM32) | (1 << WGM33); + //setting the waveform generation mode to 14: + TCCR3A |= (1 << WGM31) | (0 << WGM30); + TCCR3B |= (1 << WGM32) | (1 << WGM33); - //setting the TOP value: - OCR3A = MAX_TIMER_COUNT; //results in 50Hz at 2MHz Clock + //setting the TOP value: + ICR3 = MAX_TIMER_COUNT; //results in 50Hz at 2MHz Clock + } //setting the output to non inverted: TCCR3A |= (1 << COM3C1); @@ -102,24 +104,87 @@ uint8_t Servo::attach(int pin, int min, int max, int defaultPos) { pinActive[1] = BOOL_TRUE; this->servoPin = 3; } - else if (pin == 7) + else if (pin == 5) + { + if (pinActive[0] == BOOL_FALSE && pinActive[1] == BOOL_FALSE) + { + //resetting the control register A, B, C: + TCCR3A = 0x0; + TCCR3B = 0x0; + TCCR3C = 0x0; + + //setting the prescaler to 8 (2MHz): + TCCR3B |= (1 << CS31); + + //setting the waveform generation mode to 14: + TCCR3A |= (1 << WGM31) | (0 << WGM30); + TCCR3B |= (1 << WGM32) | (1 << WGM33); + + //setting the TOP value: + ICR3 = MAX_TIMER_COUNT; //results in 50Hz at 2MHz Clock + } + + //setting the output to non inverted: + TCCR3A |= (1 << COM3A1); + + OCR3A = this->defaultPos; //setting the pulse width + + //OC3A, Port E, Bit 3; setting pin 5 as output: + DDRE |= (1 << PE3); //bit 3 (pin 5) as output + + pinActive[2] = BOOL_TRUE; + this->servoPin = 5; + } + else if (pin == 6) { - if (pinActive[3] == BOOL_FALSE) + if (pinActive[4] == BOOL_FALSE && pinActive[5] == BOOL_FALSE) { - //resetting the control register A and B: + //resetting the control register A, B, C: TCCR4A = 0x0; TCCR4B = 0x0; + TCCR4C = 0x0; + + //setting the prescaler to 8 (2MHz): + TCCR4B |= (1 << CS41); + + //setting the waveform generation mode to 14: + TCCR4A |= (1 << WGM41) | (0 << WGM40); + TCCR4B |= (1 << WGM42) | (1 << WGM43); + + //setting the TOP value: + ICR4 = MAX_TIMER_COUNT; //results in 50Hz at 2MHz Clock } - //setting the prescaler to 8 (2MHz): - TCCR4B |= (1 << CS41); + //setting the output to non inverted: + TCCR4A |= (1 << COM4A1); - //setting the waveform generation mode to 15: - TCCR4A |= (1 << WGM41) | (1 << WGM40); - TCCR4B |= (1 << WGM42) | (1 << WGM43); + OCR4A = this->defaultPos; //setting the pulse width - //setting the TOP value: - OCR4A = MAX_TIMER_COUNT; //results in 50Hz at 2MHz Clock + //OC4A, Port H, Bit 3; setting pin 6 as output: + DDRH |= (1 << PH3); //bit 3 (pin 6) as output + + pinActive[3] = BOOL_TRUE; + this->servoPin = 6; + } + else if (pin == 7) + { + if (pinActive[3] == BOOL_FALSE && pinActive[5] == BOOL_FALSE) + { + //resetting the control register A, B, C: + TCCR4A = 0x0; + TCCR4B = 0x0; + TCCR4C = 0x0; + + //setting the prescaler to 8 (2MHz): + TCCR4B |= (1 << CS41); + + //setting the waveform generation mode to 14: + TCCR4A |= (1 << WGM41) | (0 << WGM40); + TCCR4B |= (1 << WGM42) | (1 << WGM43); + + //setting the TOP value: + ICR4 = MAX_TIMER_COUNT; //results in 50Hz at 2MHz Clock + } //setting the output to non inverted: TCCR4A |= (1 << COM4B1); @@ -129,27 +194,28 @@ uint8_t Servo::attach(int pin, int min, int max, int defaultPos) { //OC4B, Port H, Bit 4; setting pin 7 as output: DDRH |= (1 << PH4); //bit 4 (pin 7) as output - pinActive[2] = BOOL_TRUE; + pinActive[4] = BOOL_TRUE; this->servoPin = 7; } else if (pin == 8) { - if (pinActive[2] == BOOL_FALSE) - { - //resetting the control register A and B: - TCCR4A = 0x0; - TCCR4B = 0x0; - } + if (pinActive[3] == BOOL_FALSE && pinActive[4] == BOOL_FALSE) + { + //resetting the control register A, B, C: + TCCR4A = 0x0; + TCCR4B = 0x0; + TCCR4C = 0x0; //setting the prescaler to 8 (2MHz): TCCR4B |= (1 << CS41); - //setting the waveform generation mode to 15: - TCCR4A |= (1 << WGM41) | (1 << WGM40); + //setting the waveform generation mode to 14: + TCCR4A |= (1 << WGM41) | (0 << WGM40); TCCR4B |= (1 << WGM42) | (1 << WGM43); //setting the TOP value: - OCR4A = MAX_TIMER_COUNT; //results in 50Hz at 2MHz Clock + ICR4 = MAX_TIMER_COUNT; //results in 50Hz at 2MHz Clock + } //setting the output to non inverted: TCCR4A |= (1 << COM4C1); @@ -159,27 +225,28 @@ uint8_t Servo::attach(int pin, int min, int max, int defaultPos) { //OC4C, Port H, Bit 5; setting pin 8 as output: DDRH |= (1 << PH5); //bit 5 (pin 8) as output - pinActive[3] = BOOL_TRUE; + pinActive[5] = BOOL_TRUE; this->servoPin = 8; } else if (pin == 44) { - if (pinActive[5] == BOOL_FALSE) + if (pinActive[7] == BOOL_FALSE && pinActive[8] == BOOL_FALSE) { - //resetting the control register A and B: + //resetting the control register A, B, C: TCCR5A = 0x0; TCCR5B = 0x0; - } + TCCR5C = 0x0; - //setting the prescaler to 8 (2MHz): - TCCR5B |= (1 << CS51); + //setting the prescaler to 8 (2MHz): + TCCR5B |= (1 << CS51); - //setting the waveform generation mode to 15: - TCCR5A |= (1 << WGM51) | (1 << WGM50); - TCCR5B |= (1 << WGM52) | (1 << WGM53); + //setting the waveform generation mode to 14: + TCCR5A |= (1 << WGM51) | (0 << WGM50); + TCCR5B |= (1 << WGM52) | (1 << WGM53); - //setting the TOP value: - OCR5A = MAX_TIMER_COUNT; //results in 50Hz at 2MHz Clock + //setting the TOP value: + ICR5 = MAX_TIMER_COUNT; //results in 50Hz at 2MHz Clock + } //setting the output to non inverted: TCCR5A |= (1 << COM5C1); @@ -189,27 +256,28 @@ uint8_t Servo::attach(int pin, int min, int max, int defaultPos) { //OC5C, Port L, Bit 5; setting pin 44 as output: DDRL |= (1 << PL5); //bit 5 (pin 44) as output - pinActive[4] = BOOL_TRUE; + pinActive[6] = BOOL_TRUE; this->servoPin = 44; } else if (pin == 45) { - if (pinActive[4] == BOOL_FALSE) - { - //resetting the control register A and B: - TCCR5A = 0x0; - TCCR5B = 0x0; - } + if (pinActive[6] == BOOL_FALSE && pinActive[8] == BOOL_FALSE) + { + //resetting the control register A, B, C: + TCCR5A = 0x0; + TCCR5B = 0x0; + TCCR5C = 0x0; //setting the prescaler to 8 (2MHz): TCCR5B |= (1 << CS51); - //setting the waveform generation mode to 15: - TCCR5A |= (1 << WGM51) | (1 << WGM50); + //setting the waveform generation mode to 14: + TCCR5A |= (1 << WGM51) | (0 << WGM50); TCCR5B |= (1 << WGM52) | (1 << WGM53); //setting the TOP value: - OCR5A = MAX_TIMER_COUNT; //results in 50Hz at 2MHz Clock + ICR5 = MAX_TIMER_COUNT; //results in 50Hz at 2MHz Clock + } //setting the output to non inverted: TCCR5A |= (1 << COM5B1); @@ -219,9 +287,40 @@ uint8_t Servo::attach(int pin, int min, int max, int defaultPos) { //OC5B, Port L, Bit 4; setting pin 45 as output: DDRL |= (1 << PL4); //bit 4 (pin 45) as output - pinActive[5] = BOOL_TRUE; + pinActive[7] = BOOL_TRUE; this->servoPin = 45; } + else if (pin == 46) + { + if (pinActive[6] == BOOL_FALSE && pinActive[7] == BOOL_FALSE) + { + //resetting the control register A, B, C: + TCCR5A = 0x0; + TCCR5B = 0x0; + TCCR5C = 0x0; + + //setting the prescaler to 8 (2MHz): + TCCR5B |= (1 << CS51); + + //setting the waveform generation mode to 14: + TCCR5A |= (1 << WGM51) | (0 << WGM50); + TCCR5B |= (1 << WGM52) | (1 << WGM53); + + //setting the TOP value: + ICR5 = MAX_TIMER_COUNT; //results in 50Hz at 2MHz Clock + } + + //setting the output to non inverted: + TCCR5A |= (1 << COM5A1); + + OCR5A = this->defaultPos; //setting the pulse width + + //OC5A, Port L, Bit 3; setting pin 46 as output: + DDRL |= (1 << PL3); //bit 3 (pin 46) as output + + pinActive[8] = BOOL_TRUE; + this->servoPin = 46; + } } return this->servoIndex; @@ -230,13 +329,14 @@ uint8_t Servo::attach(int pin, int min, int max, int defaultPos) { void Servo::detach() { if (servoPin == 2 && pinActive[0] == BOOL_TRUE) { - if (pinActive[1] == BOOL_FALSE) + if (pinActive[1] == BOOL_FALSE && pinActive[2] == BOOL_FALSE) { - //resetting the control register A and B: + //resetting the control register A, B, C: TCCR3A = 0x0; TCCR3B = 0x0; + TCCR3C = 0x0; //resetting the TOP value: - OCR3A = 0x0; + ICR3 = 0x0; } OCR3B = 0x0; //resetting the pulse width DDRE ^= (1 << PE4); //bit 4 (pin 2) stop output @@ -245,89 +345,143 @@ void Servo::detach() { } else if (servoPin == 3 && pinActive[1] == BOOL_TRUE) { - if (pinActive[0] == BOOL_FALSE) + if (pinActive[0] == BOOL_FALSE && pinActive[2] == BOOL_FALSE) { - //resetting the control register A and B: + //resetting the control register A, B, C: TCCR3A = 0x0; TCCR3B = 0x0; + TCCR3C = 0x0; //resetting the TOP value: - OCR3A = 0x0; + ICR3 = 0x0; } OCR3C = 0x0; //resetting the pulse width DDRE ^= (1 << PE5); //bit 5 (pin 3) stop output pinActive[1] = BOOL_FALSE; this->servoPin = 0; } - else if (servoPin == 7 && pinActive[2] == BOOL_TRUE) + else if (servoPin == 5 && pinActive[2] == BOOL_TRUE) { - if (pinActive[3] == BOOL_FALSE) + if (pinActive[0] == BOOL_FALSE && pinActive[1] == BOOL_FALSE) { - //resetting the control register A and B: + //resetting the control register A, B, C: + TCCR3A = 0x0; + TCCR3B = 0x0; + TCCR3C = 0x0; + //resetting the TOP value: + ICR3 = 0x0; + } + OCR3A = 0x0; //resetting the pulse width + DDRE ^= (1 << PE3); //bit 3 (pin 5) stop output + pinActive[2] = BOOL_FALSE; + this->servoPin = 0; + } + else if (servoPin == 6 && pinActive[3] == BOOL_TRUE) + { + if (pinActive[4] == BOOL_FALSE && pinActive[5] == BOOL_FALSE) + { + //resetting the control register A, B, C: TCCR4A = 0x0; TCCR4B = 0x0; + TCCR4C = 0x0; //resetting the TOP value: - OCR4A = 0x0; + ICR4 = 0x0; + } + OCR4A = 0x0; //resetting the pulse width + DDRH ^= (1 << PH3); //bit 3 (pin 6) stop output + pinActive[3] = BOOL_FALSE; + this->servoPin = 0; + } + else if (servoPin == 7 && pinActive[4] == BOOL_TRUE) + { + if (pinActive[3] == BOOL_FALSE && pinActive[5] == BOOL_FALSE) + { + //resetting the control register A, B, C: + TCCR4A = 0x0; + TCCR4B = 0x0; + TCCR4C = 0x0; + //resetting the TOP value: + ICR4 = 0x0; } OCR4B = 0x0; //resetting the pulse width DDRH ^= (1 << PH4); //bit 4 (pin 7) stop output - pinActive[2] = BOOL_FALSE; + pinActive[4] = BOOL_FALSE; this->servoPin = 0; } - else if (servoPin == 8 && pinActive[3] == BOOL_TRUE) + else if (servoPin == 8 && pinActive[5] == BOOL_TRUE) { - if (pinActive[2] == BOOL_FALSE) + if (pinActive[3] == BOOL_FALSE && pinActive[4] == BOOL_FALSE) { - //resetting the control register A and B: + //resetting the control register A, B, C: TCCR4A = 0x0; TCCR4B = 0x0; + TCCR4C = 0x0; //resetting the TOP value: - OCR4A = 0x0; + ICR4 = 0x0; } OCR4C = 0x0; //resetting the pulse width DDRH ^= (1 << PH5); //bit 5 (pin 8) stop output - pinActive[3] = BOOL_FALSE; + pinActive[5] = BOOL_FALSE; this->servoPin = 0; } - else if (servoPin == 44 && pinActive[4] == BOOL_TRUE) + else if (servoPin == 44 && pinActive[6] == BOOL_TRUE) { - if (pinActive[5] == BOOL_FALSE) + if (pinActive[7] == BOOL_FALSE && pinActive[8] == BOOL_FALSE) { - //resetting the control register A and B: + //resetting the control register A, B, C: TCCR5A = 0x0; TCCR5B = 0x0; + TCCR5C = 0x0; //resetting the TOP value: - OCR5A = 0x0; + ICR5 = 0x0; } OCR5C = 0x0; //resetting the pulse width DDRL ^= (1 << PL5); //bit 5 (pin 44) stop output - pinActive[4] = BOOL_FALSE; + pinActive[6] = BOOL_FALSE; this->servoPin = 0; } - else if (servoPin == 45 && pinActive[5] == BOOL_TRUE) + else if (servoPin == 45 && pinActive[7] == BOOL_TRUE) { - if (pinActive[4] == BOOL_FALSE) + if (pinActive[6] == BOOL_FALSE && pinActive[8] == BOOL_FALSE) { - //resetting the control register A and B: + //resetting the control register A, B, C: TCCR5A = 0x0; TCCR5B = 0x0; + TCCR5C = 0x0; //resetting the TOP value: - OCR5A = 0x0; + ICR5 = 0x0; } OCR5B = 0x0; //resetting the pulse width DDRL ^= (1 << PL4); //bit 4 (pin 45) stop output - pinActive[5] = BOOL_FALSE; + pinActive[7] = BOOL_FALSE; this->servoPin = 0; } + else if (servoPin == 46 && pinActive[8] == BOOL_TRUE) + { + if (pinActive[6] == BOOL_FALSE && pinActive[7] == BOOL_FALSE) + { + //resetting the control register A, B, C: + TCCR5A = 0x0; + TCCR5B = 0x0; + TCCR5C = 0x0; + //resetting the TOP value: + ICR5 = 0x0; + } + OCR5A = 0x0; //resetting the pulse width + DDRL ^= (1 << PL3); //bit 3 (pin 46) stop output + pinActive[8] = BOOL_FALSE; + this->servoPin = 0; + } } void Servo::detachAll() { if (pinActive[0] == BOOL_TRUE) { - //resetting the control register A and B: + //resetting the control register A, B, C: TCCR3A = 0x0; TCCR3B = 0x0; + TCCR3C = 0x0; //resetting the TOP value: - OCR3A = 0x0; + ICR3 = 0x0; OCR3B = 0x0; //resetting the pulse width DDRE ^= (1 << PE4); //bit 4 (pin 2) stop output @@ -335,11 +489,12 @@ void Servo::detachAll() { } if (pinActive[1] == BOOL_TRUE) { - //resetting the control register A and B: + //resetting the control register A, B, C: TCCR3A = 0x0; TCCR3B = 0x0; + TCCR3C = 0x0; //resetting the TOP value: - OCR3A = 0x0; + ICR3 = 0x0; OCR3C = 0x0; //resetting the pulse width DDRE ^= (1 << PE5); //bit 5 (pin 3) stop output @@ -347,51 +502,94 @@ void Servo::detachAll() { } if (pinActive[2] == BOOL_TRUE) { - //resetting the control register A and B: + //resetting the control register A, B, C: + TCCR3A = 0x0; + TCCR3B = 0x0; + TCCR3C = 0x0; + //resetting the TOP value: + ICR3 = 0x0; + + OCR3A = 0x0; //resetting the pulse width + DDRE ^= (1 << PE3); //bit 3 (pin 5) stop output + pinActive[2] = BOOL_FALSE; + } + if (pinActive[3] == BOOL_TRUE) + { + //resetting the control register A, B, C: TCCR4A = 0x0; TCCR4B = 0x0; + TCCR4C = 0x0; //resetting the TOP value: - OCR4A = 0x0; + ICR4 = 0x0; + + OCR4A = 0x0; //resetting the pulse width + DDRH ^= (1 << PH3); //bit 3 (pin 6) stop output + pinActive[3] = BOOL_FALSE; + } + if (pinActive[4] == BOOL_TRUE) + { + //resetting the control register A, B, C: + TCCR4A = 0x0; + TCCR4B = 0x0; + TCCR4C = 0x0; + //resetting the TOP value: + ICR4 = 0x0; OCR4B = 0x0; //resetting the pulse width DDRH ^= (1 << PH4); //bit 4 (pin 7) stop output - pinActive[2] = BOOL_FALSE; + pinActive[4] = BOOL_FALSE; } - if (pinActive[3] == BOOL_TRUE) + if (pinActive[5] == BOOL_TRUE) { - //resetting the control register A and B: + //resetting the control register A, B, C: TCCR4A = 0x0; TCCR4B = 0x0; + TCCR4C = 0x0; //resetting the TOP value: - OCR4A = 0x0; + ICR4 = 0x0; OCR4C = 0x0; //resetting the pulse width DDRH ^= (1 << PH5); //bit 5 (pin 8) stop output - pinActive[3] = BOOL_FALSE; + pinActive[5] = BOOL_FALSE; } - if (pinActive[4] == BOOL_TRUE) + if (pinActive[6] == BOOL_TRUE) { - //resetting the control register A and B: + //resetting the control register A, B, C: TCCR5A = 0x0; TCCR5B = 0x0; + TCCR5C = 0x0; //resetting the TOP value: - OCR5A = 0x0; + ICR5 = 0x0; OCR5C = 0x0; //resetting the pulse width DDRL ^= (1 << PL5); //bit 5 (pin 44) stop output - pinActive[4] = BOOL_FALSE; + pinActive[6] = BOOL_FALSE; } - if (pinActive[5] == BOOL_TRUE) + if (pinActive[7] == BOOL_TRUE) { - //resetting the control register A and B: + //resetting the control register A, B, C: TCCR5A = 0x0; TCCR5B = 0x0; + TCCR5C = 0x0; //resetting the TOP value: - OCR5A = 0x0; + ICR5 = 0x0; OCR5B = 0x0; //resetting the pulse width DDRL ^= (1 << PL4); //bit 4 (pin 45) stop output - pinActive[5] = BOOL_FALSE; + pinActive[7] = BOOL_FALSE; + } + if (pinActive[8] == BOOL_TRUE) + { + //resetting the control register A, B, C: + TCCR5A = 0x0; + TCCR5B = 0x0; + TCCR5C = 0x0; + //resetting the TOP value: + ICR5 = 0x0; + + OCR5A = 0x0; //resetting the pulse width + DDRL ^= (1 << PL3); //bit 3 (pin 46) stop output + pinActive[8] = BOOL_FALSE; } } @@ -440,26 +638,41 @@ void Servo::writeMicroseconds(int value) { OCR3C = 0x0; OCR3C = this->pulseWidth * 2; } - else if (this->servoPin == 7 && pinActive[2] == BOOL_TRUE) + else if (this->servoPin == 5 && pinActive[2] == BOOL_TRUE) + { + OCR3A = 0x0; + OCR3A = this->pulseWidth * 2; + } + else if (this->servoPin == 6 && pinActive[3] == BOOL_TRUE) + { + OCR4A = 0x0; + OCR4A = this->pulseWidth * 2; + } + else if (this->servoPin == 7 && pinActive[4] == BOOL_TRUE) { OCR4B = 0x0; OCR4B = this->pulseWidth * 2; } - else if (this->servoPin == 8 && pinActive[3] == BOOL_TRUE) + else if (this->servoPin == 8 && pinActive[5] == BOOL_TRUE) { OCR4C = 0x0; OCR4C = this->pulseWidth * 2; } - else if (this->servoPin == 44 && pinActive[4] == BOOL_TRUE) + else if (this->servoPin == 44 && pinActive[6] == BOOL_TRUE) { OCR5C = 0x0; OCR5C = this->pulseWidth * 2; } - else if (this->servoPin == 45 && pinActive[5] == BOOL_TRUE) + else if (this->servoPin == 45 && pinActive[7] == BOOL_TRUE) { OCR5B = 0x0; OCR5B = this->pulseWidth * 2; } + else if (this->servoPin == 46 && pinActive[8] == BOOL_TRUE) + { + OCR5A = 0x0; + OCR5A = this->pulseWidth * 2; + } } } diff --git a/src/Servo_Hardware_PWM.h b/src/Servo_Hardware_PWM.h index 2095d18..18d19cc 100644 --- a/src/Servo_Hardware_PWM.h +++ b/src/Servo_Hardware_PWM.h @@ -1,7 +1,7 @@ /* - Servo_Hardware_PWM.h - This Library allows Arduino/Genuino Mega boards to control up to 6 servos with the integrated 16-bit hardware PWM timer/counter. + Servo_Hardware_PWM.h - This Library allows Arduino/Genuino Mega boards to control up to 9 servos with the integrated 16-bit hardware PWM timer/counter. Created by Daniel Duller, 11. January, 2019. - Changed by Daniel Duller, 14. October, 2019. + Changed by Daniel Duller, 16. November, 2019. ############################################################################### MIT License @@ -29,7 +29,7 @@ ######################################################### - Only works on pin 2, 3, 7, 8, 44, and 45 on Arduino Mega! + Only works on pin 2, 3, 5, 6, 7, 8, 44, 45 and 46 on Arduino Mega! ######################################################### Tested on Arduino Mega 2560 R3. ######################################################### @@ -37,9 +37,9 @@ The methods are: - Servo --- Class for manipulating servo motors connected to Arduino pins. (max. 6 elements) + Servo --- Class for manipulating servo motors connected to Arduino pins. (max. 9 elements) - attach(pin) --- Attaches a servo motor to an i/o pin. (only pin 2, 3, 7, 8, 44, and 45) + attach(pin) --- Attaches a servo motor to an i/o pin. (only pin 2, 3, 5, 6, 7, 8, 44, 45 and 46) attach(pin, min, max) --- Attaches a servo motor to an i/o pin with a custom lower and upper pulse width limit. @@ -67,20 +67,18 @@ #include -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -#warning "INFO: Servos can only be connected to the following pins: 2, 3, 7, 8, 44, and 45" -#else +#if !defined(__AVR_ATmega1280__) && !defined(__AVR_ATmega2560__) #error "ERROR: This library only supports boards with an ATmega1280 or ATmega2560 processor. (Arduino/Genuino Mega/Mega1280/Mega2560)" #endif -#define Servo_VERSION 1.2.1 //software version of this library +#define Servo_VERSION 1.3.0 //software version of this library #define MIN_PULSE_WIDTH 500 //the shortest pulse sent to a servo #define MAX_PULSE_WIDTH 2500 //the longest pulse sent to a servo #define DEFAULT_PULSE_WIDTH 1500 //default pulse width when servo is attached #define MAX_TIMER_COUNT 40000 //the timer TOP value (for creating 50Hz) -#define MAX_SERVOS 6 //6 Servos can be attached +#define MAX_SERVOS 9 //9 Servos can be attached #define INVALID_SERVO_NUMBER 255 //flag indicating an invalid servo index class Servo {