LCD 20x4 scrive a righe alterne

Ho collegato ad Arduino un LCD 20x4, usando la libreria standard LiquidCrystal.h, con la seguende riga di impostazione:
LiquidCrystal lcd(A5, A4, 5, 4, 3, 2);
A5 e A4 sono necessità. Subito dopo li ho impostati come
pinMode(A5, OUTPUT);
pinMode(A4, OUTPUT);
Poi invio una serie di frasi in sequenza ed il display me le mostra ordinate ma esse vengono scritte nell'ordine:
1
3
2
4
NON ci sono comandi di posizionamento del cursore; in pratica scrive la prima frase nella riga 1 (ok), scrive la 2a frase nella riga 3, scrive la 3a frase nella riga 2, scrive la frase finale nella riga 4.; alla fine la videata è sballata.
Avete idea di cosa possa essere successo?
i collegamenti dovrebbero essere corretti secondo il datasheet, le frasi si leggono bene, solo che sono "mischiate" di posizione.

Strano, questo era un problema che avevo avuto anche io nelle vecchie versioni della liquidcrystal.
C'e' anche una spiegazione tecnica, qui: http://web.alfredstate.edu/weimandn/lcd/lcd_addressing/lcd_addressing_index.html ma non possiedo la soluzione per le nuove versioni della libreria, che non dovrebbe avere questo difetto.
F

Federico:
Strano, questo era un problema che avevo avuto anche io nelle vecchie versioni della liquidcrystal.
C'e' anche una spiegazione tecnica, qui: http://web.alfredstate.edu/weimandn/lcd/lcd_addressing/lcd_addressing_index.html ma non possiedo la soluzione per le nuove versioni della libreria, che non dovrebbe avere questo difetto.
F

Grazie. Io sto usando quella in dotazione alla 0022 di Arduino, ce n'è una più aggiornata?
Forse mi conviene scaricarla dal Playground?
grazie ancora.

In realtà sembra che non ci sia una libreria che ha risolto questo problema, quindi bisogna ricorrere a dei trucchetti; dopo aver avuto alcune ottime indicazioni da Leo, che mi hanno chiarito diveri dubbi, ho provato a ragionare in termini di "codice", anche perché ho l'aggravante che il display mostra delle stringhe che il micro riceve via seriale da un altro micro.
Quindi ho pensato di gestire il problema della sequenza 1-3-2-4 cambiando la posizione delle stringhe, risolto.
mi resta però da cancellare l'LCD ogni tanto, quindi ho inserito un carattere speciale all'inizio della frase della nuova schermata, che viene intercettato dal micro ricevente e mi dà un clear, risolto anche questo.
Ora voglio provare ad usare lo stesso sistema per gestire le coordinate di inizio frase, se uso un carattere speciale per ogni coppia 0,0 - 0,1 - 0,2 - 0,3 posso dire all'LCD DOVE mettere la frase, da provare, che ne dite? Qualcuno ha idee, suggerimenti, soluzioni?

MI aiuto da solo, fintanto che qualche anima buona non decida di passare da queste parti.
Ho scaricato, via sito di gioblu, una libreria liquidcrystal440.h, dovrebbe servire per usare LCD 40x4, chissà che non abbiano risolto.

L'altra cosa, cercando su Internet, che ho letto in un paio di siti, è che il display 20x4 necessita del collegamento a 8 bit, ma nessuno spiega perché.

Almeno mi sono procurato due prove da fare, la manipolazione software funziona abbastanza bene ma è estremamente problematica.

Altre informazioni utili?

Il link ad 8 bit io so che serve solo a dimezzare la velocità di trasmissione. Questa cosa che risolva il problema della scrittura a righe alterne non la sapevo.

Comunque resta un problema non problema, secondo me. Io so che la riga è lunga X caratteri, non mando una stringa più lunga di X caratteri :smiley:

leo72:
Il link ad 8 bit io so che serve solo a dimezzare la velocità di trasmissione. Questa cosa che risolva il problema della scrittura a righe alterne non la sapevo.

non c'è scritto che lo risolve, ma usano la frase "DEVE essere gestito a 8 bit", quindi ho dedotto, più che altro sperato, che potesse essere una possibilità.

Comunque resta un problema non problema, secondo me. Io so che la riga è lunga X caratteri, non mando una stringa più lunga di X caratteri :smiley:

Ma io ho (poi ho fatto modifiche estreme, ma restiamo sul problema iniziale) un menu con sei righe, e non c'è verso di farglielo vedere come sei stringhe, ho provato anche a spegnere la seriale dopo ogni riga, ma niente, ricomincia da dove ha lasciato, quindi se non risolvo con questi due ultimi accorgimenti mi devo rassegnare ai "caratteri speciali" e tante righe di programmazione :fearful:

Te l'ho spiegato, un LCD non lavora come un editor di testo.
Devi usare il cursore: devi posizionare sempre il cursore nel punto in cui vuoi andare poi a far apparire il tuo testo, fosse anche la riga successiva.

lcd.Cursor(x,y);
lcd.Print(stringa);
lcd.Cursor(x,y);
lcd.Print(stringa);
ecc...

Considera che la posizione del cursore viene aggiornata in automatico per cui anche se scrivi un solo carattere, il cursore viene spostato. E' invisibile ma c'è: se lo rendi visibile, vedrai che va sempre a posizionarsi alla fine di quello che viene spedito in stampa. A meno che, ovviamente, che tu non lo sposti fisicamente da un'altra parte.

Sì ma il fatto è che la stringa arriva dall'altro micro, mentre il cursore lo posso impostare solo in locale, ecco perché ho fatto ricorso ai caratteri "speciali", così in base al carattere gli dò la posizione; solo che con "§" non mi funzionava, poi sono dovuto rientrare a casa :(, mentre con ^ sono riuscito a pilotare il "clear"

0x00
0x01
0x02
...
usa i primi valori di un byte come comandi.

menniti:
L'altra cosa, cercando su Internet, che ho letto in un paio di siti, è che il display 20x4 necessita del collegamento a 8 bit, ma nessuno spiega perché.

Assolutamente falso, il modo a 4 bit è previsto dal controller per far risparmiare pin di connessione, è perfettamente identico al modo a 8 bit con la differenza che li scrivi 4 per volta in due operazioni distinte.
La questione righe sfalsate dipende da come viene gestita la memoria caratteri, 80 byte, dal controller in funzione della geometria del display, questo vuol dire che la memoria non è lineare con la posizione del carattere sul display.
Normalmente la memoria caratteri è divisa in due banchi da 40 byte che rappresentano due righe, previste di default dal controller, da 40 caratteri e questo è l'unico caso in cui scrivendo di continuo i caratteri vanno nelle corrette posizioni sempre, con tutte le altre geometrie è necessario controllare da software la posizione del cursore e spostarlo sulla nuova riga, ovvero farlo puntare sulla corretta cella di memoria, quando necessario.

astrobeed:

menniti:
L’altra cosa, cercando su Internet, che ho letto in un paio di siti, è che il display 20x4 necessita del collegamento a 8 bit, ma nessuno spiega perché.

Assolutamente falso, il modo a 4 bit è previsto dal controller per far risparmiare pin di connessione, è perfettamente identico al modo a 8 bit con la differenza che li scrivi 4 per volta in due operazioni distinte.
La questione righe sfalsate dipende da come viene gestita la memoria caratteri, 80 byte, dal controller in funzione della geometria del display, questo vuol dire che la memoria non è lineare con la posizione del carattere sul display.
Normalmente la memoria caratteri è divisa in due banchi da 40 byte che rappresentano due righe, previste di default dal controller, da 40 caratteri e questo è l’unico caso in cui scrivendo di continuo i caratteri vanno nelle corrette posizioni sempre, con tutte le altre geometrie è necessario controllare da software la posizione del cursore e spostarlo sulla nuova riga, ovvero farlo puntare sulla corretta cella di memoria, quando necessario.

OK, comunque NON ho letto che risolveva il problema, più che altro era una speranza, in effetti con 4 bit funziona ed è anche velocissimo, quindi devo per forza usare il sistema di caratteri speciali per settare il puntatore; alla fine si tratta di una quindicina di comunicazioni, un po’ di pazienza e risolvo.

leo72:
0x00
0x01
0x02

usa i primi valori di un byte come comandi.

Questo metodo forse mi incasina la vita perché lui mi restituisce i valori dei fuse in questa forma, ecco perché avevo scartato i numeri. Comunque l’importante era verificare che dialogassero correttamente e questo c’è XD e la cosa ottima è che posso usare il connettore seriale, già previsto per eventuali convertitori USB-seriali esterni, anche per questa scheda aggiuntiva. Per il resto prima sviluppo il firmware definitivo per la versione seriale e poi ne creo una versione specifica per l’LCD. Riprendo se continuo ad avere difficoltà con i “caratteri speciali”.
Grazie ragazzi!

Ma devi instaurare un protocollo di trasmissione, altrimenti non ne esci.
0x00 può essere benissimo un comando come un dato, è solo la posizione in cui lo leggi che gli fa assumere il giusto significato.

leo72:
Ma devi instaurare un protocollo di trasmissione, altrimenti non ne esci.
0x00 può essere benissimo un comando come un dato, è solo la posizione in cui lo leggi che gli fa assumere il giusto significato.

Azz Leo, mi vuoi far passare la vecchiaia a fare questa cosa, ogni volta che uso un "if" devo aprire il reference per la sintassi e tu vuoi farmi costruire un protocollo? 4 caratteri significa che sul 328 i/o devo realizzarmi un buffer, controllare che prima ci sia una carattere "normale" altrimenti potrebbe essere un valore di fuse; il valore di fuse lo farei pecedere da uno spazio così farei la distinzione; praticamente se la serie di caratteri che mi arriva è:
00x0agemta questo è un carattere di controllo, se invece mi arriva 00x0 esuf_h è un valore di fuse. Potrei anche farcela, in realtà a me servono solo 5 caratteri:
clear, 1a, 2a, 3a, 4a riga, sempre in posizione 0; se mi riconoscesse cose come ^ & % $ £ mi semplificherei la vita, basta mandarli prima della stringa.
Credo di dover mettere dei ritardi dopo questi caratteri, anche con 4 bit la trasmissione è velocissima, forse era questo il problema ieri, non faceva a tempo ad eseguire il posizionamento che già gli arrivava la stringa. :roll_eyes:

Non puoi metterti a leggere sulla seriale "a caso", se salti il byte di comando, non sai più a che cosa si riferiscono i byte successivi né quanti byte devi leggere ecc...

Prendiamo come dati per inizio e fine trasmissioni rispettivamente 0xAA e 0x55 (non sono scelti a caso, sono 10101010b e 01010101b). Immaginiamo che vuoi pulire l'LCD:
0xAA
0x00 -> comando di clear
0x55

Adesso vuoi scrivere a 2,5:
0xAA
0x01 -> comando di posizionamento del cursore
0x02 -> X
0x05 -> Y
0x55

Adesso vuoi scrivere CIAO
0xAA
0x02 -> comando di scrittura del testo: qui si mette in ascolto fino all'arrivo del carattere di fine trasmissione
0x43 -> C
0x49 -> I
0x41 -> A
0x4F -> O
0x55

Come vedi hai delle situazioni in cui ti servono solo 3 byte, altre (l'ultimo caso) in cui non sai a priori quanti caratteri arriveranno. Se "pensi" con campi di grandezza predefinita, tagli fuori dei byte.

Ma quindi devo iniziare e finire ogni cosa che mando con questi due byte 0xAA e 0x55.
In seconda posizione metto 0x00, 0x01, 0x02 in base a cosa voglio fare (clear, posizionamento cursore, invio testo)
Dalla terza in poi mando (non nel caso del clear) o i valori di posizionamento o il testo
E' così?

Dubbi:
Nel trasmittente devo scrivere fisicamente 0xAA e 0x55? In questo caso il ricevente non deve analizzare quattro caratteri prima di capire che è un comando di inizio o fine stringa? Oppure c'è un modo per dire ad entrambi di trattarli come byte?

Ma il testo posso continuare a inviarlo come stringa o devo codificare in byte ogni singolo carattere?

Insomma :grin: :blush: :grin: :blush: potresti postarmi solo una riga tipica di trasmissione e ciò che devo scrivere sul ricevente per analizzarla correttamente? Una volta compresa la tecnica non ho più difficoltà ad implementare tutto.

In ogni caso questa cosa vale SOLO per l'LCD, i terminali seriali non ho possibilità di "programmarli" per i caratteri di controllo, giusto?

menniti:
Ma quindi devo iniziare e finire ogni cosa che mando con questi due byte 0xAA e 0x55.
In seconda posizione metto 0x00, 0x01, 0x02 in base a cosa voglio fare (clear, posizionamento cursore, invio testo)
Dalla terza in poi mando (non nel caso del clear) o i valori di posizionamento o il testo
E' così?

Sì.

Dubbi:
Nel trasmittente devo scrivere fisicamente 0xAA e 0x55? In questo caso il ricevente non deve analizzare quattro caratteri prima di capire che è un comando di inizio o fine stringa? Oppure c'è un modo per dire ad entrambi di trattarli come byte?

Serial.print(0x00, BYTE); //trasmittente

var=Serial.read(); //ricevente

Ma il testo posso continuare a inviarlo come stringa o devo codificare in byte ogni singolo carattere?

Te l'avevo già scritto :stuck_out_tongue:
Lo spedisci con Serial.print. Essendo la trasmissione seriale una trasmissione byte-byte, arriverà sempre come array di byte e verrà memorizzato nel buffer. Tu da lì lo prelievi byte per byte con Serial.read.

Insomma :grin: :blush: :grin: :blush: potresti postarmi solo una riga tipica di trasmissione e ciò che devo scrivere sul ricevente per analizzarla correttamente? Una volta compresa la tecnica non ho più difficoltà ad implementare tutto.

Di righe ne hai quante ti pare nei firmware che ti ho spedito. Devi controllare dove ho messo i loop di controllo sui byte di inizio trasmissione e poi gli switch per interpretare il comando ricevuto. Quando invii l'inizio delle trasmissioni, il codice del 328 I/O si mette in ascolto ed esegue tutto quello che gli viene detto di fare. Alla fine delle trasmissioni, esce dalla ricezione e ci rientra solo col codice di inizio.

In ogni caso questa cosa vale SOLO per l'LCD, i terminali seriali non ho possibilità di "programmarli" per i caratteri di controllo, giusto?

Non ho capito.

Tutto abbastanza chiaro, scusa ma per me sono cose completamente nuove, a parte serial.print e serial.read che sto già usando; ora mi è chiaro che per ogni stringa o comando devo fare un certo numero di trasmissioni, una iniziale ed una finale in formato "byte", le altre idem (se parliamo di clear o cursore) oppure normali stringhe per i testi.
In ricezione, per ogni carattere ricevuto, verifico se è un comando o un carattere di stringa e mi regolo di conseguenza.
L'ultima richiesta era riferita all'uso del serial monitor perché a volte mi arriva qualche "disturbo" e lui mi mostra caratteri strani, però quando faccio serial.print poi non ho più il controllo di cosa arriva al PC, quindi intendevo dire che mentre con l'LCD posso tentare di ignorare caratteri strani, perché intercetto il passaggio serial.read->lcd.print, col serial monitor non posso fare nulla.

Aggiungo, forse te l'avevo già detto una volta, che quanto ti metti d'impegno a spiegare in modalità "for dummies" hai una capacità che farebbe sfigurare molti miei colleghi (non me, che a spiegare sono bravo quanto te ;)), mentre io, nella veste del dummy, sono perfetto, non capisco un c... nemmeno se me le porgi col cucchiaino :blush:

Grazie Leo, a buon rendere :~

Sono a lavoro, non ho la libertà che ho a casa per stare a spiegare nei dettagli, comunque poniamo il caso che tu voglia spedire una stringa:

TRASMETTITORE:

Serial.beginTransmission(xxx);
Serial.write(0xAA); //equivale a print(xx, BYTE)
Serial.print(testo);
Serial.write(0x55);
Serial.endTransmission();

RICEVITORE

void loop() {
    do {
        if (Serial.available()) {
            comando=Serial.read();
            switch (comando) {
                case 0x00: //stampo la stringa
                    dato=0;
                    do {
                        dato = Serial.read();
                        x=0;
                        if (dato != 0x55) { //carattere terminatore
                            lcd.print(char(dato));
                            x++;
                        } else {
                            break;
                        }
                    } while ((Serial.available()) && (x<20)); // scrive finché ci sono dati o finché non si arriva a fine riga
                    break;
                case 0x01: //altri case
                    ........ ecc .....
                    break;
           }
        }
    }
}

O qualcosa di simile, insomma… codice non provato :sweat_smile:

porc... mi sa che sto perdendo colpi anche a spiegare. Leo! avevo capito sul serio tutto quanto, l'ultima parte era per "giustificare" il fatto che ti eri dovuto sobbarcare tutti quei post per farmi capire questa cosa :blush:
GIURO che non ti stavo più chiedendo il codice :blush:
Però, ormai la fatica è fatta :grin:
Quel "Transmission" mi è nuovo, non ti stai riferendo ad una lib particolare vero? io non ne sto usando nessuna, a parte quella per il keypad e per l'LCD.
Comunque domani mi metto al lavoro e provo; dal punto di vista hardware vado meglio XD, infatti ho rivisto l'intero progetto ed ho deciso di fare qualcosa di ancora più professionale, ormai la cosa merita un aspetto serio, entro fine settimana avrò le idee più chiare.
Grazie ancora. XD XD