2

Have been working on a Button Menu for a while now and can't break thru to the 3rd level, which in theory would give access to levels 4/5/6/etc. It's layed out long hand, I'll neaten the code up after its working. Could you pls have a look and see if you can access level 3.... Also if there is an alternative for multi level menus, happy to look at those also, just after something that works, have tried dozens that i have found on the web.....either no sketch with the video(how i hate that) or sketch just doesn't work period. Thanks in advance Doug

    /*
Description : Simple Menu function on LCD
          Button Function:
            Up/Down - change Menu Page
            Select - enter page
            Left - Exit

Link: http://youtu.be/cMqif5ICS5M

+++++++++++++++++++++++++++++++++++++++++++++++++++*/
*/ 
#include <LiquidCrystal_I2C.h> //from newliquidcrystal library
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

int keypad_pin = A0;
int keypad_value = 0;
int keypad_value_old = 0;

bool menu2 = false;
char btn_push;

int selection1 = 0;
int selection2 = 0;

int mainMenuPage = 1;
int mainMenuPageOld = 1;
int mainMenuTotal = 4;

int levelMenuPage = 1;
int levelMenuPageOld = 1;
int levelMenuTotal = 4;

void setup()
{
  Serial.begin(9600);
lcd.begin(20, 4);  //Initialize a 2x16 type LCD

MainMenuDisplay();
delay(1000);

}
void loop()
{
MainmenuBtn();

if((btn_push == 'S')&&(menu2 == false))//enter selected menu
{
  Serial.println("i'm here");
    WaitBtnRelease();
    switch (mainMenuPage)
    {
        case 1:
          MenuA();
          break;
        case 2:
          MenuB();
          break;
        case 3:
          MenuC();
          break;
        case 4:
          MenuD();
          break;
    }

      MainMenuDisplay();
      WaitBtnRelease();
  }
  else
{
   if((btn_push == 'S')&&(menu2 == true))//enter selected menu
{
  LevelmenuBtn();
    WaitBtnRelease();
    switch (levelMenuPage)
    {
        case 1:
          MenuA2();
          break;
        case 2:
          MenuB2();
          break;
        case 3:
          MenuC2();
          break;
        case 4:
          MenuD2();
          break;
    }

      LevelMenuDisplay();
      WaitBtnRelease();
  }


  delay(10);
} 
}
//--------------- End of loop() loop ---------------------
void MainmenuBtn()
{
  btn_push = ReadKeypad();
WaitBtnRelease();
if(btn_push == 'U')
{
    mainMenuPage++;
    if(mainMenuPage > mainMenuTotal)
      mainMenuPage = 1;
      Serial.println(mainMenuPage);
}
else if(btn_push == 'D')
{
    mainMenuPage--;
    Serial.print(mainMenuPage);
    if(mainMenuPage == 0)
      mainMenuPage = mainMenuTotal; 
      Serial.println(mainMenuPage);   
}

if(mainMenuPage != mainMenuPageOld) //only update display when page change
{
    MainMenuDisplay();
    mainMenuPageOld = mainMenuPage;
}
}
void LevelmenuBtn()
{
  btn_push = ReadKeypad();
WaitBtnRelease();
if(btn_push == 'U')
{
    mainMenuPage++;
    if(levelMenuPage > levelMenuTotal)
      levelMenuPage = 1;
      Serial.println(levelMenuPage);
}
else if(btn_push == 'D')
{
    levelMenuPage--;
    Serial.print(levelMenuPage);
    if(levelMenuPage == 0)
      levelMenuPage = levelMenuTotal; 
      Serial.println(levelMenuPage);   
}

if(levelMenuPage != levelMenuPageOld) //only update display when page change
{
    LevelMenuDisplay();
    levelMenuPageOld = levelMenuPage;
}
}
void MainMenuDisplay()
{
lcd.clear();
lcd.setCursor(0,0);
switch (mainMenuPage)
{
    case 1:
      lcd.print("1. Menu A");
      break;
    case 2:
      lcd.print("2. Menu B");
      break;
    case 3:
      lcd.print("3. Menu C");
      break;
    case 4:
      lcd.print("4. Menu D");
      break;
}
}
void LevelMenuDisplay()
{
lcd.clear();
lcd.setCursor(0,0);
switch (levelMenuPage)
{
    case 1:
      lcd.print("1. Menu A2");
      break;
    case 2:
      lcd.print("2. Menu B2");
      break;
    case 3:
      lcd.print("3. Menu C2");
      break;
    case 4:
      lcd.print("4. Menu D2");
      break;
}
}
void MenuA()
{  
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Inside Menu A");
 menu2 = true;
while(ReadKeypad()!= 'N')
{
    //Insert Task for Menu A here
 selection1=1;
 Serial.print("Selection1=");
 Serial.println(selection1);  
}
}
void MenuA2()
{  
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Inside Menu A2");
menu2 = false;
while(ReadKeypad()!= 'N')
{
    //Insert Task for Menu A here
 selection2=1;
 Serial.print("Selection2=");
 Serial.println(selection2);  
}
}
void MenuB()
{  
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Inside Menu B");
menu2 = true;
while(ReadKeypad()!= 'N')
{
    //Insert Task for Menu B here

 selection1=2;
 Serial.print("Selection1=");
 Serial.println(selection1);    
}
}
void MenuB2()
{  
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Inside Menu B2");
menu2 = false;
while(ReadKeypad()!= 'N')
{
    //Insert Task for Menu B here
 selection2=2;
 Serial.print("Selection2=");
 Serial.println(selection2);   
}
}
void MenuC()
{  
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Inside Menu C");
menu2 = true;
while(ReadKeypad()!= 'N')
{
    //Insert Task for Menu C here
 selection1=3;
 Serial.print("Selection1=");
 Serial.println(selection1);    
}
}
void MenuC2()
{  
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Inside Menu C2");
menu2 = false;
while(ReadKeypad()!= 'N')
{
    //Insert Task for Menu C here
 selection2=3;
 Serial.print("Selection2=");
 Serial.println(selection2);        
}
}
void MenuD()
{  
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Inside Menu D");
menu2 = true;
while(ReadKeypad()!= 'N')
{
    //Insert Task for Menu D here
 selection1=4;
 Serial.print("Selection1=");
 Serial.println(selection1);  
}
}
void MenuD2()
{  
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Inside Menu D2");
menu2 = false;
while(ReadKeypad()!= 'N')
{
    //Insert Task for Menu D here
 selection2=4;
 Serial.print("Selection2=");
 Serial.println(selection2);        
}
} 

char ReadKeypad()
{
/* Keypad button analog Value
no button pressed 1023
nul     <450
select  <400
left    <350
down    <290
up      <190
right   <50
*/
keypad_value = analogRead(keypad_pin);

if(keypad_value < 50)
return 'R';
else if(keypad_value < 190)
return 'U';
else if(keypad_value < 290)
return 'D';
else if(keypad_value < 350)
return 'L';
else if(keypad_value < 400)
return 'S';
else if(keypad_value < 450)
return 'N';

}

void WaitBtnRelease()
{
  while( analogRead(keypad_pin) < 600){}
}
4
  • Doug, please give us the setup. Are there just 3 buttons with BUTTON1 selecting the MAINMENU and BUTTON2 scrolling UP the menu selected by BUTTON1 and BUTTON3 scrolling DOWN the menu selected by BUTTON1. And by pressing again BUTTON1,the selection is SET - as in the layout below: BUTTON1 selects CURRENT from selections like VOLTAGE, CURRENT, AMPHR. BUTTON2 selects UPWARDS 100mA, 300mA, 500mA, 750mA, 1000mA BUTTON3 selects DOWNWARDS 100mA, 300mA, 500mA, 750mA, 1000mA Finally, PRESSING BUTTON1 fixes on the selection made by either BUTTON2 OR BUTTON3. We need to know how many buttons there are an
    – joporjeppe
    Commented Dec 26, 2017 at 23:39
  • please give us the setup. Are there just 3 buttons with BUTTON1 selecting the MAINMENU and BUTTON2 scrolling UP the menu selected by BUTTON1 and BUTTON3 scrolling DOWN the menu selected by BUTTON1. And by pressing again BUTTON1,the selection is SET - as in the layout below: BUTTON1 selects CURRENT from selections like VOLTAGE, CURRENT, AMPHR. BUTTON2 selects UPWARDS 100mA, 300mA, 500mA, 750mA, 1000mA BUTTON3 selects DOWNWARDS 100mA, 300mA, 500mA, 750mA, 1000mA Finally, PRESSING BUTTON1 fixes on the selection made by either BUTTON2 OR BUTTON3.
    – sa_leinad
    Commented Dec 27, 2017 at 7:17
  • We need to know how many buttons there are and what each button do, and which button FIXES the selection made. Thanks, George
    – sa_leinad
    Commented Dec 27, 2017 at 7:17
  • Look to this section of the code " ****read buttons*** " and you will see that I have listed the buttons used and their purpose..I have included the 6th button NULL to indicate that you can have more buttons than I have actually used (5) if required. Please read and study the code and comments as all the info you need is their. The final code is listed below and has the header containing "/* Rebuilt by Doug 07/02/2017 Australia." This is tested and works
    – Doug
    Commented Dec 29, 2017 at 22:20

1 Answer 1

3

Ok...nobody bought into this and I understand why...menus have been done to death, but not being one to quite I have answered my own question. Here is a simple, fool proof button menu, that i think has NO limit in depth. I have just tested this before posting, so if you don't get it to work, check your wiring. instructions at the bottom of the sketch.

    /* Rebuilt by Doug 07/02/2017 Australia.
 * This is a bare bones menu using buttons to navigate and select, there are no special libraries, 
 * I am using an I2C LCD2004, but any display will work with minor mods. This has been translated from, 
 * I believe Slovakian, that was fun, stripped down and modified for button control, I have found that 
 * buttons are less picky than rotary encoders, even the good ones, just my experience.
 * I believe that I have removed all unnecessary script, but I may have missed some.
 * look at the last 2 --page()-- sections for instruction on extending down even further, I don't think 
 * that there is a limit to how many levels you can have, how many do you really need.
 * The original sketch is from: Stanislav Petrek of Slovakia, you can find sketch on YouTube comments.
 * https://www.youtube.com/watch?v=gIP29m12wjQ&t=41s
 * Have fun with the translation  ;-}
 * The last thing I did before posting was to relaod and test this sketch, so it works.      
 */
#include <LiquidCrystal_I2C.h> //from newliquidcrystal library
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

// menu system
int poz = 0; //  cursor position on actual page
int poz_max = 1;
int poz_min = 0;

int pozOld = 0;
int pozNew = 0;

int page = 0; //  actual page
int page_max = 1;
int page_min = 0;

int press = 0;
int press_max = 1;

int keypad_pin = A0;                      //analoge A0 to sense button values.
int keypad_value = 0;
int keypad_value_old = 0;

//bool menu2 = false;
char btn_push;
//****************************************************************setup*****************************************
void setup() {
Serial.begin(9600);
lcd.begin(20, 4);
lcd.clear();
lcd.home();
}
//************************************************************loop************************************************
void loop() {
MainmenuBtn();
if (btn_push == 'S') //enter selected menu
{
press++;
delay(250);
if (press > press_max) {
  press = 0;
}
}
// page select
switch (page) {

case 0:
  page0();
  break;
case 1:
  page1();
  break;
case 2:
  page2();
  break;
case 3:
  page3();
  break;
case 4:
  page4();
  break;
case 5:
  page5();
  break;
}
}
//****************************************************up/down************************************************
void MainmenuBtn()
{
btn_push = ReadKeypad();
WaitBtnRelease();
if (btn_push == 'U')
{
poz++;
if (poz > poz_max) {
  poz = poz_max;
}
}
else if (btn_push == 'D')
{
poz--;
if (poz < poz_min) {
  poz = poz_min;
}
}
pozNew = poz;
if (pozNew != pozOld) { //only update display when page change
pozOld = pozNew;
}
}
//*************************************************************read buttons***********************************
char ReadKeypad()
{
/* Keypad button analog Value
no button pressed 1023
*********************adjust these values to suit your keypad***********************
nul     >400
select  <400
left    <350
down    <290
up      <190
right   <50
*/
keypad_value = analogRead(keypad_pin);
if (keypad_value < 50)
return 'R';
else if (keypad_value < 190)
return 'D';
else if (keypad_value < 290)
return 'U';
else if (keypad_value < 350)
return 'L';
else if (keypad_value < 400)
return 'S';
else if (keypad_value > 400)
return 'N';
}
//********************************************************button release*************************************
void WaitBtnRelease()
{
while ( analogRead(keypad_pin) < 600) {}
}
//*******************************************************Front Page 0*******************************************
void page0() {
poz_min = 0;
poz_max = 3;
press_max = 1;

lcd.setCursor(0, 0);
lcd.print("Pg1 Pg2 Pg3 Pg4     ");
lcd.setCursor(0, 2);
lcd.print("                    ");
lcd.setCursor(0, 3);
lcd.print("                    ");

switch (poz)
{
case 0:
  lcd.setCursor(0, 1);
  lcd.print("---                 ");
  if (press == 1) {
    press = 0;
    poz = 0;
    page = 1;
  }
  break;
case 1:
  lcd.setCursor(0, 1);
  lcd.print("    ---             ");
  if (press == 1) {
    press = 0;
    poz = 0;
    page = 2;
  }
  break;
case 2:
  lcd.setCursor(0, 1);
  lcd.print("        ---         ");
  if (press == 1) {
    press = 0;
    poz = 0;
    page = 3;
  }
  break;
case 3:
  lcd.setCursor(0, 1);
  lcd.print("            ---     ");
  if (press == 1) {
    press = 0;
    poz = 0;
    page = 4;
  }
  break;
}
}
//*************************************************Pages 1*****************************************
void page1() {
poz_min = 0;
poz_max = 2;
press_max = 1;

lcd.setCursor(0, 0);
lcd.print("Page1               ");
lcd.setCursor(0, 1);
switch (poz) {

case 0:
  lcd.print("Page1 Case0         ");
  if (press == 1) {
    press = 0;
  }
  break;
case 1:
  lcd.print("Page1 Case1         ");
  if (press == 1) {
    press = 0;
  }
  break;

case 2:
  lcd.print("Page1 Case2    exit ");
  if (press == 1) {
    press = 0;
    page = 0;
    poz = 0;
  }
  break;
}
}
//*************************************************Pages 2*****************************************
void page2() {
poz_min = 0;
poz_max = 2;
press_max = 1;

lcd.setCursor(0, 0);
lcd.print("Page2               ");
lcd.setCursor(0, 1);
switch (poz) {

case 0:
  lcd.print("Page2 Case0         ");
  if (press == 1) {
    press = 0;
  }
  break;
case 1:
  lcd.print("Page2 Case1         ");
  if (press == 1) {
    press = 0;
  }
  break;

case 2:
  lcd.print("Page2 Case2  exit   ");
  if (press == 1) {
    press = 0;
    page = 0;
    poz = 1;
  }
  break;
}
}
//*************************************************Pages 3*****************************************
void page3() {
poz_min = 0;
poz_max = 2;
press_max = 1;
lcd.setCursor(0, 0);
lcd.print("Page3               ");

switch (poz)
{
case 0:
  lcd.setCursor(0, 1);
  lcd.print("Page3 Case0         ");
  if (press == 1) {
    lcd.setCursor(0, 1);
    lcd.print("                    ");
    //navi();
  }
  break;

case 1:
  lcd.setCursor(0, 1);
  lcd.print("Page3 Case1         ");
  if (press == 1) {
    press = 0;
  }
  break;

case 2:
  lcd.setCursor(0, 1);
  lcd.print("Page3 Case2  exit   ");
  if (press == 1) {
    press = 0;
    page = 0;
    poz = 2;
  }
  break;
}
}
//*************************************************Pages 4*****************************************
void page4() {
poz_min = 0;
poz_max = 1;
press_max = 1;

lcd.setCursor(0, 0);
lcd.print("Page4               ");
lcd.setCursor(0, 1);
switch (poz) {

case 0:
  lcd.print("Page4 Case0  branch ");
  if (press == 1) {
    press = 0;
    page = 5;                                   //branches to page5() menu
    poz = 0;                                    //at position 0 on button 'S' press
    break;

  case 1:
    lcd.setCursor(0, 1);
    lcd.print("Page4 Case1  exit   ");
    if (press == 1) {
      press = 0;
      page = 0;
      poz = 3;
    }
    break;
  }
  }
}
//*************************************************Pages 5*****************************************
void page5() {
poz_min = 0;                      //see void MainmenuBtn()
poz_max = 1;                      //see void MainmenuBtn()
press_max = 1;                    //used when you have multiple selection within a section-increase number
                                  //see  original script for example
lcd.setCursor(0, 0);
lcd.print("Page5               ");
lcd.setCursor(0, 1);
switch (poz) {

case 0:
  lcd.print("Page5 Case0         ");
  break;

case 1:
  lcd.setCursor(0, 1);
  lcd.print("Page5 Case1  exit   ");
  if (press == 1) {                 //variable set to '1' when the 'S' key is pressed
    press = 0;
    page = 4;                         //this is the page() that you return to after the 'S' button is pressed
    poz = 1;                          //this is the 'case' number that you will return to for that page
  }
  break;
}
}

I have only inserted print statements where operational code can be placed, to keep it universally open. To reduce the size of the Global variables use the >>lcd.print(F("TEXT"));<< method, it works really well. Also works on Serial.print....Something for you to fiddle with.

8
  • I think that the reason why nobody tried this is that you did a huge work on your first example, so maybe someone (I admit, me too) postponed this because they had too few time at the moment. Anyway good job at actually writing a working version and thumbs up for your attitude. If your own answer successfully answers your question, mark it as accepted (when you can) so that everybody coming here will know that your code works
    – frarugi87
    Commented Feb 7, 2017 at 13:22
  • Thanks Mate...will do, but how do I mark as accepted???, never done it before.
    – Doug
    Commented Feb 7, 2017 at 21:53
  • What do you know, there is a HELP page up top...I have to wait 48 hours to accept... ;-) Update--have just about finished making a Menu with this and it is quite smooth once I got the hang of it..several levels deep. There actually is no practical limit to the depth. pleasantly surprised.
    – Doug
    Commented Feb 8, 2017 at 9:20
  • yes, you have to wait (that's to prevent some people from abusing this function to quickly gain reputation, I think). But.. Well, this is a perfectly legit case: you asked, nobody answered, you found a solution and shared it... Thank you for your effort :)
    – frarugi87
    Commented Feb 8, 2017 at 10:54
  • I am pretty new to all this but I cannot find a simple answer in your code. What pin numbers on the Arduino do I use to attach each button to? I am using standard everyday push buttons and a breadboard for this project. A0 is not enough for it to work. There has to be more to it. What am I missing?
    – Deve
    Commented Aug 4, 2017 at 16:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.