Componenti · 18 min di lettura

Matrice LED MAX7219 con Arduino: testo scorrevole e orologio

Matrice LED MAX7219 con Arduino: collegamento 8x8 e 4 in 1 8x32, testo scorrevole con MD_Parola, testo a specchio risolto con FC16_HW, orologio ed ESP32.

Il MAX7219 è un driver economico che pilota da solo 64 LED ed è il modo più semplice per usare una matrice LED con Arduino. Lo trovi soprattutto in due versioni: un modulo con una sola matrice a punti 8x8 e un modulo 4 in 1 da 8x32 punti con quattro matrici affiancate. Il MAX7219 riceve da Arduino solo 3 fili di segnale (DIN, CS, CLK); si occupa da solo di scansionare le righe centinaia di volte al secondo, di regolare la luminosità e di ricordare lo stato di ogni LED. Così Arduino resta libero per testo scorrevole, orologi, tabelloni segnapunti o animazioni, e puoi allungare il display quanto vuoi collegando i moduli uno dopo l'altro.

In questo articolo imparerai come funziona il MAX7219, come collegare il modulo in SPI ad Arduino Uno, ESP32 e Raspberry Pi Pico, come mettere in cascata i moduli e come mostrare il tuo primo testo scorrevole con la libreria MD_Parola. Poi risolverai il problema del testo a specchio o capovolto, quello che blocca più spesso i principianti, scegliendo il tipo di hardware giusto (FC16_HW); calcolerai luminosità e consumo, mostrerai lettere accentate e caratteri personalizzati e costruirai un orologio con un modulo RTC e un'animazione pixel per pixel. Le ultime sezioni spiegano come inviare messaggi dal telefono con un ESP32, il codice MicroPython per il Pico e le soluzioni agli errori più comuni.

Modulo LED a matrice di punti MAX7219 4 in 1 8x32
Modulo a matrice di punti MAX7219 4 in 1: quattro matrici 8x8 con un MAX7219 sotto ciascuna; si alimenta dal lato IN e si collega al modulo successivo dal lato OUT.

Che cos'è il MAX7219 e come funziona?

Non è possibile collegare 64 LED uno per uno ai pin di Arduino, per questo le matrici LED usano il multiplexing. In una matrice 8x8 i LED sono collegati a una griglia di 8 righe e 8 colonne. In ogni istante il MAX7219 attiva un solo gruppo di LED (un "digit" nel datasheet, cioè una riga o una colonna della matrice), indica attraverso le altre linee quali degli otto LED di quel gruppo devono accendersi e poi passa al gruppo successivo. Tutti gli otto gruppi vengono scansionati circa 800 volte al secondo; l'occhio non riesce a seguire questa velocità, quindi l'immagine appare fissa. Nel frattempo il chip conserva lo schema di ogni gruppo nella propria RAM da 8x8 bit, limita la corrente dei LED con un'unica resistenza e regola la luminosità su 16 livelli.

Arduino comunica con il MAX7219 tramite un'interfaccia seriale a 3 fili che funziona in modo simile all'SPI. Ogni comando è un pacchetto da 16 bit: il byte alto indica in quale registro scrivere e il byte basso contiene il valore. Finché CS (LOAD nel datasheet) è LOW, i bit entrano da DIN a ogni fronte di salita di CLK; quando CS torna HIGH, il pacchetto viene scritto nel registro. È la stessa idea dello shift register 74HC595, ma dato che il MAX7219 si occupa anche della scansione e della limitazione della corrente, richiede molto meno lavoro. Il funzionamento generale dell'SPI lo trovi nell'articolo Che cos'è l'SPI?.

CaratteristicaValore
Tensione di alimentazione4,0–5,5 V (in pratica 5 V)
InterfacciaSeriale a 3 fili (DIN, CLK, CS), fino a 10 MHz
LED pilotati64 (una matrice 8x8 o 8 cifre a 7 segmenti)
Frequenza di scansione800 Hz tipici (8 cifre)
Corrente per segmentoImpostata dalla resistenza RSET, massimo 40 mA (sui moduli di solito 10 kΩ)
Luminosità16 livelli, duty cycle da 1/32 a 31/32
Corrente in shutdownCirca 150 µA
Soglia HIGH in ingressoAlmeno 3,5 V (con alimentazione a 5 V)
Collegamento in cascataUscita DOUT verso l'ingresso DIN del chip successivo

Il MAX7219 ha 14 registri indirizzabili, ma quelli che ti servono per una matrice LED sono nella tabella qui sotto. Le librerie li impostano al posto tuo; sapere a cosa servono, però, aiuta molto quando cerchi un guasto. Ad esempio, alla prima accensione il chip parte in modalità shutdown con il display spento: se il codice di inizializzazione non viene eseguito, il modulo sembra completamente morto. Il fratello MAX7221 ha gli stessi registri, ma aggiunge un vero pin CS compatibile SPI e driver dei segmenti a pendenza limitata che riducono le interferenze elettromagnetiche.

IndirizzoRegistroFunzione
0x00No-OpLascia invariato questo chip mentre un pacchetto va a un altro chip della catena
0x01–0x08Digit 0–7Lo schema a 8 bit di ciascuna delle otto righe (o colonne)
0x09Decode ModeDecodifica BCD per i 7 segmenti; disattivata (0x00) per una matrice
0x0AIntensityLuminosità, da 0x0 a 0xF
0x0BScan LimitNumero di cifre da scansionare; 7 (tutte e otto) per una matrice
0x0CShutdown0: modalità shutdown, 1: funzionamento normale
0x0FDisplay Test1: tutti i LED si accendono alla massima luminosità

Modulo 8x8 singolo o modulo 4 in 1 da 8x32?

I due moduli che incontrerai più spesso usano lo stesso circuito; la differenza sta in come la matrice LED è collegata al MAX7219 e nella forma della scheda. Il modulo singolo su scheda verde monta un MAX7219 in contenitore DIP (24 pin) e una matrice 8x8 come la 1088AS, con i pin di ingresso (VCC, GND, DIN, CS, CLK) a un'estremità e quelli di uscita (VCC, GND, DOUT, CS, CLK) all'altra. Sul modulo 4 in 1 a scheda blu, quattro MAX7219 SMD si trovano sotto le matrici e i quattro blocchi sono già collegati in cascata in fabbrica; sulla scheda di solito c'è la sigla FC-16. Per un testo scorrevole lungo, il modulo 4 in 1 è più economico e più ordinato.

Modulo a matrice LED MAX7219 8x8 singolo
Modulo MAX7219 8x8 singolo: scheda verde, MAX7219 in contenitore DIP e matrice a punti 8x8; nel codice di solito si vede correttamente con il tipo di hardware GENERIC_HW.
CaratteristicaModulo 8x8 singoloModulo 4 in 1 8x32 (FC-16)
Risoluzione8x8 = 64 LED32x8 = 256 LED
Numero di MAX72191 (contenitore DIP)4 (contenitore SMD)
Tipo di hardware nel codiceDi solito GENERIC_HWDi solito FC16_HW
Caratteri visibili insieme14–6 (secondo la larghezza delle lettere)
Corrente massima alla massima luminositàCirca 330 mACirca 1,3 A
Uso idealeIcone, dado, faccine, piccoli giochiTesto scorrevole, orologi, segnapunti

Collegamento del MAX7219: Arduino Uno, ESP32 e Pico

Il modulo ha cinque pin: VCC e GND per l'alimentazione, DIN per i dati, CLK per il clock e CS per la selezione del chip (caricamento). Per impostazione predefinita MD_Parola e MD_MAX72XX usano l'SPI hardware: in questo caso DIN deve andare al pin MOSI della scheda e CLK al pin SCK, mentre per CS puoi scegliere qualsiasi pin digitale. Puoi controllare dove si trovano i pin SPI hardware della tua scheda con lo strumento Pinout. Collega sempre i fili al lato di ingresso (IN) del modulo, l'estremità con la scritta DIN; l'estremità con DOUT serve per il modulo successivo.

Pin del moduloArduino UnoESP32Raspberry Pi Pico
VCC5V5V (VIN)VBUS (5 V)
GNDGNDGNDGND
DIND11 (MOSI)GPIO 23 (MOSI)GP19 (SPI0 TX)
CSD10GPIO 5GP17
CLKD13 (SCK)GPIO 18 (SCK)GP18 (SPI0 SCK)
Non alimentare un modulo MAX7219 dal pin a 3,3 V: il chip ha bisogno di almeno 4 V. Anche a 5 V, un solo modulo 8x8 può assorbire più di 300 mA alla massima luminosità e un modulo 4 in 1 fino a 1,3 A. La porta USB del computer e il fusibile USB di Arduino sono limitati a 500 mA. Se Arduino si riavvia o l'immagine sfarfalla quando alzi la luminosità, alimenta il modulo con un alimentatore esterno da 5 V (almeno 2 A per un modulo 4 in 1) e collega sempre il GND dell'alimentatore al GND di Arduino.

I pin di ESP32 e Pico lavorano a 3,3 V, mentre il datasheet del MAX7219 richiede almeno 3,5 V come livello HIGH con alimentazione a 5 V. I segnali a 3,3 V sono quindi tecnicamente appena sotto il limite. La maggior parte dei moduli funziona lo stesso, ma con fili lunghi o con certi lotti di chip possono comparire punti accesi a caso e immagini disturbate. La soluzione affidabile è un buffer come il 74HCT125, che accetta 3,3 V come HIGH e fornisce 5 V in uscita, oppure un convertitore di livello logico veloce sulle linee DIN, CLK e CS. Anche tenere i fili di segnale sotto i 20 cm spesso risolve il problema.

Collegare i moduli in cascata (daisy chain)

Il pin DOUT del MAX7219 restituisce i dati entrati da DIN 16,5 cicli di clock dopo. Quando colleghi il lato OUT di un modulo al lato IN del successivo, DOUT va al DIN del chip seguente, mentre CLK e CS sono in comune a tutti i chip. Così da Arduino escono sempre solo 3 fili di segnale, ma il display può essere lungo 8, 16 o 32 blocchi. A ogni aggiornamento la libreria invia i pacchetti lungo tutta la catena e, quando CS sale, tutti si aggiornano nello stesso istante. Sui moduli 4 in 1 questo collegamento è già presente sulla scheda; per ottenere un display da 8 blocchi (64x8) con due moduli 4 in 1, basta collegare i pin OUT del primo ai pin IN del secondo e impostare MAX_DEVICES a 8 nel codice.

Nella libreria la numerazione dei blocchi parte dal modulo più vicino all'ingresso DIN e cresce verso sinistra; per MD_MAX72XX l'origine delle coordinate è l'angolo in alto a destra del display. Per questo l'ingresso DIN deve restare sul lato destro, perché il testo si legga correttamente. Più la catena si allunga, più l'alimentazione diventa il vero limite: ogni 4–8 blocchi riporta 5 V e GND nella catena con fili spessi e aggiungi all'ingresso di alimentazione di ogni modulo un condensatore elettrolitico da 10 µF e uno ceramico da 100 nF. Anche il datasheet consiglia questa coppia per livellare l'ondulazione causata dai picchi di corrente dei LED.

Installare le librerie MD_MAX72XX e MD_Parola

Le due librerie più usate per il MAX7219 sono dello stesso autore (majicDesigns) e lavorano insieme. MD_MAX72XX fa il lavoro a basso livello: inizializza i moduli, scrive pixel e colonne e gestisce il font. MD_Parola si appoggia a essa e aggiunge testo scorrevole, effetti, allineamento e zone. Anche la libreria LedControl che vedi negli esempi più vecchi funziona, ma lo scorrimento del testo devi programmarlo tu. Se non hai mai installato una libreria, leggi prima Come aggiungere una libreria ad Arduino.

  1. Nell'Arduino IDE apri il Gestore librerie (Strumenti > Gestione librerie) e cerca MD_Parola.
  2. Installa la libreria MD_Parola di majicDesigns. Quando ti chiede delle dipendenze, scegli Install all così viene installata anche MD_MAX72XX.
  3. Collega il modulo come nella tabella sopra e, per un modulo 4 in 1, imposta nel codice HARDWARE_TYPE su FC16_HW e MAX_DEVICES su 4.
  4. Carica lo sketch. Se il testo appare capovolto, a specchio o ruotato, niente paura: lo correggerai con una sola riga nella sezione sul tipo di hardware.

Primo programma: testo scorrevole con MD_Parola

Arduino (C++)
1// MAX7219 4'lü modülde kayan yazı (MD_Parola) / Scrolling text on a 4-in-1 MAX7219 module (MD_Parola)
2#include <MD_Parola.h>
3#include <MD_MAX72xx.h>
4#include <SPI.h>
5
6#define HARDWARE_TYPE MD_MAX72XX::FC16_HW   // mavi PCB'li 4'lü modül / blue-PCB 4-in-1 module
7#define MAX_DEVICES 4                       // zincirdeki 8x8 blok sayısı / number of 8x8 blocks in the chain
8#define CS_PIN 10                           // DIN = D11 (MOSI), CLK = D13 (SCK)
9
10MD_Parola display = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
11
12void setup() {
13  display.begin();
14  display.setIntensity(4);                  // parlaklık 0–15 / brightness 0–15
15  display.displayClear();
16  // metin, hizalama, hız (ms/kare), bekleme (ms), giriş efekti, çıkış efekti
17  // text, alignment, speed (ms/frame), pause (ms), entry effect, exit effect
18  display.displayText("Merhaba BlueGrays!", PA_CENTER, 50, 1000, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
19}
20
21void loop() {
22  if (display.displayAnimate()) {           // efekt bittiğinde true döner / returns true when the effect ends
23    display.displayReset();                 // aynı yazıyı baştan başlat / restart the same text
24  }
25}

La riga più importante è displayText(): riceve, in quest'ordine, il testo, l'allineamento (PA_LEFT, PA_CENTER, PA_RIGHT), il tempo tra un fotogramma e l'altro in millisecondi, la pausa quando il testo è arrivato in posizione e gli effetti di entrata e di uscita. Più il valore di velocità è piccolo, più il testo scorre veloce; tra 25 e 60 ms si ottiene uno scorrimento ben leggibile. displayAnimate() avanza al massimo di un fotogramma a ogni chiamata e ritorna subito. Per questo va chiamata di continuo in loop() e nel resto del codice non devi usare delay(), altrimenti il testo avanza a scatti. Come aspettare senza bloccare il programma lo trovi nell'articolo millis() e delay().

FunzioneCosa fa
begin()Inizializza i moduli, li fa uscire dallo shutdown e pulisce il display
displayText(testo, allineamento, velocità, pausa, entrata, uscita)Imposta il testo e gli effetti da mostrare e avvia l'animazione
displayAnimate()Disegna il fotogramma successivo; restituisce true quando l'effetto è finito
displayReset()Riproduce da capo lo stesso testo e lo stesso effetto
print("...")Mostra un testo fisso senza effetti
setIntensity(0–15)Regola la luminosità di tutti i moduli
setInvert(true)Scambia LED accesi e spenti (immagine in negativo)
displayShutdown(true)Mette il display in shutdown; con false lo riaccende
begin(2) e setZone(0, 0, 1)Divide il display in zone indipendenti, ognuna con il suo testo e il suo effetto

Oltre a PA_SCROLL_LEFT ci sono molti effetti di entrata e di uscita: PA_PRINT (il testo appare di colpo), PA_SCROLL_UP e PA_SCROLL_DOWN (scorrimento verticale), PA_WIPE (tendina), PA_OPENING e PA_CLOSING (apertura e chiusura dal centro), PA_FADE (dissolvenza con la luminosità), PA_DISSOLVE, PA_BLINDS, PA_RANDOM e PA_GROW_UP. Per vederli tutti carica l'esempio Parola_Animation_Catalog da File > Esempi > MD_Parola; ricorda di adattare le righe HARDWARE_TYPE e MAX_DEVICES al tuo modulo.

Scegliere il tipo di hardware (FC16_HW) e correggere il testo a specchio

I produttori collegano la matrice 8x8 al MAX7219 in modi diversi: su alcune schede le linee "digit" del chip vanno alle righe, su altre alle colonne, e l'ordine di righe o colonne può essere invertito. La libreria compensa questa differenza con l'impostazione HARDWARE_TYPE. Se scegli il tipo sbagliato il modulo non è guasto, ma le lettere appaiono a specchio, capovolte o ruotate di 90 gradi in ogni blocco 8x8. Dato che molti codici vecchi che trovi online usano PAROLA_HW o GENERIC_HW, è il problema più frequente con i moduli 4 in 1 blu venduti oggi. La tabella indica cosa cambiare in base al sintomo; si riferisce al modulo 4 in 1 FC-16.

Cosa vediCausa probabileSoluzione
Le lettere sono a specchio (destra-sinistra) in ogni bloccoPAROLA_HW selezionato, ordine delle colonne invertitoUsa FC16_HW
Le lettere sono ruotate di 90 gradi in ogni bloccoGENERIC_HW selezionato, righe e colonne scambiateUsa FC16_HW
Le lettere sono capovolte in ogni bloccoICSTATION_HW selezionato, ordine di righe e colonne invertitoUsa FC16_HW
Tutto il testo è capovolto e scorre da sinistra a destraIl modulo è girato, con l'ingresso DIN a sinistraRuota il modulo di 180 gradi in modo che l'ingresso DIN sia a destra
Solo alcuni blocchi sono corretti, gli altri sono vuoti o confusiMAX_DEVICES non corrisponde al numero reale di blocchiImposta MAX_DEVICES al numero reale di blocchi
Sul modulo 8x8 verde prova prima GENERIC_HW, sul modulo 4 in 1 blu prova prima FC16_HW. Se l'immagine è ancora sbagliata, prova i quattro tipi uno dopo l'altro; ogni volta cambia una sola riga. Per scoprire con certezza il tipo del tuo modulo carica lo sketch MD_MAX72xx_HW_Mapper tra gli esempi di MD_MAX72XX: accende i LED uno alla volta e mostra nel Monitor seriale quale riga e quale colonna sono collegate a cosa.

Regolazione della luminosità e consumo

La luminosità dipende da due cose. La prima è la resistenza RSET sul modulo: il chip fornisce ai LED circa 100 volte la corrente che esce dal pin ISET. Sui moduli si usano di solito 10 kΩ, cioè una corrente di picco poco sopra i 40 mA con LED rossi e di circa 40 mA con LED blu e bianchi. La seconda è il registro Intensity che imposti via software: un valore n da 0 a 15 tiene accesi i LED per (2n+1)/32 di ogni intervallo di scansione, quindi 0 è la luminosità minima (1/32) e 15 la massima (31/32). Inoltre, dato che ogni riga è accesa solo per un ottavo del tempo, anche alla massima luminosità un singolo LED assorbe in media circa 5 mA. Le tensioni dirette in base al colore del LED le trovi nello strumento Tensioni dei LED.

Puoi stimare in modo approssimativo la corrente media di un modulo così: I ≈ 8 mA + 5 mA × (2n+1)/32 × L. Qui 8 mA è il consumo proprio del chip, n il valore di luminosità e L il numero di LED accesi su quel modulo (0–64); 5 mA è un ottavo della corrente di picco di 40 mA. Ad esempio, con luminosità 15 e tutti i 64 LED accesi si ottiene 8 + 5 × 0,97 × 64 ≈ 318 mA, in linea con i 330 mA del datasheet. Con un testo scorrevole di solito si accende solo il 25–35 per cento dei LED, quindi il consumo reale è molto più basso. La tabella mostra valori tipici per un modulo 4 in 1.

SituazionePer moduloModulo 4 in 1 (32x8)
Tutti i LED accesi, luminosità 15≈ 320 mA≈ 1,3 A
Tutti i LED accesi, luminosità 7≈ 160 mA≈ 630 mA
Testo scorrevole (~30% dei LED), luminosità 7≈ 55 mA≈ 210 mA
Testo scorrevole (~30% dei LED), luminosità 2≈ 25 mA≈ 90 mA
Modalità shutdown (displayShutdown)≈ 0,15 mA≈ 0,6 mA

Per abbassare il display di notte puoi regolare la luminosità in automatico con un sensore di luce LDR e mettere in shutdown il display con displayShutdown(true) quando non c'è nessuno. Se stai progettando un'insegna a batteria, inserisci i valori sopra nello strumento Durata della batteria per calcolare quante ore resisterà. In interni una luminosità di 2–4 invece di 15 di solito basta: affatica meno gli occhi e riduce la corrente dei LED a circa un terzo, fino a un sesto.

Lettere accentate e caratteri speciali (à, è, é, ò, ù)

L'Arduino IDE salva il codice in UTF-8, quindi una lettera come "è" o "à" nel testo non occupa un byte, ma due. MD_Parola cerca ogni byte come numero di carattere nel font, per questo le lettere accentate diventano simboli senza senso. Il font predefinito della libreria contiene tutto il set Latin-1 (à, è, é, ì, ò, ù e altri), quindi basta una piccola funzione che converta l'UTF-8 nei codici del font. Le lettere che non fanno parte del Latin-1, come le turche ğ, ı e ş dell'esempio qui sotto, vanno disegnate pixel per pixel e aggiunte con addChar(). Lo sketch fa entrambe le cose.

Arduino (C++)
1// MAX7219 + MD_Parola: Türkçe karakterli kayan yazı / Scrolling text with Turkish letters
2#include <MD_Parola.h>
3#include <MD_MAX72xx.h>
4#include <SPI.h>
5
6#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
7#define MAX_DEVICES 4
8#define CS_PIN 10
9
10MD_Parola display = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
11
12// Fontta olmayan 6 harf: ilk bayt genişlik, sonrakiler sütunlar (bit 0 = en üst satır)
13// 6 letters missing from the font: first byte is the width, then the columns (bit 0 = top row)
14const uint8_t trG[] = {5, 56, 69, 70, 85, 116};  // Ğ
15const uint8_t trg[] = {4, 25, 166, 166, 125};    // ğ
16const uint8_t trI[] = {3, 68, 125, 68};          // İ
17const uint8_t tri[] = {1, 124};                  // ı
18const uint8_t trS[] = {5, 70, 73, 201, 73, 49};  // Ş
19const uint8_t trs[] = {4, 88, 212, 84, 52};      // ş
20
21// UTF-8 metni fontun kodlarına çevirir / converts UTF-8 text to the font's codes
22void utf8ToFont(const char *src, char *dst, size_t size) {
23  size_t n = 0;
24  while (*src && n < size - 1) {
25    uint8_t c = *src++;
26    if (c < 0x80) { dst[n++] = c; continue; }            // ASCII aynen kalır / ASCII stays as is
27    if ((c & 0xE0) == 0xC0 && *src) {                    // 2 baytlık harf / 2-byte letter
28      uint16_t u = ((c & 0x1F) << 6) | (*src++ & 0x3F);
29      switch (u) {
30        case 0x11E: dst[n++] = (char)0x80; break;        // Ğ
31        case 0x11F: dst[n++] = (char)0x81; break;        // ğ
32        case 0x130: dst[n++] = (char)0x82; break;        // İ
33        case 0x131: dst[n++] = (char)0x83; break;        // ı
34        case 0x15E: dst[n++] = (char)0x84; break;        // Ş
35        case 0x15F: dst[n++] = (char)0x85; break;        // ş
36        default: dst[n++] = (u < 0x100) ? (char)u : '?'; // ç ö ü Ç Ö Ü ° fontta var / already in the font
37      }
38      continue;
39    }
40    while ((*src & 0xC0) == 0x80) src++;                 // desteklenmeyen karakteri atla / skip an unsupported character
41    dst[n++] = '?';
42  }
43  dst[n] = '\0';
44}
45
46char message[96];
47
48void setup() {
49  display.begin();
50  display.setIntensity(3);
51  display.addChar(0x80, trG);                // addChar begin()'den sonra / addChar after begin()
52  display.addChar(0x81, trg);
53  display.addChar(0x82, trI);
54  display.addChar(0x83, tri);
55  display.addChar(0x84, trS);
56  display.addChar(0x85, trs);
57  utf8ToFont("Günaydın İstanbul! Şehirde hava 22°C, çok güzel bir gün.", message, sizeof(message));
58  display.displayText(message, PA_LEFT, 40, 1000, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
59}
60
61void loop() {
62  if (display.displayAnimate()) display.displayReset();
63}

In ogni array di carattere personalizzato il primo byte indica la larghezza della lettera in colonne e i byte successivi sono le colonne da sinistra a destra; il bit 0 di ogni byte è la riga più in alto. Ad esempio la ı turca (i senza puntino) è una sola colonna e il valore 124 (0b01111100) accende le righe da 2 a 6; si distingue dalla i normale solo per il puntino mancante. Nelle maiuscole Ğ e İ la lettera è stata accorciata di due righe (5 invece di 7) per lasciare spazio al segno sopra. addChar() non copia i dati, ne memorizza solo l'indirizzo: gli array devono quindi essere globali e aggiunti dopo begin(). Sono stati scelti i codici 0x80–0x85 perché non compaiono mai in un testo normale. Allo stesso modo puoi aggiungere qualsiasi simbolo, come un cuore o una freccia.

Esempio di orologio: orologio digitale con modulo RTC

Modulo orologio RTC DS1307
Modulo RTC DS1307: grazie alla batteria a bottone continua a contare il tempo anche con Arduino spento; si collega al bus I2C tramite i pin SDA e SCL.

Il contatore millis() di Arduino si azzera quando manca la corrente e, a causa del risonatore ceramico della Uno, può sbagliare anche di alcuni minuti al giorno. Per un vero orologio usa un modulo orologio RTC. Collega il modulo DS1307 al bus I2C (SDA → A4, SCL → A5, VCC → 5V, GND → GND); il MAX7219 usa i pin SPI, quindi i due moduli non si disturbano. Per il codice installa dal Gestore librerie la libreria RTClib di Adafruit.

Arduino (C++)
1// MAX7219 + DS1307 RTC ile dijital saat / Digital clock with MAX7219 + DS1307 RTC
2#include <MD_Parola.h>
3#include <MD_MAX72xx.h>
4#include <SPI.h>
5#include <RTClib.h>                         // Adafruit RTClib
6
7#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
8#define MAX_DEVICES 4
9#define CS_PIN 10
10
11MD_Parola display = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
12RTC_DS1307 rtc;                             // SDA = A4, SCL = A5
13
14char timeText[8];                           // "12:34" + sonlandırıcı / + terminator
15uint8_t lastSecond = 99;
16
17void setup() {
18  display.begin();
19  display.setIntensity(2);
20  display.setTextAlignment(PA_CENTER);      // print() bu hizalamayı kullanır / print() uses this alignment
21  if (!rtc.begin()) {
22    display.print("RTC?");                  // modül bulunamadı / module not found
23    while (true) {}
24  }
25  if (!rtc.isrunning()) {
26    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));   // ilk kurulumda derleme saati / compile time on first run
27  }
28}
29
30void loop() {
31  DateTime now = rtc.now();
32  if (now.second() != lastSecond) {         // saniyede bir güncelle / update once a second
33    lastSecond = now.second();
34    // ':' ve boşluk aynı genişlikte, yazı kaymaz / ':' and space are equally wide, nothing shifts
35    sprintf(timeText, (lastSecond % 2) ? "%02d %02d" : "%02d:%02d", now.hour(), now.minute());
36    display.print(timeText);
37  }
38}

Lo sketch legge l'ora una volta al secondo e fa lampeggiare i due punti. Nel font predefinito i due punti (:) e lo spazio hanno la stessa larghezza (2 colonne), quindi le cifre non si spostano. Al primo avvio l'RTC viene impostato sul momento in cui lo sketch è stato compilato. Un DS1307 può sbagliare di circa un minuto al mese; per un orologio più preciso prendi un modulo DS3231 e nel codice usa RTC_DS3231 al posto di RTC_DS1307 e sostituisci la condizione if (!rtc.isrunning()) con if (rtc.lostPower()). Grazie al quarzo compensato in temperatura, il DS3231 sbaglia solo di circa un minuto all'anno. Puoi anche dividere il display in due zone per mostrare l'ora da un lato e la temperatura dall'altro.

Animazione: disegnare pixel per pixel con MD_MAX72XX

Per andare oltre il testo scorrevole puoi usare direttamente la libreria MD_MAX72XX. Tratta l'intera catena come un unico display a pixel: un modulo 4 in 1 ha 32 colonne e 8 righe. setPoint(riga, colonna, stato) accende o spegne un singolo LED, setColumn() scrive in un colpo solo gli 8 bit di una colonna e clear() pulisce il display. L'origine (0, 0) è l'angolo in alto a destra; i numeri di colonna crescono verso sinistra e quelli di riga verso il basso. Il codice seguente disegna una pallina che rimbalza sui bordi del display:

Arduino (C++)
1// MD_MAX72XX ile seken top animasyonu / Bouncing ball animation with MD_MAX72XX
2#include <MD_MAX72xx.h>
3#include <SPI.h>
4
5#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
6#define MAX_DEVICES 4
7#define CS_PIN 10
8
9MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
10
11int x = 0, y = 0;                           // topun konumu (sütun, satır) / ball position (column, row)
12int dx = 1, dy = 1;                         // hareket yönü / direction of travel
13
14void setup() {
15  mx.begin();
16  mx.control(MD_MAX72XX::INTENSITY, 2);
17  mx.clear();
18}
19
20void loop() {
21  const int lastCol = mx.getColumnCount() - 1;          // 4 modülde 31 / 31 with 4 modules
22  mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);      // çizim bitene kadar gönderme / hold updates while drawing
23  mx.setPoint(y, x, false);                             // eski konumu sil / erase the old position
24  x += dx;
25  y += dy;
26  if (x <= 0 || x >= lastCol) dx = -dx;                 // kenara çarpınca dön / bounce off the edge
27  if (y <= 0 || y >= 7) dy = -dy;
28  mx.setPoint(y, x, true);                              // yeni konumu yak / light the new position
29  mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);       // hepsini tek seferde gönder / send everything at once
30  delay(40);
31}

In ogni fotogramma si disattiva prima l'aggiornamento automatico (UPDATE), si cancella il vecchio pixel e si disegna quello nuovo, poi si riattiva UPDATE in modo che tutte le modifiche arrivino ai moduli in un colpo solo. Così non compare mai un fotogramma disegnato a metà. Con lo stesso metodo puoi disegnare un dado, faccine, il gioco del serpente o barre del livello sonoro. Gli esempi di MD_MAX72XX includono anche animazioni pronte come Pac-Man, occhi da robot e una clessidra. Se usi MD_Parola, raggiungi le stesse funzioni di disegno con getGraphicObject().

Messaggi via internet con ESP32: testo scorrevole dal telefono

Con un ESP32 puoi rendere wireless la tua insegna a testo scorrevole. Il codice qui sotto si collega alla rete di casa, fa scorrere prima il proprio indirizzo IP e poi mostra l'ora presa da internet (NTP). Apri quell'indirizzo IP nel browser di un telefono collegato allo stesso Wi-Fi e vedrai una casella di testo; il messaggio che scrivi inizia a scorrere al giro successivo e si alterna con l'orologio. Il modulo si collega ai pin VSPI come nella tabella: CLK al GPIO 18, DIN al GPIO 23 e CS al GPIO 5. Se sei alle prime armi con l'ESP32, leggi prima Che cos'è l'ESP32?.

Arduino (C++)
1// ESP32: telefondan mesaj + internet saati / ESP32: message from your phone + internet time
2#include <WiFi.h>
3#include <WebServer.h>
4#include <time.h>
5#include <MD_Parola.h>
6#include <MD_MAX72xx.h>
7#include <SPI.h>
8
9#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
10#define MAX_DEVICES 4
11#define CS_PIN 5                            // VSPI: CLK = GPIO 18, DIN = GPIO 23
12
13const char* ssid = "AgAdi";                 // Wi-Fi adın / your Wi-Fi name
14const char* password = "Sifre123";          // Wi-Fi şifren / your Wi-Fi password
15
16MD_Parola display = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
17WebServer server(80);
18
19char message[128];
20char nextMessage[128];
21char clockText[8] = "--:--";
22bool newMessage = false;
23bool showClock = false;
24
25const char PAGE[] = R"rawliteral(<!DOCTYPE html><html><head><meta charset="utf-8">
26<meta name="viewport" content="width=device-width"><title>MAX7219</title></head><body>
27<h2>Kayan yazı / Scrolling text</h2>
28<form action="/"><input name="m" maxlength="100"> <button>Gönder / Send</button></form>
29</body></html>)rawliteral";
30
31void handleRoot() {
32  if (server.hasArg("m")) {                 // formdan gelen mesaj / message from the form
33    server.arg("m").toCharArray(nextMessage, sizeof(nextMessage));
34    newMessage = true;
35  }
36  server.send(200, "text/html; charset=utf-8", PAGE);
37}
38
39void setup() {
40  display.begin();
41  display.setIntensity(3);
42  display.print("WiFi..");
43  WiFi.begin(ssid, password);
44  while (WiFi.status() != WL_CONNECTED) delay(500);
45  configTime(3 * 3600, 0, "pool.ntp.org");  // Türkiye UTC+3 / Turkey is UTC+3
46  snprintf(message, sizeof(message), "IP: %s", WiFi.localIP().toString().c_str());
47  server.on("/", handleRoot);
48  server.begin();
49  display.displayText(message, PA_LEFT, 40, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
50}
51
52void loop() {
53  server.handleClient();
54  if (display.displayAnimate()) {           // önceki gösterim bitti / the previous show has ended
55    showClock = !showClock;
56    if (newMessage) {                       // yeni mesaj sırayı keser / a new message jumps the queue
57      strlcpy(message, nextMessage, sizeof(message));
58      newMessage = false;
59      showClock = false;
60    }
61    if (showClock) {
62      struct tm t;
63      if (getLocalTime(&t, 10)) strftime(clockText, sizeof(clockText), "%H:%M", &t);
64      display.displayText(clockText, PA_CENTER, 40, 3000, PA_SCROLL_DOWN, PA_SCROLL_UP);
65    } else {
66      display.displayText(message, PA_LEFT, 40, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
67    }
68  }
69}

handleRoot() non manda subito sul display il messaggio arrivato dal modulo web, ma lo mette in attesa in nextMessage. Il messaggio viene copiato solo quando l'animazione in corso è finita (quando displayAnimate() restituisce true); così il testo che MD_Parola sta leggendo non cambia mai a metà. Il valore 3 × 3600 in configTime() è il fuso orario UTC+3 della Turchia; in Italia sostituisci quella riga con configTzTime("CET-1CEST,M3.5.0,M10.5.0/3", "pool.ntp.org"), che gestisce anche l'ora legale. Per messaggi con lettere accentate aggiungi a questo sketch le righe addChar() e la funzione utf8ToFont() viste sopra, e sostituisci la riga con strlcpy() con utf8ToFont(nextMessage, message, sizeof(message)). Per l'ora da internet e i pannelli web in tempo reale guarda Orologio NTP con ESP32 e Web server e WebSocket con ESP32.

MAX7219 con Raspberry Pi Pico e MicroPython

Sul Pico con MicroPython la strada più pratica è copiare sul Pico con Thonny il driver open source max7219.py (micropython-max7219). Poiché il driver usa il modulo framebuf di MicroPython, funzioni di disegno come text(), pixel(), line() e rect() sono già pronte, e sui moduli 4 in 1 FC-16 l'orientamento è corretto. Alimenta il modulo da VBUS (5 V) e collega DIN a GP19, CLK a GP18 e CS a GP17. MicroPython riserva anche il pin MISO di SPI0 (GP16), quindi non usarlo per altro. Il font di framebuf è da 8x8 pixel e solo ASCII, per cui un modulo 4 in 1 mostra 4 lettere alla volta e niente lettere accentate. Per la configurazione vedi Che cos'è il Raspberry Pi Pico? e Basi di MicroPython.

MicroPython
1# Pico + 4'lü MAX7219 modül: kayan yazı / Pico + 4-in-1 MAX7219 module: scrolling text
2from machine import Pin, SPI
3import time
4import max7219                        # max7219.py Pico'da olmalı / must be on the Pico
5
6# GP18 = SCK -> CLK, GP19 = MOSI -> DIN, GP17 -> CS; GP16 (MISO) boş kalır / GP16 (MISO) stays free
7spi = SPI(0, baudrate=5_000_000, polarity=0, phase=0, sck=Pin(18), mosi=Pin(19))
8display = max7219.Matrix8x8(spi, Pin(17, Pin.OUT), 4)
9display.brightness(3)                 # parlaklık 0–15 / brightness 0–15
10
11def scroll(text, delay_ms=35):
12    width = len(text) * 8             # her harf 8 piksel / each letter is 8 px wide
13    for x in range(32, -width, -1):   # sağdan girip solda kaybolur / enters right, leaves left
14        display.fill(0)
15        display.text(text, x, 0, 1)
16        display.show()
17        time.sleep_ms(delay_ms)
18
19while True:
20    scroll("BlueGrays + Pico")
21    display.fill(0)
22    display.text("Pico", 0, 0, 1)     # 4 harf tam sığar / exactly 4 letters fit
23    display.show()
24    time.sleep(1)
25    display.fill(0)
26    display.rect(0, 0, 32, 8, 1)      # ekran çerçevesi / display frame
27    display.show()
28    time.sleep_ms(500)

Idee di progetti con il MAX7219

  • Insegna a testo scorrevole: crea una bacheca per un negozio, un'aula o la porta della tua camera e cambia il messaggio dal telefono con un modulo Bluetooth HC-05.
  • Orologio, calendario e temperatura: mostra a turno ora e data dall'RTC e temperatura e umidità da un sensore DHT11.
  • Orologio internet e meteo: fai scorrere con un ESP32 l'ora NTP e la temperatura presa da un'API meteo.
  • Segnapunti: gestisci un display a due zone per una partita di ping pong o di basket con un telecomando IR.
  • Minigiochi: gioca a snake, a Pong o a schivare ostacoli sul display 32x8 con un joystick; altre idee in Progetti di giochi con Arduino.
  • Indicatore di livello sonoro: disegna le letture di un sensore sonoro come un grafico a barre da 32 colonne.
  • Pannello di animazioni 32x32: impila quattro moduli 4 in 1 e riproduci animazioni come pioggia, stelle o fuochi d'artificio.

Errori comuni e soluzioni

SintomoCausa probabileSoluzione
Non si accende nessun LEDManca l'alimentazione, i fili sono sul lato OUT o il pin CS non corrisponde al codiceCollega i fili al lato IN con la scritta DIN, controlla CS_PIN e l'alimentazione a 5 V
Tutti i LED sono accesi al massimo e non cambianoNon arrivano dati: DIN e CLK sono scambiati o il chip è rimasto in modalità testCollega DIN a MOSI e CLK a SCK, poi togli e ridai l'alimentazione
Lettere a specchio, capovolte o ruotate di 90 gradiHARDWARE_TYPE sbagliatoProva FC16_HW sul modulo 4 in 1 e GENERIC_HW sul modulo singolo
Tutto il testo è capovolto e scorre da sinistra a destraModulo montato al contrario, ingresso DIN a sinistraRuota il modulo di 180 gradi; l'ingresso DIN deve essere a destra
Funziona solo un blocco o il testo appare tagliatoMAX_DEVICES sbagliato o collegamento interrotto tra i moduliImposta MAX_DEVICES al numero di blocchi e controlla i fili OUT → IN
Arduino si riavvia o l'immagine sfarfalla ad alta luminositàSi supera il limite USB di 500 mA e la tensione calaUsa un alimentatore esterno da 5 V 2 A, unisci i GND e abbassa la luminosità
Punti casuali e caratteri disturbati con l'ESP32Il segnale a 3,3 V è sotto la soglia HIGH di 3,5 V e i fili sono lunghiAlza il livello con un 74HCT125 e accorcia i fili
Le lettere accentate diventano simboli senza sensoI byte UTF-8 arrivano così come sono al fontUsa il metodo utf8ToFont() e addChar()
Il testo scorrevole avanza a scattiIn loop() c'è un delay() o un'operazione lungaChiama spesso displayAnimate() e gestisci le attese con millis()
Quando qualcosa non funziona, parti dal test più semplice: lascia nel codice solo display.begin() e display.print("8888"). Se non si accende nessun LED, il problema è nel cablaggio o nell'alimentazione; misura con il multimetro che tra i pin VCC e GND del modulo ci siano 4,5–5 V. Se i LED si accendono ma le cifre sono deformate, il problema è il tipo di hardware; se funziona solo il primo blocco, controlla MAX_DEVICES o i collegamenti tra i moduli.

Il MAX7219 è uno dei modi più economici per ottenere un display d'effetto con pochi fili: il chip si occupa di scansione, limitazione della corrente e luminosità, e tu pensi solo a cosa mostrare. Comincia disegnando icone su un modulo 8x8, poi passa al testo scorrevole, all'orologio e ai messaggi wireless con un ESP32 su un modulo 4 in 1. Se vuoi LED colorati controllabili uno per uno, i WS2812B NeoPixel sono un'ottima scelta, e per un progetto che mostra solo numeri un display a 7 segmenti. Nell'app BlueGrays trovi progetti con il MAX7219 come un orologio e calendario a matrice di punti, una stazione meteo, animazioni 32x8 e testo scorrevole, passo dopo passo con schemi e codice.

Domande frequenti

Perché il testo sul mio modulo MAX7219 è a specchio o capovolto?

I produttori collegano la matrice 8x8 al MAX7219 in modi diversi e la libreria compensa con l'impostazione HARDWARE_TYPE. La maggior parte dei moduli 4 in 1 blu venduti oggi si vede correttamente con FC16_HW, i moduli singoli verdi con GENERIC_HW. Se l'immagine è ancora sbagliata, prova anche PAROLA_HW e ICSTATION_HW; nel codice cambia una sola riga.

Quanti moduli MAX7219 si possono collegare in cascata?

Il chip in sé non ha limiti e, poiché MD_MAX72XX memorizza il numero di moduli in un byte, la libreria ne accetta fino a 255. In pratica il limite lo fissano l'alimentazione e la qualità del segnale: ogni 4–8 blocchi riporta 5 V e GND nella catena, usa fili corti e aggiungi a ogni modulo un condensatore da 10 µF e uno da 100 nF. Più la catena è lunga, più ogni aggiornamento richiede tempo e RAM.

Il MAX7219 funziona con un ESP32 a 3,3 V?

Il MAX7219 ha bisogno di almeno 4 V di alimentazione, quindi alimenta il modulo dal pin 5V (VIN) dell'ESP32. Il datasheet richiede 3,5 V come livello HIGH con alimentazione a 5 V; i segnali a 3,3 V dell'ESP32 funzionano comunque sulla maggior parte dei moduli, ma sono sotto quel limite. Per un funzionamento affidabile metti un traslatore di livello come il 74HCT125 sulle linee DIN, CLK e CS.

Quanta corrente assorbe una matrice LED MAX7219?

Un modulo 8x8 con tutti i LED accesi alla massima luminosità assorbe circa 330 mA, un modulo 4 in 1 8x32 fino a 1,3 A. Con il testo scorrevole si accende solo una parte dei LED e la luminosità di solito resta tra 2 e 7, quindi un modulo 4 in 1 assorbe in genere circa 100–250 mA. In modalità shutdown ogni chip consuma solo circa 150 µA.

Come si visualizzano le lettere accentate su una matrice MAX7219?

Il font predefinito di MD_Parola contiene à, è, é, ò, ù e gli altri caratteri Latin-1, ma l'Arduino IDE li salva come due byte UTF-8. Prima di mostrarlo, converti quindi il testo nei codici del font con una piccola funzione. I caratteri che non fanno parte del Latin-1 puoi disegnarli tu e aggiungerli con addChar().

Si può pilotare un display a 7 segmenti con il MAX7219?

Sì. Il MAX7219 è stato progettato proprio per display a 7 segmenti a catodo comune fino a 8 cifre e ha una modalità BCD che decodifica le cifre da sola. Puoi usare facilmente i moduli display MAX7219 a 8 cifre con la funzione setDigit() della libreria LedControl. I display ad anodo comune, invece, non si possono collegare direttamente a questo chip.

Vedi tutti i progetti
Orologio e calendario a matrice di punti (MAX7219, DS1307)
#84Intermedio
Premium

Orologio e calendario a matrice di punti (MAX7219, DS1307)

Un pannello luminoso per la scrivania o la parete che mostra ora e data con scritte scorrevoli. Sul display LED 8x32 c'è un orologio a cifre grandi con i due punti che lampeggiano ogni secondo; all'in

5.0(37)
58
Orologio a matrice di punti, calendario e stazione meteo (MAX7219, DS1307)
#85Intermedio
Premium

Orologio a matrice di punti, calendario e stazione meteo (MAX7219, DS1307)

Un pannello a scritte scorrevoli per la scrivania o la parete che mostra a turno l'ora, la data e il clima della stanza. Sul display LED 8x32 compaiono prima la temperatura in Celsius e Fahrenheit, po

5.0(50)
66
Animazione e testo LED a matrice 4x 32x8
#90Intermedio
Premium

Animazione e testo LED a matrice 4x 32x8

Impilando quattro lunghi moduli a matrice di LED ottieni uno schermo quadrato con più di mille punti luminosi. Prima le lettere cadono dall'alto come una pioggia da film, poi si apre un sipario e due

4.6(40)
66
Matrice LED 4x 32x8 - Pacchetto di 6 animazioni
#91Intermedio
Premium

Matrice LED 4x 32x8 - Pacchetto di 6 animazioni

Quattro pannelli LED 32x8 messi uno sopra l'altro formano uno schermo quadrato su cui si alternano sei animazioni: pioggia digitale che cade, una spirale che cresce, cellule che nascono e muoiono da s

4.5(35)
48
Serpente di pixel Matrice 8x8
#88Avanzato
Premium

Serpente di pixel Matrice 8x8

Costruisci con le tue mani il classico gioco del serpente e giocaci. Su una matrice di luci colorate 8x8 guidi un serpente verde con un joystick e mangi mele rosse; a ogni mela il serpente si allunga,

4.7(39)
57
ESP32: ora reale da Internet tramite NTP
#128Avanzato
Premium

ESP32: ora reale da Internet tramite NTP

L'ESP32 si connette al Wi-Fi e recupera l'ora reale con precisione al millisecondo dai server NTP (Network Time Protocol). Grazie a `configTzTime()`, il fuso orario della Turchia (TRT, UTC+3) viene applicato automaticamente e il passaggio all'ora legale è gestito tramite la stringa POSIX TZ. L'ora viene mostrata sul Serial Monitor e su un display LCD I2C opzionale. `configTzTime()` avvia il servizio SNTP; vengono eseguite risincronizzazioni periodiche finché è disponibile l'accesso alla rete, e

4.5(13)
21
Orologio digitale con ESP32 e RTC DS1307 (I2C + LCD)
#120Intermedio
Premium

Orologio digitale con ESP32 e RTC DS1307 (I2C + LCD)

In questo progetto, utilizziamo il modulo orologio in tempo reale (RTC) DS1307 per visualizzare l'ora e la data su un display LCD 16x2 I2C. Il DS1307 è un RTC con batteria di supporto che mantiene l'ora anche se l'ESP32 si spegne. Entrambi i moduli condividono la stessa linea I2C (SDA/SCL), permettendoci di imparare a controllare più dispositivi utilizzando solo due cavi di segnale. Cosi imparerai il protocollo I2C e il funzionamento dei moduli RTC nella pratica.

4.6(26)
40
Orologio digitale con display a 7 segmenti a 4 cifre
#48Intermedio
Premium

Orologio digitale con display a 7 segmenti a 4 cifre

Un orologio digitale luminoso a quattro cifre, simile a quello del forno in cucina. Il modulo orologio DS1302 tiene l'ora, e ogni secondo l'Arduino legge ore e minuti e li mostra sul display a quattro

4.8(56)
73