problema con Switch Case

ciao a tutti, ho un problema con uno sketch che utilizzo per gestire una cella di lievitazione. tramite la funzione switch case e il conteggio del tempo passato, seleziona la porzione di codice da eseguire. fino al case 2 ( prelievitazione ) tutto bene , ma da qui dopo i 10 secondi (impostati per prova) non passa al case 3 ( lievitazione) ma dopo 20 secondi va al case 4 (attesa) e poi ricomincia. ho perso ore a cercare di capire dove sia l'errore , ma non ci arrivo ,sarà una banalità o no ? avete qualche idea? Uso IDE 1.6.11 . allego sketch per cercare di capire assieme , ciedo un grande aiuto ..devo preparare gli impasti per sabato :stuck_out_tongue_closed_eyes: :stuck_out_tongue_closed_eyes:

#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Imposta l'indirizzo del display a 0x27 con 16 caratteri per 2 linee
LiquidCrystal_I2C lcd(0x27, 20, 4);
DHT dht(8, DHT22);         // tipo sensore e pin connesso
const int toutraf = 7;     //Frigo
const int toutris = 6;     //Cavetto
const int hout = 9;        //Umidificatore ultrasuoni
const int led = 10;        // luce interna led
unsigned long prevMillis = 0;  // era la tua variabile time
#define K_15H 10000L      //tempo 1 ora per ora tutto a 10 sec per test funzionamento
#define K_25H 10000L      //tempo 2 ore
#define K_1H  10000L     //tempo 3 ore
#define K_24H 10000L    //tempo 24 ore
int fase = 0;        // 0,1,2,3,4 fasi

void setup()
{
  lcd.init();// inizializza il display
  lcd.backlight();//accende la retroilluminazione
  dht.begin();
  pinMode(toutraf, OUTPUT);
  pinMode(hout, OUTPUT);
  pinMode(toutris, OUTPUT);
}
void loop()
{
  float h = dht.readHumidity(); // Leggo il valore di umidità
  float t = dht.readTemperature(); // Leggo il valore di temperatura
  if (isnan(t) || isnan(h)) // Se almeno uno dei due valori è NaN (Not a Number)
  { lcd.clear();
    lcd.print("Impossibile leggere il sensore!");
    delay (1000);
  }
  else //altrimenti
  {
    lcd.setCursor(0, 0);
    lcd.print("Umidita' =");
    lcd.setCursor(10, 0);
    lcd.print(h);
    lcd.setCursor(0, 1);
    lcd.print("Temperat.= ");
    lcd.setCursor(10, 1);
    lcd.print(t);
  }
  unsigned long currMillis = millis();
  switch (fase)
  { case 0: Raffreddamento();  break;
    case 1: Maturazione();     break;
    case 2: Prelievitazione(); break;
    case 3: Lievitazione();    break;
    case 4: Attesa();          break;
}
    
      }
  }
}
void Raffreddamento()
{ unsigned long currMillis = millis();
  float t = dht.readTemperature();
  float h = dht.readHumidity();
  lcd.setCursor(0, 3);
  lcd.print(millis() / 1000);
  if (currMillis - prevMillis > K_1H)
  { fase = 1;                            // finita 1  ore passa a Maturazione
    prevMillis = currMillis;
  }

  else                                  // le due ore non sono passate...
  { if ( t >= 3 )
    { digitalWrite(toutraf, LOW);
      digitalWrite(toutris, HIGH);
      digitalWrite(hout, HIGH);
      lcd.setCursor(15, 0);
      lcd.print("Acc");
      lcd.setCursor(15, 1);
      lcd.print("No");
      lcd.setCursor(6, 3);
      lcd.print("Raffreddamento");
    }
    else
    { if ( t <= 3 - 1 )
      { digitalWrite(toutraf, HIGH);
        digitalWrite(toutris, HIGH);
        digitalWrite(hout, HIGH);
        lcd.setCursor(15, 0);
        lcd.print("Spe");
        lcd.setCursor(15, 1);
        lcd.print("NO ");
        lcd.setCursor(6, 3);
        lcd.print("Raffreddamento");
      }
    }
  }
}
void Maturazione()
{ unsigned long currMillis = millis();
  float t = dht.readTemperature();
  float h = dht.readHumidity();
  lcd.setCursor(0, 3);
  lcd.print(millis() / 1000);
  if (currMillis - prevMillis > K_24H)
  { fase = 2;                            // finite le 24 ora passa a Pre-levitazione
    prevMillis = currMillis;
  }
  else
  { if ( t >= 4 )
      if ( h <= 60 )
      { digitalWrite(toutraf, LOW);
        digitalWrite(toutris, HIGH);
        digitalWrite(hout, LOW);
        lcd.setCursor(15, 0);
        lcd.print("Acc");
        lcd.setCursor(6, 3);
        lcd.print("Maturazione   ");
        lcd.setCursor(15 , 1);
        lcd.print("Acc");
      }

      else
      { if ( t <= 4 - 1 )
          if ( h >= 60 )
          { digitalWrite(toutris, LOW);
            digitalWrite(toutraf, HIGH);
            digitalWrite(hout, HIGH);
            lcd.print("Maturazione   ");
            lcd.setCursor(15, 0);
            lcd.print("Spe");
            lcd.setCursor(6, 3);
            lcd.setCursor(15, 1);
            lcd.print("Spe");
          }
      }
  }
}
void Prelievitazione()
{ unsigned long currMillis = millis();
  float t = dht.readTemperature();
  float h = dht.readHumidity();
  lcd.setCursor(0, 3);
  lcd.print(millis() / 1000);
  if (currMillis - prevMillis > K_1H)
  { fase = 3;                            // finite le 1.5 ore passa a Lievitazione
    prevMillis = currMillis;
  }

  else
  { if ( t >= 13 )
      if ( h <= 80 )
      { digitalWrite(toutraf, LOW);
        digitalWrite(toutris, HIGH);
        digitalWrite(hout, LOW);
        lcd.setCursor(15, 0);
        lcd.print("Acc");
        lcd.setCursor(6, 3);
        lcd.print("Pre-lievitaz.  ");
        lcd.print("Acc");
      }

      else
      { if ( t <= 13 )
          if ( h >= 80 )
          { digitalWrite(toutraf, HIGH);
            digitalWrite(toutris, LOW);
            digitalWrite(hout, HIGH);
            lcd.setCursor(15, 0);
            lcd.print("Spe");
            lcd.setCursor(6, 3);
            lcd.print("Pre-lievita   ");
            lcd.setCursor(15, 1);
            lcd.print("Spe");
          }
      }
  }
}
void Lievitazione()
{ unsigned long currMillis = millis();
  float t = dht.readTemperature();
  float h = dht.readHumidity();
  lcd.setCursor(0, 3);
  lcd.print(millis() / 1000);
  if (currMillis - prevMillis > K_1H)
  { fase = 4;                            // finite le 2.5 ora passa a Attesa
    prevMillis = currMillis;
  }
  
  else
  { if ( t > 28 )
      if ( h < 95 )
      { digitalWrite(toutraf, LOW);
        digitalWrite(toutris, HIGH);
        digitalWrite(hout, LOW);
        lcd.setCursor(15, 0);
        lcd.print("Acc");
        lcd.setCursor(6, 3);
        lcd.print("Lievitazione  ");
        digitalWrite(hout, LOW);
        lcd.setCursor(15, 1);
        lcd.print("Acc");
      }

      else
      { if ( t < 28 )
          if ( h > 95 )
          { digitalWrite(toutraf, HIGH);
            digitalWrite(toutris, LOW);
            digitalWrite(hout, HIGH);
            lcd.setCursor(15, 0);
            lcd.print("Spe");
            lcd.setCursor(6, 3);
            lcd.print("Lievitazione  ");
            digitalWrite(hout, LOW);
            lcd.setCursor(15, 1);
            lcd.print("Spe");
          }
      }
  }
}
void Attesa()
{ unsigned long currMillis = millis();
  float t = dht.readTemperature();
  float h = dht.readHumidity();
  lcd.setCursor(0, 3);
  lcd.print(millis() / 1000);
  if (currMillis - prevMillis > K_1H)
  { fase = 0;                            // finite le 8 ora passa Raffreddamento
    prevMillis = currMillis;
  }
  else
  { if ( t >= 24 )
      if ( h <= 80 )
      { digitalWrite(toutraf, LOW);
        digitalWrite(toutris, HIGH);
        digitalWrite(hout, LOW);
        lcd.setCursor(15, 0);
        lcd.print("Acc");
        lcd.setCursor(6, 3);
        lcd.print("Attesa        ");
        digitalWrite(hout, LOW);
        lcd.setCursor(15, 1);
        lcd.print("Acc");
      }

      else
      { if ( t <= 24 )
          if ( h >= 80 )
          { digitalWrite(toutraf, HIGH);
            digitalWrite(toutris, LOW);
            digitalWrite(hout, HIGH);
            lcd.setCursor(15, 0);
            lcd.print("Spe");
            lcd.setCursor(6, 3);
            lcd.print("Attesa         ");
            digitalWrite(hout, LOW);
            lcd.setCursor(15, 1);
            lcd.print("Spe");
          }
      }
  }
}

Le temporizzazioni sembrano corrette, per il solito motivo (cella di lievitazione) mi sono imbattuto in errori strano dovuti ad un eccessivo refresh dell'lcd. Per verificare il tutto potresti commentare tutto ciò che riguarda l'lcd, attivare il debug sulla seriale per scrivere i messaggi di cambio stato e verificare se il programma funziona regolarmente.
Se così fosse potresti pensare di limitare gli aggiornamenti dell'lcd allo stretto necessario (ovvero non ogni ciclo di loop) ma solo quando esiste davvero un dato da variare (Es. se stampi l'ora e i minuti aggiorni solo una volta al minuto, oppure aggiorni i messaggi di stato solo quando uno di questi è davvero viariato) sfruttando variabili di controllo per confrontare il dato attuale con il precedente.
In ogni caso ti consiglio di aggioungere quanto prima un RTC perché se ti appoggi a millis() e relativo controllo del tempo del micro con tempi così lunghi (24,48H) rischi che a lungo andare ti vengano sballati i tempi magari anche solo di pochi minuti ma visto il costo di un RTC io l'ho inserito nel mio progetto

Non ho capito molto bene un paio di cose ...

{ if ( t <= 3 - 1 )

... perche' 3 - 1 e non semplicemente 2 ?

Poi, perche' tutte quelle graffe aperte davanti agli if degli else ? ... la sintassi dovrebbe essere "else if", non "else { if" , se non ricordo male ... :wink:

@etem, sono corrette, sono le graffe dell'else, l'if è contenuto nell'else. Essendo l'unica istruzione poteva non metterle ma male non fa :wink:

 else
 { if ()
   {
   }
 }

Nel caso specifico poteva evitare il secondo if, visto che nell'else di sicuro entri per t<3

if ( t >= 3 )
{ ...
}
else   // ovviamente qui  t <=2 ovvero t<3
{ digitalWrite(toutr ...
}

Mi pare un errore nel programma, questo non ha senso:

case 4: Attesa();          break;
      val = digitalRead(power_pin); // leggo il valore del pulsante (PREMUTO = 1, NON PREMUTO = 0)
      // se è stato premuto
      if (va...

Tutto quello che segue quel break; non verrà mai eseguito.

E quel pezzo può essere "semplificato":

val = digitalRead(power_pin); // leggo il valore del pulsante (PREMUTO = 1, NON PREMUTO = 0)
if (val == HIGH)  // se è stato premuto
{ if (backupVal == LOW)        
  { backupVal = HIGH;
  }
  else // backupVal == HIGH
  { backupVal = LOW;  
  }
  // oppure TUTTO l'if in una linea:   backupVal=(backupVal==LOW ? HIGH : LOW);
  digitalWrite(relayPin, backupVal );
  delay(100);
}

nid69ita:
@etem, sono corrette, sono le graffe dell'else, l'if è contenuto nell'else....

... a me e' sempre sembrato che la sequenza if / else dovesse essere cosi ...

   if (currMillis - prevMillis > K_1H)
   {
      ...
   } 
   else if ( t >= 3 )
   {
      ...
   }
   else
   {
      ...
   }

... con i valori a scalare, ovviamente, dato che le condizioni sono gerarchicamente esclusive (nel senso che se esegue la prima poi non controlla le altre due, se esegue la seconda poi non controlla la terza, e cosi via ... quindi K_1H DEVE essere maggiore di 3, altrimenti non avrebbe senso) ... a meno che dentro l'else non ci sia poi piu di un'if, ognuno con condizioni diverse, ma qui non mi sembra il caso ...

@etem, si puoi scriverlo anche come dici tu, ma non è un errore mettere l'if dentro con le sue graffe (magari brutto ^-^ ma non errato) .

Proverò come suggerito con la seriale, vediamo se gira tutto bene poi vi aggiorno. Non sarà scritto in maniera pulita e forse un po incasinato, ma è uno dei primi piu impegnativi per me, che faccio , non ho molto tempo da dedicarci , ogni tanto quando arrivo lo riprendo e ci rifletto sopra. Se dovessi seguire il consiglio di fabpolli e limitare gli aggiornamenti dell'lcd , come potrei fare? Uno spunto iniziale che poi provo a proseguire ,grazie a tutti per l'aiuto.

Ti faccio un esempio veloce, quando ad esempio nell'if

if ( t <= 3 - 1 )

vai a settare i pin e a scrivere sull'lcd basta che ti fai una variabile (Es. vecchioStatoMaturazione) e la inizializzi (Es. 0) quando entri nell'if che va a settare i pin e ad aggiornare l'lcd fai una roba del tipo:

if(vecchioStatoMaturazione==0){
 ...
 lcd.setCursor(...)
 vecchioStatoMaturazione = 1;
}

Per gli altri casi devi sfruttare come hai già fatto la millis() e aggiornare l'lcd a intervalli regolari che decidi tu (Es. ogni 30 secondi) in modo tale che se aggiorni lo schermo fai:

lastLcdUpdate = millis();

e ad ogni loop controlli

if(millis() - lastLcdUpdate > LCD_REFRESH_INTERVAL){
...
lastLcdUpdate = millis();
}

In questo modo hai il refresh dello schermo quando varia uno stato o ogni 30 secondi.
Un altro consiglio, potrebbe rendere più pulito il codice creare una funzione simile a quelle che già hai fatto (Maturazione(), ecc.) che si occupa di scrivere sull'lcd in modo tale da richiamarla in tutti i punti dove hai necessità di scrivere sullo schermo in questo modo se un domani devi modficare la scrittura (posizoone, informazioni, ecc.) sull'lcd intervieni in un solo punto

... ci sarebbe anche un'altra cosa, che non mi quadra ...

#define K_15H 10000L      //tempo 1 ora
#define K_25H 10000L      //tempo 2 ore
#define K_1H  10000L     //tempo 3 ore
#define K_24H 10000L    //tempo 24 ore

... a che scopo usare 4 diverse variabili, tutte settate allo stesso valore ? ...

Ho letto per 2 volte "cella di levitazione" :o è non riuscivo a capire. :confused:
Comunque lo sketch compila anche su IDE 1.8.3. Potresti aggiornarlo. In confronto alla versione 1.6.11 ci sono centinai di piccoli miglioramenti.

Le variabili sono settate tutte a 10 sec , solo per fare i test di funzionamento, nella realtà a progetto finito dovranno avere i tempi segnati nella descrizione

ho provato ad aggiornare l'lcd ogni 30 secondi ma non funziona ancora.

ho anche aggiornato IDE a 1.8.3 ma nulla

PaoloP:
Ho letto per 2 volte "cella di levitazione" :o è non riuscivo a capire. :confused:
Comunque lo sketch compila anche su IDE 1.8.3. Potresti aggiornarlo. In confronto alla versione 1.6.11 ci sono centinai di piccoli miglioramenti.

È una cella per la levitazione della pasta per pane o torte o pizza (simile a quella per la fermentazione del malto per la birra) e fa un ciclo termico.
Ciao Uwe

Ci sarebbe anche un'altra cosa, ma non ne sono sicuro ... tu prima fai "float t = dht.readTemperature", per cui metti un valore float in una variabile float, ma poi in giro per il programma vedo controlli tipo "if(t>=3)", dove indichi t con un numero int ... questa cosa e' "valida", per il compilatore di arduino, oppure se dichiari una variabile come float, dopo devi indicare nei controlli il valore con un .0 per forza ? ... non me lo ricordo mai, questo ...

Poi c'e' il fatto che in tutte le varie funzioni il tempo lo controlli sempre con la stessa variabile, ma nei test non dovrebbe importare (importa pero' nel funzionamento finale, lasciandoli come adesso non ti funzionerebbe correttamente ;))

Per il resto non saprei ... io ad esempio avrei fatto alcune cose in modo diverso, come ad esempio creare una funzione per la lettura del sensore ed il refresh del display e chiamarla solo una volta al secondo, ed anche funzioni per i vari comandi fatte in modo simile e richiamate anche quelle in base alle letture fatte ogni secondo, ma quello e' un mio modo personale di pensare ...

uwefed:
È una cella per la levitazione della pasta per pane o torte o pizza ...

... nel senso che fa "levitare" (cioe' fluttuare a mezz'aria) la pasta ? ... :wink:

(Scusa, non ho resistito :D)

nico72:
ho provato ad aggiornare l'lcd ogni 30 secondi ma non funziona ancora.

Hai fatto la prova senza lcd con le varie serial.print?
Perché ho la sensazione che stiamo girando attorno al problema, elimina una componente che di solito li genera (lcd) e prova il software se fa il suo dovere a livello logico, a quel punto se mett in pratica i vari suggerimenti sia miei che di @Etem (funzione specializzata da richiamare per fare aggiornamento lcd, ecc) forse si riesce a trovare il problema e relativa soluzione

La butto li al volo, tutta da controllare ... personalmente, nel loop io ci metterei una cosa del genere ...

...
float t;
float h;
...
tempo1 = millis();
void loop()
{
   if(millis() - tempo1 >= 1000)
   {
      tempo1 = millis();
      refdisp()
   }   

...
...
...

   refdisp()
   {
      float t = dht.readTemperature();
      float h = dht.readHumidity();
      lcd.setCursor(0, 0);
      lcd.print("Umidita' = ");
      lcd.setCursor(11, 0);
      lcd.print(h);
      lcd.setCursor(0, 1);
      lcd.print("Temperat.= ");
      lcd.setCursor(11, 1);
      lcd.print(t);
   }

...
}

... cosi fa sia le letture del sensore che l'aggiornamento del display una volta al secondo ... poi le variabili float dichiararle all'inizio come tali ...

Per quanto riguarda il ".0" da aggiungere, mi riferivo ad una cosa letta un po di tempo fa, sul fatto che se facevi operazioni matematiche con dei float, dovevi aggiungere il punto decimale ogni volta, anche se non c'erano decimali, altrimenti sarebbero state trattate come int ... non riesco pero' a ricordare se la stessa cosa valeva anche nei confronti con gli if ...

Capito. Appena rientro sabato dal lavoro ,provo le varie soluzioni.