Cambia visualizzazioni su lcd ogni n secondi senza delay

Ciao a tutti ragazzi ho bisogno di un aiutino da parte vostra

Sto provando a realizzare un piccolo programma che nel loop mi mostra su lcd diverse schermate ed ogni 5 secondi il display cambia visualizzazione ciclicamente, schermata 1-->schermata 2-->schermata n-->e ricomincia dalla 1.
Durante l'esecuzione di queste finestre vorrei poter intervenire in qualsiasi momento premendo un tasto ed entrare nella funzione Main.
Fin'ora ho usato la funzione delay per far cambiare le schermate, ma come noto mi blocca fin quando non finisce il suo ciclo.
Esiste un altro modo per fare la stessa cosa, ma che non mi blocchi e che in qualsiasi momento premo il pulsante entro nel Main?

Allego il codice che ho scritto fino ad ora che lavora con le delay

Ringrazio anticipatamente coloro che vorranno aiutarmi.

#include <LiquidCrystal.h>

#define btnRIGHT    0    //costante pulsante RIGHT   
#define btnUP       1    //costante pulsante UP 
#define btnDOWN     2    //costante pulsante DOWN    
#define btnLEFT     3    //costante pulsante LEFT    
#define btnSELECT   4    //costante pulsante SELECT   
#define btnNONE     5    //costante pulsante NONE 


////////////////////////////////////////////////////////////////////////
//////////////          Menu             ///////////////////////////////
////////////////////////////////////////////////////////////////////////

char Menu[5][17] =   {"Voce 1          ",
                      "Voce 2          ",
                      "Voce 3          ",
                      "Voce 4          ",
                      "                "};

 
int offset = 0;

////////////////////////////////////////////////////////////////////////
//////////////          LCD              ///////////////////////////////
////////////////////////////////////////////////////////////////////////

LiquidCrystal lcd(8,9,4,5,6,7);    //pin Display Arduino Mega

////////////////////////////////////////////////////////////////////////
//////////////          Keypad           ///////////////////////////////
////////////////////////////////////////////////////////////////////////

int NUM_KEYS = 5;
int adc_key_in ;       
int key = -1;
int oldkey = -1;

int adc_key_val[5] = {50 ,195 ,380 ,555 ,790 };

int get_key(unsigned int input)
{
    int k;
    
    for (k = 0; k < NUM_KEYS; k++)
    {
        if (input < adc_key_val[k])
        {
            return k;
        }
    }
    
    if (k >= NUM_KEYS)
        k = -1;     
    
    return k;
}

void setup(){
  Serial.begin(9600);
  lcd.begin(16,2);
  
}

void loop(){
  
  prima_schermata();
  delay(5000);
  
  seconda_schermata();
  delay(5000);
  
  terza_schermata();
  delay(5000);
  
  
  adc_key_in = analogRead(0);
  delay(50);
  key = get_key(adc_key_in);                      
  if (key != oldkey){
    adc_key_in = analogRead(0);
    delay(50);
    key = get_key(adc_key_in);
    if (key != oldkey){
      switch(key){
        case 1:
          lcd.clear(); 
          
          Main();
          
          break;        
      }
    }
  }

}

void PrintMenu( char item[20]){
  lcd.setCursor(0,0);
  lcd.print(item);
  
}

void Main(){

for(;;){

  PrintMenu(Menu[offset]); 
  
  adc_key_in = analogRead(0);
  delay(50);
  key = get_key(adc_key_in);
  
    if (key != oldkey)
      {
        adc_key_in = analogRead(0);
        delay(50);
        key = get_key(adc_key_in);                    
          
          if (key != oldkey)                                
          {
  
            switch(key){
              case 3:
                if (offset > 0) offset--;                    
                break;
              case 0:
                if (offset < 3) offset++;
                break;
              case 4:
                switch(offset){
                  case 0:

                    break;
                  case 1:

                    break;
                  case 2:

                  case 3:

                    break;
                }
                
            }
            oldkey = key;

      }
    }
   
  }
}

void prima_schermata(){
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Schermata 1");

}

void seconda_schermata(){
  lcd.clear(); 
  lcd.setCursor(0,0);
  lcd.print("Schermata 2");


}

void terza_schermata(){
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Schermata 3");


}

devi utilizzare millis()
guarda il tutorial blink without delay per un esempio di utilizzo :wink:

Leggi pure questo tutorial in italiano:
http://www.leonardomiliani.com/2013/programmiamo-i-compiti-con-millis/

Che bello leggere il codice formattato bene e con nomi di variabili e funzioni indicative, ottimo modo di scrivere codice continua così.

Il consiglio che ti hanno dato è quello giusto e se ti fai un giro degli ultimi topic hanno tutti lo stesso problema.
Purtroppo non c'è scritto in nessun posto che la funzione delay impegna il micro a fare nulla per tot tempo e se è impegnato non può fare altro.

Ciao.

doppiozero:
devi utilizzare millis()
guarda il tutorial blink without delay per un esempio di utilizzo :wink:

nid69ita:
Leggi pure questo tutorial in italiano:
http://www.leonardomiliani.com/2013/programmiamo-i-compiti-con-millis/

grazie ragazzi mi studio come funziona e vi faccio sapere se riesco ad applicarlo alla mia esigenza

MauroTec:
Che bello leggere il codice formattato bene e con nomi di variabili e funzioni indicative, ottimo modo di scrivere codice continua così.

Il consiglio che ti hanno dato è quello giusto e se ti fai un giro degli ultimi topic hanno tutti lo stesso problema.
Purtroppo non c'è scritto in nessun posto che la funzione delay impegna il micro a fare nulla per tot tempo e se è impegnato non può fare altro.

Ciao.

ti ingrazio MauroTec, è da poco che ho iniziato a sviluppare, ma anche nella mia infinitesimale esperienza ho capito che l'ordine è fondamentale per capirci poi qualcosa :slight_smile:
seguo il consiglio tuo, di doppiozero, e di nid69ita e vi tengo aggiornati grazie ancora

allora sono riuscito ad integrare la funzione millis al posto del delay, l'ho fatto utilizzando uno switch case sembra funzionare correttamente, però quando vado a caricare la parte di codice che interviene sulla tastiera non entra subito in Main, cioè mostra schermata 1 e se premo il tasto aspetta comunque qualche secondo

Non riesco a capire dove commetto l'errore, o se proprio il codice che ho sviluppato è errato... :confused:

Posso chiedere un piccolo aiuto a voi più esperti?

Grazie mille

vi posto il codice

#include <LiquidCrystal.h>

LiquidCrystal lcd(8,9,4,5,6,7);


#define btnRIGHT    0    //costante pulsante RIGHT   
#define btnUP       1    //costante pulsante UP 
#define btnDOWN     2    //costante pulsante DOWN    
#define btnLEFT     3    //costante pulsante LEFT    
#define btnSELECT   4    //costante pulsante SELECT   
#define btnNONE     5    //costante pulsante NONE 

int NUM_KEYS = 5;
int adc_key_in ;       
int key = -1;
int oldkey = -1;

int adc_key_val[5] = {50 ,195 ,380 ,555 ,790 };

int get_key(unsigned int input)
{
    int k;
    
    for (k = 0; k < NUM_KEYS; k++)
    {
        if (input < adc_key_val[k])
        {
            return k;
        }
    }
    
    if (k >= NUM_KEYS)
        k = -1;     
    
    return k;
}



unsigned long previousMillis = 0;       

const long interval = 2000;           

int level = 0;

void setup(){
  
  Serial.begin(9600);
  lcd.begin(16,2);
    
}

void loop(){

  unsigned long currentMillis = millis();
  
  if(currentMillis - previousMillis > interval) {

    previousMillis = currentMillis;
    
    switch(level){
      case 0:
        schermata_1();
        level = level++;
        break;
      case 1:
        schermata_2();
        level = level++;
        break;
      case 2:
        schermata_3();
        level = 0;
        break;
      }
      
      adc_key_in = analogRead(0);
        delay(50);
         key = get_key(adc_key_in);                      
         if (key != oldkey){
           adc_key_in = analogRead(0);
             delay(50);
               key = get_key(adc_key_in);
               if (key != oldkey){
                 switch(key){
                   case 1:
                     Main();
                     break;        
                  }
                  oldkey = key;
                }
         }     
    }
}

void schermata_1(){
  
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Schermata 1");

}

void schermata_2(){
  
  lcd.clear(); 
  lcd.setCursor(0,0);
  lcd.print("Schermata 2");

}

void schermata_3(){
  
  lcd.clear(); 
  lcd.setCursor(0,0);
  lcd.print("Schermata 3");

}

void Main(){
  lcd.clear();
  for(;;){
    
    lcd.setCursor(0,0);
    lcd.print("Main");
    
  }
}

ciao

Se non sbaglio hai messo la lettura dei tasti dentro il controllo di millis (basta spostare una graffa :wink: )

ciao
pippo72

pippo72:
ciao

Se non sbaglio hai messo la lettura dei tasti dentro il controllo di millis (basta spostare una graffa :wink: )

ciao
pippo72

ti ringrazio pippo72, modifica apportata funziona perfettamente ora

vado a fare un minuto di vergogna all'angoletto dopo un errore simile :stuck_out_tongue:

ti ringrazio pippo72, modifica apportata funziona perfettamente ora

vado a fare un minuto di vergogna all'angoletto dopo un errore simile :stuck_out_tongue:

Esci dall'angoletto che non è posto per te.
Con il codice ordinato ci ho messo 20s a trovare l'errore segnalato da pippo.

Occhio a:

const long interval = 2000;

In questo caso il tipo permette valori negativi, visto che non c'è apparente motivo per evitare errori difficili da trovare conviene usare anche per questa variabile il tipo unsigned long o uint32_t.

Ciao.