// // FILE: PCA9685.cpp // AUTHOR: Rob Tillaart // DATE: 24-apr-2016 // VERSION: 0.1.1 // PURPOSE: I2C PCA9685 library for Arduino // URL: // // HISTORY: // 0.1.0 2016-04-24 initial BETA version // 0.1.1 2019-01-30 testing && fixing // #include #include "PCA9685.h" // check datasheet for details #define PCA9685_MODE1 0x00 #define PCA9685_MODE2 0x01 // MODE1 REGISTERS #define PCA9685_RESTART 0x80 #define PCA9685_EXTCLK 0x40 #define PCA9685_AUTOINCR 0x20 #define PCA9685_SLEEP 0x10 #define PCA9685_SUB1 0x08 #define PCA9685_SUB2 0x04 #define PCA9685_SUB3 0x02 #define PCA9685_ALLCALL 0x01 // MODE2 REGISTERS (see datasheet) #define PCA9685_INVERT 0x10 #define PCA9685_OCH 0x08 #define PCA9685_OUTDRV 0x04 #define PCA9685_OUTNE 0x03 // SPECIAL REGISTER - FREQUENCY #define PCA9685_PRE_SCALE 0xFE // NOT IMPLEMENTED YET #define PCA9685_SUBADR(x) (0x01+(x)) // x = 1..3 #define PCA9685_ALLCALLADR 0x05 #define PCA9685_TESTMODE 0xFF ////////////////////////////////////////////////////////////// PCA9685::PCA9685(const uint8_t deviceAddress) { _address = deviceAddress; _error = 0; } void PCA9685::begin() { Wire.begin(); _error = 0; uint8_t mode1 = PCA9685_AUTOINCR | PCA9685_ALLCALL; writeReg(PCA9685_MODE1, mode1); uint8_t mode2 = PCA9685_OUTDRV; writeReg(PCA9685_MODE2, mode2); } void PCA9685::writeMode(uint8_t reg, uint8_t value) { if (reg != PCA9685_MODE1 && reg != PCA9685_MODE2) { _error = PCA9685_ERR_MODE; return; } writeReg(reg, value); } uint8_t PCA9685::readMode(uint8_t reg) { if (reg != PCA9685_MODE1 && reg != PCA9685_MODE2) { _error = PCA9685_ERR_MODE; return 0; } uint8_t value = readReg(reg); return value; } // write value to single PWM channel void PCA9685::setPWM(uint8_t channel, uint16_t onTime, uint16_t offTime) { if (channel > 15) { _error = PCA9685_ERR_CHANNEL; return; } uint8_t reg = 0x06 + (channel << 2); writeReg2(reg, onTime, offTime); } // write value to single PWM channel void PCA9685::setPWM(uint8_t channel, uint16_t offTime) { setPWM(channel, 0, offTime); } // read value from single PWM channel void PCA9685::getPWM(uint8_t channel, uint16_t* onTime, uint16_t* offTime) { if (channel > 15) { _error = PCA9685_ERR_CHANNEL; return; } uint8_t reg = 0x06 + (channel << 2); Wire.beginTransmission(_address); Wire.write(reg); _error = Wire.endTransmission(); if (Wire.requestFrom(_address, (uint8_t)4) != 4) { _error = PCA9685_ERROR; return; } uint16_t _data = Wire.read(); *onTime = (Wire.read() * 256) + _data; _data = Wire.read(); *offTime = (Wire.read() * 256) + _data; } // set update frequency for all channels void PCA9685::setFrequency(uint16_t freq) { if (freq < 24) freq = 24; if (freq > 1526) freq = 1526; // removed float operation for speed // uint8_t scaler = round(25e6 / (4096 * freq)) - 1; uint8_t scaler = 6104 / freq - 1; writeReg(PCA9685_PRE_SCALE, scaler); } void PCA9685::setON(uint8_t channel) { setPWM(channel, 0x1000, 0x0000); } void PCA9685::setOFF(uint8_t channel) { setPWM(channel, 0x0000, 0x1000); } int PCA9685::lastError() { int e = _error; _error = 0; return e; } void PCA9685::writeReg(uint8_t reg, uint8_t value) { Wire.beginTransmission(_address); Wire.write(reg); Wire.write(value); _error = Wire.endTransmission(); } void PCA9685::writeReg2(uint8_t reg, uint16_t a, uint16_t b) { Wire.beginTransmission(_address); Wire.write(reg); Wire.write(a & 0xFF); Wire.write((a >> 8) & 0x0F); Wire.write(b & 0xFF); Wire.write((b >> 8) & 0x0F); _error = Wire.endTransmission(); } // uint8_t PCA9685::readReg(uint8_t reg) { Wire.beginTransmission(_address); Wire.write(reg); _error = Wire.endTransmission(); if (Wire.requestFrom(_address, (uint8_t)1) != 1) { _error = PCA9685_ERROR; return 0; } uint8_t _data = Wire.read(); return _data; } // // END OF FILE //