[Libreria] PCF8574+HD44780 LCD I2C Library

Avevo comprato una breakout board per pilotare in I2C il classico LCD HD44780. parliamo di roba da 1,5€ :smiley:

Cercando in giro ho trovato infinite librerie, ma nessuna funzionava, tester alla mano ho notato che questo modello e' connesso fisicamente in modo diverso dalle altre, ed in piu' e' veramente completa, ha tre pullup sui pin della scelta indirizzo, in modo che saldando la piazzola si puo' cambiarlo facilmente, ha un jumper per spegnere la retroilluminazione, oppure lo si puo' sostituire con una resistenza di limitazione (non tenere il jumper connesso senza resistenza se si stanno usando i 5V) ed infine ha le pullup sul bus I2C gia' montate, quindi non serve metterle nel progetto.

Invece di continuare la ricerca ho messo mano ad una libreria del buon Mario_H rendendola compatibile e, secondo me, migliorandola. (questa la versione non funzionante http://hmario.home.xs4all.nl/arduino/LiquidCrystal_I2C/)

Visto le modifiche apportate, e comunque la non compatibilita' di questa nuova libreria con la Ver. 2.0 originale, gli ho cambiato nome in PCF8574_HD44780_I2C

In allegato ci sono anche i datasheet dei componenti:

Ver 2.2

  • Solved the "prints only the first character" bug (thanks to Brunello)

Ver 2.1 (first release compatible with this breakoutboard):

  • Changed name to PCF8574_HD44780_I2C Library
  • Added Expander I/O Port define
  • Replaced many Hex value with a more friendly _BV() macro
  • Adapted all commands and flags define to this breakout board
  • Changed Backlight logic for NPN transistor used on this breakout board
  • Adapted send() function
  • Removed unnecessary Delay from Init() function
  • Comments added to many #Define

Le nuove versioni verranno postate sul repo

Bravo Testato per aver condiviso il tuo lavoro ;)

PS: non so se lo sai, io chiedo lo stesso. Ma perché nell'inizializzazione della libreria viene spedito 4 volte il comando per passare alla modalità a 4 bit? Ci faccio caso solo ora, ma è una prerogativa di tutti i display con HD44780?

Grazie dei complimenti,

rispondo alla domanda, l'HD44780 ha un sua procedura di inizializzazine integrata che parte al reset del display, una specie di bios per capirci, che porta il display ad uno stato ben definito (interfaccia 8bit, carattere 5x8, ecc) In queste condizioni per passare ad interfacciamento 4bit serve solo l'ultima istruzione che vedi nella libreria, e che e' anche l'unico tipo di istruzione che il display e' programmato ad accettare con un unica scrittura (come saprai anche se a 4 bit il display internamente ragiona sempre ad 8 bit e richiede per qualsiasi istruzione l'invio di un doppio nibble), tranne pero', ripeto, l'istruzione che lo porta a 4bit.

Quindi ? a che servono le altre tre ? Sono preventive, nel caso in cui per qualche motivo il sistema di reset interno non funziona le tre istruzioni precedenti servono a far fare al display quello che gia' internamente dovrebbe fare da solo, cioe' portarlo ad interfacciamento 8bit, 4x8, ecc. Se il reset interno ha funzionato la ripetizione dei tre comandi non comporta problemi tecnici, impiega solo tempo.

Quindi se ci sono problemi di tempistica dell'accensione del display per motivi di progetto si possono evitare le 3 istruzioni e risparmiare 5 millesimi di secondo. Ma se non ci sono problemi di tempi (in qual caso un display impiegando 5ms in piu' per accendersi potrebbe creare problemi ?) si prevede sempre nell'init questa prevenzione, perche' il mancato pilotaggio del display, con probabili scritture di caratteri strani, e' molto piu' grave di 5ms di attesa.

Si fa lo stesso anche se lo si vuole usare ad 8 bit, cioe' normalmente in quel caso servono zero istruzioni (e' gia' ad 8 bit dopo il reset), ma per prevenzione si mettono sempre le tre che vedi in libreria.

Spero di essere stato esauriente quanto lo sei tu quando ti faccio le domande :)

Ti ringrazio. Quindi serve solo per far sì che il display passi effettivamente a 4 bit, ripetendo l'operazione nel caso in cui per qualche motivo non ricevesse l'inizializzazione.

no, al contrario, serve per assicurarsi che passi ad 8 bit, le prime tre istruzioni “preventive” sono uguali sia quando si vuole usare gli 8bit che i 4bit. Nel caso che si usa l’lcd ad 8bit non serve una 4 istruzione, nel caso dei 4 bit serve la 4 istruzione (che non e’ ripetuta, e’ singola), che e’ un’istruzione particolare, e’ l’unica che viene accettata in formato nibble dall’interfaccia che in quel momento e’ in formato byte

Aspetta, io mi riferivo a questa porzione di codice che si trova nel file cpp all'interno del metodo begin():

    // LCD start in 8bit mode, try to set 4 bit mode
    write4bits(_BV(P4) | _BV(P5));  
    delay(5); // wait min 4.1ms

    // second try
    write4bits(_BV(P4) | _BV(P5));  
    delayMicroseconds(150); // wait min 100us

    // third go!
    write4bits(_BV(P4) | _BV(P5));  
    // !NOT NECESSARY! //
    //delayMicroseconds(150);

    // finally, set to 4-bit interface
    write4bits(_BV(P5));

ci sono 4 tentativi di impostare la modalità a 4 bit

la porzione e' quella, ma:

le prime tre sono le istruzioni Preventive, la 4 e' l'istruzione, come vedi e' diversa, dei 4bit. Non ci sono dubbi sul fatto che una volta inviata un istruzione questa venga eseguita, quindi non c'e' una ripetizione dell'istruzione 4 bit, il dubbio e' sul sistema di reset/bios integrato, che essendo legato ad esevnti esterni (alimentazione instabile ? altro ?) non assicura al 100% che il sistema si avvii come dovrebbe:

schemino: 1) l'asic toshiba internamente ha un fw che all'accensione porta l'lcd in una certa situzione (8bit, 8x5, ecc) 2) se ci sono dubbi sulla possibile fallimento di questo sistema integrato toshiba stessa ci da' un'istruzione, da ripetere 3 volte, per assicurarsi che l'lcd si metta nello stato iniziale (cioe' sempre 8bit,8x5,ecc Non esiste un modo per far si' che all'accensione vada a 4bit da solo, o che vada a 5x10 da solo) 3) se lo stiamo usando ad 8bit: fine cioe' l'init e' finito e iniziamo a lavorarci 3B) se ci serve lavorare a 4bit spediamo l'istruzione per metterlo a 4bit. Sottolineavo a questo punto il fatto che questa e' un'istruzione particolare, in quanto e' fomrata da un nibble mentre stiamo lavorando ancora a 8bit

Quindi l'istruzione per i 4bit e' una sola, e non viene ripetuta

write4bits(_BV(P5));

a questo punto cambiero' la descrizione (i commenti in questa porzione non sono miei), perche' portano fuori strada, probabilmente nemmeno l'autore originale aveva capito il perche' di quella parte :D

Ho modificato commenti e formattazione, spero ora sia piu' chiaro

    // LCD automatically start in 8bit mode, but we manually repeat
    // the 8bit initialization instructions for safety
    write4bits(_BV(P4) | _BV(P5));  
    delay(5); // wait min 4.1ms
    write4bits(_BV(P4) | _BV(P5));  
    delayMicroseconds(150); // wait min 100us
    write4bits(_BV(P4) | _BV(P5));  

    // Set interface to 4bit mode
    write4bits(_BV(P5));

Ok, era il commento iniziale a fuorviarmi, con quel "LCD start in 8bit mode, try to set 4 bit mode". Quindi io pensavo che da subito venisse messo in 4bit, però effettivamente guardando le istruzioni con più attenzione l'ultima era diversa dalle altre (settava solo 1 bit mentre le precedenti ne settavano 2). Grazie del chiarimento ;)

A disposizione :)

quando trovo un po di tempo voglio renderla hex free Ho già tolto molti settaggi esadecimali, e tutti i binari, visto che ho definito tutta la porta del PCF posso sostituire tutti i comandi hex attuali con la macro _BV. Non conosco le tue preferenze, ma quando si tratta di mettere mano ai bit il _BV è quello che preferisco

Io preferisco usare le operazioni sui bit, lo sai ;) Ma se ti trovi bene con _BV continua pure ad usarla XD

ciao, complimenti per la libreria, io uso la stessa schedina che usi te ed è fatta molto bene; volevo solo chiederti a cosa mi serve la funzione lcd.home(), non mi è proprio chiara... :roll_eyes: Comunque ho un consiglio da darti se non ti offendi, il metodo che usi per creare nuovi simboli è molto strano (a me personalmente confonde, poi magari è perché sono un principiante), io ho "trovato" un metodo più intuitivo, questo: uint8_t bell[8] = {0x4,0xe,0xe,0xe,0x1f,0x0,0x4}; // come scritto da te uint8_t bell[8] = {B00100,B01110,B01110,B01110,B11111,B00000,B00100,B00000}; // come lo uso io

i due modi scrivono la stessa cosa ed occupano lo stesso quantitativo di memoria. Complimenti ancora per la libreria, buona serata :)

Ciao e grazie dei complimenti :)

Il comando Home serve per riportare ad inizio display il cursore, se dopo il comando Home inizi a scrivere sul display, senza specificare la posizione, vedrai che scrivi sempre partendo da colonna 0 rigo 0

Per quanto riguarda il metodo di dichiarazione dei simboli personalizzati puoi benissimo fare come fai tu, dipende da come si e' abituati, la cosa piu' intuitiva da fare e' usare uno dei tanti programmini che convertono il carattere direttamente nella dichiarazione necessaria, a quel punto poco importa se sia in esadecimale o in binario ;)

ho utilizzato con successo la libreria di Testato, bel lavoro, tanti pin risparmiati con I2C, ma a che distanza si può arrivare, ho letto che ci sono dei limiti.

Grazie del feedback. Usando il solo cavo si parla di centimetri, diciamo sui 10cm. Per distanze maggiori ci sono gli appositi chip che fanno da expander.

ho trovato questa guida http://tronixstuff.com/2010/10/29/tutorial-arduino-and-the-i2c-bus-part-two/

Testato grazie!!! funziona!!!

Uno e' lieto di servire ;)