Arduino salta una funzione

Buongiorno ragazzi
Sto scrivendo una macchina a stati per la lavastoviglie (modellino) con Arduino
Il ciclo consiste di 27 step che qui non ho ancora scritto per intero:

bool runCycle() {
  switch (currentCycleState) {
    case 0: // initial drain
      if (drainFunction() == true) {
        currentCycleState = 1;
        Serial.println(F("regen"));
      }
      break;
    case 1: // initial regeneration
      //implementare rigenerazione quando necessario
      currentCycleState = 2;
      fillFunctionState = 0; // ALWAYS RESET!!! fill, drain, regen, filter flush and resin washing states before calling them
      Serial.println(F("prewash fill"));
      break;
    case 2: // prewash water fill
      if (fillFunction() == true) {
        stageStartTime = millis();
        Serial.println(stageStartTime);
        Serial.println(F("prewash"));
        digitalWrite(washingPump, HIGH);
        currentCycleState = 3;
        Serial.println(cycleArray[progIndex].prewashDuration1);
      }
      break;
    case 3: // prewash cold water
      if (millis() - stageStartTime >= cycleArray[progIndex].prewashDuration1 * K) {
        Serial.println(millis());
        currentCycleState = 27;
      }
    case 27:
      Serial.println(F("CYCLE FINISHED!"));
      currentMacroState = CYCLEENDED;
      break;
  }
}

Il problema è che, arrivato allo step 2, il ciclo non prosegue allo step 3, ma sembra saltare direttamente al 27. Infatti su seriale mi stampa questo:

10:00:46.036 -> STARTING CYCLE
10:01:02.795 -> regen
10:01:02.795 -> prewash fill
10:02:06.631 -> Fill Routine Successful
10:02:06.631 -> 83398
10:02:06.671 -> prewash
10:02:06.671 -> 12
10:02:06.671 -> CYCLE FINISHED!

O, in altre parole, non mi stampa il millis() all'interno della funzione 3. Per quale motivo?

Hai dimenticato
break;
nel case 3

Hai ragione, grazie mille
Ho sistemato il problema e ho risolto, grazie ancora

Buonasera ragazzi
Mi sto scervellando da qualche ora su un problema che vi esporrò qui di seguito
Ho creato un modello di lavastoviglie (a bassissima tensione con delle pompe da acquario a 5V) con Arduino e mi trovo di fronte ad un problema: una volta selezionato il programma e premuto START, il codice viene eseguito, ma non mi attiva l'uscita della pompa di scarico. Il ciclo infatti prevede una procedura di scarico iniziale seguita dal carico

Premetto che fino a qualche ora fa il progetto utilizzava un OLED ma, a causa del rischio di finire la memoria prima del progetto, ho riscritto l'interfaccia usando un LCD. Fin quando il codice utilizzava l'OLED tutto filava liscio, ora con il display LCD sto avendo questo problema. Di seguito trovate il codice in formato zip. La cosa strana è che a seriale mi stampa la scritta "Sono qui", ma non quella "regen". Insomma sembra che la drainFunction() non venga eseguita, ma non riesco a capire il perchè. Anche i programmi che iniziano con la fase 6 anzichè la 0 (1h, Quick) non funzionano ma stampa la scritta "Sono qui". Mi potreste aiutare? Grazie

Arduino_Dishwasher_LCD.zip (10.3 KB)

Ti prego di NON aprire ulteriori thread sempre sullo stesso argomento (il modellino di "lavastoviglie") ... ne hai già troppi ...

Ora questo lo "riunisco" al precedente dove ti "saltava una funzione" ... e ricorda ... il compilatore NON sbaglia è sempre l'utente a sbagliare ... :smiling_imp:

Guglielmo

Allora, ho rivisto un attimo il codice e questo è quanto ho scoperto
Se modifico il codice in questa maniera, aggiungendo drainFunction() il ciclo funziona perfettamente, ma se lo tolgo non funge. Perchè? Considerate che fino a qualche ora fa funzionava perfettamente

switch (currentCycleState) {
    /* INITIAL DRAIN */
    case 0:
      drainFunction();
      if (drainFunction() == true) {
        currentCycleState = 1;
        Serial.println(F("regen"));
      }
      Serial.println("Sono qui");
      break;

EDIT: mi correggo, ogni volta che deve eseguire la drainFunction() devo specificarla come nel testo, altrimenti la ignora. Soluzioni?

Mi vedo costretto a citare me stesso:
" L’implementazione di una macchina a stati finiti tramite lo switch case si dimostra essere valida almeno fintantoché gli stati si possono contare sulle dita di una mano. Volendo è possibile semplificare lo switch case impiegando delle funzioni di supporto, invece lo complicherò al fine di verificare e constatare quando abbiamo raggiunto il limite. L’implementazione della macchina a stati attuale è priva di entry state ed exit state, vedremo come implementare gli entry state e quanto sono utili."

autocite

Tu hai farcito bene i case e ora fai fatica. Appena fai una modifica e il codice si rompe vuole dire che l'implementazione è debole.

Ciao.

Ti ringrazio Maurotec per la risposta.
Mi sembra di capire che debba semplificare i case usando delle funzioni o passando agli if, corretto? Ma perdonami, lo switch case non è un grandissimo if?

Però @Maurotec , perché lo stesso identico codice con l'OLED (che però mi occupava il 40% di memoria in più) veniva eseguito senza alcun problema e senza dover dichiarare in quel modo drainFunction()? C'è qualcosa che mi puzza

mmm... non mi toccare sul vivo che sono molto sensibile per adesso sono troppo fiscale. Quella che hai aggiunto non è una dichiarazione ma una "chiamata a funzione" che tra l'altro chiami anche qui:

Quindi chiami la prima volta e poi una seconda volta per ciclo di loop.

Il problema non è lo switch case o if, ma il numero di case o stati e nella teoria delle macchine a stati è stato già preso in considerazione la possibilità della esplosione degli stati, nel senso che il numero cresce spropositatamente.

La soluzione ovviamente non la ho in tasca, nel codice vedo solo confusione. Mi viene solo in mente per adesso il metodo bottom-up e mi manca la visione top-down.

Cacchio pure la rigenerazione hai previsto, ottimo.
Ciao.

Sì, voglio realizzare un modello ben completo quindi la rigenerazione è d'obbligo.

Ma rimane il dubbio, perché chiamando la funzione due vite funziona, ma una sola no? O meglio, perché nell'altro codice funziona con una sola chiamata e qui no?

Non so il motivo, ma stavo proprio guardando la funzione drainFunction() ed è contorta da seguire, comunque ho capito qualcosa anche perché so cosa fa una lavastoviglie dopo avere premuto start.
So anche cosa accade quando il pressostato è guasto (basta anche prenda un poco di aria) e la pompa non deve restare accesa per troppo tempo senza acqua. Solitamente dopo il timeout la pompa si spegne, ritenta un paio di volte in PWM (cioè accendi, attendi, spegni ecc) e se non rileva la vasca vuota va in errore.

Potresti rifare il tutto in funzione dello stato della pompa, cioè se essa è accesa attenti tot tempo e la spegni e se spenta...

PS: in quel blog trovi anche come evitare di fare clear() con il display, per evitare sfarfallio.

Ciao.

La funzione drainFunction() è contorta ma è ricavata da un service manual di una nota marca, quindi è un sistema sicuramente affidabile.

Guarderò come evitare il clear(), hai un link all'articolo?

Io mi riferisco alla implementazione, che dopo averla provata pure al simulatore non mi convince e non si comporta come dovrebbe.
L'articolo si è la continuazione e il link lo aggiunto a fine articolo.

C'è anche questo Arduino LCD con sprintf.

Comunque uso lo stesso modo in questo articolo:Termostato con arduino (2° puntata)

Ciao.

quella funzione non solo è contorta

anche:
fa uso di variabili globali
ed è incompleta

nel senso che manca di un return true quando completata
c'è un solo return, che restituisce false
pertanto questo pezzo di codice

      if (drainFunction() == true) {

non ha alcun significato
sembra nemmeno scritto dalla stessa persona che ha scritto il resto
o almeno, sembra che chi lo ha scritto si sia dimenticato su quale principio aveva fatto le varie funzioni

naturalmente questo si riflette sul funzionamento del resto del codice

visto che tutto il resto della if() non verrà mai eseguito
pertanto currentCycleState non diverrà mai 1
"regen" non sarà mai stampato
ed il case 1 non sarà mai eseguito

questo programma è stato realizzato con troppa confusione e non "decollerà" mai

serve di "smagrire" il pensiero che ci sta dietro, smagrirlo molto

anche il discorso della macchina a stati, a 27 stati.......
non sta in piedi, non è possibile avere per una semplice lavastoviglie una macchia a 27 stati

le lavastoviglie, come le lavatrici, eseguono delle "sequenze" di operazioni

funzionavano coi programmatori a camme e motoriduttore, altro che macchine a stati
anzi, coi programmatori a motoriduttore delle lavatrici i sovietici ci facevano andare gli ICBM, quindi una macchina a 27 stati per una lavastoviglie è indice di strada sbagliata e contorta

un esempio di inutile contorsione?

          case 1: // initial regeneration
      //implementare rigenerazione quando necessario
      currentCycleState = 2;
      fillFunctionState = 0; // ALWAYS RESET!!! fill, drain, regen, filter flush and resin washing states before calling them
      Serial.println(F("prewash fill"));
      break;

è un case, ovvero uno "stato" della macchina a stati, completamente inutile
sono tre righe di programma
una stampa (che non aggiunge nulla al funzionamento)
un reset di una variabile globale
e il passaggio allo stato successivo

secondo me questo è un esempio di quello che maurotec chiama "contorsione"

si spostava il reset al passo prima e si poteva eliminare l'intero stato,
senza contare che il concetto stesso di variabile globale è da ri-considerare, in un'ottica di programma contorto nel quale si perde spesso il filo delle modifiche
inoltre considerando che il passo precedente sarebbe l'avvio mi sembrerebbe normale che la variabile in oggetto sia già comunque appena resettata

e fino a che non si risolve in sede di "progettazione" del programma sarà inutile anche scrivere una singola riga di codice, che andrebbe solo ad aumentare la confusione

tradotto in italiano:

butta via quel programma e riparti da capo, dopo aver "semplificato" al massimo, prima la sequenza di lavoro della macchina, poi la tua "filosofia" di scrittura dei programmi

Perdona, ma non sto ricevendo aiuto alcuno qui sul forum, e la cosa mi amareggia non poco
La funzione chiaramente ritorna true quando finita la sua esecuzione, basta vedere qui:

case 3:
        if (millis() - drainSequenceStartTime > TIMED_DRAIN) { // if pump has been active for at least timed drain time
          digitalWrite(drainPump, LOW); // deactivate drain pump
          if (digitalRead(pressureSwitch) == HIGH) { // no more water inside the sump
            return true; // drain operation successful
          } else if (digitalRead(pressureSwitch) == LOW) { // there is still water inside the sump
            drainAttemptsCounter++;
            drainFunctionState = 0; // repeat drain phase
          }
        }
        break;

Secondariamente, ho estrapolato le informazioni da un service manual di una nota marca (Ele*****ux) in cui il ciclo di lavaggio era diviso in stati e macrostati come nell'esempio da me riportato. Non mi sembra di raggiungere i limiti di Arduino e, nel caso in cui fosse successo, mi dispiace ma significa che è poco più che un giocattolo dato che il sistema che sto realizzando è una semplice automazione a stati

Lo stato 2 è inutile scritto così, concordo, ma ovviamente manca da implementare la rigenerazione delle resine (l'ho anche scritto), ergo quel codice avrà senso più avanti

Sono d'accordo, quelle operazioni probabilmente trovano la loro collocazione ideale nell'entry/exit code di uno stato "reale".

Uno stato "reale" è una fase in attesa di un qualche evento a cui reagire, se e quando questo evento avviene.

Se una macchina a stati cresce esponenzialmente nel numero di stati necessari, probabilmente si vogliono gestire troppe cose tutte assieme, ed è il momento o di scomporla in due o tre macchine drammaticamente più semplici, o di gestire in uno stato diversi sottostati.

@Claudio_FF ti ringrazio per la risposta, l'idea è quella di inserire quelle dichiarazioni nell'exit state della funzione di rigenera, appena sarà implementata
Come potrei scomporre uno stato in diversi sottostati? Potrebbe funzionare iniziando a dividere il ciclo in prelavaggio, lavaggio, risciacqui e asciugatura?

Comunque chiedo gentilmente al moderatore @gpb01 di chiudere la discussione

... motivo? Non vedo "problemi particolari" ed altri utenti, interessati alla questione, potrebbero voler porre delle domande senza dover aprire, inutilmente, un nuovo thread sullo stesso argomento ... :roll_eyes:

Se hai ricevuto le tue risposte e non sei più interessato alla cosa ... semplicemnete abbandona la discussione, non partecipare più e lascia il thread ad altri possibili lettori :slight_smile:

Guglielmo