P9813 Driver LED con Arduino Mega è un primo articolo in cui ho voluto sperimentare un uso differente di questo driver per led economico.
Come al solito partiamo dalla premesse:
- Perché stai leggendo un articolo dedicato al P9813 su questo blog ?
- Come mi è venuto in mente di scrivere un’altro articolo su questo driver led ?
Iniziamo con ordine:
Perché stai leggendo un articolo dedicato al P9813 su questo blog ?
Qualche settimana fa ero alla ricerca di un driver di controllo per luci a led di tipo differente dai neopixel.
In particolare ero alla ricerca di un deriver per led ad almeno 6 o 9 canali con cui accendere, spegnere in modo preciso alcune catene di led.
Inoltre doveva essere un driver sufficientemente piccolo da poter essere posizionato in un progetto senza occupare troppo spazio e in grado di controllare led anche a 12v.
Ed ecco che la ricerca mi ha portato al P9813:
che, sebbene abbia solo 3 canali, usando soli 2 pin per ogni driver mi permette di creare un semplice driver a 9 canali acquistandone 3 ( link per acquisto )
Le specifiche indicano che il modulo è in grado di controllare strisce di led fino a 72W che a 12v equivale a circa 6A;
devi dividere tale valore per i 3 canali, per cui arrivi a circa 2A per canale.
Come mi è venuto in mente di scrivere un’altro articolo su questo driver led ?
ho deciso di scrivere un articolo sul P9813 Driver LED con Arduino Mega inn quanto è facile trovare esempi ed applicazioni che controllano strisce di led RGB usando la libreria FastLED con questo driver, tuttavia diventa complicato se vuoi controllare ogni singolo canale in modo indiendente.
Ed è proprio quello che mi occorre, avere uno sketch arduino in grado di controllare singolarmente i canali del P9813 senza l’uso di una libreria.
Ecco come puoi fare:
P9813 Driver LED con Arduino Mega
Per controllare il P9813 Driver LED con Arduino Mega ho scritto uno sketch che lasciasse a te la possibilità di accendere solo 1, 2 o tutti e 3 i canali del P9813.
ed ho realizzato un semplice video del montaggio che ti propongo qui:
in cui puoi vedere da due angolazioni le fasi di montaggio dei componenti e di connessione dei 3 led.
Ovviamente nell’esempio ho connesso un solo led per ciascun canale solo a scopo dimostrativo per il codice che leggerai di seguito.
P9813 Driver LED Arduino schema
Sebbene nel video avrai visto molto bene come collegare il P9813 Driver LED con Arduino Mega ti propongo lo schema seguente:
in cui i collegamenti sono schematizzati in modo davvero semplice.
come avrai notato ho rispettato anche i colori dei cavetti che ho utilizzato nell’esperimento fatto nel video in modo che questo possa agevolarti e semplificarti la fase di realizzazione.
P9813 Driver LED sketch
Infine passiamo allo sketch che non è tra i più semplici che io abbia scritto e proposto:
// Definizione dei pin #define DATA_PIN 6 #define CLOCK_PIN 7 // Funzione per inviare un bit al P9813 void sendBit(bool bitVal) { digitalWrite(CLOCK_PIN, LOW); digitalWrite(DATA_PIN, bitVal ? HIGH : LOW); digitalWrite(CLOCK_PIN, HIGH); } // Funzione per inviare un byte al P9813 void sendByte(uint8_t data) { for (int i = 0; i < 8; i++) { sendBit(data & 0x80); data <<= 1; } } // Funzione per inviare un colore (R, G, B) al modulo P9813 void sendColor(uint8_t r, uint8_t g, uint8_t b) { uint8_t flag = 0xC0 | ((~b >> 6) & 0x30) | ((~g >> 4) & 0x0C) | ((~r >> 2) & 0x03); // Invia i 4 byte di intestazione for (int i = 0; i < 4; i++) sendByte(0x00); // Invia il flag e i colori sendByte(flag); sendByte(b); sendByte(g); sendByte(r); // Invia i 4 byte di terminazione for (int i = 0; i < 4; i++) sendByte(0x00); } void setup() { pinMode(DATA_PIN, OUTPUT); pinMode(CLOCK_PIN, OUTPUT); digitalWrite(DATA_PIN, LOW); digitalWrite(CLOCK_PIN, LOW); } void loop() { sendColor(255, 0, 0); // Rosso delay(1000); sendColor(0, 255, 0); // Verde delay(1000); sendColor(0, 0, 255); // Blu delay(1000); }
ma che analizzato linea per linea sarà di migliore comprensione:
le linee 02-03: definisci i due pin a cui hai connesso rispettivamnete il pin di DATA e quello di CLOCK;
le linee 06-09: definiscono la funzione sendBit che accetta come parametro bitVal, tale valore sarà il bit inviato al driver P9813 ogni volta che viene richiamata; in particolare puoi osservare che al suo interno esegue in sequenza:
- digitalWrite(CLOCK_PIN, LOW);
- digitalWrite(DATA_PIN, bitVal ? HIGH : LOW);
- digitalWrite(CLOCK_PIN, HIGH);
la prima operazione porta il pin di Clock a 0 ( Low );
la seconda invia sul pin DATA un valore corrispondente al bitVal ricevuto;
la terza operazione porta il pin di Clock a 1 ( High );
ogni volta che la richiami eseguirà l’invio del bit dato al driver RGB;
linea 13: definisci la funzione sendByte che, come avrai capito, invia l’intero Byte, ossia 8 bit, ricevuto nel parametro data al P9813, vediamo come:
linea 14: crea un ciclo for da 0 a 7;
linea 15: l’operazione data & 0x80
estrae il bit più significativo del byte data
:
-
0x80
in binario è10000000
-
Facendo
data & 0x80
, ottieni:-
1
se il bit più significativo didata
è1
-
0
se il bit più significativo didata
è0
-
tale valore è passato alla funzione sendBit()
, che esegue quanto descritto sopra.
la linea 16: esegue l’operazionedata <<= 1
che sposta tutti i bit di data
a sinistra di una posizione;
in questo modo il secondo bit più significativo diventa il primo e nel prossimo ciclo del for
, la stessa operazione sarà eseguita sul nuovo bit più significativo.
Notice
Esempio pratico
Se data = 0b10101010 ( 170 in decimale), il ciclo eseguirà:
1. sendBit(1) // 10101010 & 10000000 → 10000000 (1)
2. sendBit(0) // 01010100 & 10000000 → 00000000 (0)
3. sendBit(1) // 10101000 & 10000000 → 10000000 (1)
4. sendBit(0) // 01010000 & 10000000 → 00000000 (0)
5. sendBit(1) // 10100000 & 10000000 → 10000000 (1)
6. sendBit(0) // 01000000 & 10000000 → 00000000 (0)
7. sendBit(1) // 10000000 & 10000000 → 10000000 (1)
8 sendBit (0) // 00000000 & 10000000 → 00000000 (0)
Così, il byte 10101010 viene trasmesso bit per bit al P9813.
linea 22: definisci la funzione sendColor() che accetta come parametri di ingresso 3 valori a 8 bit uno per ciascun canale da controllare, il primo per il rosso, il secondo per il verde ed il terzo per il blu.
concentriamoci un attimo sulle linee 23-25 perchè servono a comporre il byte colore come lo vuole il P9813
Important!
E’ importante sapere alcune informazioni sul formato di dati voluto dal P9813, il driver si aspetta un byte così definito:
[Flag] [B] [G] [R]
il “FLAG” è il valore binario un po’ più complesso da calcolare in quanto deve essere composto così:
0b11rrggbb
in cui, escludendo la notazione 0b, il valore binario è il seguente:
- 11 valore fissso ( 0x0C );
- rr è il risultato del valore invertito (~) dal parametro r e dopo una operazione di & bitwise con maschera 0x30 ( 00110000 )
- gg è il risultato del valore invertito (~) dal parametro g e dopo una operazione di & bitwise con maschera 0x0C ( 00001100 )
- bb è il risultato del valore invertito (~) dal parametro g e dopo una operazione di & bitwise con maschera 0x03 ( 00000011 )
L’inversione (~
) è necessaria perché il P9813 lavora con valori negati.
facendo un esempio per i valori ( r=255, g=0, b=0 ):
r = 255; // 0b11111111
g = 0; // 0b00000000
b = 0; // 0b00000000
prima inverti i valori:
~r = 0b00000000
~g = 0b11111111
~b = 0b11111111
poi esegui le operazioni si shift e maschera:
(~b >> 6) & 0x30 → (0b11111111 >> 6) & 0b00110000 → 0b00000011 & 0b00110000 → 0b00110000
(~g >> 4) & 0x0C → (0b11111111 >> 4) & 0b00001100 → 0b00001111 & 0b00001100 → 0b00001100
(~r >> 2) & 0x03 → (0b00000000 >> 2) & 0b00000011 → 0b00000000 & 0b00000011 → 0b00000000
Attenzione che si parte dal BLU ( b ), poi il VERDE ( g ) ed infine il ROSSO ( r ).
Il risultato lo ottieno usnado l’operatore OR ( | ) e sarà:
0b11000000 | 0b00110000 | 0b00001100 | 0b00000000 → 0b11111100 = 0xFC
So che all’inizio queste operazioni sono un po’ complesse ma con un po’ di pratica vedrai che sarà sempre più semplice.
Questa è certamente la parte più complessa dello sketch ed ha lo scopo di formare la variabile “flag” che, inviata prima degli altri byte annuncia al P9813 come leggere i valori che gli arriveranno dopo.
Continuiamo con la linea 28 che invia al driver led RGB una sequenza di 4 byte a 0, infatti la notazione esadecimale 0x00 equivale a 0x00000000 ossia 0;
le linee 31-34: inviano in sequenza: il flag, il byte di colore blu, il byte di colore verde ed il byte di colore rosso;
infine la linea 37 si comporta allo stesso modo della linea 28 ed invia una sequenza di 4 byte a 0;
Notice
in pratica se trascrivessimo la comunicazione per l’esempio appena visto avremmo:
[00000000] [00000000] [00000000] [00000000] // Intestazione
[11111100] [00000000] [00000000] [11111111] // Dati colore
[00000000] [00000000] [00000000] [00000000] // Terminazione
che ricevuti dal P9813 Driver LED con Arduino Mega accenderà alla massima luminosità il led rosso e terrà spenti i colori verde e blu.
Dopo tutte le operazioni bitwise, invio di dati e clock passiamo alle nostre due amate, semplici funzioni setup() e loop():
void Setup()
linee 41-42: impostano i pin di DATA e CLOCK in modalità OUTPUT in quanto dovranno uscire i segnali per arrivare al driver rgb;
le linee 43-44: imposta a 0 ( LOW ) il segnale inviato su questi due pin.
Diciamo che è davvero semplice come funzione grazie alla complessità delle funzioni che la precedono;
void loop()
nello sketch del P9813 Driver LED con Arduino Mega anche la funzione di loop() è semplice, accende in sequenza i 3 led come hai visto al termine del video, con un intervallo di 1 seconfdo ( 1000 millisecondi ).
la linea 48: usa la funzione sendColor() per inviare il colore “rosso” ( 255, 0, 0 );
la linea 49: imposta il tempo di attesa ( delay ) a 1 secondo;
le linee 50-51 e 52-53: eseguono la medesima operazione della 48 e 49 ma per i colori verde e blu.
In casi come questo è più semplice e produttivo creare delle funzioni complesse come le prie viste:
- sendBit()
- send(Byte)
- sendColor()
in modo da rendere più semplice il codice della setup() e della loop().
Questo approccio, che personalmente consiglio, ti permette, una volta testate le funzioni principali di invio informazioni al driver, di procedere speditamente nell’integrazione del codice principale del tuo sketch.
Inoltre predispone le prime funzioni ad essere trasformato in una libreria da includere ed utilizzare senza più preoccuparti dei calcoli bitwise, delle maschere o del protocollo da usare con il P9813.
Se sei interessato a trasformare in una semplice libreria queste funzioni scrivilo nei commenti ed io proverò a scrivere e spiegarti come ottenerla.