PCA9685 12 bit 16 kanaals led controller

De PCA9685 is een I2C bus gecontroleerde 16 kanaals LED controller voor RoodGroenBlauwAmber gekleurde achtergrond verlichting. Elke uitgang heeft zijn eigen 12 bit (4096 staps) met individuele PWM controller die op een geprogrameerde frequentie van 24 t/m 1526 Hz. (voor alle uitgangen gelijk.)
De PCA9685 is een I2C aangestuurde 16 kanaals 'LED' controller voor b.v. LCD RGBAmber (RGBA) achtergrondlicht. Elke led heeft zijn eigen 12 bit resolutie.(4096 stappen). Elke uitgang kan max. 25mA omlaag trekken en max, 10 mA leveren.
Elke uitgang kan uit/aan of PWM aangestuurd worden. De LED output driver is geprogrameerd om of een open drain met 25 mAmp 5V sink of totempaal met 25 mAmp sink. LEDS kunnen dus direct aangesloten worden tot 25 mAmp 5.5V.

Verschil met de PCA 9635:
De 9635 kan niet elke poort individueel de aan/uit programeren.
De 9635 heeft 256 steps.
Bij meerdere 9635 IC's kan er verschil in frequentie zijn.
De 9635 accepteert geen externe clock puls.
Power-On reset (POR) default state, is hoog bij de 9635.
Denk er aan dat er adres conflikten kunnen komen als de PCA9564 en PCA 9665 ook op de I2C zijn aangesloten.

Maximaal 5V externe voeding via de schroef verbindingen.
werkspanning is 2,3V t/m 5,5V. Dus voor de ESP8266 en Arduino.


Op de rechter bovenkant van de PCA9685 lees je I2C address. Daar boven zitten een rijtje weerstanden en daar boven 6 doorverbind soldeer eilandjes. Door die eilandjes boven-onder met elkaar te verbinden kan je jouw eigen I2C adres aanpassen.
Als ik mijn PCA9685 aansluit op de Arduino Uno en een I2C scanner er op loslaat krijg ik 2 I2C adressen te zien, Hex.40 (binair 0100 0000) en hex.70(binair 0111 0000).
Op https://cdn-shop.adafruit.com/datasheets/PCA9685.pdf lees ik dat er 4 software programeerbare I2C adressen zijn, 1 alle leds uit en 3 leds subcall adressen. Het moet mogelijk zijn dat 1/3 van alle op de I2C bus aangesloten devices met hetzelfde adres via een ander I2C adres aan te sturen. (dat snap ik zelf nog nog niet.)

De PCA9685 is ideaal om de ESP8266 met de 3.3V uitgangen te gebruiken om de 5V componenten aan te sturen. Je kan dus 5V servo's aansturen met de ESP8266 zonder een levelshifter.


I2C adres is standaard 0x40 met 62 mogelijkheden en 2 niet mogelijkheden. De Softreset en LED All Call kunnen niet gebruikt worden omdat ze bij starten altijd op ON staan. Het totaal wordt door subcall address en andere gereserveerde adressen nog verder gereduceerd.
Dec. 64= Hex. 40 = Bin. 1000000
6 Hardware I2C adressen. 40 t/m F7
Er zijn dus 64 mogelijke adressen (62 boards) is max. 62 x PCA9685 maal 16 PWM uitgangen = ca 992 uitgangen!!.
Kijk op de DecHexBin voor de schrijfwijze van de 64 adressen.

De groen gemarkeerde zijn dus zonder doorsolderingen oftewel standaard.

02h subadr1=1110001*
04h subadr1=1110010*
08h subadr1=1110100*
Hierbij is * gereserveerd en kan alleen gelezen worden.
Nadat de subadressen ge programmeerd zijn moet de * bit een 1 worden om de data van het subadr te acconderen.
E0h E1h ALLCALLADR 1110000*
Software Reset 00000110
LED sub Call I2C address:
E2h(0) E3h(1) =11100010
E4h(0) E5h(1) =11100100
E8h(0) E9h(1) =11101000
Achter op het board van mij vind ik de volgende info:
Gebruik V+ voor servo spanning.
VCC 3-5 V
Logic 3-5 V
V+ max. 6V Groene schroefverbinding en rode pin verbinding.
Freq. 40 - 1000 Hz
Terminal block is reverse polarity protected. Side breakout pins are not!!
Hieruit begreep ik dat de PWM V+ en GND pins niet beschermd zijn tegen plus en min verkeerd aansluiten en de andere aansluitingen wel.

Waar ik nog niet uit ben is het volgende:



3 different I2C-bus addresses can be used
Default power-up values:
power up (ALLCALLADR): E0H of 1110 000x
SUBADR1 register: E2h of 1110 001X
SUBADR2 register: E4h of 1110 010X
SUBADR3 register: E8h of 1110 100X
Programeerbaar via I2C-bus (volatile programming)
At power-up, Sub Call I2C-bus addresses are disabled.
PCA9685 zend geen ACK als E2h (R/W=0)
of E3h (R/W= 1), E4h (R/W= 0)
of E5h (R/W=1),
of E8h (R/W= 0)
of E9h (R/W= 1) is sent by the master.
Zie voor meer details Sectie 7.3.6 van de datasheet “SUBADR1 to SUBADR3, I2C-bus subaddress 1 to 3”
De software reset 0000 0001 en moet standaard 0 zijn.(Laatste bitje wat nu 1 is.)
De control register 0000 0000 is D7 t/m D0.
Zie voor alle info de datasheet
Register definities: Hardware adres zonder soldeer doorverbindingen = 0x40 t/m 0x7H met alle solderingen.
Register decimaalregister hex.D7D6D5D4D3D2D1D0Naam TypeFunctie
0 00 0 0 0 0 0 0 0 0 Mode1R/W Mode register 1
1 01 0 0 0 0 0 0 0 1 Mode2R/W Mode register 2
2 02 0 0 0 0 0 0 1 0 Subadres1R/W I2C subadres 1
3 03 0 0 0 0 0 0 1 1 Subadres2R/W I2C subadres 2
4 04 0 0 0 0 0 1 0 0 Subadres3R/W I2C subadres 3
5 05 0 0 0 0 0 1 0 1 AllCALLADRR/W I2C All call
6 06 0 0 0 0 0 1 1 0 LED0_ON_LR/W Led 0 PWM byte 0
7 07 0 0 0 0 0 1 1 1 LED0_ON_HR/W Led 0 PWM byte 1
8 08 0 0 0 0 1 0 0 0 LED0_ON_LR/W Led 0 PWM byte 2
9 09 0 0 0 0 1 0 0 1 LED0_ON_HR/W Led 0 PWM byte 3
10 0A 0 0 0 0 1 0 1 0 LED1_ON_LR/W Led 1 PWM byte 0
11 0B 0 0 0 0 1 0 1 1 LED1_ON_HR/W Led 1 PWM byte 1
12 0C 0 0 0 0 1 1 0 0 LED1_ON_LR/W Led 1 PWM byte 2
13 0D 0 0 0 0 1 1 0 1 LED1_ON_HR/W Led 1 PWM byte 3
14 0E 0 0 0 0 1 1 1 0 LED0_ON_LR/W Led 2 PWM byte 0
15 0F 0 0 0 0 1 1 1 1 LED0_ON_HR/W Led 2 PWM byte 1
16 10 0 0 0 0 1 0 0 0 LED0_ON_LR/W Led 2 PWM byte 2
17 11 0 0 0 0 1 0 0 1 LED0_ON_HR/W Led 2 PWM byte 3
18 12 0 0 0 0 1 0 1 0 LED1_ON_LR/W Led 3 PWM byte 0
19 13 0 0 0 0 1 0 1 1 LED1_ON_HR/W Led 3 PWM byte 1
20 14 0 0 0 1 0 1 0 0 LED1_ON_LR/W Led 3 PWM byte 2
21 15 0 0 0 1 0 1 0 1 LED1_ON_HR/W Led 3 PWM byte 3
De lijst gaat door t/m decimaal 69 (hex 45).
Opgemerkt wordt dat all verwijzingen na 69 worden verwezen naar Mode1 register. Auto Increment (automatisch verhogen) werkt dus ook vanaf 250 t/m 254 waar het doorgaat in Mode1(register0).



Tijd om te gaan spelen

De meeste instellingen etc. wordt in dit geval gedaan met de library PCA9685 ledDriver.
Ik zie op de PCA, links 6 pen aansluitingen. Gnd, OE, SCL, SDA, VCC en V+. Die worden op de PCA printplaat doorverbonden naar rechts, zodat je nog een PCA9685 kan aansluiten. Er zijn 6 open adressen A0 t/m A5 waar je een doorsoldeerbrug kan maken. OE = active LOW Output Enable.
Ik heb de OE en V+ niet aangesloten.
Voeding voor de leds kan je beter niet verstrekken via de Arduino 5V. Sluit dus de V+ met schroefaansluiting aan op een externe 5V.

Als je de voorbeelden ziet stelt het niet veel voor, het enige waar je rekening mee moet houden is dat de PCA verbinding maakt naar min. Op de led moet dus voedingspanning plus met de daarbij behorende weerstand en dan naar de PCA.
Je kan dus een hoger spanning dan 5V gebruiken voor de componenten zolang de min maar naar de PCA9685 gaat.
Elke uitgang heeft een 220 Ohm weerstand zodat je een led gewoon aan moet kunnen sluiten.


De ESP kan maximaal 20 V ingangspanning verdragen maar de PCA maar 5 volt. De PCA werkt op 3.3V en kan gevoed worden uit de ESP82866. De verbruikers die aan de PCA aangesloten zijn kan je beter niet uit de ESP8266 voeden. Daar is de V+ aansluiting voor die ook via de schroefaansluiting te voeden is. In het voorbeeld worden de leds en de ESP8266 dus door 9 V gevoed en de PCA door 3.3V

Er zijn er 4 groepen van 3x4 pinnen. Elke groep van 3 heeft een PWM, V+ en Gnd aansluiting. 16 Keer een uitgang PWM naar V+ of naar Gnd.
Per uitgang max. 25 mA bij 5 Volt. Geen ingang functie.

Ik las dat je 4060 stappen heb om de leds te dimmen, in het voorbeeld zijn het er maar 100. Ik heb het vermoeden dat dit komt door de library.
Je kan met PWM, leds, motoren of servo's aansturen. Eerst een voorbeeld met leds:
Aangepaste voorbeeld sketch als je de Lib van adafruit gebruikt:

#include <Wire.h>
#include <PCA9685.h>
int lamp;
int lampoud1;
int lampoud2;
int levelup;
int leveldown;
PCA9685 ledDriver;
void setup()
{
Serial.begin(9600); // start serial
Serial.println("Serial geStart");

Wire.begin(); // Wire starten!
ledDriver.begin(0x40); // standaard adres
ledDriver.init();
lamp=0;

}

void loop()
{
// aan/uit gaan
leveldown=20;
for(levelup=0;levelup<=20;levelup++)
{
ledDriver.setLEDDimmed(lamp,levelup*5);
delay(10);
ledDriver.setLEDDimmed(lampoud2,leveldown*5);
leveldown--;
Serial.print(levelup);
Serial.print("--");
Serial.println(leveldown);
delay(10);
}
// info bewaren van vorige lampstatus
lampoud2=lampoud1;
lampoud1=lamp;
// lamp 1 moet blijven branden
ledDriver.setLEDDimmed(lampoud1,100);
lamp++;
if (lamp >9)
{ lamp=0;}
}


Vervolgens een voorbeeld om met een ESP8266, servo's aan te sturen: het eerste deel is om de servo op nul 0 graden te zetten. Gebruik de volgende sketch en pas de waarden (verhoog/verlaag) bij MIN_PULSE_WIDTH aan tot de gewenste positie is ingesteld.

#include
#include
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);

#define MIN_PULSE_WIDTH 600
#define MAX_PULSE_WIDTH 2600
#define FREQUENCY 50

void setup()
{
pwm.begin();
pwm.setPWMFreq(FREQUENCY);
}

int pulseWidth(int angle)
{
int pulse_wide, analog_value;
pulse_wide = map(angle, 0, 180, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
analog_value = int(float(pulse_wide) / 1000000 * FREQUENCY * 4096);
return analog_value;
}

void loop() {
pwm.setPWM(0, 0, pulseWidth(0));
delay(1000);
}

Nu gaan we ook de maximale uitslag instellen. MAX_PULSE_WIDTH waarde verhogen/verlagen tot de 180 graden hoek gevonden is.

#include
#include
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);

#define MIN_PULSE_WIDTH 600
#define MAX_PULSE_WIDTH 2600
#define FREQUENCY 50

void setup()
{
pwm.begin();
pwm.setPWMFreq(FREQUENCY);
}

int pulseWidth(int angle)
{
int pulse_wide, analog_value;
pulse_wide = map(angle, 0, 180, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
analog_value = int(float(pulse_wide) / 1000000 * FREQUENCY * 4096);
return analog_value;
}

void loop() {
pwm.setPWM(0, 0, pulseWidth(180));
delay(1000);
}
Als we nu de uiterste waarden gevonden hebben gaan we met gebruik makend van de ADAfruit_PWMServoDriver library.

#include Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);
Vervolgens gaan we de minwaarde en maxwaarde instellen die we net gevonden hebben. De meeste servo's gebruiken een frequentie van 50 Hz. Dat is vaak vermeld op de verpakking of op internet bij datasheet merk type moter.

#define MIN_PULSE_WIDTH 600
#define MAX_PULSE_WIDTH 2600
#define FREQUENCY 50

In de setup stellen we dus die frequentie in op 50 Hz.

void setup()
{
pwm.begin();
pwm.setPWMFreq(FREQUENCY);
}
Nu moet er gerekend gaan worden. De gewenste hoek vanaf het 0 punt en maximaal 180 graden. De analoge waarde voor de servo is de puls te vermenigvuldigen met 1.000.000 om microseconden te krijgen, vermenigvuldig dat met de frequentie en 4096 voor een 12 bit resolutie.

int pulseWidth(int angle)
{
int pulse_wide, analog_value;
pulse_wide = map(angle, 0, 180, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
analog_value = int(float(pulse_wide) / 1000000 * FREQUENCY * 4096);
return analog_value;
}
Op elke regel van de loop functie kunnen we elke servo tussen de 0 en de 180 graden instellen. Daarom heeft de PWM.SET functie 3 argumenten:
1) Op welke pin van de PCA9685 is de servo verbonden?(0 t/m 15)
2) Constant 0
3) De hoek die servo moet ingaan.(0 tm 180)
En vervolgens een kleine vertraging om de servo de gelegenheid te geven om het comando uit te voeren voordat de volgende sketch regel uitgevoerd moet worden.


void loop() {
pwm.setPWM(0, 0, pulseWidth(0));
pwm.setPWM(1, 0, pulseWidth(180));
delay(1000);
pwm.setPWM(4, 0, pulseWidth(0));
delay(1000);
pwm.setPWM(0, 0, pulseWidth(180));
pwm.setPWM(1, 0, pulseWidth(90));
delay(500);
pwm.setPWM(4, 0, pulseWidth(180));
delay(1000);
pwm.setPWM(0, 0, pulseWidth(90));
pwm.setPWM(1, 0, pulseWidth(0));
delay(1000);
}
En de hele sketch van https://diyi0t.com/servo-motor-tutorial-for-arduino-and-esp8266/:


#include
#include
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);

#define MIN_PULSE_WIDTH 600
#define MAX_PULSE_WIDTH 2600
#define FREQUENCY 50

void setup()
{
pwm.begin();
pwm.setPWMFreq(FREQUENCY);
}

int pulseWidth(int angle)
{
int pulse_wide, analog_value;
pulse_wide = map(angle, 0, 180, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
analog_value = int(float(pulse_wide) / 1000000 * FREQUENCY * 4096);
return analog_value;
}

void loop() {
pwm.setPWM(0, 0, pulseWidth(0));
pwm.setPWM(1, 0, pulseWidth(180));
delay(1000);
pwm.setPWM(4, 0, pulseWidth(0));
delay(1000);
pwm.setPWM(0, 0, pulseWidth(180));
pwm.setPWM(1, 0, pulseWidth(90));
delay(500);
pwm.setPWM(4, 0, pulseWidth(180));
delay(1000);
pwm.setPWM(0, 0, pulseWidth(90));
pwm.setPWM(1, 0, pulseWidth(0));
delay(1000);
}


bronnen:

diyi0t.com servo-motor-tutorial-for-arduino-and-esp8266
https://www.adafruit.com/product/815
16 servo's
adafruit PCA9685
datasheet
registers
Arduino lib
Fritzing lib
forum.hobbycomponents.com
Youri Van Laer
python
Arduino library