Passare alla funzione superiore (annidamento)

Salve, sto creando un menu gestibile tramite 5 pulsanti. I pulsanti dal P1 al P4 svolgono le loro funzioni, mentre premendo P5 accedo a un sottomenu nel quale premendo P1 vado in un altro sottomenu e premendo P2 in un altro ancora. Per risalire voglio che si prema P5 o altri pulsanti a seconda di dove ci troviamo. Per esempio se nel menu principale tramite P5 accedo al menu di selezione ora/data, da lì premendo P1 vado nel menu di modifica ora e premendo ancora una volta P1 aumento l’ora (ora++), premendo P2 minuti++ e premendo P3 si ritorna al menu di modifica ora. La mia domanda è: come faccio a risalire nei vari menu? Ci ho messo il return ma non credo funzioni, stessa cosa se metto il nome della funzione madre. Vi allego un esempio:

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Time.h>
#include <LiquidCrystal.h>

#define buttonPin 0 // input analogico
#define debounce 20 // in ms: periodo di debounce (tra una pressione e un'altra)
#define tolleranza 500 //in ms: periodo di tolleranza di pressione azione/non azione
#define holdTime 5000 // in ms: tempo che bisogna aspettare per andare all'evento press+hold

LiquidCrystal lcd(3, 2, 13, 12, 11, 10);  //definizione pin LCD


// variabili pulsanti:
//===================================================
int buttonVal = 0; // valore letto dal pulsante
int buttonLast = 0; // valore dello stato dell'ultimo pulsante premuto (se è zero vuol dire che è passato del tempo da una pressione all'altra)
long btnDnTime; // tempo in cui il pulsante è premuto
long btnUpTime; // tempo in cui il pulsante è rilasciato
boolean ignoreUp = false; // whether to ignore the button release because the click+hold was triggered

int last_Pressed = 6;  //ultimo pulsante premuto: serve per riconoscere quando si cambiano i pulsanti in modo da saltare da una parte del menu all'INIZIO di un'altra
int current_Pressed =  6;
int i;
int cambiostato = 0; // presa 1: indice di stato temporaneo (stato non selezionato, solo scorso) Serve a mantenere traccia dello stato così da poterlo selezionare quando si tiene premuto il pulsante


// variabili Ethernet:
//=================================================

// imposta il mac dello shield Ethernet
byte mac[] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };  


/* ******** NTP Server Settings ******** */
// Imposta NTP server: us.pool.ntp.org  
IPAddress timeServer(96, 44, 157, 90); 

// Imposta l'offset (in secondi) del fuso orario (GMT +2 per Italia = +((60*60)*2))= 7200 sec)
const long timeZoneOffset = +7200L;   

// Sincronizza con l'NTP server ogni tot secondi per il testing (mettere per esempio 1 ora = 3600)
unsigned int ntpSyncTime = 15;         

// porta locale in listening per i pacchetti UDP
unsigned int localPort = 8888;

// NTP time stamp è nei primi 48 bytes del messaggio
const int NTP_PACKET_SIZE= 48;      

// Buffer per trattenere i pacchetti che arrivano e che partono
byte packetBuffer[NTP_PACKET_SIZE];  

// Istanza UDP per permettere di mandare e ricevere pacchetti sul protocollo UDP
EthernetUDP Udp;        

// Tiene traccia di quanto tempo fa abbiamo aggiornato il server NTP
unsigned long ntpLastUpdate = 0;    

// Controlla l'ultimo valore dell'orologio mostrato
time_t prevDisplay = 0;   
int anno = (year()- 1957);



//SETUP:
//================================

void setup() 
{
  Serial.begin(9600); // inizializzazione della comunicazione serial monitor a 9600 baud
  lcd.begin(16, 2); // inizializzazione schermo LCD con le dimensioni       
  Serial.println(". . .Inizializzazione. . ."); 
  
 // Setup dell' Ethernet shield e dell' NTP
   int index = 0;
   int DHCP = 0;
   DHCP = Ethernet.begin(mac);
   
   //Prova il DHCP per 30 volte
   while( DHCP == 0 && index < 30){
     delay(1000);
     DHCP = Ethernet.begin(mac);
     index++;
   }
   if(!DHCP){
    Serial.println("DHCP FALLITO");
     for(;;); // loop infinito per DHCP Failed
   }
   Serial.println("DHCP Success");
   
   // Prova a reperire data e ora
   int trys=0;
   while(!getTimeAndDate() && trys<10) {
     trys++;
   } 
}


void loop()
{
clockDisplay();  
buttonVal = analogRead(buttonPin);   // Leggi il valore del pulsante
//Serial.println(buttonVal);         // Stampa sul serial monitor il valore del pulsante premuto
scorriMenu();
}

void scorriMenu(){
[i][b].....SERIE DI IF PER I PULSANTI DA P1 A P4...[/b][/i]
// Pulsante P5 (SHORT): setta l'ora
if (buttonVal > 0 && buttonVal < 200 && buttonLast == 0 && (millis() - btnDnTime) > long(debounce))
{
   scorriClock();    // MODIFICA MENU OROLOGIO
}

void scorriClock()     // menu orologio
{    
  // Pulsante P1: SELEZIONA MENU OROLOGIO
  if (buttonVal > 1000 && buttonLast == 0 && (millis() - btnDnTime) > long(debounce) && (millis() - btnDnTime) < tolleranza)
    {
 modificaClock();
 current_Pressed=0;  // setto il pulsante che premo
 btnUpTime = millis();
 last_Pressed=0;  // setto il pulsante che ho appena premuto per il prossimo confronto
  }


// Pulsante P2: SELEZIONA MENU DATA
  if (buttonVal > 700 && buttonVal < 1000 && buttonLast == 0 && (millis() - btnDnTime) > long(debounce) && (millis() - btnDnTime) < tolleranza)
    {
  modificaData();
  current_Pressed=1;
  btnUpTime = millis();
  last_Pressed=1;
  }

// Pulsante P3
  if (buttonVal > 500 && buttonVal < 700 && buttonLast == 0 && (millis() - btnDnTime) > long(debounce))
    {
    return;
  }


// Pulsante P4: 
  if (buttonVal > 200 && buttonVal < 500 && buttonLast == 0 && (millis() - btnDnTime) > long(debounce))
    {
    return;
  }
  
  // Pulsante P5: 
  if (buttonVal > 0 && buttonVal < 200 && buttonLast == 0 && (millis() - btnDnTime) > long(debounce))
    {
    return;
  }
}

// MENU DI MODIFICA DELL'OROLOGIO
//===================================

void modificaClock()
{  //funzione per modificare l'orologio
  int currentHour = hour();
  int currentMin = minute();
  
  // PULSANTE P1 PREMUTO (SHORT): modifica ora
  if (buttonVal > 1000) {                       
  if (currentHour <= 24) currentHour++;
      else currentHour = 0;
      clockDisplay();
  }
  
  // PULSANTE P2 PREMUTO (SHORT): modifica minuti
  if (buttonVal > 700 && buttonVal < 1000){
      if (currentMin <= 59) currentMin++;
      else currentMin = 0;
      clockDisplay();
  }
  
  // PULSANTE P3 PREMUTO (SHORT): ok e torna indietro
   if (buttonVal > 500 && buttonVal < 700){
    return;
  }
}


// MENU DI MODIFICA DELLA DATA
//===================================
void modificaData(){
  int currentDay = day();
  int currentMonth = month();
  //int currentYear = year();    HO GIA' LA VARIABILE ANNO! (CHE PARTE DA 2013)
  
    // PULSANTE P1 PREMUTO (SHORT): modifica giorno
  if (buttonVal > 1000) {                       
  if (currentDay <= 31) currentDay++;
      else currentDay = 1;
      clockDisplay();
  }
  
  // PULSANTE P2 PREMUTO (SHORT): modifica mese
  if (buttonVal > 700 && buttonVal < 1000) {
      if (currentMonth <= 12) currentMonth++;
      else currentMonth = 1;
      clockDisplay();
  }
  
  // PULSANTE P3 PREMUTO (SHORT): modifica anno
  if (buttonVal > 500 && buttonVal < 700) {
      if (anno >= 2013) anno++;
      else if (anno >= 2070) anno--;
      clockDisplay();
  }
  
  // PULSANTE P4 PREMUTO (SHORT): ok e torna indietro
  if (buttonVal > 200 && buttonVal < 500) {
    return;
  }
}

Non so per il menù, ma l'LCD va in conflitto con la Ethernet. Non puoi usare i pin 10, 11, 12 e 13 se usi la Ethernet shield perche sono utilizzato dallo SPI. Sposta l'LCD in 2 ,3 ,4 ,5 ,6 e 7.

Inoltre puoi usare i pin analogici anche come ingressi digitali: per leggere i pulsanti puoi anche fare un digitalRead(A0); al posto di un analogRead(0). Metti la A davanti al numero oppure somma 14: analogRead(0) diventa digitalRead(A0) o digitalRead(14), analogRead(3) diventa digitalRead(A3) oppure digitalRead(17), ecc.

E' buona norma comunqe definire i pin analogici con la A davanti

#define buttonPin 0 // input analogico

equivale a

#define buttonPin A0 // input analogico

ma il primo provoca confusione nel caso di digitalRead. Infatti mentre analogRead(0) equivale a analogRead(A0), digitalRead(0) non è lo stesso di digitalRead(A0).

Ovviamente se hai 5 pulsanti in serie su un analogico il discorso cambia. :grin:

I pin dal 4 al 7 li ho occupati dal relé shield e sì, ho 5 pulsanti in serie su un analogico ;)

Non ho mai provato ma dovrebbe funzionare. Usa i pin 2, 3, 8, 9, e A2 e A3 per l'LCD. Usi la I2C per un RTC?

No, non ho proprio il modulo rtc...

OK, allora hai disponibili anche A4 e A5. Quindi pin a volontà. :grin:

Mi riesce difficile leggere tutto il codice e comprenderlo totalmente.

Quello che vuoi fare e di tornare alla voce di menu precedente da cui sei passato per accedere al menu corrente. Dovresti tenere traccia dei livelli del menu, esempio level_menu = 7, piggiano il tasto 5 fai eseguire level_menu--, ora level_menu vale 6. Oppure tieni traccia del menu correntemente visualizzato, il codice è simile ma cambia il nome della variabile in currentMenu.

Ciao.