El PCA9685 es un controlador de PWM controlado por I2C que podemos conectar con un procesador como Arduino para aumentar el número de salidas PWM disponibles de forma sencilla.
El PCA9685 fue originalmente diseñado para generar señales PWM, principalmente para control de LED. Sin embargo, dado que los servos emplean una señal PWM, también es frecuente emplear el PCA9685 como controlador de servos.
El PCA9685 permite generar hasta 16 señales PWM, o controlar 16 servos, únicamente empleando 2 pines. La frecuencia del PWM es ajustable hasta a 1600 Hz, y la precisión de 12 bits.
Tiene los pines en el orden correcto para simplemente conectar los servomotores, además una bornera para la alimentación de los servos y conectores para la alimentación de la parte lógica junto con los pines I2C para comunicarse con arduino.
La comunicación se realiza a través del bus I2C, por lo que es sencillo obtener los datos medidos. Dispone de 6 pines de dirección, lo que supone que puede direccionarse hasta 62 módulos Se pueden conectar hasta 62 módulos para generar un total de 992 salidas PWM.
La dirección I2C se establece soldando los puentes A0-A5, con esto podemos usar el mismo bus I2C para controlar más módulos PCA9685 u otros dispositivos I2C.
Pines de entrada
• GND Negativo, tanto para el negativo de señal como el de potencia.
• VCC Positivo lógico, se conecta al nivel en el que se usará en la salida, su rango es de 3 a 5 V máximo.
• V+ Pin opcional de entrada (cuando se usa con servosmotores u otras cargas grandes).
Pines de control
• SCL Señal de reloj del I2C, deberá ser conectada a la linea SCL del microcontrolador.
• SDA Línea de datos, deberá ser conectada a la linea SDA del microcontrolador.
• OE Habilitación de salida, se usa para habilitar o desabilitar todas las salidas en un solo lugar.
Especificaciones Técnicas
• Voltaje de Operación: 5 V
• Interfaz: I2C
• Bornera de conexión para voltaje de alimentación (con protección para polaridad inversa)
• Diseño de conector I2C para utilizar varios módulos con el mismo BUS
• Frecuencia de PWM hasta de 1.6 KHz
• Salida de 12 bits de resolución, dando una resolucion de 4us para una frecuencia de 60Hz
• Salidas configurables como Push-Pull o Open-Drain
• Se pueden activar/desactivar todas las salidas rapidamente con el Pin OE
Conexiones
La conexión es sencilla, simplemente alimentamos el módulo desde Arduino mediante GND y 5V y conectamos el pin SDA y SCL de Arduino con los pines correspondientes del sensor.
Mientras que la conexión vista desde el lado de Arduino quedaría así.
Para la conexión de los servos disponemos de 16 columnas de 3 pines. La alimentación de los servos se realiza desde una fuente de alimentación independiente, ya que requieren una corriente superior a la que un procesador puede entregar. Para ello se dispone de una clema de conexión con protección contra polaridad inversa.
Ejemplos de Código
Para realizar la lectura del PCA9685 usaremos la librería desarrollada por Adafruit, disponible aquí:
Librería Adafruit_PWMServoDriver
La librería proporciona ejemplos de código, que resulta aconsejable revisar. Los siguientes ejemplos son modificaciones a partir de los disponibles en la librería.
Generador de Salidas PWM
El siguiente código muestra el uso del PCA9685 como generador de salidas PWM. En ella generamos una salida PWM de 1600 Hz en todos los canales, y ajustamos el duty de 0% a 100%.
El PWM se configura marcando el encendido y apagado en un número de ticks entre 0 a 4095. El ancho de un tick en milisegundos dependerá de la frecuencia elegida
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
//SCL -> A5 //SDA -> A4 #include <Wire.h> #include <Adafruit_PWMServoDriver.h> Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40); void setup() { pwm.begin(); // Ajustamos la frecuencia al máximo (1600Hz) pwm.setPWMFreq(1600); } void loop() { for (uint16_t duty = 0; duty < 4096; duty += 8) { for (uint8_t pwmNum = 0; pwmNum < 16; pwmNum++) { // Ajustar PWM con ON en tick=0 y OFF en tick=duty pwm.setPWM(pwmNum, 0, duty); } } } |
Controlador de servos
El siguiente ejemplo muestra el uso del PCA9685 como controlador de servos. En el ejemplo se emplearán servos de 50 Hz. Es necesario establecer el número de ticks equivalente a 0º y 180º.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
//SCL -> A5 //SDA -> A4 #include <Wire.h> #include <Adafruit_PWMServoDriver.h> Adafruit_PWMServoDriver servoController = Adafruit_PWMServoDriver(0x40); const uint8_t frequency = 50; // Frecuencia PWM de 50Hz o T=20ms const uint8_t ServoMinTicks = 102; // ancho de pulso en ticks para pocicion 0° const uint8_t ServoMaxTicks = 512; // ancho de pulso en ticks para la pocicion 180° void setup() { servoController.begin(); servoController.setPWMFreq(frequency ); } void loop() { for (uint16_t duty = ServoMinTicks; duty < ServoMaxTicks; duty++) { for (uint8_t n = 0; n<16; n++) { servoController.setPWM(n, 0, duty); } } delay(1000); for (uint16_t duty = ServoMaxTicks; duty > ServoMinTicks; duty++) { for (uint8_t n = 0; n<16; n++) { servoController.setPWM(n, 0, duty); } } delay(1000); } |
Si queremos trabajar con ms, en lugar de ticks, necesitaremos una función que realice la conversión. Sin embargo, siempre que sea posible, es preferible el código anterior en ticks dado que permite una mayor precisión.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
//SCL -> A5 //SDA -> A4 #include <Wire.h> #include <Adafruit_PWMServoDriver.h> Adafruit_PWMServoDriver servoController = Adafruit_PWMServoDriver(0x40); const uint8_t frequency = 50; // Frecuencia PWM de 50Hz o T=20ms const uint8_t ServoMinMs = 500; // Ancho de pulso en ms para pocicion 0° const uint8_t ServoMaxMs = 2500; // Ancho de pulso en ms para la pocicion 180° void setup() { servoController.begin(); servoController.setPWMFreq(frequency); } void setServoPulse(uint8_t n, double pulseMs) { double bitlength; // 1,000,000 us per second / frequency / 4096 (12 bits) bitlength = 1000000 / frequency / 4096; double duty = pulseMs / bitlength; servoController.setPWM(n, 0, pulseMs); } void loop() { for (uint16_t pulseWidth = ServoMinMs; pulseWidth < ServoMaxMs; pulseWidth = pulseWidth + 10) { for (uint8_t n = 0; n<16; n++) { setServoPulse(n, pulseWidth); } } delay(1000); for (uint16_t pulseWidth = ServoMaxMs; pulseWidth > ServoMinMs; pulseWidth = pulseWidth - 10) { for (uint8_t n = 0; n<16; n++) { setServoPulse(n, pulseWidth); } } delay(1000); } |