Le matrici led sono dispositivi che si prestano ad essere utilizzati in molti progetti ed esperimenti con Arduino grazie alla loro estrema versatilità e semplicità di utilizzo; in questo articolo cercherò di mettere in luce gli aspetti fondamentali legati al loro collegamento con Arduino e alla programmazione degli sketch nel caso delle matrici controllate tramite il circuito integrato MAX7219.

 

matrice led 8x8Figura 1: Una matrice LED 8×8 montata su modulo con controller MAX 7219

 

Collegamenti hardware

Iniziamo con l’analizzare quali siano i collegamenti da effettuare tra il modulo e Arduno. Il modulo presenta cinque pin VCC, GND, DIN, CS e CLK, il cui compito è, nell’ordine: positivo alimentazione, negativo alimentazione, ingresso dati seriali, selezione dispositivo e clock. Questi pin andranno collegati ad altrettanti pin di Arduino come indicato nella tabella di Figura 2.

 

tabella-collegmento-arduino-max7219Figura 2: collegamenti MAX 7219 – Arduino

 

Trasmissione dei dati

I dati trasmessi devono avere un formato ben definito affinché il controller della matrice li interpreti in modo corretto. Il formato dei dati si può ricavare dal datasheet del MAX 7219:

 

max7219 formato datiFigura 3: Formato dati MAX 7219
(Fonte: datasheet Maxim Integrated Products 19-4452)

 

I bit saranno caricati nel buffer di Figura 3 e 4 a partire da D0, andranno quindi inviati in “ordine inverso” cioè a partire dai quattro bit più a sinistra (quelli con la X in Figura 3, il cui valore verrà ignorato), seguiti dai quattro bit dell’indirizzo e completati dagli 8 bit dei dati.

max7219 caricamento buffer datiFigura 4: Schema del buffer di ingresso
(Fonte: datasheet Maxim Integrated Products 19-4452)

 

Per trasmettere i sedici bit che costituiscono un comando si può utilizzare la libreria SPI oppure scrivere una semplice funzione per il trasferimento dei dati come quella riportata qui sotto:

void writeByte(byte data) 
{   
  for(byte i=0;i<8;i++)
  {          
    digitalWrite(currentClkPin,LOW);
    digitalWrite(currentDinPin,data&0x80);
    data = data<<1;
    digitalWrite(currentClkPin,HIGH);
  }
}
void write(byte address, byte data)
{
        digitalWrite(currentCSPin,LOW);
        writeByte(address);
        writeByte(data);
        digitalWrite(currentCSPin,HIGH);
}

 

La prima funzione si occupa di scrivere un singolo byte, passato come primo parametro, bit per bit iniziando da quello più significativo (data&0x80), alzando ed abbassando opportunamente la linea di clock e facendo uno shift dei dati verso sinistra per ogni ciclo di clock.

La seconda funzione invia all’indirizzo specificato dal primo parametro il dato passato come secondo paramentro e si preoccupa di generare un fronte si salita sul pin CS.

I più attenti avranno sicuramente individuato tre variabili non definite nello snippet di codice riportato qui sopra:

  • currentClkPin
  • currentCSPin
  • currentDinPin

Nel caso delle due funzioni prese autonomamente per comandare un singolo modulo andranno definite come variabili globali e rappresenteranno nell’ordine:

  • Il pin di Arduino a cui è collegato il pin CLK (clock) del modulo
  • Il pin di Arduino a cui è collegato il pin CS (chip select) del modulo
  • Il pin di Arduino a cui è collegato il pin DIN (data in) del modulo

Con riferimento alla tabella di figura 2 (collegamenti MAX 7219 – Arduino) il codice di inizializzazione delle variabili globali da inserire all’inizio dello sketch sarà:

int currentClkPin=2;
int currentCSPin=3;
int currentDinPin=4;

 

Inizializzazione di Arduino

La prima cosa da fare, dal punto di vista software, prima di poter iniziare ad accendere i led della matrice è inizializzare i pin necessari per la comunicazione tra Arduino e il controller MAX7219. Per farlo è necessario impostare in OUTPUT i tre pin Clk, Cs e Din e dare loro i valori iniziali, rispettivamente LOW, LOW, LOW.

Il pin CS, anche se il nome può trarre in inganno, serve a trasferire i bit caricati nello shift register del controller ai registri veri e propri: quando sul pin CS si verifica una transizione LOW->HIGH, i bit di dati vengono effettivamente caricati nel registro indicato dai bit di indirizzo.

Quindi, indipendentemente dal fatto che nello shift register ci siano dei dati, questi verranno effettivamente recepiti dal controller solo a seguito di un passaggio LOW->HIGH del pin CS (questo diventerà molto importatnte quando si andrà a lavorare con più di una matrice).

La funzione setup() dello sketch inizierà quindi nel modo seguente:

void setup()
{
  pinMode(currentClkPin,OUTPUT);
  pinMode(currentDinPin,OUTPUT);
  pinMode(currentCSPin,OUTPUT);

  digitalWrite(currentCSPin,LOW);
  digitalWrite(currentClkPin,LOW);
  digitalWrite(currentDinPin,LOW);

 

Inizializzazione della matrice

Ora che sono impostati correttamente i pin di Arduino possiamo passare a inviare i dati di inizializzazione del controller del modulo. I dati da inviare per una inizializzazione sicura sono i seguenti:

  • Metodo di decodifica: nessuna decodifica
  • Cifre del display: 7
  • Spegnimento: No
  • Test display: No

L’invio dei dati si effettua scrivendo il valore desiderato all’indirizzo dell’opzione corrispondente. In pratica si vanno a riempire i valori dei registri che il controller utilizza per svolgere il suo compito.

Oltre ai quattro registri indicati sopra dai datasheet si può individuare un quinto registro che permette di determinare la luminosità dei led della matrice.

  • Luminosità: 3

Sempre dai datasheet si può ricavare l’indirizzo di ciascuno dei registri:

 

max7219-full-registers-table
Tabella 1: Elenco dei registri e relativi indirizzi del MAX 7219
(Fonte: Datasheets Maxim Integrated Products)

 

Il codice di inizializzazione della matrice da aggiungere alla funzione setup() sarà quindi:

  write(0x09, 0x00);       //decode (always no decode)
  write(0x0a, 0x03);       //Brightness (0..15)
  write(0x0b, 0x07);       //Display digits (always 7, digit = column)
  write(0x0c, 0x01);       //Shutdown (0x01 Normal | 0x00 Shutdown)
  write(0x0f, 0x00);       //Display test (0x01 Test | 0x00 Normal)

 

Inviare le informazioni di accensione dei LED

Ora che la matrice, o meglio il suo controller è correttamente inizializzato, è possibile passare alla trasmissione dei dati di accensione dei singoli LED.

I LED sono organizzati sulla matrice in 8 colonne ciascuna composta da 8 LEDs. Per ciascuna colonna esiste un registro a 8 bit identificato da uno specifico indirizzo. I LED di ogni colonna sono accesi o spenti in funzione di come sono impostati gli 8 bit del suo registro.

disposizione-LEDs
Figura 5: Disposizione dei LEDs nella matrice

 

I registri che controllano lo stato dei LED si trovano agli indirizzi che vanno da 0x01 a 0x08; i valori da assegnare ai singoli registri possono essere calcolati come indicato più avanti. In generale il più semplice codice da aggiungere allo sketch per impostare i led accesi e spenti sarà simile al seguente:

  write(0x01, 0xff);       // digit 0 -> first column
  write(0x02, 0x81);       // digit 1
  write(0x03, 0x81);       // digit 2
  write(0x04, 0x81);       // digit 3
  write(0x05, 0x81);       // digit 4
  write(0x06, 0x81);       // digit 5
  write(0x07, 0x81);       // digit 6
  write(0x08, 0xff);       // digit 7 -> last column
}

 

Per completare questo sketch non dimenticate la funizione loop() che in questo caso sarà vuota.

void loop()
{
}

 

Calcolo del valore dei registri

Per calcolare il valore dei registri in modo semplice e veloce è sufficiente associare ad ogni LED di una colonna un valore progressivo a partire dal primo verso l’ottavo in questa successione: 1, 2, 4, 8, 16, 32, 64, 128.

Poi, partendo da zero si sommano i valori corrispondenti ai LED che si vogliono accendere. Ad esempio: se volessimo accendere il secondo e il quarto led di una colonna dovremmo impostare il relativo registro a 10. (2+8 cioè il valore associato al secondo led della colonna + il valore associato al quarto led della colonna).

 

Lo sketch completo

Riassumento i passaggi fondamentali sono:

  • Cablaggio
  • Inizializzazione variabili global (Pin Arduino per DIN/CS/CLK)
  • Inizializzazione pin Arduino (in OUTPUT e con i valori inizali corretti)
  • Inizializzazione controller (invio dati configurazione registri da 0x09 a 0x0f)
  • Inizializzazione stato dei LED (invio dati configurazione registri da 0x01 a 0x08)

 

Lo sketch definitivo per questo progetto è dunque:

int currentClkPin=2;
int currentCSPin=3;
int currentDinPin=4;

void writeByte(byte data) 
{   
  for(byte i=0;i<8;i++)
  {          
    digitalWrite(currentClkPin,LOW);
    digitalWrite(currentDinPin,data&0x80);
    data = data<<1;
    digitalWrite(currentClkPin,HIGH);
  }
}

void write(byte address, byte data)
{
        digitalWrite(currentCSPin,LOW);
        writeByte(address);
        writeByte(data);
        digitalWrite(currentCSPin,HIGH);
} 

void setup() 
{
   pinMode(currentClkPin,OUTPUT);
   pinMode(currentDinPin,OUTPUT);
   pinMode(currentCSPin,OUTPUT);
   digitalWrite(currentClkPin,LOW);
   digitalWrite(currentDinPin,LOW);
   digitalWrite(currentCSPin,LOW);

   write(0x09, 0x00);       //decode (always no decode)
   write(0x0a, 0x03);       //Brightness (0..15)
   write(0x0b, 0x07);       //Display digits (always 7, digit = column)
   write(0x0c, 0x01);       //Shutdown (0x01 Normal | 0x00 Shutdown)
   write(0x0f, 0x00);       //Display test (0x01 Test | 0x00 Normal)

   write(0x01, 0xff);       // digit 0 -> first column
   write(0x02, 0x81);       // digit 1
   write(0x03, 0x81);       // digit 2
   write(0x04, 0x81);       // digit 3
   write(0x05, 0x81);       // digit 4
   write(0x06, 0x81);       // digit 5
   write(0x07, 0x81);       // digit 6
   write(0x08, 0xff);       // digit 7 -> last column

}

void loop() 
{
 
}

 

Se sulla vostra matrice è comparso un quadrato, allora tutto è andato per il meglio! In caso contrario non vi scoraggiate e ripercorrete passo passo tutte le operazioni, vedrete che alla fine tutto funzionerà! In ogni caso ricordatevi di seguire Sisuino BLOG!!! Alla prossima.

 

QuadratoSuMatriceLED

 Figura 6: Risultato dello sketch di questo progetto