LCD Menu system with encoder

Hi, I am trying to create a menu system using a RepRapDiscount Smart Controller and the Arduino MEGA 2560.

My problem is that the menu items are automatically scrolled/cycled through on the screen (line 4) and a temporary selection is stored (line 2). I would like to be able to scroll through the menu items with the encoder (lines 1-4). select an item by pressing the encoder, and then scrolling through the subitems and selecting one with another press of the encoder.

Here is my code: starting with defined global variables:

#include <MenuBackend.h>    //MenuBackend library - copyright by Alexander Brevig
#include <LiquidCrystal.h>

const int buttonPinLeft = 31;      // pin for the Up button
const int buttonPinRight = 33;    // pin for the Down button
const int buttonPinEsc = 41;     // pin for the Esc button
const int buttonPinEnter = 35;   // pin for the Enter button

int lastButtonPushed = 0;

int lastButtonEnterState = LOW;
int lastButtonEscState = LOW;
int lastButtonLeftState = LOW;
int lastButtonRightState = LOW;


long lastEnterDebounceTime = 0;
long lastEscDebounceTime = 0;
long debounceDelay = 500;

int buttonRightState = 0;
int buttonLeftState = 0;

int ENCODER_PULSES_PER_STEP = 4;

int lastEncoded = 0;
long encoderValue = 0; //keeps track of absolute position of encoder
int encoderPosition;

LiquidCrystal lcd(16, 17, 23, 25, 27, 29);

//Menu variables
MenuBackend menu = MenuBackend(menuUsed,menuChanged);
//initialize menuitems
    MenuItem menu1Item1 = MenuItem("Item1");
      MenuItem menuItem1SubItem1 = MenuItem("Item1SubItem1");
      MenuItem menuItem1SubItem2 = MenuItem("Item1SubItem2");
      
    MenuItem menu1Item2 = MenuItem("Item2");
      MenuItem menuItem2SubItem1 = MenuItem("Item2SubItem1");
      MenuItem menuItem2SubItem2 = MenuItem("Item2SubItem2");
      MenuItem menuItem2SubItem3 = MenuItem("Item2SubItem3");
      
    MenuItem menu1Item3 = MenuItem("Item3");

HERE IS VOID SETUP()

void setup()
{
  
  Serial.begin(9600);
  pinMode(buttonPinLeft, INPUT);
  pinMode(buttonPinRight, INPUT);
  pinMode(buttonPinEnter, INPUT);
  pinMode(buttonPinEsc, INPUT);
  digitalWrite(buttonPinEnter, LOW);
  digitalWrite(buttonPinEsc, HIGH);
  digitalWrite(buttonPinLeft, HIGH);
  digitalWrite(buttonPinRight, HIGH);
  
  lcd.begin(20, 4);
  //Serial.print("in setup");
  //configure menu
  menuSetup();
 // menu.toRoot();
  lcd.setCursor(0,0);
  lcd.print("Mosaic Manufacturing");

}

AND VOID LOOP:

void loop()
{
  Serial.println(lastButtonPushed);
  readButtons();
  navigateMenus();
}

HERE I SETUP THE MENU

void menuSetup()
{
     Serial.println("Setting up menu...");
   //add the file menu to the menu root
   menu.getRoot().add(menu1Item1);
   //setup the settings menu item
        menu1Item1.addRight(menu1Item2).addRight(menu1Item3);
        menu1Item1.add(menuItem1SubItem1).addRight(menuItem1SubItem2);
        menu1Item2.add(menuItem2SubItem1).addRight(menuItem2SubItem2).addRight(menuItem2SubItem3);
      }

MENUCHANGED SUBFUNCTION:

void menuChanged(MenuChangeEvent changed){
  
  MenuItem newMenuItem=changed.to; //get the destination menu
  
  lcd.setCursor(0,3); //set the start position for lcd printing to the second row
  
  if(newMenuItem.getName()==menu.getRoot()){
      lcd.print("Main Menu       ");
  }else if(newMenuItem.getName()=="Item1"){
      lcd.print("Item1           ");
  }else if(newMenuItem.getName()=="Item1SubItem1"){
      lcd.print("Item1SubItem1");
  }else if(newMenuItem.getName()=="Item1SubItem2"){
      lcd.print("Item1SubItem2   ");
  }else if(newMenuItem.getName()=="Item2"){
      lcd.print("Item2           ");
  }else if(newMenuItem.getName()=="Item2SubItem1"){
      lcd.print("Item2SubItem1   ");
  }else if(newMenuItem.getName()=="Item2SubItem2"){
      lcd.print("Item2SubItem2   ");
  }else if(newMenuItem.getName()=="Item2SubItem3"){
      lcd.print("Item2SubItem3   ");
  }else if(newMenuItem.getName()=="Item3"){
      lcd.print("Item3           ");
  }
}

MENUUSED SUBFUNCTION:

void menuUsed(MenuUseEvent used){
  lcd.setCursor(0,0);
  lcd.print("You used        ");
  lcd.setCursor(0,1);
  lcd.print(used.item.getName());
  //delay(1000);  //delay to allow message reading
  lcd.setCursor(0,0);
  lcd.print("Mosaic Manufacturing");
  menu.toRoot();  //back to Main
}

CODE TO READ BUTTONS:

void  readButtons(){  //read buttons status
  int reading;
  int buttonEnterState=HIGH;             // the current reading from the Enter input pin
  int buttonEscState=HIGH;
  int buttonLeftState=HIGH;
  int buttonRightState=HIGH;

  //Enter button
                  // read the state of the switch into a local variable:
                  reading = digitalRead(buttonPinEnter);
                  // check to see if you just pressed the enter button
                
                  // If the switch changed
                  if (reading != lastButtonEnterState) {
                    // reset the debouncing timer
                    lastEnterDebounceTime = millis();
                  }
                  
                  if ((millis() - lastEnterDebounceTime) > debounceDelay) {
                    // whatever the reading is at, take it as the actual current state:
                    buttonEnterState=reading;
                    lastEnterDebounceTime=millis();
                  }
                  
                  // save the reading. 
                  lastButtonEnterState = reading;
                  

    //Esc button
                  // state of the switch into a local variable:
                  reading = digitalRead(buttonPinEsc);

                  // check to see if you just pressed the Down button
                
                  // If the switch changed, due to noise or pressing:
                  if (reading != lastButtonEscState) {
                    // reset the debouncing timer
                    lastEscDebounceTime = millis();
                  }
                  
                  if ((millis() - lastEscDebounceTime) > debounceDelay) {
                    // whatever the reading is at, it's been there for longer
                    // than the debounce delay, so take it as the actual current state:
                    buttonEscState = reading;
                    lastEscDebounceTime=millis();
                  }
                  
                  // save the reading.  Next time through the loop,
                  // it'll be the lastButtonState:
                  lastButtonEscState = reading;
                  
  //Update encoder wheel
                  buttonRightState = HIGH;
                  buttonLeftState = HIGH;
                  
                  updateEncoder();
                     
                  if (abs(encoderValue) >= ENCODER_PULSES_PER_STEP)
                  {
                    encoderPosition = encoderValue / ENCODER_PULSES_PER_STEP;
                    encoderValue = 0;
                    if (encoderPosition == 1){
                      buttonRightState = LOW;
                    }
                    if (encoderPosition == -1){
                      buttonLeftState = LOW;
                    }
                  }
                     
   //Down button
                  lastButtonRightState = buttonRightState;
                  
    //Up button
                  lastButtonLeftState = buttonLeftState;

                  //records which button has been pressed
                  if (buttonEnterState==LOW){
                    lastButtonPushed=buttonPinEnter;

                  }else if(buttonEscState==LOW){
                    lastButtonPushed=buttonPinEsc;

                  }else if(buttonRightState==LOW){
                    lastButtonPushed=buttonPinRight;

                  }else if(buttonLeftState==LOW){
                    lastButtonPushed=buttonPinLeft;

                  }else{
                    lastButtonPushed=0;
                  }
}

I believe the encoder code is working correctly, it's the menu system that has an error. I want the items to show up on the screen to be able to scroll through them and select by pressing the encoder button. Right now the items are being cycled through on line 4 and it stores an item on line 2.

Also, here are two other subfunctions to navigate menus & update the encoder

CODE TO NAVIGATE MENUS:

void navigateMenus() {
  MenuItem currentMenu=menu.getCurrent();
  
  switch (lastButtonPushed){
    case buttonPinEnter:
      if(!(currentMenu.moveDown())){  //if the current menu has a child and has been pressed enter then menu navigate to item below
        menu.use();
      }else{  //otherwise, if menu has no child and has been pressed enter the current menu is used
        menu.moveDown();
       }
      break;
    case buttonPinEsc:
      menu.toRoot();  //back to main
      break;
    case buttonPinRight:
      menu.moveRight();
      break;
    case buttonPinLeft:
      menu.moveLeft();
      break;
  }
  
  lastButtonPushed=0; //reset the lastButtonPushed variable
}

AND TO UPDATE THE ENCODER:

void updateEncoder(){
  
  int MSB = digitalRead(buttonPinLeft); //MSB = most significant bit
  int LSB = digitalRead(buttonPinRight); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) {
    encoderValue ++; //clockwise
    //buttonRightState = HIGH;
    //buttonLeftState = LOW;
  }
  
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) {
    encoderValue --; //cclockwise
    //buttonRightState = HIGH;
    //buttonLeftState = LOW;
  }
  
  
  lastEncoded = encoded; //store this value for next time
}

You can post ALL of your code as an attachment. I'm not going to bother trying to sew that mess back together, and a lot of other people aren't either.

If you said something about the specific problem you are having, I missed it.

Roger

The problem I am having is that the menu items are being cycled through automatically on the LCD screen (line 4).

I want to make it so that turning the encoder scrolls through the menu items, and pressing the encoder goes into the menu's subitems.

The problem I am having is that the menu items are being cycled through automatically

What is causing the menu items to cycle? Why can't you change the displayed menu only when the encoder value changes?

and pressing the encoder goes into the menu's subitems.

So, what is the problem?