Ago 182013
 

In un precedente articolo ve l’avevo promesso: ho scritto una libreria che permette di comandare display HD44780 attraverso un 74HC595 in contemporanea al controllo di uscite digitali poste sulla stessa linea. Vi dirò di più, potete tranquillamente utilizzare più di un display in contemporanea senza alcun problema e quante uscite digitali volete, sino ad un massimo di 256 chip 74HC595 per cui potreste comandare 256 display o 2048 uscite digitali, o una situazione mista come 5 display e 2008 uscite digitali. Comunque ne ho provati solamente due per cui la velocità effettiva che si avrebbe utilizzando 256 chip in serie non ho idea di quale possa essere, ma dubito che ci sia qualcuno a cui servono così tante uscite in contemporanea. Nulla vieta di creare due linee distinte, solo che per ogni linea impiegate tre pin digitali di Arduino in più. Una raccamandazione: almeno per i display usate il condensatore di decoupling, ossia il condensatore ceramico da 0.1uF (100nF) che deve connettere Vcc e GND stando il più vicino possibile ai pin dell’integrato. Vi dico ciò perchè senza di esso avevo notato che dopo diverse migliaia di istruzioni inviate al display, saltuariamente vi era qualche isolato errore di interpretazione che andava ad alterare il contenuto del display. Dopo decine di ore di debugging del software senza trovare nessun errore, mi sono detto: che sia quello? Detto fatto, ho messo i condensatori in ogni chip e non ho avuto più problemi.

Usare la libreria per gestire uscite digitali

La libreria può esssere utilizzata sia ad alto che a basso livello, ho infatti creato una classe in cui tutte le variabili e le funzioni sono pubbliche in questo modo è possibile interagire con la libreria a qualsiasi livello. L’utilizzo ad alto livello è estremamente semplice. Dopo aver incluso la libreria con #include <HC595.h>, dobbiamo preparare un’istanza alla classe hc595:

hc595 My595(12,11,13,2); // latch,clock,data,number of 74hc595

Come vedete ci sono 4 parametri che corrispondono ai tre pin di latch, clock e data e per ultimo il numero di 74HC595 messi in serie su quella linea. Nel caso specifico abbiamo il latch collegato al pin 12 di Arduino, il clock all’11, data al 13 e sono connessi in serie due chip 74HC595. A questo punto se vogliamo settare le uscite di un determinato chip non facciamo altro che:

My595.Set595Pin(Leds,1);
Send595();

In questo caso setta i singoli bit che compongono il char Leds per le uscite dello shif register numero 1 (secondo parametro). Fate MOLTA attenzione che il primo shift register sarà il numero 0 per cui l’1 rappresenta il secondo chip.Tutte le funzioni che cominciano con “Set” non fanno altro che modificare il buffer interno senza inviare nulla agli shift register. In questo modo è possibile modificare il contenuto di numerosi shift register con un solo ciclo di scrittura verso il display. Se volete inviare subito i dati aggiornati agli shift register usate la funzione Send595();. Come vi dicevo potete accedere direttamente a tutte le funzioni e variabili della classe per cui se volete settare in modo diretto il buffer interno risparmiando una chiamata a funzione, potete sostituire la My595.Set595Pin(Leds,1) con My595.Buffer[1]=Leds;

Se per qualche motivo non mantenete una singola variabile ma volete usare dei bool per ogni singola uscita, potete farlo:

My595.Set595Pin(D7,D6,D5,D4,D3,D2,D1,D0, 1);

Dove D7-D0 sono i singoli bit che possono essere settati a 0/1, true/false, o quel che più vi aggrada, basta che siano dati binari. L’ultimo parametro, come in tutte le funzioni, è il numero dello shift register su cui andiamo ad agire.

Se usate solamente uscite digitali non vi serve altro, basta settare il buffer o in modo diretto o con una delle due versioni della SetPin e poi inviare il risultato con la Send595. Se avete numerosi shift register da comandare vi conviene prima settare tutti i pin e poi utilizzare una singola Send595 per inviare tutti i dati con un’unico ciclo, a meno che ovviamente non dobbiate avere determinati effetti di sincronizzazione fra le vare uscite.

Usare la libreria per comandare display HD44780

L’stanza è identica a prima per cui non ci sono novità. La prima cosa da fare subito dopo è il reset del display. Per farlo c’è una funzione specifica:

My595.ResetDisplay(LCD595_BASIC_DISPLAY_INIT | LCD595_MORELINES ,0);

Il primo parametro permette di selezionare numero di righe e font oltre che a fare il reset vero e proprio. Il secondo indica il chip a cui è collegato il display nella catena. I parametri che possono essere specificati nel primo sono:

LCD595_BASIC_DISPLAY_INIT: usa i parametri standar del chip HD44780
 LCD595_USEFONT_5X10 : usa il font 5x10 anzichè il 5x8
 LCD595_MORELINES: per display con più di una riga.

Anche se non fanno specificatamente parte del reset fisico del display, la libreria in questa fase esegue anche un’operazione di accensione del display e sua “pulizia”. Il cursore viene mantenuto spento. A questo punto il display è pronto ad operare. Fra le opzioni più comuni c’è lo spostamento del cursore e la scrittura di un carattere o una stringa. Queste tre operazioni sono delegate ad altrettante tre funzioni:

My595.SetCursor(0,3,2,0);

I primi due parametri sono la X e la Y, ricordandoci che le coordinate partono da 0 e NON da 1. L’ultimo parametro è il numero di shift register a cui e connesso il display. E il terzo parametro? Questo serve solamente nei display a 4 righe e anche in quel caso nel 90% delle volte lo lascerete sempre a 1. Purtroppo nei display LCD l’indirizzo di memoria del primo carattrere di ogni singola riga non è standardizzato. Ad esempio io ho un display 16×4: se cercate in rete troverete che gli indirizzi delle prime celle sono normalmente 0x00,0x40,0x14,0x54 che corrispondono al parametro 1 della mia libreria. Ma il caso vuole che l’unico display che ho di questa grandezza ha come indirizzi 0x00,0x40,0x10,0x50 che ho associato al 2 in questo misterioso terzo parametro. Probabilmente ci sono molti altri casi diversi per cui è presumibile che ne vengano aggiunti altri in futuro. Per la cronaca nemmeno la LiquidCrystal originale gestisce correttamente il mio display. Oltre a questa funzione è possibile interagire a più basso livello con un’altra funzione:

My595.SetDDRAM_Address(40,0);

Questa setta in modo diretto l’indirizzo della cella di memoria del display; il primo parametro indica l’indirizzo di memoria ed il secondo il chip a cui è connesso il display.

Una volta settata la posizione del cursore potete scriverci una lettera singola o una stringa con le due funzioni apposite:

My595.DisplayChar('Z',0);
My595.DisplayWrite("McMajan",0);

La prima scrive il carattere Z nella posizione del cursore, mentre la seconda scrive la stringa McMajan sempre dove si trova il cursore in quel momento.

C’è poi un’altra funzione che permette di inviare comandi al display che è la SendLcdCommand. In ingresso prende un char contenente gli 8 bit che compongono il comando, poi ci pensa la funzione a separare i primi bit dagli ultimi, settare il pin RS e quant’altro. Questa funziona può essere usata per comandare il display a basso livello, o può essere usata con delle costanti che ho preparato già pronte per l’uso. Ad esempio:

My595.SendLcdCommand(LCD595_DISPLAY_ON_C,0);

Questo comando accende il display (se non lo fosse) ed accende anche il cursore fisso (C). Il secondo parametro, come sempre, indica la posizione dello shift register nella catena. Vediamo le altri costanti pronte all’uso:

LCD595_DISPLAY_ON_CB: Accende il display accendendo il cursore e facendo lampeggiare il carattere corrispondente.
 LCD595_DISPLAY_ON_C: Accende il display accendendo il cursore ma senza fal lampeggiare il carattere corrispondente.
 LCD595_DISPLAY_ON_B: Accende il display settando il lampeggiamento della posizione cursore
 LCD595_DISPLAY_ON: Accende il display senza cursore
 LCD595_DISPLAY_OFF: Spegene il display.
 LCD595_DISPLAY_CLEAR: Pulisce il display facendo un clear.

Per finire ho implementato una funzione simile alla createChar della LiquidCrystal, per creare caratteri personalizzati. La funzione può essere richiamata con un My595.CreateChar(0,MyChar,0). Il primo parametro indica il carattere da ridefinire (da 0 a 7), il secondo contiene l’array con la mappatura del carattere e l’ultimo indica il display a cui applicare la funzione. Per preparare e stampare un carattere potreste usare:

 byte MyChar[8] = {0,10,21,10,0,17,14,0};  // preparo l'array con i valori
 My595.CreateChar(0,MyChar,0); // mappo il carattere 0 sul display 0
 My595.SetCursor(5,2,2,0); // metto il cursore del display 0 su 5,2 usando coordinate per display di tipo 2
 My595.DisplayChar(0,0);  // scrivo il carattere 0 sul display 0

Sketch di esempio

#include 

hc595 My595(12,11,13,2); // latch,clock,data,number of 74hc595
unsigned char Leds;
char str[12];

void setup() 
{
 My595.ResetDisplay(LCD595_BASIC_DISPLAY_INIT | LCD595_MORELINES ,0);
 Leds=0;
}

void loop()
{
  My595.Set595Pin(Leds,1);

  itoa(Leds,str,10);
  strcat(str,"   ");
  My595.SetCursor(0,3,2,0);
  My595.DisplayWrite(str,0);
  My595.SetCursor(Leds%13,Leds%2,1,0);
  My595.DisplayChar(32+Leds%96,0);
  Leds++;
  delay(800);
}

La sketch di esempio è molto semplice e riflette i comandi prima descritti uno ad uno. Prevede l’uso di due 74HC595 in serie, sul primo è stato collegato un display LCD usando lo schema di collegamento visto nel precedente articolo e che rispecchia il funzionamento della LiquidCrystal originale. Qui sotto ho comunque riportato uno schema che fonde i due menzionati per cui avete un riferimento già pronto. Sul secondo shif register ho collegato dei semplici led, giusto per mostrarne la corretta attivazione, si noti comunque l’utilizzo dell’ULN2083A visto che il 74HC595 non è in grado di erogare sufficiente corrente per tutti i LED (in realtà il prototipo nasce per collegare dei relè, ma il discorso è lo stesso). In questo modo vedete all’opera quello che è lo scopo principale della libreria, ossia l’utilizzo di display LCD e uscite digitali in contemporanea sulla stessa serie di shift register. La variabile Led viene inizializzata a 0 ed incrementata di uno ad ogni ciclo. Il valore viene utilizzato in modo diretto per impostare i led collegati sul secondo shift register, inoltre il valore viene scritto sul display e viene utilizzato anche per rappresentare alcuni dei caratteri disponibili che vengono scritti in modo alternato fra la prima e seconda riga, avanzando verso destra di un carattere alla volta.LCD e Out 74hc595_schem
Ma più di mille parole vale sicuramente il video qui sotto che vi mostra il funzionamento della libreria in azione. La complessità dei collegamenti dipende dal fatto che questo è un prototipo che utilizzo per altri scopi. C’è un Arduino creato in casa con i componenti minimali, ci sono due 74HC595 in uscita di cui uno collegato ad un ULN2803, cosa legata al fatto che nel mio circuito definitivo verranno collegati dei relè e comunque il 74HC595 non è adatto ad erogare sufficiente corrente per tutti i Led. Per lo stesso motivo i led sono alimentati

Considerazioni

Chiunque conosca la programmazione C++ non potrà che dire che la libreria è scritta in maniera grezza, infatti vengono ignorati i più basilari aspetti della programmazione come l’uso di metodi e variabili private. Sono però dell’idea che la programmazione a così basso livello non possa lasciare posto ad inutili complicazioni ed astrazioni del software che portano ad eccessivi sprechi delle poche risorse disponibili. Certo l’uso delle classi ci permette di semplificare la trasportabilità del software in quanto possiamo aggregare funzioni e variabili di uno specifico oggetto tutte insieme. Ho voluto scrivere queste ultime righe solo per spiegare che non ho scritto il software in questo modo perchè non sia in grado di fare di meglio ma è un risultato cercato per rendere la libreria il più possibile leggera e flessibile.

Successivamente alla scrittura di questo articolo ho preparato una pagina apposita per il download della libreria in modo da poter tenere traccia degli aggiornamenti man mano che vengono rilasciati.

La pagina per il DOWNLOAD LA TROVATE QUI.

 

  9 Responses to “Arduino e 74HC595: libreria per display HD44780 compatibili e uscite digitali.”

  1.  

    Ciao,scusa mi riesci a fare un esempio per pilotare delle uscite digitali.
    Nella libreria non esiste nessun esempio per questo scopo,altrimenti ti pubblico il mio codice d’esempio .
    Quello che io ho scritto non funziona correttamente.

    Grazie,mauro

  2.  

    Ciao ,ti allego il codice di prova della libreria,Grazie Mauro

    //
    // Demo of hc595 library
    //

    #include
    #include

    //
    // Comparazione Pin Arduino ÷ Pin hc595
    //
    // Pin 8 Arduino >> Pin 11 hc595
    // Pin 9 Arduino >> Pin 12 hc595
    // Pin 10 Arduino >> Pin 14 hc595
    //

    hc595 My595(8,9,10,1); // Latch,Clock,Data,Quantità hc595 utilizzati
    int led = 13 ;

    //
    // Inizializzazione solo alla 1^ Accensione
    //

    void setup() {

    My595.Set595Pin(1,1,1,1,1,1,1,1,0); // Tutti Spenti
    My595.Send595();
    pinMode(led, OUTPUT);
    delay(100);
    }

    //
    // Programma Principale
    //

    void loop() {

    //
    // Accesi [ D7÷D4 ] Spenti [ D3÷D0 ]
    //

    My595.Set595Pin(0,0,0,0,1,1,1,1,0);
    My595.Send595();
    digitalWrite(led, HIGH );
    delay(500);

    //
    // Spenti [ D7÷D4 ] Accesi [ D3÷D0 ]
    //

    My595.Set595Pin(1,1,1,1,0,0,0,0,0);
    My595.Send595();
    digitalWrite(led, LOW );
    delay(500);
    }

    ////////////////////// End //////////////////////

  3.  

    Ciao, allora, mi manca un dettaglio fondamentale, ossia capire cosa c’è che non ti funziona 🙂 Detto questo manca l’inclusione, immagino una svista, #include . Poi quando i bit sono settati a 1 l’uscita è “accesa”, non spenta, ripeti questa imprecisione in tutti i commenti per cui immagino ci sia un errore.
    Poi c’è un’altra cosa che non mi torna: come costruttore usi:
    hc595 My595(8,9,10,1); // Latch,Clock,Data,Quantità hc595 utilizzati
    qundi il latch è collegato al pin 8 e clock al 9.
    Nei commenti scrivi che
    // Pin 8 Arduino >> Pin 11 hc595
    // Pin 9 Arduino >> Pin 12 hc595

    e dalla documentazione della mia libreria (che ho ricontrollato) ricavo:
    latch ST (pin 12 of 74HC595) – Latch – Storage register clock
    clock SH (pin 11 of 74HC595) – Shift register clock
    data DS (pin 14 of 74HC595) – Serial Data input

    quindi il latch secondo i tuoi commenti si collegherebbe al pin 11 del 74hc595 che però come vedi qui sotto corrisponde al pin 12 e non all’11. Quindi se i tuoi commenti sono corrispondenti allo schema che hai preparato, hai invertito quesi due pin

    Per il resto se i pin settati sono corretti dovresti ottenere l’inversione ogni mezzo secondo delle 4 porte che hai alternato nel listato ed in contemporanea l’accensione e spegnimento del led interno

  4.  

    Ciao,scusa ,ma tutti i commenti sono solo imperfezioni di scrittura,il circuito e il codice sono corretti.
    Il problema che riscontro è che gli otto led non si accendono per 500ms,ma danno solo un impulso lieve.Il led sulla scheda si accende correttamente.
    Grazie

  5.  

    scusa, mi è morto il pc, ora sono con quello di mia moglie, in attesa che arrivi la nuova “bestia”. …. domanda semplice: ma hai collegato direttamente i led sul 74hc595?

  6.  

    Ciao, ho iniziato da poco ad approcciarmi ad arduino, ho scaricato la libreria HC595 ma quando la inserisco nella cartella library e verifico un qualsiasi sketc mi da questo errore:

    Error reading file (C:\Documents and Settings\MANU PC\Documenti\Arduino\libraries\hc595\library.properties:1): Invalid line format, should be ‘key=value’

    Errore durante la compilazione per la scheda Arduino/Genuino Uno.

    non riesco a capire cosa sia.