Mi sono da poco arrivate quattro matrici LED 8×8 già montate su una pratica schedina dotata di controller, il famoso MAX 7219, e di header già saldati e quindi belle e pronte per essere posizionate su una spaziosa breadboard. Ho già fatto qualche semplice esperimento di base ma ora è il giunto il momento per iniziare un vero e proprio progetto “psichedelico”.

 

matrice led virtuale

 

Nell’ultimo Week End Project (Matrici LED 8×8 con Arduino e MAX7219) troverete alcune informazioni di base per pilotare i singoli moduli 8×8 e una elaborazione del codice di base frutto delle prime sperimentazioni con i nuovi modulini.

L’idea che sta alla base di questo nuovo progetto è dare vita a una libreria per la gestione di matrici multiple attraverso la loro astrazione e la loro combinazione in una unica matrice LED virtuale di dimensioni pari a (Nx8)x8, dove N è il numero di moduli usati. Nel caso preso in esame, con quattro moduli, costruiremo una matrice (4×8)x8 ovvero 32×8.

 

Materiale necessario

Per completare gli esperimenti di questo post sarà necessario avere:

  • 1 Arduino
  • 4 Moduli matrice LED 8×8 con controller MAX 7219
  • 1 Breadboard
  • 28 Ponticelli da breadboard

 

Pilotare le singole matrici 8×8

 matrice led 8x8Figura 1: La matrice 8×8 e il max 7219 montati sul modulo

 

Inizializzare e iniziare ad utilizzare una singola matrice è una operazione piuttosto semplice. Dopo aver effettuato i collegamenti necessari è sufficiente trasmettere i dati corretti sulla linea DIN (data in) sincronizzandoli con il clock inviato sulla linea CLK e impostare la linea CS in modo da generare una transizione LOW->HIGH. Per una dettagliata descrizione di come inizializzare ed utilizzare una matrice singola vi rimando all’articolo: Matrici LED 8×8 con Arduino e MAX7219 linkato all’inizio del post.

Quando vogliamo gestire più matrici contemporaneamente la questione si complica e per collegarle abbiamo a disposizione in linea di massima 2 opzioni:

  • Collegamento in serie
  • Collegamento in parallelo

La differenza sostanziale tra le due opzioni è l’utilizzo delle linee DIN/DOUT e CS e si riflette in come andrà realizzato il software di gestione.

 

Collegamento in serie

Nel collegamento in serie i pin Vcc, GND, CS e CLK di tutti i moduli sono collegati tra loro e ai rispettivi pin di Arduino mentre DIN e DOUT sono collegati in cascata (anche detta daisy chain): il pin DIN del primo modulo sarà collegato al pin di Arduino dal quale usciranno i dati per le matrici, il pin DIN del secondo modulo sarà collegato al pin DOUT del primo, il pin DIN del terzo al DOUT del secondo e così via.

 

matrici LED in serie
Figura 2: Collegamento in serie

Per utilizzare con successo più matrici collegate in questo modo è necessario inviare 16xN bits di dati in modo da riempire tutti gli shift register delle N matrici prima di applicare ai pin CS, collegati in parallelo, la transizione LOW->HIGH.

Per primi andranno inviati i 16 bits da caricare nella ultima matrice della serie, seguiti da quelli per la penultima, fino alla prima. Se una matrice non deve ‘fare niente’ sarà comunque necessario inviare i 16 bits per caricare il suo shift register con un comando NOP (address 0x00, data 0x00).

Il vantaggio risiede nel fatto che indipendentemente dal numero di matrici utilizzate il numero di pin di Arduino necessari è limitato a 3 (Din, Cs e Clk).

Di contro, l’evidente svantaggio è la necessità di inviare una quantità di dati direttamente proporzionale al numero di matrici utilizzato (16xN bits) ogni volta che si deve modificare anche solo un registro di una singola matrice.

 

Collegamento in parallelo

Nel collegamento in parallelo i pin Vcc, GND, CLK e DIN di tutti i moduli sono collegati tra loro e ai rispettivi pin di Arduino mentre i pin CS di ciascun modulo sono collegati in modo indipendente ad altrettanti pin di Arduino (i pin DOUT non vengono utilizzati in questa configurazione).

In questo modo tutti gli shift register dei moduli vengono caricati contemporaneamente con i 16 bit trasmessi con una operazione write, ma solo il modulo che riceverà sul suo pin CS la transizione LOW->HIGH caricherà effettivamente i dati nel registro specificato.

Il vantaggio di questa configurazione è che è possibile indirizzare con una singola operazione di scrittura ogni registro di ogni matrice indipendentemente dal numero di matrici collegate.

L’evidente svantaggio è la necessità di disporre di un pin per matrice per il controllo del segnale CS, quindi N pin CS.

 

matrici LED in paralleloFigura 3: Collegamento in parallelo

 

La scelta per questo progetto

Per questo progetto ho deciso di collegare i moduli secondo lo schema parallelo. Questo perché ho intenzione di sviluppare un sistema di ottimizzazione dei dati inviati che permetta di modificare anche un singolo registro senza dover ritrasmettere tutti i dati di configurazione attraverso tutte le matrici nel momento in cui le variazioni della matrice virtuale lo consentano.

 

max7219 Array test breadboard
Figura 4: Collegamento delle N matrici a Arduino

 

Installazione della libreria

Per installare la libreria è sufficiente scaricare il file compresso linkato qui sotto e scompattarne il contenuto nella cartella delle librerie di Arduino. In alternativa se si utilizza il nuovo IDE 1.6.x è possibile utilizzare la apposita funzione di caricamento semplificato delle librerie.

Dopo aver scaricato il file zip, aprire il menu Sketch, selezionare ‘Include Library’ e poi ‘Add .ZIP Librery…’. A questo punto selezionare il file zip appena scaricato e confermare il caricamento.

 

installazione libreria max7216-array

Figura 5: Installazione della libreria

 

Dopo aver riavviato l’IDE la libreria verrà visualizzata tra le librerie disponibili insieme agli esempi di utilizzo a corredo.

 

esempi libreria arduino max7216 array
Figura 6: Lireria installata nell’IDE

Per chi preferisce, la libreria è disponibile per il download o il checkout anche su github all’indirizzo:

 

Inizializzazione e utilizzo base

Vediamo come iniziare a utilizzare la libreria partendo da uno sketch nuovo. Per prima cosa sarà necessario includere la libreria come di consueto si fa con le librerie built-in:

#include "max7219array.h";

 

Nel caso in cui vogliamo utilizzare le funzioni di scrittura sarà necessario includere anche un “font”, cioè una mappa di come dovranno accendersi i LED quando chiederemo alla libreria di visualizzare delle lettere sulla matrice virtuale. La libreria, oltre a consentire un utilizzo avanzato in cui definire i propri fontfles, offre la possibilità di scegliere tra due font inclusi nel pacchetto:

  • font1: max7219_font_4px.h
  • font2: max7219_font_5px.h

 

#include "max7219_font_4px.h";

 

Poi sarà necessario definire una variabile globale che rappresenti la matrice virtuale:

max7219array myMatrix;

 

Ora la classica funzione setup() in cui effettuare l’inizializzazione vera e propria. In questo caso, come esempio di base, ci limiteremo a inizializzare la matrice virtuale con i 4 moduli collegati come in Figura 4 e scrivere al suo interno la stringa “M-7219”.

Con i metodi setClkPin e setDinPin si potranno specificare quali pin di Arduino utilizzare per il clock e per i dati. In questo caso rispettivamente pin 10 e pin 8:

void setup()
{

    myMatrix.setClkPin(10);
    myMatrix.setDinPin(8);

 

Poi, utilizzando il metodo addModule si potranno ‘presentare’ alla libreria le matrici che compongono l’array e specificare i pin CS che arduino dedicherà a ciascuna matrice:

    myMatrix.addModule(13);
    myMatrix.addModule(12);
    myMatrix.addModule(11);
    myMatrix.addModule(9);

 

A questo punto la libreria si sarà già occupata di inizializzare tutti i moduli e caricare tutti i registri di configurazione dei LED a zero per presentare una matrice virtuale completamente spenta.

Ora è possibile iniziare a ‘disegnare’. Per questo esempio utilizzeremo il metodo plotstring che disegnerà sulla matrice virtuale la stringa passata come argomento usando il font incluso all’inizio dello sketch:

    myMatrix.plotstring("M-7219");

Ultimo ma non meno importante il metodo che consente di visualizzare sugli N moduli reali ciò che è stato disegnato sulla matrice vrtuale:

    myMatrix.flush();
}

 

Chiude lo scketch la funzione loop() che non deve mai mancare:

void loop()
{
    myMatrix.rotateleft();
    myMatrix.flush();
    delay(100);
}

Per questo sketch di esempio, nella funzione loop si effettua ciclicamente, con un periodo di 100 millisecondi, una rotazione di tutti i pixel della matrice virtuale verso sinistra e un flush della matrice virtuale sui moduli fisici per visualizzare effettivamente la rotazione.

 

Prossimi passi

Questa versione è la prima sufficientemente completa e stabile per essere utilizzata, ma presenta ancora alcuni aspetti da sviluppare:

  • Rimuovere il limite per cui permette di aggiungere fino a 8 moduli e alloca il buffer per tutti e 8 staticamente.
  • Non implementa ancora i meccanismi di ottimizzazione del ridisegnao della matrice virtuale.
  • Non implementa ancora i metodi per lo scorrimento di testo la cui dimensione ecceda le dimensioni della matrice virtuale.

In attesa di queste nuove funzionalità e di un nuovo post con i relativi esempi usate i commenti qui sotto per segnalare eventuali comportamenti imprevisti e suggerire nuove funzionalità che pensate debbano essere aggiunte a questa libreria per renderla più adatta alle vostre esigenze.

 

Reference

Qui di seguito riporto tutti i metodi disponibili nella libreria, il formato dei parametri per chiamarli e il loro utilizzo.

Funzioni di inizializzazione

void setClkPin(byte clkPin);
Imposta il pin da utilizzare come linea di clock. Come parametro di deve passare il numero relativo al pin diArduino che verrà collegato a tutti i din CLK delle matrici fisiche.

void setDinPin(byte dinPin);
Imposta il pin da utilizzare come linea dati. Come parametro di deve passare il numero relativo al pin diArduino che verrà collegato a tutti i din DIN delle matrici fisiche.

void addModule(byte moduleCsPin);
Aggiunge un modulo alla matrice virtuale. Come parametro si deve passare il numero relativo al pin da utilizzare per il controllo del segnale CS della matrice che si sta aggiungendo.

void writeByte(byte module, byte data);
Invia un singolo byte al modulo specificato.

void write(byte module, byte address, byte data);
Imposta un registro specifico (parametro address) del modulo indicato (parametro module) con il valore passato nel parametro ‘data’.

void initModule(byte module);
Inizializza il modulo indicato. Viene chiamata automaticamente quando i moduli vengono aggiunti alla matrice virtuale cn addModule.

Funzioni che agiscono su tutti i moduli

void test(byte seconds);
Accende tutti i LED di tutte le matrici per un tempo pari a ‘seconds’ secondi.

void setBrightness(byte brightness);
Imposta la luminosità delle matrici al valore passato nel parametro ‘brightness’. Il valore è un numero da 0 a 15.

void shutdown();
Spegne tutti i LED mantenendo la ultima configurazione di accensione.

void resume();
Riaccende tutti i led con l’ultima configurazione di accensione.

Funzioni di disegno

void plot(byte x,byte y, byte color);
Accende o spegne un singolo LED della matrice virtuale. X rappresenta la colonna, Y la riga e color deve essere 1 per accendere il LED specificato o 0 per spegnerlo.

void plotline(int x1,int y1, int x2, int y2,int color);
Disegna o cancella una linea tra i LED individuati dalle coppie di valori x1,y1 e x2,y2. x1,y1 sono la colonna e la riga del LED di inizio, x2,y2 sono la colonna e la riga del LED di fine e color deve essere 1 per disegnare e 0 per cancellare.

Funzioni testo

void setPos(int x);
Imposta la posizione corrente. La prossima operazione di “stampa” di un testo (lettera o stringa) partirà dalla colonna indicata come parametro.

void plotletter(char letter);
Disegna una lettera nella posizione corrente. char è la lettera da disegnare. Sono diseganbili tutte le lettere e i simboli presenti nel font incluso all’inizio dello scketch.

void plotletterat(int x, char letter);
Disegna una lettera nella posizione specificata. x è la colonna dalla quale inizierà il disegno della lettera, char è la lettera da disegnare. Sono diseganbili tutte le lettere e i simboli presenti nel font incluso all’inizio dello scketch.

void plotstring(char string[]);
Disegna tutti i caratteri della stringa passata come parametro a partire dalla posizione corrente.

Funzioni che agiscono su tutta la matrice virtuale

void rotateleft();
Sposta tutti i pixel (LED) della matrice di una posizione verso sinistra facendo rientrare a destra la prima colonna.

void rotateright();
Sposta tutti i pixel (LED) della matrice di una posizione verso destra facendo rientrare a sinistra l’ultima colonna.

void shiftleft();
Sposta tutti i pixel (LED) della matrice di una posizione verso sinistra inserendo a destra una colonna spenta.

void shiftright();
Sposta tutti i pixel (LED) della matrice di una posizione verso destra inserendo a sinistra una colonna spenta.

void clear();
Spegne tutti i LED della matrice virtuale.

void invert();
Esegue un “not” sullo stato di tutti i LED della matrice. Quelli accesi vengono spenti, quelli spenti vengono accesi.

void flush();
Trasferisce la configurazione della matrice virtuale ai moduli di controllo delle matrici fisiche. Di fatto visualizza sui moduli fisici ciò che è stato disegnato sulla matrice virtuale.