Adafruit_PWM Arduino Sketch

This sketch is used by Exercise: Adafruit PWM I2C Module.

Full Source Code

The main code is in Adafruit_PWM.ino.

 1/*************************************************** 
 2  This is an example for our Adafruit 16-channel PWM & Servo driver
 3  PWM test - this will drive 16 PWMs in a 'wave'
 4
 5  Pick one up today in the adafruit shop!
 6  ------> http://www.adafruit.com/products/815
 7
 8  These displays use I2C to communicate, 2 pins are required to  
 9  interface. For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4
10
11  Adafruit invests time and resources providing this open source code, 
12  please support Adafruit and open-source hardware by purchasing 
13  products from Adafruit!
14
15  Written by Limor Fried/Ladyada for Adafruit Industries.  
16  BSD license, all text above must be included in any redistribution
17 ****************************************************/
18
19#include <Wire.h>
20// #include <Adafruit_PWMServoDriver.h>
21#include "Adafruit_PWMServoDriver.h"
22
23// called this way, it uses the default address 0x40
24Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
25// you can also call it with a different address you want
26//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
27
28void setup() {
29  Serial.begin(9600);
30  Serial.println("16 channel PWM test!");
31
32  // if you want to really speed stuff up, you can go into 'fast 400khz I2C' mode
33  // some i2c devices dont like this so much so if you're sharing the bus, watch
34  // out for this!
35
36  pwm.begin();
37  pwm.setPWMFreq(1600);  // This is the maximum PWM frequency
38    
39  // save I2C bitrate
40  uint8_t twbrbackup = TWBR;
41  // must be changed after calling Wire.begin() (inside pwm.begin())
42  TWBR = 12; // upgrade to 400KHz!
43    
44}
45
46void loop() {
47  // Drive each PWM in a 'wave'
48  for (uint16_t i=0; i<4096; i += 8) {
49    for (uint8_t pwmnum=0; pwmnum < 16; pwmnum++) {
50      pwm.setPWM(pwmnum, 0, (i + (4096/16)*pwmnum) % 4096 );
51    }
52  }
53}

The supporting code is in Adafruit_PWM.ino.

  1/*************************************************** 
  2  This is a library for our Adafruit 16-channel PWM & Servo driver
  3
  4  Pick one up today in the adafruit shop!
  5  ------> http://www.adafruit.com/products/815
  6
  7  These displays use I2C to communicate, 2 pins are required to  
  8  interface. For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4
  9
 10  Adafruit invests time and resources providing this open source code, 
 11  please support Adafruit and open-source hardware by purchasing 
 12  products from Adafruit!
 13
 14  Written by Limor Fried/Ladyada for Adafruit Industries.  
 15  BSD license, all text above must be included in any redistribution
 16 ****************************************************/
 17
 18// #include <Adafruit_PWMServoDriver.h>
 19#include "Adafruit_PWMServoDriver.h"
 20#include <Wire.h>
 21#if defined(__AVR__)
 22 #define WIRE Wire
 23#elif defined(CORE_TEENSY) // Teensy boards
 24 #define WIRE Wire
 25#else // Arduino Due
 26 #define WIRE Wire1
 27#endif
 28
 29// Set to true to print some debug messages, or false to disable them.
 30#define ENABLE_DEBUG_OUTPUT true
 31
 32Adafruit_PWMServoDriver::Adafruit_PWMServoDriver(uint8_t addr) {
 33  _i2caddr = addr;
 34}
 35
 36void Adafruit_PWMServoDriver::begin(void) {
 37 WIRE.begin();
 38 reset();
 39}
 40
 41
 42void Adafruit_PWMServoDriver::reset(void) {
 43 write8(PCA9685_MODE1, 0x0);
 44}
 45
 46void Adafruit_PWMServoDriver::setPWMFreq(float freq) {
 47  //Serial.print("Attempting to set freq ");
 48  //Serial.println(freq);
 49  freq *= 0.9;  // Correct for overshoot in the frequency setting (see issue #11).
 50  float prescaleval = 25000000;
 51  prescaleval /= 4096;
 52  prescaleval /= freq;
 53  prescaleval -= 1;
 54  if (ENABLE_DEBUG_OUTPUT) {
 55    Serial.print("Estimated pre-scale: "); Serial.println(prescaleval);
 56  }
 57  uint8_t prescale = floor(prescaleval + 0.5);
 58  if (ENABLE_DEBUG_OUTPUT) {
 59    Serial.print("Final pre-scale: "); Serial.println(prescale);
 60  }
 61  
 62  uint8_t oldmode = read8(PCA9685_MODE1);
 63  uint8_t newmode = (oldmode&0x7F) | 0x10; // sleep
 64  write8(PCA9685_MODE1, newmode); // go to sleep
 65  write8(PCA9685_PRESCALE, prescale); // set the prescaler
 66  write8(PCA9685_MODE1, oldmode);
 67  delay(5);
 68  write8(PCA9685_MODE1, oldmode | 0xa1);  //  This sets the MODE1 register to turn on auto increment.
 69                                          // This is why the beginTransmission below was not working.
 70  //  Serial.print("Mode now 0x"); Serial.println(read8(PCA9685_MODE1), HEX);
 71}
 72
 73void Adafruit_PWMServoDriver::setPWM(uint8_t num, uint16_t on, uint16_t off) {
 74  //Serial.print("Setting PWM "); Serial.print(num); Serial.print(": "); Serial.print(on); Serial.print("->"); Serial.println(off);
 75
 76  WIRE.beginTransmission(_i2caddr);
 77  WIRE.write(LED0_ON_L+4*num);
 78  WIRE.write(on);
 79  WIRE.write(on>>8);
 80  WIRE.write(off);
 81  WIRE.write(off>>8);
 82  WIRE.endTransmission();
 83}
 84
 85// Sets pin without having to deal with on/off tick placement and properly handles
 86// a zero value as completely off.  Optional invert parameter supports inverting
 87// the pulse for sinking to ground.  Val should be a value from 0 to 4095 inclusive.
 88void Adafruit_PWMServoDriver::setPin(uint8_t num, uint16_t val, bool invert)
 89{
 90  // Clamp value between 0 and 4095 inclusive.
 91  val = min(val, 4095);
 92  if (invert) {
 93    if (val == 0) {
 94      // Special value for signal fully on.
 95      setPWM(num, 4096, 0);
 96    }
 97    else if (val == 4095) {
 98      // Special value for signal fully off.
 99      setPWM(num, 0, 4096);
100    }
101    else {
102      setPWM(num, 0, 4095-val);
103    }
104  }
105  else {
106    if (val == 4095) {
107      // Special value for signal fully on.
108      setPWM(num, 4096, 0);
109    }
110    else if (val == 0) {
111      // Special value for signal fully off.
112      setPWM(num, 0, 4096);
113    }
114    else {
115      setPWM(num, 0, val);
116    }
117  }
118}
119
120uint8_t Adafruit_PWMServoDriver::read8(uint8_t addr) {
121  WIRE.beginTransmission(_i2caddr);
122  WIRE.write(addr);
123  WIRE.endTransmission();
124
125  WIRE.requestFrom((uint8_t)_i2caddr, (uint8_t)1);
126  return WIRE.read();
127}
128
129void Adafruit_PWMServoDriver::write8(uint8_t addr, uint8_t d) {
130  WIRE.beginTransmission(_i2caddr);
131  WIRE.write(addr);
132  WIRE.write(d);
133  WIRE.endTransmission();
134}

The supporting definitions are in Adafruit_PWM.ino.

 1/*************************************************** 
 2  This is a library for our Adafruit 16-channel PWM & Servo driver
 3
 4  Pick one up today in the adafruit shop!
 5  ------> http://www.adafruit.com/products/815
 6
 7  These displays use I2C to communicate, 2 pins are required to  
 8  interface. For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4
 9
10  Adafruit invests time and resources providing this open source code, 
11  please support Adafruit and open-source hardware by purchasing 
12  products from Adafruit!
13
14  Written by Limor Fried/Ladyada for Adafruit Industries.  
15  BSD license, all text above must be included in any redistribution
16 ****************************************************/
17
18#ifndef _ADAFRUIT_PWMServoDriver_H
19#define _ADAFRUIT_PWMServoDriver_H
20
21#if ARDUINO >= 100
22 #include "Arduino.h"
23#else
24 #include "WProgram.h"
25#endif
26
27
28#define PCA9685_SUBADR1 0x2
29#define PCA9685_SUBADR2 0x3
30#define PCA9685_SUBADR3 0x4
31
32#define PCA9685_MODE1 0x0
33#define PCA9685_PRESCALE 0xFE
34
35#define LED0_ON_L 0x6
36#define LED0_ON_H 0x7
37#define LED0_OFF_L 0x8
38#define LED0_OFF_H 0x9
39
40#define ALLLED_ON_L 0xFA
41#define ALLLED_ON_H 0xFB
42#define ALLLED_OFF_L 0xFC
43#define ALLLED_OFF_H 0xFD
44
45
46class Adafruit_PWMServoDriver {
47 public:
48  Adafruit_PWMServoDriver(uint8_t addr = 0x40);
49  void begin(void);
50  void reset(void);
51  void setPWMFreq(float freq);
52  void setPWM(uint8_t num, uint16_t on, uint16_t off);
53  void setPin(uint8_t num, uint16_t val, bool invert=false);
54
55 private:
56  uint8_t _i2caddr;
57
58  uint8_t read8(uint8_t addr);
59  void write8(uint8_t addr, uint8_t d);
60};
61
62#endif