Search Code

Arduino Code and Video for PCA9685 16-Channel 12-Bit Servo Controller V1

Arduino Code and Video for PCA9685 16-Channel 12-Bit Servo Controller V1

In this tutorial, we will explore how to use the PCA9685 16-channel 12-bit servo controller from NXP Semiconductor. This module allows you to control up to 16 servos or dim a bank of LEDs with precision using pulse width modulation (PWM). By the end of this tutorial, you will have a working setup that can control multiple servos individually or simultaneously.

PCA9685 module-0

To clarify the tutorial content further, I encourage you to watch the accompanying video (in video at 00:00) for a visual demonstration of the setup and coding process.

Hardware Explained

The PCA9685 module is a compact board that can control multiple servos via I2C communication. It features 16 channels, allowing you to connect up to 16 servos, each with its own control signal. The module operates at a 5V power supply and is designed to handle PWM signals, which are essential for controlling the position of servos accurately.

The board includes dedicated pins for power (VCC), ground (GND), and communication (SDA and SCL). The SDA pin is used for data transmission, while the SCL pin is the clock signal, both of which connect to the Arduino's analog pins A4 and A5, respectively. This setup ensures reliable communication between the Arduino and the PCA9685 module.

Datasheet Details

ManufacturerNXP Semiconductor
Part numberPCA9685
Logic/IO voltage3.3 V to 5.5 V
Supply voltage2.3 V to 5.5 V
Output current (per channel)25 mA max
Peak current (per channel)100 mA max
PWM frequency guidance24 Hz to 1.6 kHz
Input logic thresholds0.3 V (low) / 0.7 V (high)
Voltage drop / RDS(on) / saturation0.5 V max
Thermal limits-40 °C to 125 °C
PackageHTSSOP-28
Notes / variants16-channel PWM controller

  • Ensure a 5V power supply with sufficient current (1A recommended).
  • Do not power the servos directly from the Arduino to avoid damage.
  • Use the correct I2C pins: SDA to A4 and SCL to A5.
  • Adjust pulse width values according to your specific servos.
  • Check wiring for correct polarity: GND, VCC, and signal.
  • Consider heat-sinking for high-current applications.

Wiring Instructions

Arduino wiring for PCA9685 to control 16 servo motors
Arduino wiring for PCA9685 to control 16 servo motors

To wire the PCA9685 to your Arduino, start by connecting the power and ground. Connect the VCC pin on the PCA9685 to the 5V output on the Arduino. Then connect the GND pin on the PCA9685 to the GND on the Arduino. Next, connect the SDA pin on the PCA9685 to pin A4 on the Arduino, and the SCL pin to pin A5.

For the servos, connect the signal wire to the corresponding channel on the PCA9685 (e.g., CH0 for the first servo), the power wire to a separate power supply (as the servos may require more current than the Arduino can provide), and the ground wire to the common ground shared with the PCA9685. Make sure that the signal, power, and ground wires are correctly aligned to avoid damaging your components.

Code Examples & Walkthrough

In the setup section of the code, we initialize the PCA9685 module with pwm.begin() and set the PWM frequency with pwm.setPWMFreq(60);. This sets the communication frequency for the servos.

void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");
  pwm.begin();
  pwm.setPWMFreq(60);  // Analog servos run at ~60 Hz updates
}

Within the loop, we control the servos by setting the PWM values corresponding to the desired angles. The function angleToPulse(int ang) maps the angle to the appropriate pulse width, which is essential for accurate servo positioning.

void loop() {
  for( int angle =0; angle<181; angle +=20){
    delay(500);
    pwm.setPWM(0, 0, angleToPulse(angle) );
  }
}

Finally, the function angleToPulse(int ang) converts the angle to pulse width using the defined minimum and maximum pulse lengths. This allows you to easily control the servo's position based on the angle you want to achieve.

int angleToPulse(int ang){
   int pulse = map(ang,0, 180, SERVOMIN,SERVOMAX);
   Serial.print("Angle: ");Serial.print(ang);
   Serial.print(" pulse: ");Serial.println(pulse);
   return pulse;
}

Demonstration / What to Expect

Once everything is wired correctly and the code is uploaded, you should see the servo moving through the specified angles in increments of 20 degrees. If the servo does not behave as expected, check the wiring for correct connections and ensure that the power supply is adequate (in video at 12:30).

Video Timestamps

  • 00:00 - Introduction to PCA9685
  • 02:30 - Wiring instructions
  • 05:00 - Code walkthrough
  • 10:15 - Demonstration of servo control
  • 12:30 - Troubleshooting common issues

Images

PCA9685 module-0
PCA9685 module-0
PCA9685 module-1
PCA9685 module-1
PCA9685 module-2
PCA9685 module-2
PCA9685 module-3
PCA9685 module-3
PCA9685 module
PCA9685 module
Arduino wiring for PCA9685 to control 16 servo motors
Arduino wiring for PCA9685 to control 16 servo motors
36-PCA9685 video V1: Arduino Code to control 16 servo motor, Basic
Language: C++
/*
 * Original source: https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
 * This is the Arduino code for the PCA9685 16-channel servo controller.
 * Watch the video for details and demo: http://youtu.be/y8X9X10Tn1k
 *  get code and wiring diagram from http://robojax.com/RTJ27
 
 * Watch the video for this code: 
 * 
 * Related Videos:
V5 video of PCA9685 32 Servo with ESP32 with WiFi: https://youtu.be/bvqfv-FrrLM
V4 video of PCA9685 32 Servo with ESP32 (no WiFi): https://youtu.be/JFdXB8Za5Os
V3 video of PCA9685: how to control 32 servo motors: https://youtu.be/6P21wG7N6t4
V2 Video of PCA9685: 3 different ways to control servo motors: https://youtu.be/bal2STaoQ1M
V1 Video introduction to PCA9685 to control 16 servos: https://youtu.be/y8X9X10Tn1k

 * Written by Ahmad Shamshiri for Robojax Video channel: www.Robojax.com
 * Date: December 16, 2017, in Ajax, Ontario, Canada
 * Permission granted to share this code, given that this
 * note is kept with the code.
 * Disclaimer: This code is "AS IS" and for educational purposes only.
 * This code has been downloaded from https://robojax.com
 * 
 */
/*************************************************** 
  This is an example for our Adafruit 16-channel PWM & Servo driver.
  Servo test - this will drive 16 servos, one after the other.

  Pick one up today in the Adafruit shop!
  ------> http://www.adafruit.com/products/815

  These displays use I2C to communicate; 2 pins are required to  
  interface. For Arduino UNOs, that's SCL -> Analog 5, SDA -> Analog 4.

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution.
 ****************************************************/

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);

// Depending on your servo make, the pulse width min and max may vary; you 
// want these to be as small/large as possible without hitting the hard stop
// for max range. You'll have to tweak them as necessary to match the servos you
// have!
#define SERVOMIN  125 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  575 // this is the 'maximum' pulse length count (out of 4096)

// our servo # counter
uint8_t servonum = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");

  pwm.begin();
  
  pwm.setPWMFreq(60);  // Analog servos run at ~60 Hz updates

  //yield();
}

// the code inside loop() has been updated by Robojax
void loop() {


  for( int angle =0; angle<181; angle +=20){
    delay(500);
    pwm.setPWM(0, 0, angleToPulse(angle) );
  }

  delay(1000);
 
}

/*
 * angleToPulse(int ang)
 * gets angle in degrees and returns the pulse width.
 * Also prints the value on the serial monitor.
 * Written by Ahmad Shamshiri for Robojax, Robojax.com
 */
int angleToPulse(int ang){
   int pulse = map(ang,0, 180, SERVOMIN,SERVOMAX);// map angle of 0 to 180 to Servo min and Servo max 
   Serial.print("Angle: ");Serial.print(ang);
   Serial.print(" pulse: ");Serial.println(pulse);
   return pulse;
}
37-PCA9685 video V1: Arduino Code with mapping PWM
Language: C++
/*
 * Original source: https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
 * This is the Arduino code for the PCA9685 16-channel servo controller.
we have simple code with mapping PWM for simplicity explained in the video at 18:27

 * Watch the video for details and demo: http://youtu.be/y8X9X10Tn1k
 get this code and wiring from for this video:  http://robojax.com/RJT27

 * Written by Ahmad Nejrabi for Robojax Video channel: www.Robojax.com
 * Date: December 15, 2017, in Ajax, Ontario, Canada
 * Permission granted to share this code, given that this
 * note is kept with the code.
 * Disclaimer: This code is "AS IS" and for educational purposes only.
 * 
 */
/*************************************************** 
  This is an example for our Adafruit 16-channel PWM & Servo driver.
  Servo test - this will drive 16 servos, one after the other.

  Pick one up today in the Adafruit shop!
  ------> http://www.adafruit.com/products/815

  These displays use I2C to communicate; 2 pins are required to  
  interface. For Arduino UNOs, that's SCL -> Analog 5, SDA -> Analog 4.

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);

// Depending on your servo make, the pulse width min and max may vary; you 
// want these to be as small/large as possible without hitting the hard stop
// for max range. You'll have to tweak them as necessary to match the servos you
// have!
#define SERVOMIN  125 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  575 // this is the 'maximum' pulse length count (out of 4096)

// our servo # counter
uint8_t servonum = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");

  pwm.begin();
  
  pwm.setPWMFreq(60);  // Analog servos run at ~60 Hz updates

  //yield();
}

// the code inside loop() has been updated by Robojax
void loop() {

    pwm.setPWM(0, 0, 125 );
	delay(500);
    pwm.setPWM(0, 0, 255 );
	delay(500);
    pwm.setPWM(0, 0, 450 );
	delay(500);
    pwm.setPWM(0, 0, 575 );
	delay(500);	

 
}

Things you might need

Resources & references

No resources yet.

Files📁

Arduino Libraries (zip)