Doesn't stay in sub menu

So hello everyone. I'm creating simple menu with few sub menus,on my lcd screen. But i have run into small problem, i can't stay in my sub menu. When i press select button, it goes into submenu section and after maybe 1-2 sec it goes back to main menu.

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

LiquidCrystal_I2C lcd(0x27, 16, 2);

int upButton = 10;
int downButton = 11;
int selectButton = 12;
int menu = 1;

void setup() {
  lcd.begin();
  lcd.backlight();
  pinMode(upButton, INPUT_PULLUP);
  pinMode(downButton, INPUT_PULLUP);
  pinMode(selectButton, INPUT_PULLUP);
  updateMenu();
}

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

void updateMenu() {
  switch (menu) {
    case 0:
      menu = 1;
      break;
    case 1:
      lcd.clear();
      lcd.print(">MenuItem1");
      lcd.setCursor(0, 1);
      lcd.print(" MenuItem2");
      break;
    case 2:
      lcd.clear();
      lcd.print(" MenuItem1");
      lcd.setCursor(0, 1);
      lcd.print(">MenuItem2");
      break;
    case 3:
      lcd.clear();
      lcd.print(">MenuItem3");
      lcd.setCursor(0, 1);
      lcd.print(" MenuItem4");
      break;
    case 4:
      lcd.clear();
      lcd.print(" MenuItem3");
      lcd.setCursor(0, 1);
      lcd.print(">MenuItem4");
      break;
    case 5:
      menu = 4;
      break;
  }
}

void executeAction() {
  switch (menu) {
    case 1:
      action1();
      break;
    case 2:
      action2();
      break;
    case 3:
      action3();
      break;
    case 4:
      action4();
      break;
  }
}

void action1() {
  lcd.clear();
  lcd.print(">Executing #1");
  delay(1500);
}
void action2() {
  lcd.clear();
  lcd.print(">Executing #2");
  delay(1500);
}
void action3() {
  lcd.clear();
  lcd.print(">Executing #3");
  delay(1500);
}
void action4() {
  lcd.clear();
  lcd.print(">Executing #4");
  delay(1500);
}

Thanks in advanced

Hello,
your sketch do what you have coded :slight_smile:
You may better structure your sketch wrt IPO model.
Input: Buttons, including debouncing
Processing: FSM for LCD handling
Output: your desired functions

And avoid the usage of the delay() function. A homebrewed timer function will be the better way always.

1 Like

Hello
I modified your sketch and I think that was what you had in mind to achieve your design goal.
Please review it and don't hesitate if you have more questions.
A microLogic analyzer to see what happens inside I have not deleted.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
enum {Up, Down, Select};
const int UpButton {A0};
const int DownButton = {A1};
const int SelectButton = {A2};
int menu = 1;

struct BUTTON {
  byte pin;
  bool state;
  int click;
  unsigned long timeStamp;
  unsigned long duration;
} button[] {
  {UpButton, 1, 1, 0, 20},
  {DownButton, 1, 1, 0, 20},
  {SelectButton, 1, 1, 0, 20},
};

void debounce() {
  for (auto &make : button) {
    if (millis() - make.timeStamp >= make.duration) {
      make.timeStamp = millis();
      make.state = digitalRead(make.pin);
    }
  }
}
enum {Pressed, Released, Nothing};
int click (BUTTON &button) {
  if (button.click == button.state) return Nothing;
  button.click = button.state;
  return button.click;
}

void setup() {
  lcd.init(); // initialize the lcd
  lcd.backlight();
  lcd.setContrast(255);
  for (auto make : button) pinMode(make.pin, INPUT_PULLUP);
  updateMenu();
  Serial.begin(9600);
  Serial.println("und los geht´s");
}

void loop() {
  debounce();
  int buttonRead = click(button[Down]);
  if (buttonRead == Pressed) Serial.println("DownButton pressed");
  if (buttonRead == Pressed) {
    menu++;
    updateMenu();
  }
  buttonRead = click(button[Up]);
  if (buttonRead == Pressed) Serial.println("UpButton pressed");
  if (buttonRead == Pressed) {
    menu--;
    updateMenu();
  }
  buttonRead = click(button[Select]);
  if (buttonRead == Pressed) Serial.println("SelectButton pressed");
  if (buttonRead == Pressed) {
    static bool selectAction;
    if (!selectAction) executeAction();
    if (selectAction) updateMenu();
    selectAction = !selectAction;
  }
}
void updateMenu() {
  switch (menu) {
    case 0:
      menu = 1;
      break;
    case 1:
      lcd.clear();
      lcd.print(">MenuItem1");
      lcd.setCursor(0, 1);
      lcd.print(" MenuItem2");
      break;
    case 2:
      lcd.clear();
      lcd.print(" MenuItem1");
      lcd.setCursor(0, 1);
      lcd.print(">MenuItem2");
      break;
    case 3:
      lcd.clear();
      lcd.print(">MenuItem3");
      lcd.setCursor(0, 1);
      lcd.print(" MenuItem4");
      break;
    case 4:
      lcd.clear();
      lcd.print(" MenuItem3");
      lcd.setCursor(0, 1);
      lcd.print(">MenuItem4");
      break;
    case 5:
      menu = 4;
      break;
  }
}
void executeAction() {
  switch (menu) {
    case 1:
      action1();
      break;
    case 2:
      action2();
      break;
    case 3:
      action3();
      break;
    case 4:
      action4();
      break;
  }
}
void action1() {
  lcd.clear();
  lcd.print(">Executing #1");
}
void action2() {
  lcd.clear();
  lcd.print(">Executing #2");
}
void action3() {
  lcd.clear();
  lcd.print(">Executing #3");
}
void action4() {
  lcd.clear();
  lcd.print(">Executing #4");
}


1 Like

Ok, i have a lot of questions :smiley:
First, why are you using enum with buttons?
Second, why const int UpButton {A0}; is in {} brackets? I changed to 2,3,4 digital bin btw.
And last, button massive (button[] {
{UpButton, 1, 1, 0, 20},
{DownButton, 1, 1, 0, 20},
{SelectButton, 1, 1, 0, 20}) , why is used massive, in such i guess "simple task"?

Btw, amazing work, big thanks!

Hello
Here ny answers:
First, why are you using enum with buttons?
The enum´s are used give the name a number.
Up=0
Down=1
Select =2
Second, why const int UpButton {A0}; is in {} brackets?
This one way of many ways to inialize variables with values
And last, button massive (button {
The complete instruction is:

struct BUTTON {
  byte pin;
  bool state;
  int click;
  unsigned long timeStamp;
  unsigned long duration;
} button[] {
  {UpButton, 1, 1, 0, 20},
  {DownButton, 1, 1, 0, 20},
  {SelectButton, 1, 1, 0, 20},
};

I have make an object for the buttons containing all relevant information and data for an easy way to use within the sketch.

1 Like

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