MODULI: Esempio DOT MATRIX
Per il nostro esempio è necessario utilizzare una matrice di LED 8x8
Questo modulo è spesso confezionato come matrice di LED dove gli anodi risultano connessi per colonna mentre i catodi per riga (o viceversa). Un LED si accende quando la riga corrispondente al suo catodo è connessa attraverso una resistenza alla terra (LOW) mentre la colonna, corrispondente al suo anodo, è connessa ai +5V. (HIGH)
La matrice 8x8 a LED ha 16 piedini. Ogni piedino è associato ad una riga o ad una colonna. Per controllare la matrice 8x8 a LED tramite Arduino occorre quindi collegare sia le righe che le colonne. Il LED si accende quando il piedino corrispondente alla sua colonna è posto ad HIGH mentre quello relativo alla sua riga è posto a LOW. Se la colonna e la riga non sono posti rispettivamente ad HIGH e LOW nessuna tensione scorre attraverso il LED e quindi questo non si accende.
Ecco qui il tipico schema delle connessioni di una matrice a LED 8x8. COL e ROW si riferiscono alle righe e alle colonne mentre la numerazione sui PIN è relativa alla sua piedinatura.
![]() |
|
Per controllare questo dispositivo, senza l'ausilio di un opportuno integrato, devo utilizzare ben 16 porte di Arduino come si può notare nell'esempio sottostante:
Codice Sorgente A
Obiettivo progetto: Costruire un circuito e un programma che accende in sequenza i LED della matrice come rappresentato in figura
soluzione:
Costruiamo il seguente circuito
Le connessioni sono evidenziate nella seguente tabella:
Pin
Dot Matrix |
Pin Arduino (D)igitale / (A)nalogico |
(R)iga / (C)olonna Dot Matrix |
---|---|---|
1 | D5 | R5 |
2 | D4 | R7 |
3 | D3 | C2 |
4 | D2 | C3 |
5 | A0 | R8 |
6 | A1 | C5 |
7 | A2 | R6 |
8 | A3 | R3 |
9 | D13 | R1 |
10 | D12 | C4 |
11 | D11 | C6 |
12 | D10 | R4 |
13 | D9 | C1 |
14 | D8 | R2 |
15 | D7 | C7 |
16 | D6 | C8 |
Si osservi che la matrice di LED ha una protuberanza sul lato contenente la serie di pin che va da 1 a 8.
Ecco il codice associato
/* Codice che effettua in serie: - accensione dei led in colonna da sinistra verso destra - accensione dei led sulla riga dall'alto verso il basso - accensione in sequenza del primo led fino al 64-esimo */ // Nell'array pin[0..16] (la posizione 0 è fittizia e serve per far iniziare l'indice dell'array da 1) // viene schematizzata la connessione dei pin della matrice di LED con i pin di arduino. // In pin[i] è inserito il pin di arduino connesso all'i-esimo pin della matrice di LED. // Si tenga presente che i pin di arduino 14 ... 17 corrispondono rispettivamente a: // A0 => 14-esimo pin di arduino // A1 => 15-esimo pin di arduino // A2 => 16-esimo pin di arduino // A3 => 17-esimo pin di arduino int pins[17]= {-1, 5, 4, 3, 2, 14, 15, 16, 17, 13, 12, 11, 10, 9, 8, 7, 6}; // la colonna "c" della matrice di LED è connessa al pin di arduino cols[c] che corrisponde a // pin[j] dove "j" è il pin della matrice di LED associata alla colonna "c" int cols[8] = {pins[13], pins[3], pins[4], pins[10], pins[06], pins[11], pins[15], pins[16]}; // la riga "r" della matrice di LED è connessa al pin di arduino rows[r] che corrisponde a // pin[j] dove "j" è il pin della matrice di LED associata alla riga "r" int rows[8] = {pins[9], pins[14], pins[8], pins[12], pins[1], pins[7], pins[2], pins[5]}; /* Ponendo tutte le colonne a HIGH e le righe a LOW tutti i LED si accendono */ void AllLedON() { for (int i = 1; i <= 8; i++) { digitalWrite(cols[i - 1], HIGH); digitalWrite(rows[i - 1], LOW); } delay(1000); AllLedOFF(); } /* Ponendo tutte le colonne e le righe rispettivamente ad uno stato differente da HIGH e LOW tutti i LED si spengono */ void AllLedOFF() { for (int i = 1; i <= 8; i++) { digitalWrite(cols[i - 1], LOW); digitalWrite(rows[i - 1], HIGH); } } /* Accende il LED sulla riga r e colonna C */ void LedON(int r, int c) { AllLedOFF(); digitalWrite(cols[c - 1], HIGH); digitalWrite(rows[r - 1], LOW); delay(100); } void setup() { // pone i pin di Arduino come pin di output for (int i = 1; i <= 16; i++) pinMode(pins[i], OUTPUT); // Pone tutti i led della matrice a OFF AllLedOFF(); } void loop() { int i, c, r; // Accende la colonna c-esima da sinistra a destra for (c=1; c<=8; c++) { for (r=1; r<=8; r++) digitalWrite(rows[r - 1], LOW); digitalWrite(cols[c - 1], HIGH); delay(300); digitalWrite(cols[c - 1], LOW); for (r=1; r<=8; r++) digitalWrite(rows[r - 1], HIGH); } // accende la riga r-esima dall'alto al basso for (r=1; r<=8; r++) { for (c=1; c<=8; c++) digitalWrite(cols[c - 1], HIGH); digitalWrite(rows[r - 1], LOW); delay(300); digitalWrite(rows[r - 1], HIGH); for (i=1; i<=8; i++) digitalWrite(cols[i - 1], LOW); } // Accende un singolo LED dalla prima posizione fino alla 64-esima for (r=1; r<=8; r++) for (c=1; c<=8; c++) LedON(r,c); AllLedOFF(); // AllLedON(); }
Esercitazione pratica 1:
Obiettivo progetto: Scrivere sulla matrice a led un grosso più (spesso 2 righe e 2 colonne) ed accendere i punti corrispondenti ai 4 angoli
Suggerimento:
Completare in scioltezza prendendo spunto dall'esempio precedente
/* Codice che disegna un grosso più ed accende i led corrispondenti ai
4 angoli della matrice a LED. Nella composizione della soluzione prendere
spunto dall'esercizio precedente
*/
// Nell'array pin[0..16] (la posizione 0 è fittizia e serve per far iniziare l'indice dell'array da 1)
// viene schematizzata la connessione dei pin della matrice di LED con i pin di arduino.
// In pin[i] è inserito il pin di arduino connesso all'i-esimo pin della matrice di LED.
// Si tenga presente che i pin di arduino 14 ... 17 corrispondono rispettivamente a:
// A0 => 14-esimo pin di arduino
// A1 => 15-esimo pin di arduino
// A2 => 16-esimo pin di arduino
// A3 => 17-esimo pin di arduino
int pins[17]= {-1, 5, 4, 3, 2, 14, 15, 16, 17, 13, 12, 11, 10, 9, 8, 7, 6};
// la colonna "c" della matrice di LED è connessa al pin di arduino cols[c] che corrisponde a
// pin[j] dove "j" è il pin della matrice di LED associata alla colonna "c"
int cols[8] = {pins[13], pins[3], pins[4], pins[10], pins[06], pins[11], pins[15], pins[16]};
// la riga "r" della matrice di LED è connessa al pin di arduino rows[r] che corrisponde a
// pin[j] dove "j" è il pin della matrice di LED associata alla riga "r"
int rows[8] = {pins[9], pins[14], pins[8], pins[12], pins[1], pins[7], pins[2], pins[5]};
/* Ponendo tutte la colonna a HIGH e la riga a LOW tutti i LED si accendono */
void RigaON(int r)
{
// A VOI L'ONERE E L'ONORE!
}
/* Ponendo tutte la colonna a HIGH e la riga a LOW tutti i LED si accendono */
void ColonnaON(int c)
{
// A VOI L'ONERE E L'ONORE!
}
/*
Ponendo tutte le colonne e le righe rispettivamente ad uno stato differente da HIGH e LOW
tutti i LED si spengono
*/
void AllLedOFF()
{
for (int i = 1; i <= 8; i++)
{
digitalWrite(cols[i - 1], LOW);
digitalWrite(rows[i - 1], HIGH);
}
}
void setup()
{
// pone i pin di Arduino come pin di output
for (int i = 1; i <= 16; i++)
pinMode(pins[i], OUTPUT);
// Pone tutti i led della matrice a OFF
AllLedOFF();
}
void loop()
{
// A VOI L'ONERE E L'ONORE!
}
soluzione:
Il problema è che le combinazioni che consentono l'accensione dei led richiesti non sono tra loro compatibili (clicca qui per scaricare il file di excel che simula l'accensione del LED matrix in base all'input sui 16 pin.
Pertanto è necessario ovviare attivando velocemente ed in sequenza le singole combinazioni. Il breve tempo di permanenza della luminosità sul LED, anche dopo che non risulta più alimentato, occulta il trucchetto utilizzato facendo sembrare che i led siano stati tutti accesi contemporaneamente. Ecco la soluzione:
/* Codice che disegna un grosso più ed accende i led corrispondenti ai 4 angoli della matrice a LED. Nella composizione della soluzione prendere spunto dall'esercizio precedente */ // Nell'array pin[0..16] (la posizione 0 è fittizia e serve per far iniziare l'indice dell'array da 1) // viene schematizzata la connessione dei pin della matrice di LED con i pin di arduino. // In pin[i] è inserito il pin di arduino connesso all'i-esimo pin della matrice di LED. // Si tenga presente che i pin di arduino 14 ... 17 corrispondono rispettivamente a: // A0 => 14-esimo pin di arduino // A1 => 15-esimo pin di arduino // A2 => 16-esimo pin di arduino // A3 => 17-esimo pin di arduino int pins[17]= {-1, 5, 4, 3, 2, 14, 15, 16, 17, 13, 12, 11, 10, 9, 8, 7, 6}; // la colonna "c" della matrice di LED è connessa al pin di arduino cols[c] che corrisponde a // pin[j] dove "j" è il pin della matrice di LED associata alla colonna "c" int cols[8] = {pins[13], pins[3], pins[4], pins[10], pins[06], pins[11], pins[15], pins[16]}; // la riga "r" della matrice di LED è connessa al pin di arduino rows[r] che corrisponde a // pin[j] dove "j" è il pin della matrice di LED associata alla riga "r" int rows[8] = {pins[9], pins[14], pins[8], pins[12], pins[1], pins[7], pins[2], pins[5]}; /* Ponendo tutte la colonna a HIGH e la riga a LOW i LED della riga si accendono */ void RigaON(int r) { for (int c=1; c<=8; c++) digitalWrite(cols[c - 1], HIGH); digitalWrite(rows[r-1], LOW); AllLedOFF(); } void LedON(int r, int c) { digitalWrite(cols[c - 1], HIGH); digitalWrite(rows[r - 1], LOW); AllLedOFF(); } /* Ponendo tutte la riga LOW e la colonna a HIGH i LED della colonna si accendono */ void ColonnaON(int c) { // A VOI L'ONERE E L'ONORE! for (int r=1; r<=8; r++) digitalWrite(rows[r - 1], LOW); digitalWrite(cols[c-1], HIGH); AllLedOFF(); } /* Ponendo tutte le colonne e le righe rispettivamente ad uno stato differente da HIGH e LOW tutti i LED si spengono */ void AllLedOFF() { for (int i = 1; i <= 8; i++) { digitalWrite(cols[i - 1], LOW); digitalWrite(rows[i - 1], HIGH); } } void setup() { // pone i pin di Arduino come pin di output for (int i = 1; i <= 16; i++) pinMode(pins[i], OUTPUT); // Pone tutti i led della matrice a OFF AllLedOFF(); } void loop() { LedON(1,1); LedON(1,8); LedON(8,1); LedON(8,8); ColonnaON(4); ColonnaON(5); RigaON(4); RigaON(5); }
INTEGRATO MAX7219
Analizzando il progetto precedente si nota un notevole dispendio di pin. Utilizzando invece l'integrato MAX7219 è possibile pilotare tutti i 64 LED riducendo il numero di PIN utilizzati di Arduino a soli 3 fili (più quelli per l'alimentazione).
La piedinatura del chip MAX7219 è la seguente (vedi datasheet):
Il significato dei PIN è illustrato nella tabella sottostante
PIN | SIGLA | SIGNIFICATO |
1 | DIN = DataIN | Serial-Data Input: il dato viene caricato nello shift register (registro a scorrimento) interno sul fronte di salita del CLK |
2, 3, 5–8, 10, 11 | Y0 ...
Y7 o DIG7 ... DIG0 |
Pin connessi alle righe. Il MAX7219 porta tali uscite a V+ quando vengono spenti |
4, 9 | GND | Tutti e 2 i pin devono essere collegati alla terra |
12 | LOAD - CS | Quando questo pin è posto a LOW (Chip Select Input) il dato serializzato viene caricato nello shift register. Gli ultimi 16 bit all'ingresso seriale DataIn vengono bloccati sul fronte di salita del pin LOAD. |
13 | CLK | Serial-Clock Input. La frequenza massima ammessa è 10MHz.. I bit inviati (in pacchetti da 16 bit) al pin DataIn vengono shiftati all'interno dello shift register ad ogni fronte di salita del CLK indipendentemente dalla stato del pin LOAD. Sul fronte di discesa di CLK, i dati vengono riproposti sul pin DOUT. L'ingresso CLK è attivo solo quando il pin CS è LOW. |
14-17, 20-23 | SEGA -SEGG, SEGDP o X0 ... X7 | Pin connessi alle colonne. Nel MAX7219, quando un segmento è spento il pin è posto a GND. |
18 | ISSET | E' connesso a VDD attraverso una resistenza (RSET) per impostare il picco di corrente sui segmenti SEGA .. SEGG e DP. La luminosità dei display può essere controllata con un resistore esterno RSET connesso tra V+ e ISET. La corrente di picco nei segmenti (SEGx e DP) è nominalmente 100 ISET. RSET può essere fissa o variabile ma deve comunque essere ≥ 9,53 Ω. |
19 | V+ | Pin connesso ai +5V |
24 | DOUT | Serial-Data Output. Il dato serializzato su DIN verrà riproposto in DOUT dopo 16.5 cicli di clock sul fronte di discesa del CLK. Questo pin è utilizzato per mettere in serie diversi MAX7219. |
Che vengono connessi alla matrice LED in questo modo
Il chip MAX7219 ha un registro a 16 bit suddiviso in 2 parti: ADDRESS e DATA, ciascuna di 8 bit. Il formato dei dati è il seguente:
I bit D12-D15 non hanno alcun particolare significato e vengono utilizzati per lo scorrimento. I bit D8...D11 vengono utilizzati per indirizzare i registri interni del MAX7219 e corrispondono ai comandi disponibili nel chip. Tali comandi sono descritti nella tabella sottostante:
Indirizzo | Significato |
0x00 | NOP: nessuna operazione |
0x01 | Digit 0 |
0x02 | Digit 1 |
... | ... |
0x08 | Digit 7 |
0x09 | DECODE MODE - definisce, per ogni cifra, se viene utilizzato il codice BCD, B oppure nessun codice. |
0x0A | INTENSITY Register - Setta l'intensità della luminosità del LED. I valori vanno da 0 a 15. |
0x0B | SCAN_LIMIT Register - Setta il numero di bit utilizzati |
0x0C | SHUTDOWN Register
- Quando il MAX7219 è in modalità shutdown l’oscillatore viene fermato,
i driver dei segmenti (SEGy) vengono posti a massa
mentre quelli dei display (DIGx) a V+, spegnendo così
tutti i LED. I dati nei registri rimangono inalterati e il display driver può essere programmato. La modalità shutdown può essere utilizzata per risparmiare potenza o per far lampeggiare i display. |
0x0F | DISPLAY_TEST Register - se posto a 1 tutti i led risultano accesi |
Codice Sorgente B
Obiettivo progetto: Obiettivo del nostro progetto è quello di visualizzare sul display 8x8 i caratteri alfanumerici(0..9, a...z, A...Z) digitati sulla tastiera del PC. Se si digita un carattere non ammesso i LED del display vengono tutti spenti. Contemporaneamente sul Serial Monitor viene invece visualizzato un messaggio che indica il carattere digitato oppure un avviso di errore nel caso il simbolo non sia alfanumerico.
soluzione:
Impostiamo il seguente circuito visibile nell'immagine sottostante
Ecco il codice associato al nostro progetto. La cosa più interessante di questo codice è che non fa uso di librerie esterne.
/* Esempio creato prendendo spunto dall'esempio a questo indirizzo: http://linksprite.com/wiki/index.php5?title=LED_Matrix_Kit Visualizza un carattere alfanumerico sul display a LED 8x8 */ int Max7219_pinCLK = 10; // pin su arduino connesso al CLK di MAX7219 int Max7219_pinCS = 9; // pin su arduino connesso al CAS di MAX7219 int Max7219_pinDIN = 8; // pin su arduino connesso al DIN di MAX7219 unsigned char disp1[38][8]= { {B00111100,B01111110,B01100110,B01100110,B01100110,B01100110,B01111110,B00111100}, //0. {B00011000,B00111000,B00011000,B00011000,B00011000,B00011000,B00111100,B00111100}, //1 {B00111100,B01111110,B01100110,B00001110,B00011000,B00110000,B01111110,B01111110}, //2 {B00111100,B01111110,B01100110,B00001110,B00001100,B01100110,B01111110,B00111100}, //3 {B00001110,B00011110,B00111110,B01110110,B01100110,B01111111,B00111111,B00000110}, //4 {B01111110,B01111110,B01100000,B01111100,B00011110,B01000110,B01111110,B00111110}, //5 {B00111110,B01111110,B01100000,B01111100,B01111110,B01100110,B01111110,B00111100}, //6 {B01111110,B01111110,B00000110,B00001110,B00011100,B00111000,B01110000,B01100000}, //7 {B00111100,B01111110,B01100110,B00111100,B01100110,B01100110,B01111110,B00111100}, //8 {B00111100,B01111110,B01100110,B01111110,B00111110,B00000110,B01111110,B00111100}, //9 {B01111110,B11111111,B11000011,B11000011,B11111111,B11111111,B11000011,B11000011}, //A {B11111110,B11111111,B11000011,B11111111,B11111110,B11000011,B11111111,B11111110}, //B {B01111110,B11111111,B11000011,B11000000,B11000000,B11000011,B11111111,B01111110}, //C {B11111100,B11111110,B11000111,B11000011,B11000011,B11000111,B11111110,B11111100}, //D {B11111111,B11111111,B11000000,B11110000,B11110000,B11000000,B11111111,B11111111}, //E {B11111111,B11111111,B11000000,B11110000,B11110000,B11000000,B11000000,B11000000}, //F {B01111110,B11111110,B11000000,B11001110,B11001111,B11000011,B11111110,B01111110}, //G {B11000011,B11000011,B11000011,B11111111,B11111111,B11000011,B11000011,B11000011}, //H. {B00111100,B00011000,B00011000,B00011000,B00011000,B00011000,B00011000,B00111100}, //I {B00111100,B00011000,B00011000,B00011000,B00011000,B11011000,B11111000,B01110000}, //J {B11001110,B11011100,B11111000,B11110000,B11111000,B11011100,B11001110,B11000111}, //K {B01100000,B01100000,B01100000,B01100000,B01100000,B01100000,B01111110,B01111110}, //L {B11000011,B11100111,B11111111,B11111111,B11011011,B11000011,B11000011,B11000011}, //M {B11000011,B11100011,B11110011,B11111011,B11011111,B11001111,B11000111,B11000011}, //N {B01111100,B11111110,B11000110,B11000110,B11000110,B11000110,B11111110,B01111100}, //O {B01111110,B01111111,B01100011,B01111111,B01111110,B01100000,B01100000,B01100000}, //P {B01111100,B11111110,B11000110,B11000110,B11001110,B11001110,B11111110,B01111011}, //Q {B01111110,B01111111,B01100011,B01111111,B01111110,B01111100,B01101110,B01100111}, //R {B01111110,B11111110,B11100000,B11111000,B00111110,B00001110,B11111110,B11111100}, //S {B11111111,B11111111,B00011000,B00011000,B00011000,B00011000,B00011000,B00011000}, //T {B11000110,B11000110,B11000110,B11000110,B11000110,B11000110,B11111110,B01111100}, //U {B11000011,B11000011,B01100110,B01100110,B01100110,B00111100,B00111100,B00011000}, //V {B11000011,B11011011,B11111111,B11111111,B01111110,B01100110,B01100110,B00100100}, //W {B11000011,B01100110,B00111100,B00011000,B00111100,B01100110,B11000011,B11000011}, //X {B01100110,B01100110,B01100110,B01111110,B00111100,B00011000,B00011000,B00011000}, //Y //{0xFF,0xFF,0x0E,0x1C,0x38,0x70,0xFF,0xFF}, //Z in Hex {B11111111,B11111111,B00001110,B00011100,B00111000,B01110000,B11111111,B11111111}, //Z {B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000}, //Tutto spento [36] {B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111} //Tutto acceso [37] }; void Write_Max7219_byte(unsigned char DATA) { unsigned char i; for(i=1; i<=8;i++) { digitalWrite(Max7219_pinCLK,LOW); digitalWrite(Max7219_pinDIN,DATA&0x80); // Estraggo il bit in 8 posizione (0x80 => 1000 0000) DATA = DATA<<1; // Shift a sinistra di un posto i bit in DATA digitalWrite(Max7219_pinCLK,HIGH); // sull'arco di salita del CLK il DIN viene // shiftato all'interno dello shift register } } void Write_Max7219(unsigned char address,unsigned char dat) { digitalWrite(Max7219_pinCS,LOW); // Abilito la scrittura sul Data IN Write_Max7219_byte(address); // indirizzo registro/comando da eseguire (bit D8 .. D11) Write_Max7219_byte(dat); // bit da porre in D0..D7 (rappresentano il valore utilizzato dal comando) digitalWrite(Max7219_pinCS,HIGH); // Termino la scrittura sul Data IN } void Init_MAX7219(void) { Write_Max7219(0x09, 0x00); // decodifica: BCD Write_Max7219(0x0a, 0x0F); // luminosità 1..15 Write_Max7219(0x0b, 0x07); // limite scan;gestisco tutte le 8 righe Write_Max7219(0x0c, 0x01); // Shutdown command: Display spento: 0x00 - Acceso (normal mode):0x01 Write_Max7219(0x0f, 0x00); // Test command:Test Mode (tutti i LED accesi): 0x01 - Normal mode: 0x00) } void setup() { // setto i pin come output pinMode(Max7219_pinCLK,OUTPUT); pinMode(Max7219_pinCS,OUTPUT); pinMode(Max7219_pinDIN,OUTPUT); delay(50); Init_MAX7219(); Serial.begin(9600); } void loop() { int Valore,j,i; String Frase=""; if (Serial.available()) // se ho caratteri disponibili sul monitor seriale { Valore=Serial.read(); // Legge il dato sul Serial Monitor dell'IDE di Arduino if (Valore <='9' && Valore >= '0') // Stabilisco la posizione nel vettore j=Valore-(int)'0'; else if (Valore <='Z' && Valore >='A') j=Valore-(int)'A'+10; else if (Valore <='z' && Valore >='a') j=Valore-(int)'a'+10; else j=36; for (i=0;i<8;i++) Write_Max7219(i+1,disp1[j][i]); // scrivo l'(i+1)-esima riga della mappa di bit if (j>=36) Frase="Carattere non visualizzabile: '"+String((char)Valore)+"'"; else Frase="Carattere visualizzato sul display 8x8: '"+String((char)Valore)+"'"; Serial.println(Frase); } }
Analizziamo ora alcune istruzioni importanti presenti nel programma.
L'istruzione DATA & 0x80
all'interno della funzione Write_Max7219_byte() ha
il compito di estrarre l'ottavo bit dal byte DATA. Infatti 0x80
(in esadecimale) corrisponde a:
16*8 = 128 in
base 10
1000000 in base 2.
L'operatore di bitwise
AND & (ovvero che opera sul singolo
bit) applicato a due byte A e
B restituisce un byte A & B
dove l'i-esimo bit è posto a 1 solo se i 2 bit in
A e B, che si trovano nella medesima
posizione i, sono uguali a 1.
La maschera 0x80 quindi azzera tutti gli altri bit ad esclusione dell'ottavo che viene riportato pari pari nel risultato finale. In altre parole l'istruzione DATA & 0x80 prende in considerazione solo l'ottavo bit scartando i restanti.
L'istruzione DATA = DATA << 1; utilizza l'operatore di shift a sinistra <<. Tale istruzione fa scorrere i bit del byte DATA di una posizione a sinistra (elimina sostanzialmente l'ottavo bit appena analizzato con l'istruzione DATA & 0x80). In generale l'istruzione A << n restituisce il byte ottenuto facendo scorrere i bit di A di n posizioni a sinistra. I primi n bit (quelli liberati dallo scorrimento) vengono riempiti con 0.
Quindi la sequenza: DATA << 1 equivale a spostare di un posto verso sinistra la sequenza di bit. Abbinata a Data & 0x80 permette di estrarre da DATA un bit alla volta.
Per generare la mappa di bit da caricare sul display 8x8 possiamo utilizzare il seguente programma javascript
|
Codifica Binaria: |
Esercitazione pratica 2:
Obiettivo progetto: Scrivere sulla matrice a led i simboli digitati sul keypad (utilizzare l'applicazione sovrastante per determinare la mappa di bit corrispondente ai simboli mancanti * e #. Completare in scioltezza partendfo dal seguente template:
/* Codice che disegna sul display a matrice di LED il simbolo premuto sul
tastierino a membrana 3x4
*/
int Max7219_pinCLK = 10; // pin su arduino connesso al CLK di MAX7219
int Max7219_pinCS = 9; // pin su arduino connesso al CAS di MAX7219
int Max7219_pinDIN = 12; // pin su arduino connesso al DIN di MAX7219
unsigned char disp1[38][8]=
{
{B00111100,B01111110,B01100110,B01100110,B01100110,B01100110,B01111110,B00111100}, //0.
{B00011000,B00111000,B00011000,B00011000,B00011000,B00011000,B00111100,B00111100}, //1
{B00111100,B01111110,B01100110,B00001110,B00011000,B00110000,B01111110,B01111110}, //2
{B00111100,B01111110,B01100110,B00001110,B00001100,B01100110,B01111110,B00111100}, //3
{B00001110,B00011110,B00111110,B01110110,B01100110,B01111111,B00111111,B00000110}, //4
{B01111110,B01111110,B01100000,B01111100,B00011110,B01000110,B01111110,B00111110}, //5
{B00111110,B01111110,B01100000,B01111100,B01111110,B01100110,B01111110,B00111100}, //6
{B01111110,B01111110,B00000110,B00001110,B00011100,B00111000,B01110000,B01100000}, //7
{B00111100,B01111110,B01100110,B00111100,B01100110,B01100110,B01111110,B00111100}, //8
{B00111100,B01111110,B01100110,B01111110,B00111110,B00000110,B01111110,B00111100}, //9
// A VOI L'ONERE E L'ONORE! //*
// A VOI L'ONERE E L'ONORE! //#
{B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000}, //Tutto spento [36]
{B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111} //Tutto acceso [37]
};
void Write_Max7219_byte(unsigned char DATA)
{
unsigned char i;
for(i=1; i<=8;i++)
{
digitalWrite(Max7219_pinCLK,LOW);
digitalWrite(Max7219_pinDIN,DATA&0x80); // Estraggo il bit in 8 posizione
DATA = DATA<<1; // Shift a sinistra di un posto i bit in DATA
digitalWrite(Max7219_pinCLK,HIGH); // sull'arco di salita del CLK il DIN viene
// shiftato all'interno dello shift register
}
}
void Write_Max7219(unsigned char address,unsigned char dat)
{
digitalWrite(Max7219_pinCS,LOW); // Abilito la scrittura sul Data IN
Write_Max7219_byte(address); // indirizzo registro/comando da eseguire (bit D8 .. D11)
Write_Max7219_byte(dat); // bit da porre in D0..D7 (rappresentano il valore utilizzato dal comando)
digitalWrite(Max7219_pinCS,HIGH); // Termino la scrittura sul Data IN
}
void Init_MAX7219(void)
{
Write_Max7219(0x09, 0x00); // decodifica: BCD
Write_Max7219(0x0a, 0x0F); // luminosità 1..15
Write_Max7219(0x0b, 0x07); // limite scan;gestisco tutte le 8 righe
Write_Max7219(0x0c, 0x01); // Shutdown command: Display spento: 0x00 - Acceso (normal mode):0x01
Write_Max7219(0x0f, 0x00); // Test command:Test Mode (tutti i LED accesi): 0x01 - Normal mode: 0x00)
}
// PARTE RELATIVA AL KEYPAD
#include <Keypad.h>
const byte ROWS = 4; //4 righe
const byte COLS = 3; //3 colonne
char keys[ROWS][COLS] =
{
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[ROWS] = {8, 7, 6, 5}; // Pin di arduino connessi ai pin 1,2,3 e 4 delle righe del keypad
byte colPins[COLS] = {4, 3, 2}; // Pin di arduino connessi ai pin 5,6,7 delle righe del keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
void setup()
{
// setto i pin come output
pinMode(Max7219_pinCLK,OUTPUT);
pinMode(Max7219_pinCS,OUTPUT);
pinMode(Max7219_pinDIN,OUTPUT);
delay(50);
Init_MAX7219();
}
void loop()
{
char key = keypad.getKey();
if (key != NO_KEY)
{
// A VOI L'ONERE E L'ONORE!
}
}
soluzione:
Impostiamo il seguente progetto
e carichiamo questa soluzione
/* Codice che disegna sul display a matrice di LED il simbolo premuto sul tastierino a membrana 3x4 */ int Max7219_pinCLK = 10; // pin su arduino connesso al CLK di MAX7219 int Max7219_pinCS = 9; // pin su arduino connesso al CAS di MAX7219 int Max7219_pinDIN = 11; // pin su arduino connesso al DIN di MAX7219 unsigned char disp1[38][8]= { {B00111100,B01111110,B01100110,B01100110,B01100110,B01100110,B01111110,B00111100}, //0. {B00011000,B00111000,B00011000,B00011000,B00011000,B00011000,B00111100,B00111100}, //1 {B00111100,B01111110,B01100110,B00001110,B00011000,B00110000,B01111110,B01111110}, //2 {B00111100,B01111110,B01100110,B00001110,B00001100,B01100110,B01111110,B00111100}, //3 {B00001110,B00011110,B00111110,B01110110,B01100110,B01111111,B00111111,B00000110}, //4 {B01111110,B01111110,B01100000,B01111100,B00011110,B01000110,B01111110,B00111110}, //5 {B00111110,B01111110,B01100000,B01111100,B01111110,B01100110,B01111110,B00111100}, //6 {B01111110,B01111110,B00000110,B00001110,B00011100,B00111000,B01110000,B01100000}, //7 {B00111100,B01111110,B01100110,B00111100,B01100110,B01100110,B01111110,B00111100}, //8 {B00111100,B01111110,B01100110,B01111110,B00111110,B00000110,B01111110,B00111100}, //9 {B00011000,B11011011,B11111111,B00111100,B00111100,B11111111,B11011011,B00011000}, //* {B01100110,B11111111,B11111111,B01100110,B01100110,B11111111,B11111111,B01100110}, //# {B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000}, //Tutto spento [12] {B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111} //Tutto acceso [13] }; void Write_Max7219_byte(unsigned char DATA) { unsigned char i; for(i=1; i<=8;i++) { digitalWrite(Max7219_pinCLK,LOW); digitalWrite(Max7219_pinDIN,DATA&0x80); // Estraggo il bit in 8 posizione DATA = DATA<<1; // Shift a sinistra di un posto i bit in DATA digitalWrite(Max7219_pinCLK,HIGH); // sull'arco di salita del CLK il DIN viene // shiftato all'interno dello shift register } } void Write_Max7219(unsigned char address,unsigned char dat) { digitalWrite(Max7219_pinCS,LOW); // Abilito la scrittura sul Data IN Write_Max7219_byte(address); // indirizzo registro/comando da eseguire (bit D8 .. D11) Write_Max7219_byte(dat); // bit da porre in D0..D7 (rappresentano il valore utilizzato dal comando) digitalWrite(Max7219_pinCS,HIGH); // Termino la scrittura sul Data IN } void Init_MAX7219(void) { Write_Max7219(0x09, 0x00); // decodifica: BCD Write_Max7219(0x0a, 0x0F); // luminosità 1..15 Write_Max7219(0x0b, 0x07); // limite scan;gestisco tutte le 8 righe Write_Max7219(0x0c, 0x01); // Shutdown command: Display spento: 0x00 - Acceso (normal mode):0x01 Write_Max7219(0x0f, 0x00); // Test command:Test Mode (tutti i LED accesi): 0x01 - Normal mode: 0x00) } // PARTE RELATIVA AL KEYPAD #include <Keypad.h> const byte ROWS = 4; //4 righe const byte COLS = 3; //3 colonne char keys[ROWS][COLS] = { {'1','2','3'}, {'4','5','6'}, {'7','8','9'}, {'*','0','#'} }; byte rowPins[ROWS] = {8, 7, 6, 5}; // Pin di arduino connessi ai pin 1,2,3 e 4 delle righe del keypad byte colPins[COLS] = {4, 3, 2}; // Pin di arduino connessi ai pin 5,6,7 delle righe del keypad Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); void setup() { // setto i pin come output pinMode(Max7219_pinCLK,OUTPUT); pinMode(Max7219_pinCS,OUTPUT); pinMode(Max7219_pinDIN,OUTPUT); delay(50); Init_MAX7219(); for (int i=0 ; i<8; i++) Write_Max7219(i+1,disp1[12][i]); // accendo tutti i bit } void loop() { int i, j; char key = keypad.getKey(); if (key != NO_KEY) { // A VOI L'ONERE E L'ONORE! if (key <='9' && key >= '0') // Stabilisco la posizione nel vettore j=key-(int)'0'; else if (key=='*') j=10; // posizione nel vettore di '*' else if (key=='#') j=11; // posizione nel vettore di '#' for (i=0 ; i<8; i++) Write_Max7219(i+1,disp1[j][i]); // scrivo l'(i+1)-esima riga della mappa di bit } }
Codice Sorgente C
Obiettivo progetto: Costruire un programma equivalente al primo esempio utilizzando la libreria LEDCONTROL. Pertanto sulla matrice 8x8 dovremo vedere questa esecuzione
soluzione:
Per poter utilizzare questo codice è necessario installare la libreria LEDCONTROL disponibile in questo link. Per installarla basta scompattare il file zip e copiare la cartella prodotta all'interno della cartella contenente le librerie di Arduino (solitamente C:\Program Files\Arduino\libraries). Terminare aggiungendo la cartella appena copiata, mediante il menu "Add Library", all'interno dell'IDE di Arduino
al termine dell'importazione i files vengono ricopiati nella cartella
C:\Users\<User>\Documents\Arduino\libraries. Se ci sono problemi nell'installazione occorre
eliminare la cartella della libreria appena ricopiata e ripetere l'operazione.
Il manuale della libreria è disponibile cliccando
qui.
Vediamo alcune delle funzioni più utilizzate:
LedControl(int dataPin, int
clkPin, int csPin, int numDevices);
SEMANTICA
Crea un
nuovo gestore della matrice a LED
PARAMETRI :
int dataPin
Pin su Arduino dove vengono letti i dati shiftati
int clockPin
Pin del clock
int csPin Pin per
selezionare la matrice a led a cui spedire i
dati
int numDevices Massimo numero di Matrici a Led che possono
essere
controllate
void setLed(int addr, int row, int
col, boolean stato);
SEMANTICA
Imposta lo stato del
led
PARAMETRI :
addr quale LED Matrix utilizzare (0 il
primo ..)
row numero di riga (0..7)
col numero di colonna (0..7)
stato se true il led
viene acceso
altrimenti se
false viene spento.
void setRow(int addr, int
row, byte value);
SEMANTICA
Imposta i led di una riga
PARAMETRI :
addr quale LED Matrix utilizzare (0 il
primo ..)
row numero di riga (0..7)
value accende i led della riga corrispondenti a 1
e spegne tutti gli altri
void setColumn(int
addr, int col, byte value);
SEMANTICA
Imposta i led di
una colonna
PARAMETRI :
addr quale LED Matrix
utilizzare (0 il primo ..)
row numero di
colonna (0..7)
value accende i led della colonna
corrispondenti a 1
e
spegne tutti gli altri
Impostiamo i seguenti collegamenti
Ecco il codice associato al nostro progetto.
#include <LedControl.h> /* Impostiamo i PIN utilizzati: Pin 8: connesso al pin DataIn Pin 10: connesso al CLK Pin 9: connesso a LOAD/CS Con l'ultimo parametro di LedControl impostiamo il nr di display 8x8 utilizzati */ /* * SINTASSI * void setLed(int addr, int row, int col, boolean stato); * SEMANTICA * Imposta lo stato del led * PARAMETRI : * addr quale LED Matrix utilizzare (0 il primo ..) * row numero di riga (0..7) * col numero di colonna (0..7) * stato se true il led viene acceso * altrimenti se false viene spento. */ LedControl lc=LedControl(8,10,9,1); /* Accende tutti i LED del DISPLAY */ void AllLedON() { for (int r=0 ; r<8 ; r++) lc.setRow(0,r,B11111111); delay(1000); lc.clearDisplay(0); } void setup() { /* Durante la costruzione dell'oggetto LEDControl il MAX72XX è posto in modalità "power-saving". Dobbiamo quindi "risvegliare" l'integrato */ lc.shutdown(0,false); // lo 0 è relativo al MAX72XX dove agire // equivale a "Write_Max7219(0x0c, 0x01);" lc.setIntensity(0,15); // luminosità 1..15 lc.setScanLimit(0,7); // limite scan;gestisco tutte le 8 righe // non necessario: la libreria pone nell'inizializzazione // dell'oggetto LEDControl questo valore al massimo (7) lc.clearDisplay(0); // La decodifica BCD e il settaggio del "Display Test Register" non sono disponibili // poichè impostati direttamente nel costruttore della classe LCDControl } void loop() { int r, c; lc.clearDisplay(0); // Accende la colonna c-esima da sinistra a destra for (c=0; c <8 ; c++) { lc.setColumn(0,c,B11111111); delay(300); lc.setColumn(0,c,(byte)0); // Spengo la colonna } // accende la riga r-esima dall'alto al basso for (r=0; r <8 ; r++) { lc.setRow(0,r,B11111111); delay(300); lc.setRow(0,r,(byte)0); // Spengo la riga } // Accende un singolo LED dalla prima posizione fino alla 64-esima for (r=0 ; r<8 ; r++) for (c=0; c<8 ; c++) { lc.setLed(0,r,c,true); // Accendo il singolo LED delay(100); lc.setLed(0,r,c,false); // Spengo il singolo LED } // Accendo tutti i LED // AllLedON(); }