Library for interfacing with the NXP PCA9685 PWM controller over an I2C connection. Designed with the Adafruit breakout board (of the same name) in mind.
Dependents: Hexapod_Library main_robot_gant_v22
PCA9685.cpp
00001 #ifndef PCA9685_LIBRARY_CPP 00002 #define PCA9685_LIBRARY_CPP 00003 00004 00005 #include "mbed.h" 00006 #include "PCA9685.h" 00007 #include "definitions.h" 00008 00009 00010 PCA9685::PCA9685(uint8_t i2c_address, I2C i2c_object, float frequency) : 00011 00012 i2c_addr(i2c_address), 00013 freq(frequency), 00014 i2c(i2c_object) 00015 00016 { 00017 00018 } 00019 00020 void PCA9685::init(void) 00021 { 00022 00023 reset(); 00024 00025 uint8_t prescale = (uint8_t) (OSC_CLOCK / (4096 * PWM_SCALER * freq)) - 1; 00026 00027 write_8(MODE1, 0x21); //0010 0001 : AI ENABLED 00028 write_8(MODE2, 0x07); //0000 0111 : NOT INVRT, CHANGE ON STOP, TOTEM POLE, \OE = 1, LEDn = HIGH IMP 00029 00030 set_prescale(prescale); 00031 00032 } 00033 00034 void PCA9685::reset(void) 00035 { 00036 00037 write_8(MODE1,0x00); 00038 00039 } 00040 00041 void PCA9685::set_prescale(uint8_t prescale) 00042 { 00043 00044 uint8_t oldmode = read_8(MODE1); 00045 uint8_t newmode = (oldmode&0x7F) | 0x10; // set the sleep bit 00046 00047 write_8(MODE1, newmode); // send the device to sleep 00048 wait_ms(5); 00049 write_8(PRESCALE, prescale); // set the prescaler 00050 write_8(MODE1, oldmode); 00051 wait_ms(5); 00052 write_8(MODE1, oldmode | 0xa1); // wake up the device 00053 00054 } 00055 00056 00057 //NB REQUIRES AUTO-INCREMENT MODE ENABLED 00058 //0 <= pwm_output <= 15 00059 //0 <= (count_on || count_off) <= 4095 00060 void PCA9685::set_pwm_output(int pwm_output, uint16_t count_on, uint16_t count_off) 00061 { 00062 00063 char msg[5]; 00064 00065 msg[0] = LED0_ON_L + (4 * pwm_output); 00066 msg[1] = count_on; 00067 msg[2] = count_on >> 8; 00068 msg[3] = count_off; 00069 msg[4] = count_off >> 8; 00070 00071 i2c.write(i2c_addr, msg, 5); 00072 00073 } 00074 00075 void PCA9685::set_pwm_output_on_0(int pwm_output, uint16_t count_off) 00076 { 00077 00078 char msg[3]; 00079 00080 msg[0] = LED0_ON_L + 2 + (4 * pwm_output); 00081 msg[1] = count_off; 00082 msg[2] = count_off >> 8; 00083 00084 i2c.write(i2c_addr,msg,3); 00085 00086 } 00087 00088 00089 //NB REQUIRES AUTO-INCREMENT MODE ENABLED 00090 //0 <= pwm_output <= 15 00091 void PCA9685::set_pwm_duty(int pwm_output, float duty_cycle) 00092 { 00093 00094 if (duty_cycle > 1.0) { 00095 duty_cycle = 1.0; 00096 } 00097 if (duty_cycle < 0.0) { 00098 duty_cycle = 0.0; 00099 } 00100 00101 uint16_t count_off = (uint16_t) (duty_cycle * 4095); 00102 uint16_t count_on = 0x0000; 00103 00104 set_pwm_output(pwm_output, count_on, count_off); 00105 00106 } 00107 00108 00109 //NB REQUIRES AUTO-INCREMENT MODE ENABLED 00110 //0 <= pwm_output <= 15 00111 void PCA9685::set_pwm_pw(int pwm_output, float pulse_width_us) 00112 { 00113 00114 float period_us = (1e6/freq); 00115 00116 float duty = pulse_width_us/period_us; 00117 00118 set_pwm_duty(pwm_output, duty); 00119 00120 } 00121 00122 00123 void PCA9685::update(void) 00124 { 00125 00126 i2c.stop(); 00127 00128 } 00129 00130 00131 00132 void PCA9685::write_8(uint8_t reg, uint8_t msg) 00133 { 00134 00135 char send[2]; //Store the address and data in an array 00136 send[0] = reg; 00137 send[1] = msg; 00138 i2c.write(i2c_addr, send, 2); 00139 00140 } 00141 00142 uint8_t PCA9685::read_8(uint8_t reg) 00143 { 00144 00145 char send[1] ; 00146 send[0] = reg; 00147 i2c.write(i2c_addr, send, 1); 00148 char recieve[1]; 00149 i2c.read(i2c_addr, recieve, 1); 00150 return recieve[0]; 00151 00152 } 00153 00154 int PCA9685::convert_pwm_value(float pulse_width_us, float period_us) 00155 { 00156 00157 int result; 00158 float interim; 00159 00160 interim = ((pulse_width_us / period_us) * 4095); //scale the pulse width to a 12-bit scale 00161 result = (int) interim; //round the value to the nearest integer 00162 00163 return result; 00164 00165 } 00166 00167 #endif
Generated on Mon Jul 18 2022 07:49:20 by
1.7.2