Creare un menù con un LCdI2C e un keypad 4x4

Salve a tutti, scrivo a voi in preda alla disperazione più profonda. Ormai da diversi giorni sto cercando di creare un menù a più sezioni usando un keypad 4x4. Le ho provate davvero tutte, le mie risorse di programmazione (ormai deboli) si sono completamente esaurite...
Avete dei suggerimenti su come posso implementare un sistema di questo tipo?
Ho necessità di un menù principale a 4 voci con un sottomenù di altre 4 voci.
MAIN

opt-1 | opt-2 | opt-3 | opt-4
|
|
ops.1-1 | opt 1-2 | opt-1.3 | opt 1-4

Vi sarei davvero grato se poteste aiutarmi..
Valerio

Posta il codice ed eventualmente lo schema elettrico.

Il codice per ora è parecchio incasinato..ma ve lo mostro...

sto cercando di costruire la struttura da zero, usando i vettori

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



/*
* 0 = Menù principale
* 1 = Menù Setup
* 2 = Menù Leggi sensori 
* 3 = Menù Avvia
*/

/*
 * setup | selezione sensori | set time | set umidità minima | set umidità max
 * leggi sensori | 
 * avvia irrigazione |
 * stop |
 */

int menuLivello;

// righe e colonne del pad
const byte ROWS = 4; 
const byte COLS = 4; 

// massima profondità dei menù

int menuCorrente;// menù principale

char keys[ROWS][COLS] = { 
 {'1','2','3','A'},
 {'4','5','6','B'},
 {'7','8','9','C'},
 {'*','0','#','D'}
};

// definisci il menù con le sue sottosezioni

// primo numero: menù radice
// secondo numero: posizione del menù a cui è riferita la sottosezione 

char* menu[2][6] = {
 {"0","0","Setup","Leggi sensori","Attiva Irrigazione","Stop"  },
 {"0","2","Selezione sensori","Set time","Set umidità min","Set umidità max"  },
};

//i Pin a cui sono connesse le righe del KeyPad
byte rowPins[ROWS] = {2,3,4,5}; 
// i Pin a cui sono connesse le colonne del KeyPad
byte colPins[COLS] = {6,7,8,9}; 

LiquidCrystal_I2C lcd(0x27, 20, 4);
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

//-----------------------------------------------------------------
//        setup()
//-----------------------------------------------------------------
void setup() {  

 // avvia monitor seriale per il debug
 Serial.begin(9600);

 // Setup LCD
 lcd.init();
 lcd.backlight();
 lcd.clear();                     

 // mostra il primo menù
 menuCorrente = 0;
 menuLivello = 0;     
}

//-----------------------------------------------------------------
//        loop
//-----------------------------------------------------------------
void loop() {
 mostraMenu(menuCorrente);
}

//-----------------------------------------------------------------
//        mostraMenu()
//-----------------------------------------------------------------

void mostraMenu(int livelloMenu){
 
 // mostra gli elementi del menù mostrandone uno per riga

 int colonnaMenu;
 int posizione = 0;
 
 for(int cont=0; cont<=4; cont++){
   
   colonnaMenu = cont+2;
   
   lcd.setCursor(1,cont);
   lcd.print(menu[livelloMenu][colonnaMenu]);
 } 

 mostraSelettore(posizione);
 
}

//-----------------------------------------------------------------
//          mostraSelettore()
//-----------------------------------------------------------------

void mostraSelettore(int colonna){

int posizioneSelettore;
int x;
// il selettore sarà visualizzato nella riga del menù corrente
posizioneSelettore = colonna; 

lcd.setCursor(0,posizioneSelettore);
lcd.print(">");

//debug();

// loop infinito
 while(x>=0){

   // legge il tasto premuto sul keypad
   char key = keypad.getKey();

   if (key=='A'){          //------------------------- UP

     lcd.setCursor(0,colonna);
       lcd.print(" ");
       colonna--;
       lcd.setCursor(0,colonna);
       lcd.print(">");

       menuCorrente = colonna;

   }  
   else if (key=='B'){     //------------------------- DOWN
       
       lcd.setCursor(0,colonna);
       lcd.print(" ");
       colonna++;
       lcd.setCursor(0,colonna);
       lcd.print(">");

       menuCorrente = colonna;
   } 
   else if (key=='*'){     //------------------------- BACK
        
   }
   else if (key=='#'){     //------------------------- ENTER

     Serial.print("menuCorrente: ");
     Serial.println(menu[colonna+2][1]);

     Serial.print("colonna: ");
     Serial.println(colonna);
    

     if (menu[menuCorrente][1] == colonna+2){
       lcd.clear();
     }
     
     
   }
 
   //Serial.print(menuCorrente);
   
 }

}

Il codice devi racchiuderlo nei tag code, vedi sezione 7 del regolamento, spiega bene come fare ( pulsante </> ).
Altrimenti parte del codice può essere visualizzata male o mancare perchè interpretato come attributo del testo stesso.

Per favore riedita il tuo post precedente e usa i tag code. Grazie

Ho fatto quanto richiesto. Ti ringrazio

Valerio

Quello che non dici è se il display è un 40x4 ? Ma si suppone.
Ora quale sarebbe il problema ?
Sulla presentazione del menu, devi giocare a posizionare un "puntatore" che indica quale opzione stai scegliendo. Magari il puntatore lo puoi anche costruire con i caratteri personalizzati.
Una volta che hai il vettore del punto di selezione gli associ una relativa matrice di funzioni, ma questo non te lo so dire per certo, oppure un indice che lo fai passare in un giro di switch/case

   selezione = colonna * riga;
   switch (selezione) {
        case 0:
           funzione0();
        break;
        case 1:
           funzione1();
        break;
        case 2:
           funzione2();
        break;
        case n:
           funzionen();
        break;
   }

Ciao

Il mio problema sta proprio nel comprendere la posizione del selettore, non tanto nel menù principale, dove è ovviamente semplice, ma nel momento in cui accedo alle sotto-sezioni.
Io l'ho costruito in questo modo:

ho creato una funzione che mostra il menù passando come parametro la posizione (0 per il principale e altr numeri per le posizioni più profonde) all'interno della quale ho una nuova funzione che si occupa di mostrare il selettore e delle sezioni dentro ciclo while infinito che spostano lo stesso a seconda di quale pulsante viene premuto.

//-----------------------------------------------------------------
//          mostraSelettore()
//-----------------------------------------------------------------

void mostraSelettore(int colonna){

int posizioneSelettore;
int x;
// il selettore sarà visualizzato nella riga del menù corrente
posizioneSelettore = colonna; 

lcd.setCursor(0,posizioneSelettore);
lcd.print(">");

//debug();

// loop infinito
while(x>=0){

  // legge il tasto premuto sul keypad
  char key = keypad.getKey();

  if (key=='A'){          //------------------------- UP

    lcd.setCursor(0,colonna);
      lcd.print(" ");
      colonna--;
      lcd.setCursor(0,colonna);
      lcd.print(">");

      menuCorrente = colonna;

  }  
  else if (key=='B'){     //------------------------- DOWN
      
      lcd.setCursor(0,colonna);
      lcd.print(" ");
      colonna++;
      lcd.setCursor(0,colonna);
      lcd.print(">");

      menuCorrente = colonna;
  } 
  else if (key=='*'){     //------------------------- BACK
       
  }
  else if (key=='#'){     //------------------------- ENTER

    Serial.print("menuCorrente: ");
    Serial.println(menu[colonna+2][1]);

    Serial.print("colonna: ");
    Serial.println(colonna);
   

    if (menu[menuCorrente][1] == colonna+2){
      lcd.clear();
    }
    
    
  }

  //Serial.print(menuCorrente);
  
}

}

Il mio problema è capire in quale posizione mi trovo e quindi associare e visualizzare la linea della matrice corrispondente.

Dal punto di vista logico non so se la scelta che ho fatto è quella giusta. Ho creato una matrice di stringhe strutturata in questo modo:

char* menu[2][6] = {
{"0","0","Setup","Leggi sensori","Attiva Irrigazione","Stop"  },
{"0","2","Selezione sensori","Set time","Set umidità min","Set umidità max"  },
};

La prima riga rappresenta il contenuto del primo menù, mentre la seconda contiene il sottomenù numero 1 (associato quindi alla prima selezione "Setup").

Non so se sono riuscito a spiegare il problema ... il mio dubbio è di stare percorrendo delle strade logiche contorte.

Poi ce ne sono altri, basta cercare arduino MenuBackend in youtube o una motoricerca.

Ti ringrazio per il link. lO sketch è per l'uso dei bottoni e io ho provato a modificarlo per adattarlo al keypad ma all'atto della compilazione ricevo questo errore:

Arduino:1.8.1 (Mac OS X), Scheda:"Arduino/Genuino Uno"

thelast:36: error: 'menuUsed' was not declared in this scope
 MenuBackend menu = MenuBackend(menuUsed,menuChanged);
                                ^
thelast:36: error: 'menuChanged' was not declared in this scope
 MenuBackend menu = MenuBackend(menuUsed,menuChanged);
                                         ^
In file included from /Volumes/Home/Arduino/thelast/thelast.ino:2:0:
/Users/netnull/Documents/Arduino/libraries/LiquidCrystal_I2C/LiquidCrystal_I2C.h: In function 'void setup()':
/Users/netnull/Documents/Arduino/libraries/LiquidCrystal_I2C/LiquidCrystal_I2C.h:154:9: error: 'int LiquidCrystal_I2C::init()' is private
    int  init();
         ^
thelast:60: error: within this context
   lcd.init();
            ^
exit status 1
'menuUsed' was not declared in this scope

Come suggerito ho modificato il file Menubackend.h e ho inserito quanto richiesto alla riga 195

Hai idea di cosa possa essere il problema?

Ho cercato in rete e ho provato ogni soluzione proposta ma continuo ad ottenere questo fastidioso errore

Arduino:1.8.1 (Mac OS X), Scheda:"Arduino/Genuino Uno"

thelast:36: error: 'menuUsed' was not declared in this scope
 MenuBackend menu = MenuBackend(menuUsed, menuChanged);
                                ^
thelast:36: error: 'menuChanged' was not declared in this scope
 MenuBackend menu = MenuBackend(menuUsed, menuChanged);
                                          ^
exit status 1
'menuUsed' was not declared in this scope

Questo report potrebbe essere più ricco di informazioni abilitando l'opzione
"Mostra un output dettagliato durante la compilazione"
in "File -> Impostazioni"

Pare che le due variabili, menuUsed, menuChanged, non sono state instanziate.
Allega lo sketch con le variazioni. Dove hai scaricato la libreria Menubackend.h, metti il link, per favore.

Risolto. A quanto pare la mia versione dell'IDE non funziona con quello sketch.
Ho risolto facendo un downgrade alla versione 1.6.5

Allora è probabile che sia la libreria anzianotta.