PrettyPrint

domenica 10 marzo 2024

Arduino: visualizzare numero decimale su multidisplay LED 7 segmenti

L'obiettivo è quello di visualizzare la tensione letta da un ingresso analogico di Arduino UNO R3, compresa fra 0 e 5V, su un multidisplay LED 7segmenti integrato, a 4 cifre, ad anodo comune:

I MULTIDISPLAY LED 7SEGMENTI




Questi display LED hanno in comune gli 8 LED di ogni cifra (7 segmenti per il numero e 1 per il punto decimale) , consentendo così di risparmiare notevolmente i pin di I/O per il collegamento al microcontrollore, mentre sono ovviamente separati i 4 pin comuni (anodo o catodo comune) per consentirne l'accensione o spegnimento; la tensione di comando (0V nel caso del CC o 5V nel caso del CA) ovviamente non sarà fissa, ma erogata da un pin I/O di un microcontrollore, come quello della scheda Arduino UNO R3:

La gestione di questi display LED multipli avviene in mutliplexing a divisione di tempo, "accedendo", quindi, un display per volta per un brevissimo tempo (dai 2 ai 5 ms). Sfruttando l'illusione ottica della persistenza della visione dell'occhio umano, il numero da visualizzare apparirà come se fosse fisso:



Fonte: https://en.wikipedia.org/wiki/Multiplexed_display#/media/File:7segment_multiplexing.gif


I vantaggi sono molteplici: si risparmiano 20 pin I/O del microcontrollore, aggiuntivi rispetto al display singolo (ne occorrono infatti 4 per comandare i 4 pin comuni), si riduce l'assorbimento energetico, essendo un solo display acceso, e non quattro, per ogni lettura.

Occorre, però, un software di gestione leggermente più complesso, che "spacchetti" innanzitutto il numero, intero o decimale, a 4 cifre in 4 singole cifre, predisponendo pure l'accensione dell'eventuale punto decimale o l'eventuale spegnimento degli zeri non significativi.

Esistono librerie molto efficienti a tale scopo (come SevSegment) ma ovviamente è sempre formativo provvedere alla creazione di una propria libreria, anche se meno sofisticata, ma innanzitutto orientata alla semplicità e alla comprensibilità per un target "scolastico".

Le funzioni utente sono tre:

DISPLAY7S

Questa funzione attiva i segmenti (e l'eventuale punto decimale) in funzione del numero da visualizzare.

Essa accetta in ingresso due parametri:

- il numero decimale (da 0 a 9) da visualizzare
- un eventuale flag per l'accensione del punto decimale: 1 (acceso), 0 (spento); 
  invocando la funzione solo con il primo parametro, questo flag è di default 0

Una successiva istruzione di selezione multipla, assegna ai vari segmenti lo stato in funzione del numero che si intende visualizzare. Impostati i vari stati, le istruzione di scrittura digitale provvedono a spegnere o accendere i segmenti secondo gli stati impostati.

DISPLAYEN

Questa funzione attiva un solo display alla volta, per un brevissimo tempo.

Essa accetta in ingresso un solo parametro: l'indice del display che si intende accendere (da 0, il primo, a 3, l'ultimo). Il display verrà dunque acceso per 5ms e successivamente spento

FLOATTO4DGT

Questa funzione provvede a "spacchettare" il numero decimale da visualizzare nelle 4 cifre, provvedendo anche a impostare l'accensione dell'eventuale punto decimale.

Essa accetta tre parametri:

- il numero decimale da visualizzare (che ovviamente dovrà essere compreso fra 0 e 9999)
- l'indirizzo del vettore delle cifre del multidisplay
- l'indirizzo del vettore dei punti decimali del multidisplay

DEFINIZIONI FUNZIONAMENTO DEL DISPLAY

Occorrerà innanzitutto impostare delle costanti simboliche: SON e SOFF, rispettivamente i livelli logici per avere l'accensione o lo spegnimento del segmento (e anche del punto decimale). Se abbiamo, quindi, un CA (anodo comune) SON sarà LOW e SOFF sarà HIGH.

Viceversa i livelli logici per l'accensione e lo spegnimento del display, quelli cioè applicati al pin comune, saranno sempre i negati di quelli che accendono i segmenti:

#define SON LOW // SEGM ON :LOW (CA) / HIGH (CC) #define SOFF HIGH // SEGM OFF :HIGH (CA) / LOW (CC) #define CON !SON #define COFF !SOFF

Infine si definiranno i pin di Arduino collegati ai segmenti (con la lettera maiuscola: A,B, C ecc) e le variabili di stato dei segmenti (con la lettera minuscola a,b,c) oltre ai due vettori delle cifre del display e dei punti decimali.

Di seguito lo sketch completo:

MUX_4_LED_ADC.INO

/******************************************************/ /* DEFINIZIONI FUNZIONAMENTO DISPLAY */ /******************************************************/ #define SON LOW // SEGM ON :LOW (CA) / HIGH (CC) #define SOFF HIGH // SEGM OFF :HIGH (CA) / LOW (CC) #define CON !SON // COMUNE ON : NOT SON #define COFF !SOFF // COMUNE OFF: NOT SOFF const int A = 11 ; //pin a cui è collegato il seg. A const int B = 12 ; const int C = 8; const int D = 7 ; const int E = 6 ; const int F = 10 ; const int G = 9; const int DP = 13; const int C1 = 5; // pin comune della cifra 1 (sx) const int C2 = 4; const int C3 = 3; const int C4 = 2; int a,b,c,d,e,f,g; // stato dei singoli segmenti: ON/OFF int display[4]; //vettore cifre display int puntodec[4]; //vettore punti decimali /******************************************************/ /* FUNZIONE SPACCHETTAMENTO FLOAT -> CIFRE */ /******************************************************/ int floatTo4dgt (float n, int dgt[], int dp[]) { int parte_int, parte_dec, n_dec, n_int; float temp; if (n<0 || n>9999) { return -1; // float non valido (max 4 cifre) } else { parte_int = (int) n; temp = n - parte_int; if (n == 0) // visualizzato come 0.000 n_dec = 3; else { if (parte_int<10 || n==0.0) n_dec = 3; //numero cifre dopo la virgola else if (parte_int < 100) n_dec = 2; else if (parte_int < 1000) n_dec = 1; else n_dec = 0; } n_int = 4 - n_dec; // numero cifre prima della virgola for (int i = 0; i < n_dec; i++) { temp=temp*10; // shift a sx di n_dec posiz. } parte_dec = (int) temp; //toglie lo 0 dopo la virgola if (n_dec == 3) { dgt[0] = parte_int; dgt[1] = parte_dec / 100; dgt[2] = (parte_dec % 100) / 10; dgt[3] = (parte_dec % 100) % 10; dp[0] = 1; dp[1] = 0; dp[2] = 0; dp[3] = 0; } if (n_dec == 2) { dgt[0] = parte_int / 10; dgt[1] = parte_int % 10; dgt[2] = parte_dec / 10; dgt[3] = parte_dec % 10; dp[0] = 0; dp[1] = 1; dp[2] = 0; dp[3] = 0; } if (n_dec == 1) { dgt[0] = parte_int / 100; dgt[1] = (parte_int % 100) / 10; dgt[2] = (parte_int % 100) % 10; dgt[3] = parte_dec; dp[0] = 0; dp[1] = 0; dp[2] = 1; dp[3] = 0; } if (n_dec == 0) { dgt[0] = parte_int / 1000; dgt[1] = (parte_int % 1000) / 100; dgt[2] = ((parte_int % 1000) % 100) / 10; dgt[3] = ((parte_int % 1000) % 100) % 10; dp[0] = 0; dp[1] = 0; dp[2] = 0; dp[3] = 0; } return 0; } } /******************************************************/ /* FUNZIONE ATTIVAZIONE SINGOLO DISPLAY */ /******************************************************/ void displayEn(int i) { switch(i) { case 0: digitalWrite(C1, CON); delay(5); digitalWrite(C1, COFF); break; case 1: digitalWrite(C2, CON); delay(5); digitalWrite(C2, COFF); break; case 2: digitalWrite(C3, CON); delay(5); digitalWrite(C3, COFF); break; case 3: digitalWrite(C4, CON); delay(5); digitalWrite(C4, COFF); } } /******************************************************/ /* FUNZIONE CONVERSIONE NUMERO -> COD. 7 SEG */ /******************************************************/ void display7seg(int val, int dp=0) { switch(val) { case 0: a=SON;b=SON;c=SON;d=SON;e=SON;f=SON;g=SOFF; break; case 1: a=SOFF;b=SON;c=SON;d=SOFF;e=SOFF;f=SOFF;g=SOFF; break; case 2: a=SON;b=SON;c=SOFF;d=SON;e=SON;f=SOFF;g=SON; break; case 3: a=SON;b=SON;c=SON;d=SON;e=SOFF;f=SOFF;g=SON; break; case 4: a=SOFF;b=SON;c=SON;d=SOFF;e=SOFF;f=SON;g=SON; break; case 5: a=SON;b=SOFF;c=SON;d=SON;e=SOFF;f=SON;g=SON; break; case 6: a=SON;b=SOFF;c=SON;d=SON;e=SON;f=SON;g=SON; break; case 7: a=SON;b=SON;c=SON;d=SOFF;e=SOFF;f=SOFF;g=SOFF; break; case 8: a=SON;b=SON;c=SON;d=SON;e=SON;f=SON;g=SON; break; case 9: a=SON;b=SON;c=SON;d=SON;e=SOFF;f=SON;g=SON; break; default: // spegne il display a=SOFF;b=SOFF;c=SOFF;d=SOFF;e=SOFF;f=SOFF;g=SOFF; } // accende/spegne ogni seg. secondo il // corrispondente stato assegnato in precedenza digitalWrite(A, a); digitalWrite(B, b); digitalWrite(C, c); digitalWrite(D, d); digitalWrite(E, e); digitalWrite(F, f); digitalWrite(G, g); digitalWrite(DP, dp==1?SON:SOFF); } /******************************************************/ /* CORPO SKETCH */ /******************************************************/ float mvolt; //tensione misurata (in mV) void setup() { pinMode(A, OUTPUT); pinMode(B, OUTPUT); pinMode(C, OUTPUT); pinMode(D, OUTPUT); pinMode(E, OUTPUT); pinMode(F, OUTPUT); pinMode(G, OUTPUT); pinMode(DP, OUTPUT); pinMode(C1,OUTPUT); //pin comune Display cifra 1 pinMode(C2,OUTPUT); pinMode(C3,OUTPUT); pinMode(C4,OUTPUT); } void loop() { // legge la tensione in mV mvolt=map(analogRead(A0),0,1023,0,5000); // Chiama la funzione di "spacchettamento" (passa i Volt) floatTo4dgt (mvolt/1000.0, display, puntodec); // Invia il codice 7segmenti // e attiva in sequenza i 4 display for(int i=0; i<4; i++) { display7seg(display[i], puntodec[i]); displayEn(i); } }