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