Skip to content

Commit c9b843a

Browse files
authored
Merge pull request #62 from photodude/patch-1
Add a `writeMicroseconds()` function
2 parents 27073c9 + e73f40c commit c9b843a

File tree

3 files changed

+76
-9
lines changed

3 files changed

+76
-9
lines changed

Adafruit_PWMServoDriver.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,56 @@ void Adafruit_PWMServoDriver::setPin(uint8_t num, uint16_t val, bool invert) {
278278
}
279279
}
280280

281+
/*!
282+
* @brief Sets the PWM output of one of the PCA9685 pins based on the input microseconds, output is not precise
283+
* @param num One of the PWM output pins, from 0 to 15
284+
* @param Microseconds The number of Microseconds to turn the PWM output ON
285+
*/
286+
void Adafruit_PWMServoDriver::writeMicroseconds(uint8_t num, uint16_t Microseconds) {
287+
#ifdef ENABLE_DEBUG_OUTPUT
288+
Serial.print("Setting PWM Via Microseconds on output");
289+
Serial.print(num);
290+
Serial.print(": ");
291+
Serial.print(Microseconds);
292+
Serial.println("->");
293+
#endif
294+
295+
double pulse = Microseconds;
296+
double pulselength;
297+
pulselength = 1000000; // 1,000,000 us per second
298+
299+
// Read prescale and convert to frequency
300+
double prescale = Adafruit_PWMServoDriver::readPrescale();
301+
prescale += 1;
302+
uint32_t freq = 25000000; // Chip frequency is 25MHz
303+
freq /= prescale;
304+
freq /= 4096; // 12 bits of resolution
305+
306+
#ifdef ENABLE_DEBUG_OUTPUT
307+
Serial.print(freq); Serial.println(" Calculated PCA9685 chip PWM Frequency");
308+
#endif
309+
310+
pulselength /= freq; // us per period from PCA9685 chip PWM Frequency using prescale reverse frequency calc
311+
312+
#ifdef ENABLE_DEBUG_OUTPUT
313+
Serial.print(pulselength); Serial.println(" us per period");
314+
#endif
315+
316+
pulselength /= 4096; // 12 bits of resolution
317+
318+
#ifdef ENABLE_DEBUG_OUTPUT
319+
Serial.print(pulselength); Serial.println(" us per bit");
320+
#endif
321+
322+
pulse /= pulselength;
323+
324+
#ifdef ENABLE_DEBUG_OUTPUT
325+
Serial.print(pulse);Serial.println(" pulse for PWM");
326+
#endif
327+
328+
Adafruit_PWMServoDriver::setPWM(num, 0, pulse);
329+
}
330+
281331
uint8_t Adafruit_PWMServoDriver::read8(uint8_t addr) {
282332
_i2c->beginTransmission(_i2caddr);
283333
_i2c->write(addr);

Adafruit_PWMServoDriver.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ class Adafruit_PWMServoDriver {
8888
void setPWM(uint8_t num, uint16_t on, uint16_t off);
8989
void setPin(uint8_t num, uint16_t val, bool invert=false);
9090
uint8_t readPrescale(void);
91+
void writeMicroseconds(uint8_t num, uint16_t Microseconds);
9192

9293
private:
9394
uint8_t _i2caddr;

examples/servo/servo.ino

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@ Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
3131
// want these to be as small/large as possible without hitting the hard stop
3232
// for max range. You'll have to tweak them as necessary to match the servos you
3333
// have!
34-
#define SERVOMIN 150 // this is the 'minimum' pulse length count (out of 4096)
35-
#define SERVOMAX 600 // this is the 'maximum' pulse length count (out of 4096)
34+
#define SERVOMIN 150 // This is the 'minimum' pulse length count (out of 4096)
35+
#define SERVOMAX 600 // This is the 'maximum' pulse length count (out of 4096)
36+
#define USMIN 611 // This is the rounded 'minimum' microsecond length based on the minimum pulse of 150
37+
#define USMAX 2441 // This is the rounded 'maximum' microsecond length based on the maximum pulse of 600
38+
#define FREQ 60 // Analog servos run at ~60 Hz updates
3639

3740
// our servo # counter
3841
uint8_t servonum = 0;
@@ -43,29 +46,29 @@ void setup() {
4346

4447
pwm.begin();
4548

46-
pwm.setPWMFreq(60); // Analog servos run at ~60 Hz updates
49+
pwm.setPWMFreq(FREQ); // Analog servos run at ~60 Hz updates
4750

4851
delay(10);
4952
}
5053

51-
// you can use this function if you'd like to set the pulse length in seconds
52-
// e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. its not precise!
54+
// You can use this function if you'd like to set the pulse length in seconds
55+
// e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. It's not precise!
5356
void setServoPulse(uint8_t n, double pulse) {
5457
double pulselength;
5558

5659
pulselength = 1000000; // 1,000,000 us per second
57-
pulselength /= 60; // 60 Hz
60+
pulselength /= FREQ; // Analog servos run at ~60 Hz updates
5861
Serial.print(pulselength); Serial.println(" us per period");
5962
pulselength /= 4096; // 12 bits of resolution
6063
Serial.print(pulselength); Serial.println(" us per bit");
61-
pulse *= 1000000; // convert to us
64+
pulse *= 1000000; // convert input seconds to us
6265
pulse /= pulselength;
6366
Serial.println(pulse);
6467
pwm.setPWM(n, 0, pulse);
6568
}
6669

6770
void loop() {
68-
// Drive each servo one at a time
71+
// Drive each servo one at a time using setPWM()
6972
Serial.println(servonum);
7073
for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
7174
pwm.setPWM(servonum, 0, pulselen);
@@ -78,6 +81,19 @@ void loop() {
7881

7982
delay(500);
8083

84+
// Drive each servo one at a time using writeMicroseconds(), it's not precise due to calculation rounding!
85+
// The writeMicroseconds() function is used to mimic the Arduino Servo library writeMicroseconds() behavior.
86+
for (uint16_t microsec = USMIN; microsec < USMAX; microsec++) {
87+
pwm.writeMicroseconds(servonum, microsec);
88+
}
89+
90+
delay(500);
91+
for (uint16_t microsec = USMAX; microsec > USMIN; microsec--) {
92+
pwm.writeMicroseconds(servonum, microsec);
93+
}
94+
95+
delay(500);
96+
8197
servonum ++;
82-
if (servonum > 7) servonum = 0;
98+
if (servonum > 7) servonum = 0; // Testing the first 8 servo channels
8399
}

0 commit comments

Comments
 (0)