Problema con sottomenu

salve a tutti,
spero di non aver sbagliato qualche sosa sul caricare il mio primo codice qui...
Sto cercando di creare un progetto sketch, una lavatrice. Sto usando la programmazioni a stati, ho creato un menu' principale il tutto comandato da un encoder (codice che devo perfezionare).
il mio problema sono i sotto menu, non riesco a farlo funzionare, entro nel sottomenu creato anchesso con swtch case ma se provo a selezionare mi esce fuori nel menu principale.
vi posto il codice

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// Caratteri LCD
byte freccia[8]  = {B00000, B01110, B01110, B01110, B11111, B01110, B00100}; 
byte pallino[8] = {B00000, B00000, B00110, B01111, B01111, B00110, B00000};

//void LavaggioRapido();

const int upButton = 3;
const int downButton = 2;
const int selectButton = 8;

 int stato = 1 ;


int stopstato = 4;
int start = 5;


int pin2=9;   //Entrada 2 del L293D
int pin7=10;  //Entrada 7 del L293D

int buzzer=12; //buzzer

void setup() {
  Serial.begin(9600);
  lcd.begin(20,4);
  lcd.backlight();
  lcd.createChar(0, pallino);
  lcd.createChar(1, freccia);
  
  pinMode(upButton, INPUT_PULLUP);
  pinMode(downButton, INPUT_PULLUP);
  pinMode(selectButton, INPUT_PULLUP);
   pinMode(stopstato, INPUT);
    pinMode(start, INPUT);
    pinMode(53, OUTPUT);
 lavaggiMenu();

}
 

}
void loop() {

   if (!digitalRead(downButton)){
    //delay(50);
    stato++;
    lavaggiMenu();    
    delay(100);
    while (!digitalRead(downButton));
  }
 if (!digitalRead(upButton)){
    delay(100);
    stato--;
    lavaggiMenu();
    delay(100);
    while(!digitalRead(upButton));
  }
  if (!digitalRead(selectButton)){// tasto encoder seleziona
 
     lavaggiMenu();
      scelta();     
    delay(100);
    while (!digitalRead(selectButton));
  }

   }
 

//funzione menu programmi lavaggi
void lavaggiMenu() {
          
 switch (stato) {
   case 0:
     stato = 1;
  break;
  case 1:
    lcd.clear();
   lcd.setCursor(0, 0);lcd.write(byte(0));
   lcd.setCursor(2, 0);lcd.print("LAVAGGIO RAPIDO"); 
   lcd.setCursor(2, 1);lcd.print("LAVAGGIO LENTO");
   lcd.setCursor(2, 2);lcd.print("LAVAGGIO DELICATI");
   lcd.setCursor(2, 3);lcd.print("LAVAGGIO ECO");
  break;
  case 2:
   lcd.clear();
   lcd.setCursor(0,1);lcd.write(byte(0));
   lcd.setCursor(2, 0);lcd.print("LAVAGGIO RAPIDO"); 
   lcd.setCursor(2, 1);lcd.print("LAVAGGIO LENTO");
   lcd.setCursor(2, 2);lcd.print("LAVAGGIO DELICATI");
   lcd.setCursor(2, 3);lcd.print("LAVAGGIO ECO");
  break;
  case 3:
   lcd.clear();
   lcd.setCursor(0, 2);lcd.write(byte(0));
   lcd.setCursor(2, 0);lcd.print("LAVAGGIO RAPIDO"); 
   lcd.setCursor(2, 1);lcd.print("LAVAGGIO LENTO");
   lcd.setCursor(2, 2);lcd.print("LAVAGGIO DELICATI");
   lcd.setCursor(2, 3);lcd.print("LAVAGGIO ECO");  
  break;
  case 4:
   lcd.clear();
   lcd.setCursor(0, 3);lcd.write(byte(0));
   lcd.setCursor(2, 0);lcd.print("LAVAGGIO RAPIDO"); 
   lcd.setCursor(2, 1);lcd.print("LAVAGGIO LENTO");
   lcd.setCursor(2, 2);lcd.print("LAVAGGIO DELICATI");
   lcd.setCursor(2, 3);lcd.print("LAVAGGIO ECO");
  break;
  case 5:
   lcd.clear();
   lcd.setCursor(0, 0);lcd.write(byte(0));
   lcd.setCursor(2, 0); lcd.print("risciacquo");
   lcd.setCursor(2, 1); lcd.print("Centrifuga");
   lcd.setCursor(2, 2); lcd.print("Scarico");
   lcd.setCursor(2, 3); lcd.print("Esci");
  break;
  case 6:
   lcd.clear();
   lcd.setCursor(0, 1); lcd.write(byte(0));
   lcd.setCursor(2, 0); lcd.print("risciacquo");
   lcd.setCursor(2, 1); lcd.print("Centrifuga");
   lcd.setCursor(2, 2); lcd.print("Scarico");
   lcd.setCursor(2, 3); lcd.print("Esci");
  break;
  case 7:
   lcd.clear();
   lcd.setCursor(0, 2); lcd.write(byte(0));
   lcd.setCursor(2, 0); lcd.print("risciacquo");
   lcd.setCursor(2, 1); lcd.print("Centrifuga");
   lcd.setCursor(2, 2); lcd.print("Scarico");
   lcd.setCursor(2, 3); lcd.print("Esci");
  break;
  case 8:
   lcd.clear();
   lcd.setCursor(0, 3);lcd.write(byte(1));
   lcd.setCursor(2, 0); lcd.print("risciacquo");
   lcd.setCursor(2, 1); lcd.print("Centrifuga");
   lcd.setCursor(2, 2); lcd.print("Scarico");
   lcd.setCursor(2, 3); lcd.print("Esci");
  break;
  case 9:
   stato = 8;
  break; 
  
  }
  
}

// scelta menu 
void scelta() {
    //int stato = 1;
 
  switch (stato) {
    case 1:
      LavaggioRapido();
      break;
      
    case 2:
      LavaggioLento();
      break;
    case 3:
      CapiDelicati();
      break;
    case 4:
      Lavaggioeco();
      break;
      case 5:
    risciacquo();
      break;     
      case 6:
    centrifuga();
      break;
       case 7:       
    scarico();
      break;      
       case 8:      
       esci();
      break;
  
  }
}

 int sez = 20;
void LavaggioRapido() { 
 
  if (!digitalRead(downButton)){
    sez++;    
    LavaggioRapido();      
    delay(100);
    while (!digitalRead(downButton));
  }
 if (!digitalRead(upButton)){
    delay(100);
      sez--;    
    LavaggioRapido();   
    delay(100);
    while(!digitalRead(upButton));
  } 
switch (sez) {
  
 case 20:
   lcd.clear();
   lcd.setCursor(0, 3); lcd.write(byte(0));
   lcd.setCursor(2, 0); lcd.print("LAVAGGIO RAPIDO");
   lcd.setCursor(2, 1); lcd.print("55 minuti");
   lcd.setCursor(1, 3); lcd.print("Avvio");
   lcd.setCursor(16, 3); lcd.print("Esci");
  break;
   case 21:
    lcd.clear();
   lcd.setCursor(15, 3); lcd.write(byte(0));
   lcd.setCursor(2, 0); lcd.print("LAVAGGIO RAPIDO");
   lcd.setCursor(2, 1); lcd.print("55 minuti");
   lcd.setCursor(1, 3); lcd.print("Avvio");
   lcd.setCursor(16, 3); lcd.print("Esci");
   break;}

      
}

void LavaggioLento() {
  lcd.clear();
  lcd.print("Lavaggio Lento");
  delay(1500);
   lavaggiMenu();
    
}
void CapiDelicati() {
  lcd.clear();
  lcd.print("Capi Delicati");
  delay(1500);
}
void Lavaggioeco() {
  lcd.clear();
  lcd.print("Centrifuga");
  delay(1500);
}

void risciacquo() {
  lcd.clear();
  lcd.print("Centrifuga");
  delay(1500);
}
void centrifuga() {
  lcd.clear();
  lcd.print("Centrifuga");
  delay(1500);
}
void scarico() {
  lcd.clear();
  lcd.print("Centrifuga");
  delay(1500);
}
void esci() {
  lcd.clear();
   delay(1500);
  avvio();
}

Secondo me il menu e la selezione delle funzioni è pensata male e non funziona. Tu premi un pulsante cambia stato e visualizzi scritte, ma non hai selezionato niente, cambiando stato avrai già una funzione corrispondente.

Allora io vedrei una funzione menu che ti stampa le possibili scelte, con un ciclo while(true) infinito che resta sempre nella funzione, tramite un tre pulsanti "possono essere gli stessi usati per altri scopi", uno aumento il valore di una variabile, l'altro diminuisco la variabile, il terzo conferma e esegue un break che fa uscire dal while e dalla funzione.

Io in realtà rivedrei tutto il programma...

void Menu(){

    char testo[4][20]={"LAVAGGIO RAPIDO","LAVAGGIO LENTO","LAVAGGIO DELICATI","LAVAGGIO ECO"};
    while(true){
        if(digitalRead(pulsante1)==0)
            stato++;
        else if(digitalRead(pulsante2)==0)
            stato--;
         else if(digitalRead(pulsante3)==0)
             break; // esco dal while e dalla funzione
         lcd.setCursor(2, 0);lcd.print(testo[stato]); 
        delay(300); // Un rallentamento della stampa su lcd, altrimenti sarebbe ogni millisecondi
    }


 }
type or paste code here

Grazie.... da questo menu vorrei passare ad un sotto menu,uso sempre la stessa tecnica?
Esempio seleziono "lavaggio rapido" il quale mi porta in un altro menu dove mi appare " la durata del lavaggio e due opzioni, continua o esci.
Naturalmente se esco mi porta al menu principale.
Sto usando un encoder con pulsante per muovermi nel sistema

Si io farei i sotto menu allo stesso modo, un ciclo infinito che continua fino a che non si preme un pulsante che genera un break.
Se hai delle variabili globali dichiarate fuori da ogni funzione, la modifica che fai nei sotto menu a queste variabili, sono visibili in tutto il programma e usarle per i tuoi scopi.

Se esci da una funzione, un sottomenu, torni alla funzione loop()

Farei una modifica al menu. Andiamo ad incrementare e diminuire la variabile e visualizziamo l'elemento dell'array di stringhe, ma potremmo arrivare a un numero maggiore di 4 elementi che non esisto o a meno di zero, che anche non esistono. Risolviamo il problema.

void Menu(){

    char testo[4][20]={"LAVAGGIO RAPIDO","LAVAGGIO LENTO","LAVAGGIO DELICATI","LAVAGGIO ECO"};
    while(true){
        if(digitalRead(pulsante1)==0){
            stato++;
            if(stato>3)stato=0; // Se arriva all'ultimo elemento torna al primo
        }else if(digitalRead(pulsante2)==0){
            stato--;
            if(stato<0)stato=3; // Se è meno di zero torna al massimo
         }else if(digitalRead(pulsante3)==0)
             break; // esco dal while e dalla funzione
         lcd.setCursor(2, 0);lcd.print(testo[stato]); 
        delay(300); // Un rallentamento della stampa su lcd, altrimenti sarebbe ogni millisecondi
    }

Ok, come faccio a collegare il menu principale con il sottomenu?
Scusami, ma sto studiando uno sviluppo a macchine a stati con switch case.
Quedyo con i vettori mi è più difficile. Tipo quando richiamo lavaggio rapido, nel sottomenu dovrò far partire un altra funzione corrispondente.

ciao a tutti, chiedo venia ma non riesco ad uscirne, vi posto il codice,

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

const int pin15 = 9;
const int pin10 = 10;
int ilcd = 7;
int p_carico = 6; // pompa carico acqua
int p_scarico = 8; // pompa scarico acqua
const byte stopPin = 3;

int valorHorario = 0;
int valorAntihorario = 0;
int tiempo = 1000;

int upButton = 2;
int downButton = 5;
int selectButton = 4;
int menu = 1;
int stato = 1;

unsigned long t1, dt;

void setup() {
  lcd.begin(20, 4);
  lcd.backlight();
  pinMode(upButton, INPUT_PULLUP);
  pinMode(downButton, INPUT_PULLUP);
  pinMode(selectButton, INPUT_PULLUP);
  pinMode(pin10, OUTPUT);
  pinMode(pin15, OUTPUT);
  pinMode(ilcd, OUTPUT);
  digitalWrite(ilcd, HIGH);
  updateMenu();
}

void loop() {
  if (!digitalRead(downButton)) {
    menu++;
    updateMenu();
    delay(200);
    while (!digitalRead(downButton));
  }
  if (!digitalRead(upButton)) {
    menu--;
    updateMenu();
    delay(300);
    while (!digitalRead(upButton));
  }
  if (!digitalRead(selectButton)) {
    executeAction();
    updateMenu();
    delay(300);
    while (!digitalRead(selectButton));
  }
}

void updateMenu() {
  switch (menu) {
    case 0:
      menu = 1;
      break;
    case 1:
      lcd.clear();
      lcd.print(">LAVAGGIO RAPIDO");
      lcd.setCursor(0, 1);
      lcd.print(" LAVAGGIO LENTO");
      break;
    case 2:
      lcd.clear();
      lcd.print(" LAVAGGIO RAPIDO");
      lcd.setCursor(0, 1);
      lcd.print(">LAVAGGIO LENTO");
      break;
    case 3:
      lcd.clear();
      lcd.print(">LAVAGGIO LANA");
      lcd.setCursor(0, 1);
      lcd.print(" LAVAGGIO DELI");
      break;
    case 4:
      lcd.clear();
      lcd.print(" LAVAGGIO LANA");
      lcd.setCursor(0, 1);
      lcd.print(">LAVAGGIO DELI");
      break;
    case 5:
      lcd.clear();
      lcd.print(">CENTRIFUGA");
      break;
    case 6:
      menu = 5;
  }
}

void executeAction() {
  switch (menu) {
    case 1:
      executiv();
      stato = 1;
      break;
    case 2:

      break;
    case 3:

      break;
    case 4:

      break;
    case 5:

      break;
  }
}

void executiv() {
  switch (stato) {
    case 1:
      prelavaggio();
      break;
    case 2:
      caricoacqua();
      break;
    case 3:
      motoredxsx();
      break;
    case 4:
      centrifuga();
      break;
    case 5:
      finito();
      break;
  }
}
void prelavaggio() {// INIZIO SCARICO

  lcd.clear();
  lcd.setCursor(4, 1); lcd.print("PRELAVAGGIO");
  t1 = millis();
  stato = 2;
  analogWrite(p_scarico, 200);
  dt = millis() - t1;
  for (int i = 0; i <= 8; i++) { // inizio carico acqua
    lcd.setCursor(i, 3); lcd.print(char(3));
    delay(500);
    if (digitalRead(stopPin)) {
      break; stopCiclo();
    }
  } stato = 2;
}

void caricoacqua() {
  if (digitalRead(stopPin)) {
    stopCiclo();
  }
  dt = millis() - t1;
  if (dt > 3000) {
    lcd.clear();
    lcd.setCursor(4, 1); lcd.print("lavaggio");
    analogWrite(p_scarico, 0);
    analogWrite(p_carico, 150);
    digitalWrite(11, HIGH);
    analogWrite(pin15, 40);
    t1 = millis();
    stato = 3;
  }
}

void motoredxsx() {
  dt = millis() - t1;
  if (digitalRead(stopPin)) {
    stopCiclo();
  }
  if (dt > 3000) {
    lcd.clear();
    lcd.setCursor(6, 1); lcd.print("LAVAGGIO1");
    digitalWrite(11, LOW);
    analogWrite(p_carico, 0);
    analogWrite(pin15, 0);
    analogWrite(pin10, 40);
    t1 = millis();
    stato = 4;
  }
}
void scaricoacqua() {
  dt = millis() - t1;
  if (digitalRead(stopPin)) {
    stopCiclo();
  }
  if (dt > 3000) {
    lcd.clear();
    lcd.setCursor(7, 1); lcd.print("scarico+");
    stato = 4;
    t1 = millis();
  }
}

void centrifuga() {//stato 10
  dt = millis() - t1;
  if (digitalRead(stopPin)) {
    finito();
  }
  if (dt > 1000) {
    lcd.clear();
    analogWrite(pin10, 255);
    analogWrite(pin15, 0);
    lcd.setCursor(5, 1); lcd.print("CENTRIFUGA");
    for (int i = 0; i <= 8; i++) { // inizio carico acqua
      lcd.setCursor(i, 3); lcd.print(char(3));
      delay(600);
      if (digitalRead(stopPin)) {
        break;
      }
    }
    for (int i = 200; i >= 20; i--) {
      analogWrite(pin10, i);
      analogWrite(11, i);
      delay (10);
    } stato = 5;
  }
}

void finito() {
  lcd.clear();
  lcd.setCursor(7, 1); lcd.print("fine");
  delay(1000);
  lcd.setCursor(7, 1); lcd.print("pronto!");
  digitalWrite (11, LOW);
  analogWrite(p_carico, 0);
  analogWrite(p_scarico, 0);
  analogWrite(pin15, 0);
  analogWrite(pin10, 0);
  stato = 1;
}

void stopCiclo() {
  //if ((menu != 1)) {
  lcd.clear();
  lcd.setCursor(2, 0); lcd.print("ARRESTO lavaggio");
  delay(1000);
  lcd.clear();
  digitalWrite (11, LOW);
  analogWrite(p_carico, 0);
  analogWrite(p_scarico, 0);
  analogWrite(pin15, 0);
  analogWrite(pin10, 0);
  lcd.setCursor(6, 1); lcd.print("PRONTO!");
  // stato = 1;
  // }
}

se provo a compilarlo, seleziono lavaggio rapido, parte con il prelavaggio ma poi esce e torna al menu principale, non capisco perche' non continua con gli altri stati selezionati. se faccio la prova con un solo switch case con la stessa modalita funziona. il problema nasce come inserisco altri switch case.
scusatemi ma mi sta facendo impazzire ho provato centinaia di prove... è diventata un'ossessione :sweat_smile:

Il problema è che chiami la executeAction() solo quando il pulsante Select è premuto.
Finito il prelavaggio il controllo torna al loop() e non trovando il pulsante premuto continua a ciclare nel loop().

Senza stravolgere il tuo sketch, ho provato ad aggiunere una variabile di stato dichiarata all'inizio
bool attiva = false;
Poi nel loop() ho cambiato così:

  if (!digitalRead(selectButton)) {
    attiva = true;
    updateMenu();
    delay(300);
    while (!digitalRead(selectButton));
  }

  if (attiva) {
    executeAction();
  }

Adesso esegue in sequenza la varie fasi, ma da qualche parte devi riportare a false la variabile altrimenti continua a ripetere tutte le fasi all'infinito...

Proverò anche la tua soluzione... grazie.
Forse, "attiva = false" basterà aggiunerlo nella funzione finito().
Ieri sera ho provato ad aggingere un ciclo while allo switch case executiv(). Poi sempre nello switch al case 5, sotto la funzione finito(), ho messo un return al posto del break, adesso sembra che funziona. Appena provo la tua soluzione ti faccio sapere

Sì, quella di ciclare dentro la executive() è un'altra soluzione. Vedi con quale ti trovi meglio anche in base a come sviluppi le altre fasi del programma.

un consiglio, lo sketch si comporra di 4 lavaggi... uno rapido, uno lento, delicati , piu' risciaquo, centrifuga.

void executiv() {
  
 while(true){
  switch (stato) {
    case 1:
      prelavaggio();
      break;
    case 2:
      caricoacqua();
      break;
    case 3:
      motoredxsx();
      break;
    case 4:
      centrifuga();
      break;
    case 5:
      finito();
      break;
    case 6:
      
      break;
    case 7:
      
      break;
    case 8:
      
      break;
    case 9:
      
      break;
    case 10:
      prela1();
      break;
    case 11:
      
    case 90:
      lavaggiMenu();
      return;
    case 99:
      stopCiclo();
      break;
     
  }
 }
}

vorrei fare uno switch come questo postato, e impostarlo cosi: da uno a dieci per il lavaggio, poi da 10 a 20 un altro lavaggio e cosi per gli altri... alcune fasi saranno uguali per tutti tipo prelavaggio, centrifuga finito ecc... si differenziaranno solo i tempi di durata....
arriaviamo al punto, c'è un modo per non far diventare gli stati ripetitivi ?
tipo con il lavaggio rapido imposto stato 1, poi 2 e cosi via.... lavaggio lento... sempre stato 1 e esempio due volte stato 2 e cosi via....

Non sono sicuro di aver capito bene cosa intendi...
Cmq secondo me dovresti prima definire bene tutte le fasi di tutti i lavaggi e poi decidere come impostare lo sketch.
Per il doppio lavaggio potrebbe bastare passare un parametro alla funzione col numero di volte da ripetere. Oppure passare sempre un parametro ad ogni funzione per indicare quale sarà la funzione successiva.
Però senza avere chiaro tutto il meccanismo sparo un po' a casaccio...

Allora vediamo se posso essere più chiaro.... nello switch vorrei impostare lavaggio rapido, da case 1 a tipo case...,cosi composto : prelavaggio(), girimotoredxsx(), scarico, caricoacqua(), ecc... ecc... fino a finire con la funzione finito().
Dal case 10 imposto l'altro prog. Di lavaggio esempio quello lento... inizierò con il prelavaggio ma essendo lento la durata cambierà magari facendogli fare più fasi... non volevo ripetere ad esempio la funzione prelavaggio(), chiamandola prelavaggio1, essenzialmente uguale.... volevo capire se c'è una qualche stringa da inserire alla funzione che dica dove andare quando parte con un lavaggio rispetto che con un altro... lavaggio rapido va da case 2 a case 3.... mentre lavaggio lento va da case 2 al 5... non so se sono stato più chiaro :smile:

Quanti case fare glielo dici tu... Impostando opportunamente le varie variabili.

Curiosità... Ma se la sequenza di ogni lavaggio è sempre uguale non conviene una cosa del genere?

case 1:
      prelavaggio();
      caricoacqua();
      motoredxsx();
      centrifuga();
      finito();
      break;
case 2:
      prelavaggio();
      caricoacqua();
      motoredxsx(); // se deve girare di più chiami la funzione 2 volte 
      motoredxsx();
      centrifuga();
      finito();
      break;

:sweat_smile: avvolte le soluzioni più semplici sono quelle che non vediamo... perdonami sono un neofita e mi sono messo a pensare in grande, forse troppo, ma in questo modo sto imparando spero più velocemente leggendo studiando e provando... domani ci provo.
Grazie sempre per la tu disponibilità :+1:

Ho implementato un interrupt sul pin 2, in modo che quando viene premuto metta in pausa il "lavaggio". Funziona, ma solo quando è fuori dal ciclo for, avevo capito che funzionasse in qualsiasi funzione.
Altro dubbio volevo inserire il millis invece del delay, ma non va, legge il codice, accende il led senza eseguire l'intermittenza e va avanti... passando nell'altro stato. Ho aggiunto una flag... ho forzato con un ciclo tipo while( i < 4){ // codice } magari lo fa una volta, al secondo tentativo non esegue più....:woozy_face:

oltre a descrivere il problema dovresti anche postare lo sketch.
senza si può tirare a indovinare...

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.