Gestire automaticamente due schermate su LCD 20X4

Premesso che evito di chiedere perché le risposte spesso sono… cerca su Google studia qua e la ecc. questo è già stato fatto… ma spesso si entra in confusione e si peggiora anziché risolvere, i libri poi quasi tutti scritti da persone che capiscono nulla o poco di DIDATTICA tutti prodighi a spiegare nei minimi dettagli listati molto semplici (troppo facile) ma abbandonano ben presto il lettore a se stesso perché proporre due tre esempi “sensati”per le funzioni importanti (listati realmente utili a qualcosa di concreto e non posticci / fantasiosi ) costa molta fatica sia scriverli che testarli e poi spiegarli dettagliatamente, specie se i listati relativi sono mediamente lunghi. Molti scopiazzano semplicemente a desta e a manca, hanno di fatto un solo obiettivo far soldi con Arduino, spacciandosi per insegnanti. Ad oggi non ho trovato un libro serio chiaro ed esaustivo didatticamente valido (in italiano ovviamente). Veniamo al problema. Ho realizzato con Arduino (basandomi anche su alcuni listati) un sistema a Lcd 20X4 I2C che svolge molte funzioni (Orologio/Antifurto/Meteo/Sens. Ultrasonico) e nell’insieme funziona, ma richiede qualche miglioria a livello di visualizzazione/gestione display. Ho una prima schermata di presentazione, durata ad es.30 Sec. Poi l’LCD deve essere ripulito e passare automaticamente alla seconda schermata. La pulizia del display deve avvenire una sola ed unica volta. Attualmente ho risolto con un secondo Timer/millis ( il primo Timer infatti non viene mai azzerato, prosegue nel conteggio e così deve rimanere) che al raggiungimento dei 30000mS ripulisce l’LCD e in questo specifico caso il Timer 2 viene azzerato, ma questo comporta che ogni 30000mS l’LCD effettua un breve lampeggio (di fatto ripulisce l’lcd ogni 30Sec.) quindi il problema è solo questo : evitare il breve lampeggio ogni 30000mS anche se tutto sommato è un problema accettabile, se non trovo una soluzione (ragionevolmente breve e semplice) con il vostro aiuto. Prima di fare ricorso a questo secondo Timer ho fatto svariati tentativi infruttuosi con il primo Timer (quello che non viene mai azzerato) tipo questo
if (millis() - previousMillis == 30000) {lcd.clear(); lcd.home(); }
questo comando viene ignorato, oppure simile a quello presente nel listato parziale (ma che contiene le varie if utilizzate in questa parte/sezione del programma) dove ho provato anche && all’interno di una if, ma anche questo comando viene ignorato. Fatti poi altri tentativi ma alla fine si fa peggio invece che risolvere. Grazie per l’eventuale supporto se esiste una soluzione semplice al problema.

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);  
  long previousMillis = 0;
  long interval = 4000;
  
  void setup() {
  lcd.init();// Inizializza il display I2C
  lcd.backlight();//accende la retroilluminazione 
  }
  void loop() {
  if (millis() - previousMillis < 1600) { // Segnale di avvio beep
  tone(5, 980, 500);
  delay(50);
  noTone(5);
  }    
  if (millis()- previousMillis < interval){
  lcd.setCursor(0,0);
  lcd.print(" Prima schermata ");
  lcd.setCursor(1,2);
  lcd.print("Elapse Time : ");
  lcd.print(millis()/1000.0); 
  }
  if (millis()- previousMillis >3900 && millis()- previousMillis <4000) {
  lcd.clear();
  lcd.home();
  lcd.print("Cancello lcd");// messaggio temporaneo di verifica esecuzione comando
  delay(2000);
  }
  if (millis() - previousMillis > interval) {
  lcd.setCursor(0,2);
  lcd.print("  -  2 Schermata  -    ");}
  delay (1000);
 }

Usa una variabile di stato.

All inizio la variabile la metti zero:

byte schermatainiziale = 0;

poi nel loop controlli

if (millis() - previousMillis > 30000 & schermatainiziale == 0) {lcd.clear(); lcd.home(); schermatainiziale = 1;}

Cosí viene eseguito solo 1 volta.
Il controllo del tempo trascorso non lo farei con == ma con > perché se per caso il loop() dura piú di 1 ms puó capitare che la condizione non é mai vera.

Ciao Uwe

Non ho capito molto il problema, comunque, alcune note ...

  1. tutto ciò che riguarda millis() deve essere unsigned long e non long

  2. difficilmente beccerai ESATTAMENTE il millisecondo in cui millis() - previousMillis == 30000 ... per cui quel IF verrà effettuata solo se ... sei veramente fortunato :smiley:
    E' molto meglio mettere millis() - previousMillis >= 30000 così da riuscire ad entrare nel IF allo scadere del tempo o ... qualche millisecondo dopo :wink:

  3. NON ho capito se questa pulizia la devi effettuare una sola volta o ogni 30 sec. ... se la devi fare una sola volta ti basta una flag che ti dice che l'hai già fatta, per cui ... nei periodi di 30 secondi successivi non la fai più.

Guglielmo

Usi millis() e poi metti i delay... meglio usare solo millis().

Ma se la "sigla iniziale" di 30 secondi la deve fare una sola volta all'avvio, potresti metterla nel setup.

se ho capito il problema e non vuoi vedere un lampeggio ad ogni cambio schermata ogni 30 secondi non devi usare lcd.clear() ma solo lcd.home() e sovrascirvere il display con il nuovo testo avendo l'accortezza di cancellare le scritte vecchie con eventuali spazi vuoti se il testo della nuova schermata non è lungo quanto la schermata precedente.

Salve. Intanto un ringraziamento a tutti per le numerose risposte, sono partito dalla più semplice proposta da Zef cioè utilizzare solo lcd.home questa soluzione non produce i risultati voluti, infatti diverse scritte della seconda schermata risultano sovrascritte alla prima è vero il contrario che nel mio caso posso omettere lcd.home (la 2 schermata contiene infatti indirizzi precisi di posizionamento dei dati) ma lasciarla non guasta. La soluzione successiva semplice geniale e funzionale è quella proposta da Uwefed funziona perfettamente è un comando utile anche per altri utilizzi futuri, faccio tesoro anche degli altri suggerimenti/soluzioni che valuterò con calma, riguardo unsigned long o solo long torniamo al discorso didattica ho letto da varie parti libriccini internet ecc e se ho utilizzato solo "long" evidentemente l'ho acquisito da un listato di riferimento, ma se non erro "unsigned long" non può memorizzare valori negativi ed estende il range max di conteggio, ma nel mio caso non utilizzo valori negativi e non ho problemi di range max, almeno nel breve. Concordo poi che beccare al "volo" 30000 o altro valore con precisione è arduo e inizialmente ho valutato anche questo problema, alla fine anche se non sono stato chiarissimo nell'esposizione dell'anomalia, grazie a voi ho risolto, anche se si trattava di un fatto marginale rispetto alle molteplici funzioni che svolge il programma e che al momento funzionano correttamente.
Saluti e Buon ferragosto.

auriol:
Ho una prima schermata di presentazione, durata ad es.30 Sec. Poi l’LCD deve essere ripulito e passare automaticamente alla seconda schermata. La pulizia del display deve avvenire una sola ed unica volta.

Beh anche io non ho ben capito cosa intendi fare, ma quanto meno per il problema come l’hai esposto io farei una cosa del genere, prova e fammi sapere:

  ...  
  long interval = 4000; // Quanto tempo deve restare la prima schermata
  bool welcome = true; // Flag per indicare che sul display è presente la prima schermata

  void setup() {
    lcd.init();// Inizializza il display I2C
    lcd.backlight();//accende la retroilluminazione 

    // Segnale di avvio beep (tanto vale metterlo qui)
    tone(5, 980, 500);
    delay(50);
    noTone(5);
    // Prima schermata (anche questa va qui)
    lcd.setCursor(0,0);
    lcd.print(" Prima schermata ");
  }

  void loop() {
    if (welcome) { // Se è ancora presente la prima schermata
      if (millis()- previousMillis < interval){ // Il tempo non è finito, aggiorno il time mostrato
        lcd.setCursor(1,2);
        lcd.print("Elapsed Time: ");
        lcd.print(millis()/1000.0); 
      }
      if (millis()- previousMillis >= interval) { // Fine tempo prima schermata!
        lcd.clear();
        lcd.home();
        lcd.print("Cancello lcd");// messaggio temporaneo di verifica esecuzione comando
        delay(2000);
        welcome = false; // Evito che entri nuovamente in questa if()
      }
    }
    else { // Normale gestione (seconda schermata o quello che deve fare)
      lcd.setCursor(0,2);
      lcd.print("  -  2 Schermata  -    ");
    }
  }
 }

Se può essere d’aiuto a qualcuno, qui di seguito, condivido un piccolo Sketch (commentato in italiano) che stampa su uno schermo lcd 16x2 diverse schermate a rotazione intervallate da un tempo prestabilito quando i dati/messaggi sono superiori alle due righe.

#include <LiquidCrystal.h>

// inizialisco la libreria associando i pin allo schermo LCD
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

unsigned long time; // inizializzo la variabile time
unsigned long previousMillis = 0; // definisco una variabile dove memorizzo il tempo trascorso (ovviamente per il primo ciclo sarà uguale a zero)
unsigned long intervall = 4000; // definisco l’intervallo che deve trascorrere tra le schermate

void setup(){
lcd.begin(16, 2); // definisco il tipo di schermo utilizzato (16 colonne e due righe)
lcd.setCursor(4, 0); // posiziono il cursore sulla quinta colonna (valore 4) e prima riga (valore 0)
lcd.print("— START —"); // stampo messaggio di partenza
delay(2000); // inserisco una pausa prima di cancellare lo schermo
lcd.clear(); // pulisco lo schermo
}

void loop(){
time=millis(); // attribuisco alla variabile time i millisecondi trascorsi

if(time - previousMillis < intervall){ // condizione iniziale dove il tempo trascorso è inferiore all’intervallo
lcd.setCursor(0, 0); // posiziono il cursore sulla prima colonna (valore 0) e prima riga (valore 0)
lcd.print(“SCHERMATA 1”); // stampo il primo messaggio
lcd.setCursor(0, 1); // posiziono il cursore sulla prima colonna (valore 0) e seconda riga (valore 1)
lcd.print(“dati schermata 1”);
}
if((time - previousMillis > intervall) && (time - previousMillis < 2intervall)){ // condizione dove il tempo è compreso tra il valore dell’intervallo e il suo doppio
lcd.setCursor(0, 0);
lcd.print(“SCHERMATA 2”);
lcd.setCursor(0, 1);
lcd.print(“dati schermata 2”);
}
if((time - previousMillis > 2
intervall) && (time - previousMillis < 3intervall)){ // condizione dove il tempo è compreso tra il doppio del valore dell’intervallo e il suo triplo
lcd.setCursor(0, 0);
lcd.print(“SCHERMATA 3”);
lcd.setCursor(0, 1);
lcd.print(“dati schermata 3”);
}
if((time - previousMillis > 3
intervall) && (time - previousMillis < 4intervall)){
lcd.setCursor(0, 0);
lcd.print(“SCHERMATA 4”);
lcd.setCursor(0, 1);
lcd.print(“dati schermata 4”);
}
if(time - previousMillis > 4
intervall){
previousMillis = millis(); // resetto il loop allineando il valore previousMillis al tempo trascorso millis()
}
}

>toticap: … prima di tutto, essendo il tuo primo post, nel rispetto del regolamento (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti QUI (spiegando bene quali conoscenze hai di elettronica e di programmazione … possibilmente evitando di scrivere solo una riga di saluto) e di leggere con MOLTA attenzione il su citato REGOLAMENTO

… poi, in conformità al suddetto regolamento, punto 7, devi editare il tuo post (quindi NON scrivendo un nuovo post, ma utilizzando il bottone More → Modify che si trova in basso a destra del tuo post) e racchiudere il codice all’interno dei tag CODE (… sono quelli che in edit inserisce il bottone con icona fatta così: </>, tutto a sinistra). Grazie,

Guglielmo