This is a library for the PCA9685 ported from the Adafruit Ardiuno library.
PCA9685Lib.cpp@0:1ecf26e0cf3c, 2015-02-13 (annotated)
- Committer:
- rvasquez6089
- Date:
- Fri Feb 13 22:02:35 2015 +0000
- Revision:
- 0:1ecf26e0cf3c
- Child:
- 2:ec40a85eba51
This is the first Revision of the PCA9685 Library.; I have ported this library from the Adafruit PWM Servo Library and added 1 new feature.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
rvasquez6089 | 0:1ecf26e0cf3c | 1 | /* |
rvasquez6089 | 0:1ecf26e0cf3c | 2 | This is a library for our Adafruit 16-channel PWM & Servo driver |
rvasquez6089 | 0:1ecf26e0cf3c | 3 | |
rvasquez6089 | 0:1ecf26e0cf3c | 4 | Pick one up today in the adafruit shop! |
rvasquez6089 | 0:1ecf26e0cf3c | 5 | ------> http://www.adafruit.com/products/815 |
rvasquez6089 | 0:1ecf26e0cf3c | 6 | |
rvasquez6089 | 0:1ecf26e0cf3c | 7 | These displays use I2C to communicate, 2 pins are required to |
rvasquez6089 | 0:1ecf26e0cf3c | 8 | interface. For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4 |
rvasquez6089 | 0:1ecf26e0cf3c | 9 | |
rvasquez6089 | 0:1ecf26e0cf3c | 10 | Adafruit invests time and resources providing this open source code, |
rvasquez6089 | 0:1ecf26e0cf3c | 11 | please support Adafruit and open-source hardware by purchasing |
rvasquez6089 | 0:1ecf26e0cf3c | 12 | products from Adafruit! |
rvasquez6089 | 0:1ecf26e0cf3c | 13 | |
rvasquez6089 | 0:1ecf26e0cf3c | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. |
rvasquez6089 | 0:1ecf26e0cf3c | 15 | BSD license, all text above must be included in any redistribution |
rvasquez6089 | 0:1ecf26e0cf3c | 16 | ****************************************************/ |
rvasquez6089 | 0:1ecf26e0cf3c | 17 | |
rvasquez6089 | 0:1ecf26e0cf3c | 18 | /***************************** |
rvasquez6089 | 0:1ecf26e0cf3c | 19 | This program was ported from https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library. |
rvasquez6089 | 0:1ecf26e0cf3c | 20 | I also added some functions. |
rvasquez6089 | 0:1ecf26e0cf3c | 21 | Shundo Kishi |
rvasquez6089 | 0:1ecf26e0cf3c | 22 | */ |
rvasquez6089 | 0:1ecf26e0cf3c | 23 | |
rvasquez6089 | 0:1ecf26e0cf3c | 24 | #include "PCA9685Lib.h" |
rvasquez6089 | 0:1ecf26e0cf3c | 25 | |
rvasquez6089 | 0:1ecf26e0cf3c | 26 | |
rvasquez6089 | 0:1ecf26e0cf3c | 27 | void LEDarr::operator=(uint16_t duty) |
rvasquez6089 | 0:1ecf26e0cf3c | 28 | { |
rvasquez6089 | 0:1ecf26e0cf3c | 29 | PCALib->setDuty(LEDnum, duty); |
rvasquez6089 | 0:1ecf26e0cf3c | 30 | } |
rvasquez6089 | 0:1ecf26e0cf3c | 31 | |
rvasquez6089 | 0:1ecf26e0cf3c | 32 | PCA9685Lib::PCA9685Lib(I2C i2cobj, int addr) : _i2caddr(addr) , i2c(i2cobj) |
rvasquez6089 | 0:1ecf26e0cf3c | 33 | { |
rvasquez6089 | 0:1ecf26e0cf3c | 34 | for(int i = 0; i<16 ; i++) |
rvasquez6089 | 0:1ecf26e0cf3c | 35 | { |
rvasquez6089 | 0:1ecf26e0cf3c | 36 | LED[i].PCALib = this; |
rvasquez6089 | 0:1ecf26e0cf3c | 37 | LED[i].LEDnum = i; |
rvasquez6089 | 0:1ecf26e0cf3c | 38 | } |
rvasquez6089 | 0:1ecf26e0cf3c | 39 | } |
rvasquez6089 | 0:1ecf26e0cf3c | 40 | |
rvasquez6089 | 0:1ecf26e0cf3c | 41 | void PCA9685Lib::i2c_probe(void) |
rvasquez6089 | 0:1ecf26e0cf3c | 42 | { |
rvasquez6089 | 0:1ecf26e0cf3c | 43 | printf("Searching for I2C devices...\n"); |
rvasquez6089 | 0:1ecf26e0cf3c | 44 | |
rvasquez6089 | 0:1ecf26e0cf3c | 45 | int count = 0; |
rvasquez6089 | 0:1ecf26e0cf3c | 46 | for (int address=4; address<256; address+=2) { |
rvasquez6089 | 0:1ecf26e0cf3c | 47 | if (!i2c.write(address, NULL, 0)) { // 0 returned is ok |
rvasquez6089 | 0:1ecf26e0cf3c | 48 | printf(" - I2C device found at address 0x%02X\r\n", address); |
rvasquez6089 | 0:1ecf26e0cf3c | 49 | count++; |
rvasquez6089 | 0:1ecf26e0cf3c | 50 | } |
rvasquez6089 | 0:1ecf26e0cf3c | 51 | } |
rvasquez6089 | 0:1ecf26e0cf3c | 52 | printf("%d devices found\r\n", count); |
rvasquez6089 | 0:1ecf26e0cf3c | 53 | } |
rvasquez6089 | 0:1ecf26e0cf3c | 54 | |
rvasquez6089 | 0:1ecf26e0cf3c | 55 | void PCA9685Lib::begin(void) { |
rvasquez6089 | 0:1ecf26e0cf3c | 56 | reset(); |
rvasquez6089 | 0:1ecf26e0cf3c | 57 | } |
rvasquez6089 | 0:1ecf26e0cf3c | 58 | |
rvasquez6089 | 0:1ecf26e0cf3c | 59 | void PCA9685Lib::setI2Cfreq(int freq) { |
rvasquez6089 | 0:1ecf26e0cf3c | 60 | i2c.frequency(freq); |
rvasquez6089 | 0:1ecf26e0cf3c | 61 | } |
rvasquez6089 | 0:1ecf26e0cf3c | 62 | |
rvasquez6089 | 0:1ecf26e0cf3c | 63 | void PCA9685Lib::reset(void) { |
rvasquez6089 | 0:1ecf26e0cf3c | 64 | write8(PCA9685_MODE1, 0x0); |
rvasquez6089 | 0:1ecf26e0cf3c | 65 | } |
rvasquez6089 | 0:1ecf26e0cf3c | 66 | |
rvasquez6089 | 0:1ecf26e0cf3c | 67 | void PCA9685Lib::setPrescale(uint8_t prescale) { |
rvasquez6089 | 0:1ecf26e0cf3c | 68 | uint8_t oldmode = read8(PCA9685_MODE1); |
rvasquez6089 | 0:1ecf26e0cf3c | 69 | uint8_t newmode = (oldmode&0x7F) | 0x10; // sleep |
rvasquez6089 | 0:1ecf26e0cf3c | 70 | write8(PCA9685_MODE1, newmode); // go to sleep |
rvasquez6089 | 0:1ecf26e0cf3c | 71 | wait_ms(5); |
rvasquez6089 | 0:1ecf26e0cf3c | 72 | write8(PCA9685_PRESCALE, prescale); // set the prescaler |
rvasquez6089 | 0:1ecf26e0cf3c | 73 | write8(PCA9685_MODE1, oldmode); |
rvasquez6089 | 0:1ecf26e0cf3c | 74 | wait_ms(5); |
rvasquez6089 | 0:1ecf26e0cf3c | 75 | write8(PCA9685_MODE1, oldmode | 0xa1); |
rvasquez6089 | 0:1ecf26e0cf3c | 76 | } |
rvasquez6089 | 0:1ecf26e0cf3c | 77 | |
rvasquez6089 | 0:1ecf26e0cf3c | 78 | void PCA9685Lib::setPWMFreq(float freq) { |
rvasquez6089 | 0:1ecf26e0cf3c | 79 | //Serial.print("Attempting to set freq "); |
rvasquez6089 | 0:1ecf26e0cf3c | 80 | //Serial.println(freq); |
rvasquez6089 | 0:1ecf26e0cf3c | 81 | float prescaleval = 25000000; |
rvasquez6089 | 0:1ecf26e0cf3c | 82 | prescaleval /= 4096; |
rvasquez6089 | 0:1ecf26e0cf3c | 83 | prescaleval /= freq; |
rvasquez6089 | 0:1ecf26e0cf3c | 84 | //Serial.print("Estimated pre-scale: "); Serial.println(prescaleval); |
rvasquez6089 | 0:1ecf26e0cf3c | 85 | uint8_t prescale = floor(prescaleval + 0.5) - 1; |
rvasquez6089 | 0:1ecf26e0cf3c | 86 | //Serial.print("Final pre-scale: "); Serial.println(prescale); |
rvasquez6089 | 0:1ecf26e0cf3c | 87 | setPrescale(prescale); |
rvasquez6089 | 0:1ecf26e0cf3c | 88 | } |
rvasquez6089 | 0:1ecf26e0cf3c | 89 | |
rvasquez6089 | 0:1ecf26e0cf3c | 90 | void PCA9685Lib::setPWM(uint8_t num, uint16_t on, uint16_t off) { |
rvasquez6089 | 0:1ecf26e0cf3c | 91 | // hmm doesnt work, whyso? ( Not in AI mode. See line 54 above. ( Works now!! :D ) |
rvasquez6089 | 0:1ecf26e0cf3c | 92 | |
rvasquez6089 | 0:1ecf26e0cf3c | 93 | char cmd[5]; |
rvasquez6089 | 0:1ecf26e0cf3c | 94 | cmd[0] = LED0_ON_L + 4 * num; |
rvasquez6089 | 0:1ecf26e0cf3c | 95 | cmd[1] = on; |
rvasquez6089 | 0:1ecf26e0cf3c | 96 | cmd[2] = on >> 8; |
rvasquez6089 | 0:1ecf26e0cf3c | 97 | cmd[3] = off; |
rvasquez6089 | 0:1ecf26e0cf3c | 98 | cmd[4] = off >> 8; |
rvasquez6089 | 0:1ecf26e0cf3c | 99 | i2c.write(_i2caddr, cmd, 5); |
rvasquez6089 | 0:1ecf26e0cf3c | 100 | |
rvasquez6089 | 0:1ecf26e0cf3c | 101 | /*write8(LED0_ON_L+4*num, on); |
rvasquez6089 | 0:1ecf26e0cf3c | 102 | write8(LED0_ON_H+4*num, on >> 8); |
rvasquez6089 | 0:1ecf26e0cf3c | 103 | write8(LED0_OFF_L+4*num, off); |
rvasquez6089 | 0:1ecf26e0cf3c | 104 | write8(LED0_OFF_H+4*num, off >> 8);*/ |
rvasquez6089 | 0:1ecf26e0cf3c | 105 | } |
rvasquez6089 | 0:1ecf26e0cf3c | 106 | |
rvasquez6089 | 0:1ecf26e0cf3c | 107 | // Set pwm duty in us order |
rvasquez6089 | 0:1ecf26e0cf3c | 108 | void PCA9685Lib::setDuty(uint8_t num, uint16_t duty) { |
rvasquez6089 | 0:1ecf26e0cf3c | 109 | float pulselength = 10000; // 10,000 us per second |
rvasquez6089 | 0:1ecf26e0cf3c | 110 | duty = 4094 * duty / pulselength; |
rvasquez6089 | 0:1ecf26e0cf3c | 111 | setPWM(num, 0, duty); |
rvasquez6089 | 0:1ecf26e0cf3c | 112 | } |
rvasquez6089 | 0:1ecf26e0cf3c | 113 | |
rvasquez6089 | 0:1ecf26e0cf3c | 114 | uint8_t PCA9685Lib::read8(char addr) { |
rvasquez6089 | 0:1ecf26e0cf3c | 115 | i2c.write(_i2caddr, &addr, 1); |
rvasquez6089 | 0:1ecf26e0cf3c | 116 | char rtn; |
rvasquez6089 | 0:1ecf26e0cf3c | 117 | i2c.read(_i2caddr, &rtn, 1); |
rvasquez6089 | 0:1ecf26e0cf3c | 118 | return rtn; |
rvasquez6089 | 0:1ecf26e0cf3c | 119 | } |
rvasquez6089 | 0:1ecf26e0cf3c | 120 | |
rvasquez6089 | 0:1ecf26e0cf3c | 121 | void PCA9685Lib::write8(char addr, char d) { |
rvasquez6089 | 0:1ecf26e0cf3c | 122 | char cmd[2]; |
rvasquez6089 | 0:1ecf26e0cf3c | 123 | cmd[0] = addr; |
rvasquez6089 | 0:1ecf26e0cf3c | 124 | cmd[1] = d; |
rvasquez6089 | 0:1ecf26e0cf3c | 125 | i2c.write(_i2caddr, cmd, 2); |
rvasquez6089 | 0:1ecf26e0cf3c | 126 | } |
rvasquez6089 | 0:1ecf26e0cf3c | 127 | |
rvasquez6089 | 0:1ecf26e0cf3c | 128 |