diff --git a/library.properties b/library.properties index a7a4772..4047ffe 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Servo -version=1.1.3 +version=3.0.0 author=Michael Margolis, Arduino maintainer=Arduino sentence=Allows Arduino/Genuino boards to control a variety of servo motors. diff --git a/src/Servo.h b/src/Servo.h index a125658..5ff9601 100644 --- a/src/Servo.h +++ b/src/Servo.h @@ -17,17 +17,17 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -/* - A servo is activated by creating an instance of the Servo class passing +/* + A servo is activated by creating an instance of the Servo class passing the desired pin to the attach() method. - The servos are pulsed in the background using the value most recently + The servos are pulsed in the background using the value most recently written using the write() method. - Note that analogWrite of PWM on pins associated with the timer are + Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached. - Timers are seized as needed in groups of 12 servos - 24 servos use two + Timers are seized as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four. - The sequence used to sieze timers is defined in timers.h + The sequence used to seize timers is defined in timers.h The methods are: @@ -35,14 +35,13 @@ attach(pin ) - Attaches a servo motor to an i/o pin. attach(pin, min, max ) - Attaches to a pin setting min and max values in microseconds - default min is 544, max is 2400 - + write() - Sets the servo angle in degrees. (invalid angle that is valid as pulse in microseconds is treated as microseconds) - writeMicroseconds() - Sets the servo pulse width in microseconds - read() - Gets the last written servo pulse width as an angle between 0 and 180. + writeMicroseconds() - Sets the servo pulse width in microseconds + read() - Gets the last written servo pulse width as an angle between 0 and 180. readMicroseconds() - Gets the last written servo pulse width in microseconds. (was read_us() in first release) - attached() - Returns true if there is a servo attached. - detach() - Stops an attached servos from pulsing its i/o pin. + attached() - Returns true if there is a servo attached. + detach() - Stops an attached servos from pulsing its i/o pin. */ #ifndef Servo_h @@ -50,8 +49,8 @@ #include -/* - * Defines for 16 bit timers used with Servo library +/* + * Defines for 16 bit timers used with Servo library * * If _useTimerX is defined then TimerX is a 16 bit timer on the current board * timer16_Sequence_t enumerates the sequence that the timers should be allocated @@ -75,14 +74,14 @@ #error "This library only supports boards with an AVR, SAM, SAMD, NRF52 or STM32F4 processor." #endif -#define Servo_VERSION 2 // software version of this library +#define Servo_VERSION 3 // software version of this library -#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo -#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo +#define MIN_PULSE_WIDTH 1000 // the shortest pulse (in us) sent to a servo +#define MAX_PULSE_WIDTH 2000 // the longest pulse (in us) sent to a servo #define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached -#define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds +#define REFRESH_INTERVAL 20000 // minimum time to refresh servos in microseconds -#define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer +#define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer #define MAX_SERVOS (_Nbr_16timers * SERVOS_PER_TIMER) #define INVALID_SERVO 255 // flag indicating an invalid servo index @@ -91,8 +90,8 @@ typedef struct { uint8_t nbr :6 ; // a pin number from 0 to 63 - uint8_t isActive :1 ; // true if this channel is enabled, pin not pulsed if false -} ServoPin_t ; + uint8_t isActive :1 ; // true if this channel is enabled, pin not pulsed if false +} ServoPin_t ; typedef struct { ServoPin_t Pin; @@ -104,17 +103,17 @@ class Servo public: Servo(); uint8_t attach(int pin); // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure - uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes. + uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes. void detach(); - void write(int value); // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds - void writeMicroseconds(int value); // Write pulse width in microseconds + void write(int value); // if value is < the minimum pulse width it's treated as an angle, otherwise as pulse width in microseconds + void writeMicroseconds(int value); // Write pulse width in microseconds int read(); // returns current pulse width as an angle between 0 and 180 degrees int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release) - bool attached(); // return true if this servo is attached, otherwise false + bool attached(); // return true if this servo is attached, otherwise false private: uint8_t servoIndex; // index into the channel data for this servo - int8_t min; // minimum is this value times 4 added to MIN_PULSE_WIDTH - int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH + uint16_t min; // minimum pulse width in microseconds + uint16_t max; // maximum pulse width in microseconds }; #endif diff --git a/src/avr/Servo.cpp b/src/avr/Servo.cpp index ed7376e..301cb1c 100644 --- a/src/avr/Servo.cpp +++ b/src/avr/Servo.cpp @@ -44,9 +44,6 @@ uint8_t ServoCount = 0; // the total number #define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel #define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel -#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo -#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo - /************ static functions common to all instances ***********************/ static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA) @@ -240,9 +237,8 @@ uint8_t Servo::attach(int pin, int min, int max) if(this->servoIndex < MAX_SERVOS ) { pinMode( pin, OUTPUT) ; // set servo pin to output servos[this->servoIndex].Pin.nbr = pin; - // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128 - this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS - this->max = (MAX_PULSE_WIDTH - max)/4; + this->min = min; + this->max = max; // initialize the timer if it has not already been initialized timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex); if(isTimerActive(timer) == false) @@ -263,11 +259,9 @@ void Servo::detach() void Servo::write(int value) { - if(value < MIN_PULSE_WIDTH) - { // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) - if(value < 0) value = 0; - if(value > 180) value = 180; - value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX()); + if(value < this->min) + { // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) + value = map(value, 0, 180, this->min, this->max); } this->writeMicroseconds(value); } @@ -278,11 +272,7 @@ void Servo::writeMicroseconds(int value) byte channel = this->servoIndex; if( (channel < MAX_SERVOS) ) // ensure channel is valid { - if( value < SERVO_MIN() ) // ensure pulse width is valid - value = SERVO_MIN(); - else if( value > SERVO_MAX() ) - value = SERVO_MAX(); - + value = constrain(value, this->min, this->max); // ensure pulse width is valid value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009 @@ -295,7 +285,7 @@ void Servo::writeMicroseconds(int value) int Servo::read() // return the value as degrees { - return map( this->readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180); + return map(this->readMicroseconds()+1, this->min, this->max, 0, 180); } int Servo::readMicroseconds() @@ -315,4 +305,3 @@ bool Servo::attached() } #endif // ARDUINO_ARCH_AVR - diff --git a/src/megaavr/Servo.cpp b/src/megaavr/Servo.cpp index daf7596..41655fd 100644 --- a/src/megaavr/Servo.cpp +++ b/src/megaavr/Servo.cpp @@ -20,9 +20,6 @@ static volatile int8_t currentServoIndex[_Nbr_16timers]; // index for the serv #define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel #define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel -#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo -#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo - void ServoHandler(int timer) { if (currentServoIndex[timer] < 0) { @@ -131,9 +128,8 @@ uint8_t Servo::attach(int pin, int min, int max) if (this->servoIndex < MAX_SERVOS) { pinMode(pin, OUTPUT); // set servo pin to output servos[this->servoIndex].Pin.nbr = pin; - // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128 - this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS - this->max = (MAX_PULSE_WIDTH - max)/4; + this->min = min; + this->max = max; // initialize the timer if it has not already been initialized timer = SERVO_INDEX_TO_TIMER(servoIndex); if (isTimerActive(timer) == false) { @@ -157,15 +153,10 @@ void Servo::detach() void Servo::write(int value) { - // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) - if (value < MIN_PULSE_WIDTH) + // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) + if (value < this->min) { - if (value < 0) - value = 0; - else if (value > 180) - value = 180; - - value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX()); + value = map(value, 0, 180, this->min, this->max); } writeMicroseconds(value); } @@ -176,11 +167,7 @@ void Servo::writeMicroseconds(int value) byte channel = this->servoIndex; if( (channel < MAX_SERVOS) ) // ensure channel is valid { - if (value < SERVO_MIN()) // ensure pulse width is valid - value = SERVO_MIN(); - else if (value > SERVO_MAX()) - value = SERVO_MAX(); - + value = constrain(value, this->min, this->max); // ensure pulse width is valid value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead servos[channel].ticks = value; @@ -189,7 +176,7 @@ void Servo::writeMicroseconds(int value) int Servo::read() // return the value as degrees { - return map(readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180); + return map(readMicroseconds()+1, this->min, this->max, 0, 180); } int Servo::readMicroseconds() @@ -208,4 +195,4 @@ bool Servo::attached() return servos[this->servoIndex].Pin.isActive; } -#endif \ No newline at end of file +#endif diff --git a/src/nrf52/Servo.cpp b/src/nrf52/Servo.cpp index a49f093..092a069 100644 --- a/src/nrf52/Servo.cpp +++ b/src/nrf52/Servo.cpp @@ -35,7 +35,7 @@ Servo::Servo() { if (ServoCount < MAX_SERVOS) { this->servoIndex = ServoCount++; // assign a servo index to this instance - } else { + } else { this->servoIndex = INVALID_SERVO; // too many servos } @@ -43,7 +43,6 @@ Servo::Servo() uint8_t Servo::attach(int pin) { - return this->attach(pin, 0, 2500); } @@ -57,11 +56,11 @@ uint8_t Servo::attach(int pin, int min, int max) if(min < servo_min) min = servo_min; if (max > servo_max) max = servo_max; - this->min = min; - this->max = max; - + this->min = min; + this->max = max; + servos[this->servoIndex].Pin.isActive = true; - + } return this->servoIndex; } @@ -73,13 +72,13 @@ void Servo::detach() void Servo::write(int value) -{ +{ if (value < 0) value = 0; else if (value > 180) value = 180; value = map(value, 0, 180, MIN_PULSE, MAX_PULSE); - + writeMicroseconds(value); } @@ -117,7 +116,7 @@ int Servo::read() // return the value as degrees } int Servo::readMicroseconds() -{ +{ uint8_t channel, instance; uint8_t pin=servos[this->servoIndex].Pin.nbr; instance=(g_APinDescription[pin].ulPWMChannel & 0xF0)/16; @@ -131,4 +130,4 @@ bool Servo::attached() return servos[this->servoIndex].Pin.isActive; } -#endif // ARDUINO_ARCH_NRF52 \ No newline at end of file +#endif // ARDUINO_ARCH_NRF52 diff --git a/src/sam/Servo.cpp b/src/sam/Servo.cpp index 21f901f..0762a73 100644 --- a/src/sam/Servo.cpp +++ b/src/sam/Servo.cpp @@ -38,9 +38,6 @@ static volatile int8_t Channel[_Nbr_16timers ]; // counter for the s #define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel #define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel -#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo -#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo - /************ static functions common to all instances ***********************/ //------------------------------------------------------------------------------ @@ -202,9 +199,8 @@ uint8_t Servo::attach(int pin, int min, int max) if (this->servoIndex < MAX_SERVOS) { pinMode(pin, OUTPUT); // set servo pin to output servos[this->servoIndex].Pin.nbr = pin; - // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128 - this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS - this->max = (MAX_PULSE_WIDTH - max)/4; + this->min = min; + this->max = max; // initialize the timer if it has not already been initialized timer = SERVO_INDEX_TO_TIMER(servoIndex); if (isTimerActive(timer) == false) { @@ -228,15 +224,10 @@ void Servo::detach() void Servo::write(int value) { - // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) - if (value < MIN_PULSE_WIDTH) + // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) + if (value < this->min) { - if (value < 0) - value = 0; - else if (value > 180) - value = 180; - - value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX()); + value = map(value, 0, 180, this->min, this->max); } writeMicroseconds(value); } @@ -247,11 +238,7 @@ void Servo::writeMicroseconds(int value) byte channel = this->servoIndex; if( (channel < MAX_SERVOS) ) // ensure channel is valid { - if (value < SERVO_MIN()) // ensure pulse width is valid - value = SERVO_MIN(); - else if (value > SERVO_MAX()) - value = SERVO_MAX(); - + value = constrain(value, this->min, this->max); // ensure pulse width is valid value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead servos[channel].ticks = value; @@ -260,7 +247,7 @@ void Servo::writeMicroseconds(int value) int Servo::read() // return the value as degrees { - return map(readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180); + return map(readMicroseconds()+1, this->min, this->max, 0, 180); } int Servo::readMicroseconds() @@ -280,4 +267,3 @@ bool Servo::attached() } #endif // ARDUINO_ARCH_SAM - diff --git a/src/samd/Servo.cpp b/src/samd/Servo.cpp index 42a3877..5e0bd23 100644 --- a/src/samd/Servo.cpp +++ b/src/samd/Servo.cpp @@ -38,9 +38,6 @@ static volatile int8_t currentServoIndex[_Nbr_16timers]; // index for the serv #define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel #define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel -#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo -#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo - #define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY); /************ static functions common to all instances ***********************/ @@ -217,9 +214,8 @@ uint8_t Servo::attach(int pin, int min, int max) if (this->servoIndex < MAX_SERVOS) { pinMode(pin, OUTPUT); // set servo pin to output servos[this->servoIndex].Pin.nbr = pin; - // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128 - this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS - this->max = (MAX_PULSE_WIDTH - max)/4; + this->min = min; + this->max = max; // initialize the timer if it has not already been initialized timer = SERVO_INDEX_TO_TIMER(servoIndex); if (isTimerActive(timer) == false) { @@ -243,15 +239,10 @@ void Servo::detach() void Servo::write(int value) { - // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) - if (value < MIN_PULSE_WIDTH) + // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) + if (value < this->min) { - if (value < 0) - value = 0; - else if (value > 180) - value = 180; - - value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX()); + value = map(value, 0, 180, this->min, this->max); } writeMicroseconds(value); } @@ -262,11 +253,7 @@ void Servo::writeMicroseconds(int value) byte channel = this->servoIndex; if( (channel < MAX_SERVOS) ) // ensure channel is valid { - if (value < SERVO_MIN()) // ensure pulse width is valid - value = SERVO_MIN(); - else if (value > SERVO_MAX()) - value = SERVO_MAX(); - + value = constrain(value, this->min, this->max); // ensure pulse width is valid value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead servos[channel].ticks = value; @@ -275,7 +262,7 @@ void Servo::writeMicroseconds(int value) int Servo::read() // return the value as degrees { - return map(readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180); + return map(readMicroseconds()+1, this->min, this->max, 0, 180); } int Servo::readMicroseconds() diff --git a/src/stm32f4/ServoTimers.h b/src/stm32f4/ServoTimers.h index 12d55b7..c2923b6 100644 --- a/src/stm32f4/ServoTimers.h +++ b/src/stm32f4/ServoTimers.h @@ -65,7 +65,7 @@ // Pin number of unattached pins #define NOT_ATTACHED (-1) -#define _Nbr_16timers 14 // mumber of STM32F469 Timers +#define _Nbr_16timers 14 // Number of STM32F469 Timers #define SERVOS_PER_TIMER 4 // Number of timer channels @@ -75,8 +75,8 @@ #define MIN_ANGLE 0 #define MAX_ANGLE 180 -#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo -#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo +#define MIN_PULSE_WIDTH 1000 // the shortest pulse (in us) sent to a servo +#define MAX_PULSE_WIDTH 2000 // the longest pulse (in us) sent to a servo /** Class for interfacing with RC servomotors. */ class Servo { @@ -103,12 +103,12 @@ class Servo { * @param minPulseWidth Minimum pulse width to write to pin, in * microseconds. This will be associated * with a minAngle degree angle. Defaults to - * SERVO_DEFAULT_MIN_PW = 544. + * MIN_PULSE_WIDTH. * * @param maxPulseWidth Maximum pulse width to write to pin, in * microseconds. This will be associated * with a maxAngle degree angle. Defaults to - * SERVO_DEFAULT_MAX_PW = 2400. + * MAX_PULSE_WIDTH. * * @param minAngle Target angle (in degrees) associated with * minPulseWidth. Defaults to