MODULI: Esempio DOT MATRIX

Per il nostro esempio è necessario utilizzare una matrice di LED 8x8

Matrice 8x8 LED

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.

Schema della matrice 8x8  di LED
Pin
Dot Matrix
(R)iga /
(C)olonna

Dot Matrix
1 R5
2 R7
3 C2
4 C3
5 R8
6 C5
7 R6
8 R3
9 R1
10 C4
11 C6
12 R4
13 C1
14 R2
15 C7
16 C8

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

Matrix 8x8 - Direct Connection

soluzione:

Costruiamo il seguente circuito

Circuito 8x8 Led senza integrato

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

8x8 Led Matrix - Circuto Senza integrato

Si osservi che la matrice di LED ha una protuberanza sul lato contenente la serie di pin che va da 1 a 8.

Connessione Led Matrix

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).

8x8 LedMatrix con integrato 7219

La piedinatura del chip MAX7219 è la seguente (vedi datasheet):

MAX7219 MAX7219

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

Connessione MAX7219/LedMatrix 8x8

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:

MAX7219 16Bit Register

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.

Output 8x8 Led Matrix

soluzione:

Impostiamo il seguente circuito visibile nell'immagine sottostante

LED MATRIX Circuito

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

 0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0

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

Matrix 8x8 - Direct Connection

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

Include Library

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();
}