Difference between revisions of "PCA9685 16 Channel 12 Bit PWM Servo Driver"
(→Feature) |
|||
(9 intermediate revisions by the same user not shown) | |||
Line 6: | Line 6: | ||
==Feature== | ==Feature== | ||
1. Contains an I2C-controlled PWM driver with a built-in clock. It means, unlike the TLC5940 family, you do not need to continuously send it signals tying up your microcontroller; it's completely free running!<br> | 1. Contains an I2C-controlled PWM driver with a built-in clock. It means, unlike the TLC5940 family, you do not need to continuously send it signals tying up your microcontroller; it's completely free running!<br> | ||
− | 2. 5V compliant, which means you can control it from a 3.3V microcontroller | + | 2. 5V compliant, which means you can control it from a 3.3V microcontroller, which is good when you want to control white or blue LEDs with a 3.4V+ forward voltage<br> |
3. Supports using only two pins to control 16 free-running PWM outputs – you can even chain up 62 breakouts to control up to 992 PWM outputs.<br> | 3. Supports using only two pins to control 16 free-running PWM outputs – you can even chain up 62 breakouts to control up to 992 PWM outputs.<br> | ||
4. 3 pin connectors in 4 groups, so you can plug in 16 servos at one time (Servo plugs are slightly wider than 0.1" so you can only stack 4 adjacent ones on 0.1"-hole female headers.<br> | 4. 3 pin connectors in 4 groups, so you can plug in 16 servos at one time (Servo plugs are slightly wider than 0.1" so you can only stack 4 adjacent ones on 0.1"-hole female headers.<br> | ||
Line 51: | Line 51: | ||
|16-Channel PWM Servo Driver | |16-Channel PWM Servo Driver | ||
|- | |- | ||
− | | | + | |5V |
|VCC | |VCC | ||
|- | |- | ||
Line 62: | Line 62: | ||
|SCL | |SCL | ||
|SCL | |SCL | ||
+ | |- | ||
+ | |Vin | ||
+ | |V+ | ||
|} | |} | ||
Line 87: | Line 90: | ||
'''Step 3. Copy the code to your IDE''' (the "//" is used to comment out contents behind it)<br> | '''Step 3. Copy the code to your IDE''' (the "//" is used to comment out contents behind it)<br> | ||
− | + | <pre> | |
− | #include <Wire.h | + | #include <Wire.h> |
− | #include <Adafruit_PWMServoDriver.h | + | #include <Adafruit_PWMServoDriver.h> |
− | // called this way, it uses the default address 0x40 | + | // called this way, it uses the default address 0x40 |
− | Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); | + | Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); |
− | #define MIN_PULSE_WIDTH 650 | + | #define MIN_PULSE_WIDTH 650 |
− | #define MAX_PULSE_WIDTH 2350 | + | #define MAX_PULSE_WIDTH 2350 |
− | #define DEFAULT_PULSE_WIDTH 1500 | + | #define DEFAULT_PULSE_WIDTH 1500 |
− | #define FREQUENCY 50 | + | #define FREQUENCY 50 |
− | // our servo # counter | + | // our servo # counter |
− | uint8_t servonum = 0; | + | uint8_t servonum = 0; |
− | void setup() { | + | void setup() { |
− | Serial.begin(9600); | + | Serial.begin(9600); |
− | Serial.println("16 channel Servo test!"); | + | Serial.println("16 channel Servo test!"); |
− | pwm.begin(); | + | pwm.begin(); |
pwm.setPWMFreq(FREQUENCY); // Analog servos run at ~60 Hz updates | pwm.setPWMFreq(FREQUENCY); // Analog servos run at ~60 Hz updates | ||
− | } | + | } |
− | void loop() { | + | void loop() { |
− | pwm.setPWM(0, 0, pulseWidth(0)); | + | pwm.setPWM(0, 0, pulseWidth(0)); |
− | Serial.println("0"); | + | Serial.println("0"); |
− | delay(500); | + | delay(500); |
− | pwm.setPWM(0, 0, pulseWidth(45)); | + | pwm.setPWM(0, 0, pulseWidth(45)); |
− | Serial.println("45"); | + | Serial.println("45"); |
− | delay(500); | + | delay(500); |
− | pwm.setPWM(0, 0, pulseWidth(90)); | + | pwm.setPWM(0, 0, pulseWidth(90)); |
− | Serial.println("90"); | + | Serial.println("90"); |
− | delay(500); | + | delay(500); |
− | pwm.setPWM(0, 0, pulseWidth(135)); | + | pwm.setPWM(0, 0, pulseWidth(135)); |
− | Serial.println("135"); | + | Serial.println("135"); |
− | delay(500); | + | delay(500); |
− | pwm.setPWM(0, 0, pulseWidth(180)); | + | pwm.setPWM(0, 0, pulseWidth(180)); |
− | Serial.println("180"); | + | Serial.println("180"); |
− | delay(500); | + | delay(500); |
− | pwm.setPWM(0, 0, pulseWidth(135)); | + | pwm.setPWM(0, 0, pulseWidth(135)); |
− | Serial.println("135"); | + | Serial.println("135"); |
− | delay(500); | + | delay(500); |
− | pwm.setPWM(0, 0, pulseWidth(90)); | + | pwm.setPWM(0, 0, pulseWidth(90)); |
− | Serial.println("90"); | + | Serial.println("90"); |
− | delay(500); | + | delay(500); |
− | pwm.setPWM(0, 0, pulseWidth(45)); | + | pwm.setPWM(0, 0, pulseWidth(45)); |
− | Serial.println("45"); | + | Serial.println("45"); |
− | delay(500); | + | delay(500); |
− | } | + | } |
− | int pulseWidth(int angle) | + | int pulseWidth(int angle) |
− | { | + | { |
− | int pulse_wide, analog_value; | + | int pulse_wide, analog_value; |
− | pulse_wide = map(angle, 0, 180, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH); | + | pulse_wide = map(angle, 0, 180, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH); |
− | analog_value = int(float(pulse_wide) / 1000000 * FREQUENCY * 4096); | + | analog_value = int(float(pulse_wide) / 1000000 * FREQUENCY * 4096); |
− | Serial.println(analog_value); | + | Serial.println(analog_value); |
− | return analog_value; | + | return analog_value; |
− | }< | + | } |
− | / | + | |
+ | </pre> | ||
Save the code and click Upload. When upload is done successfully, you will see the servo rotate from 0° to 180°, then from 180° to 0°, back and forth.<br> | Save the code and click Upload. When upload is done successfully, you will see the servo rotate from 0° to 180°, then from 180° to 0°, back and forth.<br> | ||
If you want to adjust the servo to rotate to a certain position, just try to modify the angle value in the code.<br> | If you want to adjust the servo to rotate to a certain position, just try to modify the angle value in the code.<br> | ||
Line 150: | Line 154: | ||
[[File:PCA9685-5.png]]<br> | [[File:PCA9685-5.png]]<br> | ||
− | ==Address the Boards== | + | ==Connect Multiple Control Boards in Serial== |
− | Each board in the chain must be assigned a unique address. This is done with the address | + | You can connect more than one control board (62 at most) in serial to control more servos. Here we'll see how to connect two. The case is similar for connecting more than two. There are pins at the two ends of the board and you can connect those at one end of a board and pins at the other end of another board, with 6 jumper wires, as shown below. <br> |
+ | [[File:PCA9685-8.jpg]]<br> | ||
+ | |||
+ | ===Address the Boards=== | ||
+ | Each board in the chain must be assigned a unique address. This is done with the address soldering pads on the upper right edge of the board. The I2C base address for each board is 0x40. The binary address that you program with the address soldering pads is added to the base I2C address. To program the address offset, use a drop of solder to bridge the corresponding address jumper for each binary '1' in the address.<br> | ||
[[File:PCA9685-6.jpg]]<br> | [[File:PCA9685-6.jpg]]<br> | ||
[[File:PCA9685-7.png]]<br> | [[File:PCA9685-7.png]]<br> | ||
Line 160: | Line 168: | ||
Board 3: Address = 0x43 Offset = binary 00011 (bridge A0 & A1)<br> | Board 3: Address = 0x43 Offset = binary 00011 (bridge A0 & A1)<br> | ||
Board 4: Address = 0x44 Offset = binary 00100 (bridge A2)<br> | Board 4: Address = 0x44 Offset = binary 00100 (bridge A2)<br> | ||
+ | |||
+ | ===State the objects=== | ||
+ | After assigning the address, you need to state an independent object for each board in the code. See the code below: | ||
+ | <pre> | ||
+ | /***********************************************************/ | ||
+ | #include <Wire.h> | ||
+ | #include <Adafruit_PWMServoDriver.h> | ||
+ | |||
+ | Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x40); | ||
+ | Adafruit_PWMServoDriver pwm2 = Adafruit_PWMServoDriver(0x41); | ||
+ | |||
+ | void setup() { | ||
+ | Serial.begin(9600); | ||
+ | Serial.println("16 channel PWM test!"); | ||
+ | |||
+ | pwm1.begin(); | ||
+ | pwm1.setPWMFreq(1600); // This is the maximum PWM frequency | ||
+ | |||
+ | pwm2.begin(); | ||
+ | pwm2.setPWMFreq(1600); // This is the maximum PWM frequency | ||
+ | } | ||
+ | /*************************************************************/ | ||
+ | </pre> | ||
+ | After stating the objects, you can now control the servos via programming as you like! | ||
==Resources== | ==Resources== | ||
− | [http:// | + | [http://wiki.sunfounder.cc/images/e/ea/PCA9685_datasheet.pdf PCA9685_datasheet][[File:PDF.jpg]]<br> |
− | [http:// | + | [http://wiki.sunfounder.cc/images/7/7c/Python_Code.zip Python_Code][[File:ZIP.jpg]]<br> |
− | [http:// | + | [http://wiki.sunfounder.cc/images/f/fa/PWM-Servo-Driver-Library.zip PWM-Servo-Driver-Library][[File:ZIP.jpg]] |
Latest revision as of 07:30, 23 December 2019
Contents
Introduction
The PCA9685 is a 16-channel I2C-bus controlled LED controller optimized for Red/Green/Blue/Amber (RGBA) color backlighting applications. Each LED output has individual 12-bit resolution (4096 steps) PWM controller with a fixed frequency. The controller operates at a programmable frequency from a typical 24 Hz to 1526 Hz with a duty cycle that is adjustable from 0% to 100% so the LED can be set to output a specific brightness. All outputs are set to the same PWM frequency.
With the PCA9685 as the master chip, the 16-channel 12-bit PWM Servo Driver only needs 2 pins to control 16 servos, thus greatly reducing the occupant I/Os. Moreover, it can be connected to 62 driver boards at most in a cascade way, which means it will be able to control 992 servos in total.
Feature
1. Contains an I2C-controlled PWM driver with a built-in clock. It means, unlike the TLC5940 family, you do not need to continuously send it signals tying up your microcontroller; it's completely free running!
2. 5V compliant, which means you can control it from a 3.3V microcontroller, which is good when you want to control white or blue LEDs with a 3.4V+ forward voltage
3. Supports using only two pins to control 16 free-running PWM outputs – you can even chain up 62 breakouts to control up to 992 PWM outputs.
4. 3 pin connectors in 4 groups, so you can plug in 16 servos at one time (Servo plugs are slightly wider than 0.1" so you can only stack 4 adjacent ones on 0.1"-hole female headers.
5. 12-bit resolution for each output - for servos, that means about 4us resolution at an update rate of 60Hz.
6. Size: 62 x 26 mm
Principle
Based on the above introduction, we can see the module applies the PCA9685 chip as the controller. It can control the output of the 16-channel PWM values. We can manage the PWM frequency and duty cycle to control the servo precisely by programming the controller.
The turn-on time of each LED driver output and the duty cycle of PWM can be controlled independently using the LEDn_ON and LEDn_OFF registers.
If we set the LED_ON time to 409 and LED_OFF time to 1228, the duty cycle of PWM should be:
(1228-409/4096) x 100%= 20%
The servo works like this: The PWM signal captured by the receiving channel is transmitted to the signal demodulation circuit, and a DC offset voltage is generated. Next, this voltage will be compared with the potentiometer’s voltage, and then the voltage drop between them will be input into the motor driving integrated circuit to make the motor rotate clockwise or counter-clockwise. When the rotating speed reaches a certain value, it will drive the potentiometer R0 to spin by the cascaded gear reducer. The motor would not stop rotating until the voltage drop decreases to 0. The servo is controlled by PWM signal, i.e., the changed duty cycle decides where the servo rotates to.
Control a Servo
Controlling a servo rotate from 0°to 180°.
Components
-1 x PCA968 Servo Driver
-1 x Arduino Uno
-1 x Servo
-1 x 18650 Battery Holder
-2 x 18650 Li-on Batteries
-Several jump wires
Step 1. Wiring
Since the servo will use large amount of power, you need to provide this module with an independent power supply so as to ensure the servo will have adequate supply.
Connect the independent power supply to the module as shown below:
Independent Power Supply | 16-Channel PWM Servo Driver |
VCC | V+ |
GND | GND |
Connect the Arduino Uno to the module:
Arduino Uno | 16-Channel PWM Servo Driver |
5V | VCC |
GND | GND |
SDA | SDA |
SCL | SCL |
Vin | V+ |
Connect the servo to the module:
Servo | 16-Channel PWM Servo Driver |
Orange wire | PWM |
Red wire | V+ |
Brown wire | GND |
Step 2. Install the library
Open the Arduino software, and select Sketch -> Include Library -> Manage Libraries.
Search out the library file Adafruit-PWM-Servo-Driver-Library and click Install.
Step 3. Copy the code to your IDE (the "//" is used to comment out contents behind it)
#include <Wire.h> #include <Adafruit_PWMServoDriver.h> // called this way, it uses the default address 0x40 Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); #define MIN_PULSE_WIDTH 650 #define MAX_PULSE_WIDTH 2350 #define DEFAULT_PULSE_WIDTH 1500 #define FREQUENCY 50 // our servo # counter uint8_t servonum = 0; void setup() { Serial.begin(9600); Serial.println("16 channel Servo test!"); pwm.begin(); pwm.setPWMFreq(FREQUENCY); // Analog servos run at ~60 Hz updates } void loop() { pwm.setPWM(0, 0, pulseWidth(0)); Serial.println("0"); delay(500); pwm.setPWM(0, 0, pulseWidth(45)); Serial.println("45"); delay(500); pwm.setPWM(0, 0, pulseWidth(90)); Serial.println("90"); delay(500); pwm.setPWM(0, 0, pulseWidth(135)); Serial.println("135"); delay(500); pwm.setPWM(0, 0, pulseWidth(180)); Serial.println("180"); delay(500); pwm.setPWM(0, 0, pulseWidth(135)); Serial.println("135"); delay(500); pwm.setPWM(0, 0, pulseWidth(90)); Serial.println("90"); delay(500); pwm.setPWM(0, 0, pulseWidth(45)); Serial.println("45"); delay(500); } int pulseWidth(int angle) { int pulse_wide, analog_value; pulse_wide = map(angle, 0, 180, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH); analog_value = int(float(pulse_wide) / 1000000 * FREQUENCY * 4096); Serial.println(analog_value); return analog_value; }
Save the code and click Upload. When upload is done successfully, you will see the servo rotate from 0° to 180°, then from 180° to 0°, back and forth.
If you want to adjust the servo to rotate to a certain position, just try to modify the angle value in the code.
Note: If you want to control 16 servos at the same time, you can open Servo.ino, which is used to rotate the 16 servos from 0° to 180°, then return to 0°.
Connect Multiple Control Boards in Serial
You can connect more than one control board (62 at most) in serial to control more servos. Here we'll see how to connect two. The case is similar for connecting more than two. There are pins at the two ends of the board and you can connect those at one end of a board and pins at the other end of another board, with 6 jumper wires, as shown below.
Address the Boards
Each board in the chain must be assigned a unique address. This is done with the address soldering pads on the upper right edge of the board. The I2C base address for each board is 0x40. The binary address that you program with the address soldering pads is added to the base I2C address. To program the address offset, use a drop of solder to bridge the corresponding address jumper for each binary '1' in the address.
Board 0: Address = 0x40 Offset = binary 00000 (no jumpers required)
Board 1: Address = 0x41 Offset = binary 00001 (bridge A0 as in the photo above)
Board 2: Address = 0x42 Offset = binary 00010 (bridge A1)
Board 3: Address = 0x43 Offset = binary 00011 (bridge A0 & A1)
Board 4: Address = 0x44 Offset = binary 00100 (bridge A2)
State the objects
After assigning the address, you need to state an independent object for each board in the code. See the code below:
/***********************************************************/ #include <Wire.h> #include <Adafruit_PWMServoDriver.h> Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x40); Adafruit_PWMServoDriver pwm2 = Adafruit_PWMServoDriver(0x41); void setup() { Serial.begin(9600); Serial.println("16 channel PWM test!"); pwm1.begin(); pwm1.setPWMFreq(1600); // This is the maximum PWM frequency pwm2.begin(); pwm2.setPWMFreq(1600); // This is the maximum PWM frequency } /*************************************************************/
After stating the objects, you can now control the servos via programming as you like!