Gestione di un menu

Salve, sono alle prese con la creazione di un menu per la gestione del controller dell'acquario. Ho queste visualizzazioni: 1 Visualizzazione Carcia sistema .... solo in fase di setup. 2 Schermata di default (data, ora, temperatura vasca e una parte di messaggi) Da questa premendo * vado ad un menu configurazioni (Secona schermata) con: 1 - Data e ora 2 - Variabili premendo o 1 o 2 andrei ad eseguire le operazioni. Ho poi un terzo menu con: 1 - Accedere a menu dei relay 2 - Altre misurazioni vasca

..... insomma un casin!!!

Avete qualche link per prendere spunto? Questo penso potrebbe andare bene ma dovrei sezionarlo http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1273349195/0#0 .

Stiamo cercando di fare la stessa cosa ;) Per intanto ti posto bozza schema logico del menu http://img85.imageshack.us/img85/6141/menuef.jpg

L'idea e di utilizzare solo 4 pulsani: 2 freccie direzionale un "enter" ed un "esc"

Il code sta cercando di farlo mio figlio :-?

Ciao Renato (il papà di Andrea)

Ciao Renato, fortunato te che hai il figlio che ti aiuta ... per il mio pendo di dover aspettare almeno qualche decennio ... (6 mesi oggi).

Si la cosa è la stessa vediam cosa produce il pupo e poi vediamo, io ho un tastierino per poter evetnualemtne imputare anche dei dati quindi utilizzerei quelli. I pulsanti invece li uso per funzioni più veloci tipo lo spegnere le pompe per la pappa, spegnere lo skim per la pulizia ... intervenire direttamente sulle luci.

ciao, ricordo che Calamaro, con il suo bromografo DIY, aveva affrontato la questione dei menu. Magari potrebbe tornarvi utile... http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1241310950/30

Grazie. Lo avevo trovato in una precedente ricerca ma poi non lo avevo più trovato.

Sono riuscito a impostare i menu principali, ma non riesco a creare i sottomenu. Ecco il codice:

//Includi librerie
#include <WProgram.h>
#include <Wire.h>
#include <DS1307.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
#include "AnalogButtons.h"
#define ANALOG_PIN 1
//Dichiara le vaie cose
int button_pin = 1;
int button_enter_state = 0;
int button_exit_state = 0;
int button_right_state = 0;
int button_left_state = 0;
int button_value;
float temp;
int temp_pin = 0;
unsigned int cont_pag = 0;
long previousMillis = 0; 
long interval = 0; 
int led_pin = 13;
byte array_left[8] = {
  B00001,
  B00011,
  B00111,
  B01111,
  B00111,
  B00011,
  B00001,
  B00000,
};
byte array_right[8] = {
  B10000,
  B11000,
  B11100,
  B11110,
  B11100,
  B11000,
  B10000,
  B00000,
};


void setup() {
 //Impostazioni di SETUP
 lcd.createChar(0, array_left);
 lcd.createChar(1, array_right);
 pinMode(button_pin, INPUT);
 pinMode(led_pin, OUTPUT);
 lcd.begin(16, 2);

}

void loop() { 
button_enter_state = LOW;
button_exit_state = LOW;
button_right_state = LOW;
button_left_state =LOW;
  button_value = analogRead(button_pin);           
if(button_value > 944 && button_value < 947){
  button_left_state = HIGH;
}
else if(button_value > 965 && button_value < 971){
 button_right_state = HIGH;
}
else if(button_value > 988 && button_value < 993){
 button_enter_state = HIGH; 
}
else if(button_value > 999 && button_value < 1003){
 button_exit_state = HIGH; 
}
  
  if(button_exit_state == HIGH && button_right_state == LOW && button_left_state == LOW &&  button_enter_state == LOW && millis() - previousMillis > interval + 250 ){
  cont_pag = 0; //Se premo tasto EXIT torna al menu base
  }
     if(button_right_state == HIGH && button_left_state == LOW && button_exit_state == LOW &&  button_enter_state == LOW && millis() - previousMillis > interval + 250 ){
    previousMillis = millis();   
   cont_pag++; //Se premo PIU incrementa numero pagina
    if(cont_pag == 4){
      cont_pag = 1; //Se incremento a più di 3(4) portami al primo menu (non il menu base)
  }
}
else if(button_left_state == HIGH && button_right_state == LOW && button_exit_state == LOW &&  button_enter_state == LOW && millis() - previousMillis > interval + 250 ){
   previousMillis = millis(); 
  cont_pag--; //Se premo MENO diminuisci numero pagina
   if(cont_pag == 0){
      cont_pag = 3; //Se incremento a menodi 1(0) portami al terzo menu
  }
}
   switch (cont_pag) {
     case 0: //Se il numero della pagina è su menu base
     
  temp = analogRead(temp_pin);           
  temp = (5.0 * temp * 100.0)/1024.0;
 if(cont_pag == 0 &&  millis() - previousMillis > interval + 1000){
  previousMillis = millis();
  lcd.setCursor(0, 0);
  lcd.print("                ");
  lcd.setCursor(0, 1);
  lcd.print("                ");
  lcd.setCursor(1, 0);
  lcd.print(RTC.get(DS1307_HR,true));
  lcd.setCursor(3, 0);
  lcd.print(":");
  lcd.setCursor(4, 0);
  lcd.print(RTC.get(DS1307_MIN,false));
  lcd.setCursor(10, 0);
  lcd.print(RTC.get(DS1307_DATE,false));
  lcd.setCursor(12, 0);
  lcd.print("/");
  lcd.setCursor(13, 0);
  lcd.print(RTC.get(DS1307_MTH,false));
  lcd.setCursor(2, 1);
  lcd.print("Temp:");
  lcd.setCursor(7, 1);
  lcd.print(temp);
  lcd.setCursor(13, 1);
  lcd.print("C");
  }
break;

    case 1: //Se il numero della pagina è sul primo menu
    
    lcd.setCursor(0, 0);
    lcd.print("   LUCE SUMP    ");
    lcd.setCursor(0, 1);
    lcd.print("                ");  
    lcd.setCursor(0, 1);
    lcd.write(0);
    lcd.setCursor(15, 1);
    lcd.write(1);
   break;  
    
    case 2: //Se il numero della pagina è sul secondo menu
    
    lcd.setCursor(0, 0);
    lcd.print(" RABBOCCO POMPA ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    lcd.setCursor(0, 1);
    lcd.write(0);
    lcd.setCursor(15, 1);
    lcd.write(1);
    break;
    
    case 3: //Se il numero della pagina è sul terzo menu
    
    lcd.setCursor(0, 0);
    lcd.print("   POMPA SUMP   ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    lcd.setCursor(0, 1);
    lcd.write(0);
    lcd.setCursor(15, 1);
    lcd.write(1);
    
     
}

}

Lo schema logico di funzionamento è già stato postato nel secondo messaggio( http://img85.imageshack.us/img85/6141/menuef.jpg)
Qualcuno protrebbe provare un sottomenu che funzioni implementato nel codice, poi ci penserò io ad applicarlo a tutti i sottomenu. Ciao a tutti.

Andrea

@Andrea96:

nel link che ha postato Pitusso c’è un’idea di menu che avevo creato io…abbastanza semplice e sicuramente migliorabile.
Il sottomenu che avevo sviluppato era parecchio semplice, cioè all’interno di una pagina se veniva premuto enter si attivava la possibilità di usare i tasti “+” e “-” per far incrementare o decrementare una variabile.
Prova a darci un’occhio potrebbe fare al caso tuo

* nessun pesce è stato oggetto di maltrattamenti durante la fase di test di questo menu *

io ho ripreso lo sketch da federico vanzati e l’ho leggermente modificato :smiley:

Includerei anche i molluschi ^^ ;D

Renato alla fine qualche cosa io sono risucito a fare, anche se non so se son peggio come programmatore o elettrrico.
Comunque qui sotto il codice ancora con tutta la cacca che mi serve per la verifica, ho fatto solo il primo livello dei menu adesso pulisco e faccio il secondo intanto se vuoi vedere …
grazie pitusso e ovviamente il codice di calamaro mi è servito per cercare di capire …

/*-------------------------------------------Definizione inclusioni ----------------------------------------------*/
#include <Wire.h>
#include <LCDi2cR.h>                       //   robot-electronics.co.uk 
LCDi2cR lcd = LCDi2cR(4,40,0x63,0);
#define VERSION "1.24"
/*========================================================================== Variabili di temporizzazione =======================================================================*/
//long tempo_btn = 0, debounce = 300;  //Tempo tra due letture successive di un bottone (300 ms)
int keyInput, livello, menu, ritorno;
/*===============================================================================================================================================================================*/
void setup()
{ 
  lcd.clear();
  lcd.init();                           // Init the display, clears the display
 
  lcd.print("Keypad Ver ");             // Show Version
  lcd.print (VERSION);
  keyInput=40;
  livello=0;
  menu=0;
  ritorno=0;
  delay(5000);
}  //setup
void loop ()  //Start Loop
{
if(ritorno == 1)
{
  keyInput = 20;
  }
else
{                                                     //Lettura stato tastiera per determinare cosa fare
  keyInput=lcd.keypad();
   }
 
  if(keyInput == 40 && livello==0)                    // Ciclo menu di funzionamento nulla di premuto
  {
    lcd.clear ();
    lcd.setCursor(0,0);        
    lcd.print("CICLO FUNZIONI   ");  
    lcd.setCursor(2,0);
    lcd.print("key input   "); 
    lcd.print(keyInput);
    lcd.setCursor(3,0);
    lcd.print("liv "); 
    lcd.print(livello);
    lcd.print(" menu  ");
    lcd.print(menu);
    delay (1000); 
  }
   if(keyInput == 20 && livello==0)                     // Se premo * (20) e il livello è 0
  { 
    lcd.clear ();
    livello = 1;                                      //Definisco che sono a livello 1
    menu=1;                                           //Menu 1 MENU PRINCIPALE
    ritorno = 0;
    lcd.setCursor(0,0);        
    lcd.print("MENU PRINCIPALE   ");             
    lcd.setCursor(1,0);        
    lcd.print("1 REGOLAZIONI");
    lcd.setCursor(2,0);
    lcd.print("2 ACCENSIONI ");
    lcd.setCursor(3,0);
    lcd.print("liv ");    
    lcd.print(livello); 
    lcd.print(" key ");
    lcd.print(keyInput);
    lcd.print(" men ");
    lcd.print(menu);
  }
  
  if(menu==1 && livello ==1 && ritorno ==0)                   //Se sei nel menu 1 e livello 1
  { 
  keyInput=lcd.keypad();  //Leggi pressione del tastp
  
  switch (keyInput)
  {
  case 1:                                                     // Premi uno per regolare ora
      lcd.clear ();
      lcd.setCursor (0,0);
      lcd.print ("1 IMPOSTA ORA");
      lcd.setCursor (1,0);
      lcd.print ("2 IMPOSTA VARIABILI");
      lcd.setCursor (2,0);
      lcd.print ("# MENU PRECEDENTE");
      lcd.setCursor (3,0);
      livello = 2;
      lcd.print("liv ");    
      lcd.print(livello); 
      lcd.print(" menu  ");
      lcd.print(menu);
      break;
  
 case 2:                                                        //Menu accensioni
    lcd.clear ();
    lcd.setCursor(0,0);        
    lcd.print("MENU ACCENSIONI   ");                            // Clear prev entry
    lcd.setCursor (2,0);
    lcd.print ("# MENU PRECEDENTE");
    lcd.setCursor (3,0);
    livello = 2;
    lcd.print("liv ");    
    lcd.print(livello); 
    lcd.print(" menu  ");
    lcd.print(menu);
    break;
       
}                                             // End switch
}                                             // End if menu 1 livello 1

 if(livello==2 && menu ==1 )
  { 
  keyInput=lcd.keypad();
  switch (keyInput)
  {  
  case 30:
  livello = 0;
  ritorno = 1;
  lcd.clear ();
  lcd.setCursor(0,0);        
  lcd.print("sei nella cacca   ");
  lcd.setCursor (3,0);
  lcd.print("liv ");    
  lcd.print(livello); 
  lcd.print(" menu  ");
  lcd.print(menu);
  break;
  }
  }
} //Loop

Accetto volentieri consigli su come migliorare … direi che ne ho proprio bisogno …

M

per i menu, io li ho sempre fatti con lo switch case: pulito, semplice ma soprattutto leggibile!

Si ma come hai fatto a gestire i sottolivelli. Non penso tu sia riuscito a fare tutto con un solo switch case. Oppure hai delle variabili che ti tengono traccia della selezione che fai sui tasti e poi le gestisci con lo switch ....

Decisamente è un po' incasinato da leggere e sopratuto da manutentare in questo modo ..... hai degli esempi dove hai usato switch ...

In riferimento a http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1241310950/30

case 2:   // Schermata Impostazione TInverno
    lcd.setCursor(0,0);
    lcd.print("    Pagina 3    ");

    if(enter == HIGH && millis() - tempo_btn > debounce)  //Premendo "enter" si entra nella sotto-modalita'
    {
      tempo_btn = millis();
      set = !set;
    }

    if(set == HIGH)
    {
      //Abilita l'ingresso in modalita' configurazione
      n_piu = 0;
      n_meno = 0;
      //Abilita i tasti "piu" e "meno" in modalita' incremento/decremento
      piu_set = digitalRead(PIU);
      meno_set = digitalRead(MENO);

      if(piu_set == HIGH && millis() - tempo_btn > debounce)  //Incremento "variabile" se premo tasto "piu"
      {
        tempo_btn = millis();
        n_piu++;
        piu_set = !piu_set;
        if( variabile < 50 )
          variabile++;
      }

      if(meno_set == HIGH && millis() - tempo_btn > debounce)  //Decremento "variabile" se premo tasto "meno"
      {
        tempo_btn = millis();
        n_meno++;
        meno_set = !meno_set;
        if( variabile > 0 )
          variabile--;
      }
    }
    lcd.setCursor(0,1);  //Scrivo la temperatura che sto impostando
    lcd.print(variabile);
    if(variabile < 10)  //Quando il numero è ad una sola cifra devo aggiungere uno spazio per mantenere il testo che viene dopo nella stessa posizione
      lcd.print(" ");
    if(set == LOW)
      lcd.print("           SET");
    else
      lcd.print("            OK");

    break;

Questa è una delle possibili soluzioni che avevi sotto il naso

Per gestire i sottolivelli potresti usare le procedure. Ovvero, nello switch case principale fai delle chiamate a procedure e per ogni procedura c'è un altro switch case che gestisce i livelli più interni. Magari così ti incasini di meno e la cosa è più modulare.

Ok ci riprovo. Federico la prima volta che lo avevo letto mi diceva poco niente ... adesso qualche cosa in più sicuramente, provo a vedere cosa riesco a fare. E' la prima volta che mi diletto sia come elettrico che come programmatore mi ci vorrà un po' ma alla fine ci arrivo. Grazie M

Ancora bruttino ma più leggibile rispetto alla prima versione e sopratutto sembra funziona. C’è da sistemare ancora la sincronizzazione del tempo per premere i pulsanti ma gira. Ho creato in un altro tab le funzioni delle videate di alcuni menù per rendere più leggibile il codice ed ho inserito anche l’RTC.
Mi piacerebbe migliorare il ritorno nei menu creando una funzione che mi riporta al numero del menù sopra … sicuramente cìè la soluzione ma per il momento mi sfugge eppure non sono distante.

Visto che il progetto per acquari sembra molto richiesto posto il codice, suggerimenti e critiche sono obbligatorie.

/*============================================================================== Variabili Pulsanti =============================================================================*/
/*===============================================================================================================================================================================*/

/*========================================================================== Variabili di temporizzazione =======================================================================*/
int keyInput, livello, menu;
long tempo_btn = 0, debounce = 500, tempo_men = 0, ritorno;  //Tempo tra due letture successive di un bottone (500 ms)
// DS1307 funzioni ora
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
int mil_time, fullYear, phase, fase;  
long YY, MM, K1, K2, K3, JD;  
double AG, IP;   
/*===============================================================================================================================================================================*/

/*========================================================================== Variabili di inclusione ============================================================================*/
#include <Wire.h>
#include <LCDi2cR.h>                       //   robot-electronics.co.uk 
LCDi2cR lcd = LCDi2cR(4,40,0x63,0);
#define DS1307_I2C_ADDRESS 0x68
#define VERSION "1.00"
#include <OneWire.h>
/*===============================================================================================================================================================================*/

/*==========================================================================     configurazione rtc  ============================================================================*/
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}

void getDateDs1307(byte *second,
          byte *minute,
          byte *hour,
          byte *dayOfWeek,
          byte *dayOfMonth,
          byte *month,
          byte *year)

{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  // A few of these need masks because certain bits are control bits
  *second     = bcdToDec(Wire.receive() & 0x7f);
  *minute     = bcdToDec(Wire.receive());
  *hour       = bcdToDec(Wire.receive() & 0x3f);  // Need to change this if 12 hour am/pm
  *dayOfWeek  = bcdToDec(Wire.receive());
  *dayOfMonth = bcdToDec(Wire.receive());
  *month      = bcdToDec(Wire.receive());
  *year       = bcdToDec(Wire.receive());
}


void setup()
{
  lcd.clear();
  lcd.init();  // Init the display, clears the display
  lcd.setCursor(0,5);
  lcd.print("Open Reef");             // Show Version
  lcd.setCursor(1,8);
  lcd.print (VERSION);
  keyInput=40;
  livello=0;
  menu=0;
  ritorno=0;
  delay(5000);
}  // setup()...


void loop()
{
   getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
   mil_time = (hour *100) + minute;
   fullYear = (2000 + year);
 
   keyInput=lcd.keypad();
 
 if (menu == 0 && keyInput == 20)
 { 
    menu = 1;
 }
 if (menu == 0 && keyInput ==40)
  { 
    menu = 40;
 }
 switch (menu)
  { 
  case 40:
    //Schermata ciclo sistema
    lcd.clear();
    circle();
    menu = 0;
    delay(100); 
    break;
    
  case 1:
 
    lcd.clear();
    lcd.setCursor(0,0);        
    lcd.print("MENU PRINCIPALE   ");             
    lcd.setCursor(1,0);        
    lcd.print("1 REGOLAZIONI");
    lcd.setCursor(2,0);
    lcd.print("2 ACCENSIONI ");
    lcd.setCursor(3,0);
    lcd.print("3 TARATURA ");
    
    keyInput=lcd.keypad();
    
    if(keyInput == 1)
    {
    menu = 11;
    tempo_btn = millis();   
    }
    if(keyInput == 2)
    {
    menu = 12;
    tempo_btn = millis();   
    }
    if(keyInput == 3)
    {
    menu = 13;   
    tempo_btn = millis();
    }
    if(keyInput == 30)
    {
    menu = 0;   
    tempo_btn = millis();
    }
    delay(100);
    break;
 case 11:
    //Schermata menu regolazioni
    lcd.clear();
    lcd.setCursor(0,0);        
    lcd.print("MENU REGOLAZIONI   ");
    lcd.setCursor(1,0);        
    lcd.print("1 DATA E ORA ");
    lcd.setCursor(2,0);        
    lcd.print("2 VARIABILI  ");
    lcd.setCursor(3,0);  
    lcd.print(tempo_btn); 
    ritorno = millis();

    keyInput=lcd.keypad();
    if(keyInput == 1 && millis() - tempo_btn > debounce)
    {
    menu = 21;
    tempo_btn = millis();   
    }
    if(keyInput == 2 && millis() - tempo_btn > debounce)
    {
    menu = 22;
    tempo_btn = millis();    
    }
    if(keyInput == 30 && millis() - tempo_btn > debounce)
    {
    menu = 1;
    tempo_btn = millis();    
    }
    delay(100);
    break;
case 12:
    //Schermata menu principale 
    noMenu();
    if(keyInput == 30 && millis() - tempo_btn > debounce)
    {
    menu = 1;
    tempo_btn = millis();    
    }
    break; 
case 13:
    //Schermata menu principale 
    noMenu(); 
    if(keyInput == 30 && millis() - tempo_btn > debounce)
    {
    menu = 1;
    tempo_btn = millis();    
    }
    break;
case 21:
    //Schermata menu principale 
    noMenu();
    if(keyInput == 30 && millis() - tempo_btn > debounce)
    {
    menu = 11;
   tempo_btn = millis();    
    } 
    
    break;   
case 22:
    //Schermata menu principale 
    noMenu();
    if(keyInput == 30 && millis() - tempo_btn > debounce)
    {
    menu = 11;
    tempo_btn = millis();    
    } 
    break;    
  } //switch...  
} //loop()...

Il codice di alcuni menù invece è qui.

void noMenu ()
{
    lcd.clear();
    lcd.setCursor(1,6);        
    lcd.print("MENU  ");
    lcd.print(menu);
    lcd.setCursor(2,3);        
    lcd.print("NON DISPONIBILE");
    delay(300);
}    

void menu1 ()
{

    lcd.clear();
    //Print data and hour
    lcd.clear();
    lcd.setCursor(0,0);
  if(dayOfMonth < 10)
     lcd.print('0');
     lcd.print(dayOfMonth, DEC);
     lcd.print("/");
   if(month < 10)
     lcd.print('0'); 
     lcd.print(month, DEC);
     lcd.print("/");
     lcd.print(fullYear, DEC);
  //Serial.print("Militar  ");
  //Serial.print(mil_time, DEC);
  //Serial.print("  Fase Lunare ");
  //Serial.println(fase, DEC);
      lcd.setCursor(0,12);
    if(hour < 10)
      lcd.print('0');
      lcd.print(hour, DEC);
      lcd.print(":");
  if(minute < 10)
      lcd.print('0');
      lcd.print(minute, DEC);
      lcd.print(":");
  if(second < 10)
      lcd.print('0');
      lcd.print(second, DEC);
      lcd.setCursor(3,0);
      lcd.print("MENU 1");
      delay(1000);
}  

void menu2 ()
{

    lcd.clear();
    //Print data and hour
    lcd.clear();
    lcd.setCursor(0,3);
    lcd.print("MENU ACCENSIONI");
    lcd.setCursor(1,9);
    lcd.print("ON");
    lcd.setCursor(2,0);
    lcd.print("12345678");
    lcd.setCursor(2,12);
    lcd.print("12345678");
    lcd.setCursor(3,9);
    lcd.print("OF");
    delay(1000);
}

void circle ()                      // Da ultimare non funziona
{

    if (tempo_men + 10000 > millis ())
    {
    menu1 ();
    }
    else
    {
    tempo_men = millis () ;
    menu2 ();
   
    }
}