lunedì 10 gennaio 2022

Arduino lcd testo scorrevole advanced

LCD e testo scorrevole

Il testo scorrevole o striscia è spesso usata per fornire un quantitativo di informazioni che supera la capacità del dispositivo di output. In TV la vediamo spesso scorrere in modo omogeneo pixel per pixel. Su un display LCD 2 righe per 16 colonne lo spazio disponibile è limitato e si fa presto a consumare le due righe e quindi anche in questo contesto un testo scorrevole torna sempre utile. Tuttavia in questo caso non c'è modo di scorrere pixel per pixel e ci si deve accontentare di traslare il testo carattere per carattere. Un esempio di testo scorrevole lo possiamo osservare grazie al simulatore online wokwi e il progetto dimostrativo è disponibile cliccando sul seguente link: lcdtestoscorrevole.

La funzione scrollText()

Con riferimento al progetto (lcdtestoscorrevole) vediamo come è fatta la funzione scrollText() che è l'unica funzione che si occupa di effettuare lo scorrimento. Ci si deve solo preoccupare di richiamarla ad intervalli regolari, fornendogli la stringa da scorrere e un buffer. La stringa da scorrere può essere statica (ad es. "Il testo scorrevole") oppure dinamica, in questo ultimo caso è possibile modificare il contenuto ma è bene fare attenzione a modificare la lunghezza. Nel progetto di esempio si è scelto di costruire dinamicamente la stringa da scorrere assemblando la data e l'orario (minuti e secondi inclusi) corrente entrambe ricavati grazie all'impiego di un RTC (Real Time Clock). La funzione in questione ha i suoi limiti legati principalmente all'impiego di due variabili statiche e quindi non può lavorare con due stringhe differenti, il limite è superabile implementando delle struct o classi e in tal caso si possono fare scorrere due stringhe differenti su entrambe le righe del display.

#define ROW_LEN 16

// scorre da destra verso sinistra
void scrollText(char *s, char *sd) {

uint8_t sIdx = 0;
static uint8_t S_sdIdx = ROW_LEN;
static uint8_t S_sIdx = 0;

if (S_sdIdx > 0) {
S_sdIdx--;
} else {
sIdx = S_sIdx;
}
uint8_t sdIdx = S_sdIdx;
int len_s = strlen(s); // 23
memset(sd, ' ', ROW_LEN);
sd[ROW_LEN] = '\0';
while (sdIdx < ROW_LEN) {
sd[sdIdx] = s[sIdx];
sdIdx++;
sIdx++;
sIdx = sIdx % len_s;
}
if (S_sdIdx == 0) {
S_sIdx++;
S_sIdx = S_sIdx % len_s;
}

} // end void scrollText(char *s, char *sd)

Il primo argomento (char *s) è l'array di caratteri (null termined) contenente il testo da scorrere. La lunghezza massima di s non deve superare i 255 caratteri a causa del tipo uint8_t usato per gli indici. Il secondo argomento (char *sd) è un array di caratteri usato come buffer (la funzione scrive in questo buffer), grande almeno ROW_LEN + 1.

Poiché come detto la funzione scrive nel buffer, questo lo dobbiamo inviare alla riga 1 del display. Ciò accade nella funzione loop() all'interno di una temporizzazione con millis() mostrata di seguito:

if (millis() - oldTime >= speedScroll) {

dateToStr();
timeToStr();

oldTime = millis();
// combina data e ora in unica variabile
strScrollText = " MauroTec Software" + strDate + strTime + " Wokwi Simulator";

scrollText(strScrollText.c_str(), scrollBuffer);

lcd.setCursor(0, 1);
lcd.print(scrollBuffer);

}

Le due chiamate a funzione dateToString() e timeToString() riempono strDate e strTime che contengono la data e orario. La variabile strScrollText viene riempita con un testo a piacere a cui si aggiunge strDate e strTime e per finire il testo "Wokwi Simulator". Adesso è il momento di chiamare la funzione scrollText() la quale provvede a riempire il buffer scrollBuffer che poi inviamo al display con lcd.print().

Algoritmo di scorrimento

Chi fosse interessato all'algoritmo può trovare utile osservare le due immagini seguenti, la prima mostra il contenuto della stringa da scorrere. Lo spazio all'indice 0 evita che venga mostrato 15:15:00L, quindi almeno uno spazio lo dobbiamo prevedere.

La seconda mostra cosa accade alla riga 1 del display. Si vede che alla prima chiamata alla funzione di scorrimento viene prelevato il carattere all'indice 0 (L) dall'array che contiene il testo da scorrere e questo viene scritto nell'array scrollBuffer all'indice 15. Alla seconda chiamata il carattere all'indice 0 questa volta viene scritto all'indice 14 di scrollBuffer, adesso tocca alla 'u' di essere copiata all'indice 15 di scrollBuffer. L'operazione di copia fino alla 16° chiamata avviene grazie al while contenuto nella funzione che 'cicla' 1 volta alla prima chiamata, 2 volte alla seconda chiamate, 3 volte alla terza e per finire 16 volte alla 16° chiamata. 

Alla 17° chiamata la L non compare alla colonna 0 al suo posto ci mettiamo la 'u', alla 18° ci mettiamo la 'n' e così via. Nota che dalla 17° chiamata in poi il ciclo while 'cicla' sempre 16 volte, tanto quanto i caratteri da visualizzare.

Terminiamo con l'immagine seguente che mostra il contenuto della riga 1 quando la colonna 0 del display mostra il carattere 2 all'indice 12 della stringa da scorrere. Il while inizia dall'indice 12 per terminare al 25° carattere (indice 24) superato questo valore si inizia da 0, a cui corrisponde lo spazio iniziale della stringa da scorrere, il tutto si ripete all'infinito.

Un ultima chicca riguardo alla macro ROW_LEN che normalmente corrisponde al numero di colonne del display, quindi 16 per il 16 colonne e 20 per il 20 colonne, ok provate indipendentemente dal numero di colonne a disposizione a modificare la macro sostituendo 16 con 10. Il risultato è che la stringa scorre è impegna solo 10 colonne e considerando uno spazio aggiuntivo di separazione ci rimangono 5 colonne utili libere sulla riga 1 a partire dalla colonna 11. Portando questo all'estremo con una classe e 4 istanza potremmo avere 4 scritte scorrevoli, ma resta da verificare quanto leggibili possano risultare.

Conclusione

Come dimostrato con una sola funzione possiamo fare scorrere del testo al fine di fornire più informazioni di quante ne possa contenere il display, in modo dinamico e non "bloccante". Immagino già queste scritte scorrevoli applicate a contesti differenti, come un stazione meteo, un voce di un menu, un parametro e relativo valore e tanto altro ancora.

Licenza Creative Commons
Quest'opera è distribuita con Licenza Creative Commons Attribuzione - Condividi allo stesso modo 4.0 Internazionale