Issue with switch statement/program

I am trying to make a menu system that displays items to a 20,4 I2C LCD from a array at the top, then use a switch statement tied to the button input to forward to the next page.

#include <Wire.h> // Allows communications over I2c
#include <LiquidCrystal_I2C.h> //from newliquidcrystal library
LiquidCrystal_I2C lcd(0x27, 20, 4);  // Set the LCD I2C address

//Input & Button Logic
const int numOfInputs = 4;
const int inputPins[numOfInputs] = { 2,3,4,5 };
int inputState[numOfInputs];
int lastInputState[numOfInputs] = { LOW,LOW,LOW,LOW };
bool inputFlags[numOfInputs] = { LOW,LOW,LOW,LOW };
long lastDebounceTime[numOfInputs] = { 0,0,0,0 };
long debounceDelay = 5;

//LCD Menu Logic
byte downArrow[8] = {
  0b00100, //   *
  0b00100, //   *
  0b00100, //   *
  0b00100, //   *
  0b00100, //   *
  0b10101, // * * *
  0b01110, //  ***
  0b00100  //   *
};

byte upArrow[8] = {
  0b00100, //   *
  0b01110, //  ***
  0b10101, // * * *
  0b00100, //   *
  0b00100, //   *
  0b00100, //   *
  0b00100, //   *
  0b00100  //   *
};

byte menuCursor[8] = {
  B01000, //  *
  B00100, //   *
  B00010, //    *
  B00001, //     *
  B00010, //    *
  B00100, //   *
  B01000, //  *
  B00000  //
};

int menuPage = 0;
int maxMenuPages = 5;
const int numOfScreens = 5;
int currentScreen = 0;
String screens[numOfScreens] = { "Display","Temperature","Relays","Fans","Timer" };

void setup() {
	for (int i = 0; i < numOfInputs; i++) {
		pinMode(inputPins[i], INPUT);
		digitalWrite(inputPins[i], HIGH); // pull-up 20k
	}
	//Serial.begin(9600);
	lcd.begin(20, 4);
	lcd.init();
	lcd.backlight();
	lcd.createChar(0, menuCursor);
	lcd.createChar(1, upArrow);
	lcd.createChar(2, downArrow);
}

void loop() {
	setInputFlags();
	resolveInputFlags();
	drawCursor();
}

void setInputFlags() {
	for (int i = 0; i < numOfInputs; i++) {
		int reading = digitalRead(inputPins[i]);
		if (reading != lastInputState[i]) {
			lastDebounceTime[i] = millis();
		}
		if ((millis() - lastDebounceTime[i]) > debounceDelay) {
			if (reading != inputState[i]) {
				inputState[i] = reading;
				if (inputState[i] == HIGH) {
					inputFlags[i] = HIGH;
				}
			}
		}
		lastInputState[i] = reading;
	}
}

void printScreen() {
	lcd.clear();
	lcd.setCursor(1, 0);
	lcd.print(screens[0]);
	lcd.setCursor(1, 1);
	lcd.print(screens[1]);
	lcd.setCursor(1, 2);
	lcd.print(screens[2]);
	lcd.setCursor(1, 3);
	lcd.print(screens[3]);
	if (menuPage == 0) {
		lcd.setCursor(19, 0);
		lcd.write(byte(2));
	}
	else if (menuPage > 0 and menuPage < maxMenuPages) {
		lcd.setCursor(19, 0);
		lcd.write(byte(2));
		lcd.setCursor(19, 3);
		lcd.write(byte(1));
	}
	else if (menuPage == maxMenuPages) {
		lcd.setCursor(15, 0);
		lcd.write(byte(1));
	}
}

void resolveInputFlags() {
	for (int i = 0; i < numOfInputs; i++) {
		if (inputFlags[i] == HIGH) {
			inputAction(i);
			inputFlags[i] = LOW;
			printScreen();
		}
	}
}

void menuItem1() { // Function executes when you select the Yellow item from main menu
	int activeButton = 0;

	lcd.clear();
	lcd.setCursor(3, 0);
	lcd.print("Yellow On");

	while (activeButton == 0) {
		switch (int(inputAction)) {
		case 4:  // This case will execute if the "back" button is pressed
			activeButton = 1;
			break;
		}
	}
}

void menuItem2() { // Function executes when you select the Green item from main menu
	int activeButton = 0;

	lcd.clear();
	lcd.setCursor(3, 0);
	lcd.print("Green On");

	while (activeButton == 0) {
		switch (int(inputAction)) {
		case 4:  // This case will execute if the "back" button is pressed
			activeButton = 1;
			break;
		}
	}
}

void menuItem3() { // Function executes when you select the Red item from main menu
	int activeButton = 0;

	lcd.clear();
	lcd.setCursor(3, 0);
	lcd.print("Red On");

	while (activeButton == 0) {
		switch (int(inputAction)) {
		case 4:  // This case will execute if the "back" button is pressed
			activeButton = 1;
			break;
		}
	}
}

void menuItem4() { // Function executes when you select the Purple item from main menu
	int activeButton = 0;

	lcd.clear();
	lcd.setCursor(3, 0);
	lcd.print("Purple On");

	while (activeButton == 0) {
		switch (int(inputAction)) {
		case 4:  // This case will execute if the "back" button is pressed
			activeButton = 1;
			break;
		}
	}
}

void drawCursor() {
	for (int x = 0; x < 3; x++) {     // Erases current cursor
		lcd.setCursor(0, x);
		lcd.print(" ");
	}

	if (menuPage == 0) {

		lcd.setCursor(0, 0);
		lcd.write(byte(0));
	}
	else if (menuPage == 1) {  // If the menu page is 0 and the cursor position is 1 that means the cursor should be on line 2
		lcd.setCursor(0, 1);
		lcd.write(byte(0));
	}
	else if (menuPage == 2) {  // If the menu page is 0 and the cursor position is 2 that means the cursor should be on line 3
		lcd.setCursor(0, 2);
		lcd.write(byte(0));
	}
	else {  // If the menu page is 0 and the cursor position is 3 that means the cursor should be on line 4
		lcd.setCursor(0, 3);
		lcd.write(byte(0));
	}
}

void inputAction(int input) {
	int activeButton = 0;
	while (activeButton == 0) {
		switch (int(input)) {
		case 0: // When button returns as 0 there is no action taken
			break;
		case 1:  // This case will execute if the "forward" button is pressed
			input = 0;
			switch (int(input)) { // The case that is selected here is dependent on which menu page you are on and where the cursor is.
			case 0:
				menuItem1();
				break;
			case 1:
				menuItem2();
				break;
			case 2:
				menuItem3();
				break;
			case 3:
				menuItem4();
				break;
			}
			activeButton = 1;
			drawCursor();
			break;
		case 2:
			input = 0;
			if (menuPage = 0) {
				menuPage--;
			}
			if (menuPage = 1) {
				menuPage--;
				menuPage = 0;
			}
			menuPage--;
			menuPage = 0;
			drawCursor();
			activeButton = 1;
			break;
		case 3:
			input = 0;
			if (menuPage = 0) {
				menuPage++;
				menuPage = 0;
			}

			if (menuPage = 1) {
				menuPage++;
				menuPage = 0;
			}

			menuPage++;
			drawCursor();
			activeButton = 1;
			break;
		}
	}
}

Only 2 of the 4 buttons work, I can only move the cursor position down 1 position or the other button that works just refers to one of case4 and just displays “Yellow On”

This has only gotten me pretty upset so far unfortunately

Any help if anyone out there is knowledgeable in switch statements I will be super thankful.

// You can have up to 10 menu items in the menuItems[] array below without having to change the base programming at all. Name them however you'd like. Beyond 10 items, you will have to add additional "cases" in the switch/case
// section of the operateMainMenu() function below. You will also have to add additional void functions (i.e. menuItem11, menuItem12, etc.) to the program.
String menuItems[] = { "Yellow", "Green", "Red", "Purple" };

// Navigation button variables
int readKey;
int savedDistance = 0;

// Menu control variables
int menuPage = 0;
int maxMenuPages = round(((sizeof(menuItems) / sizeof(String)) / 2) + .5);
int cursorPosition = 0;

// Creates 3 custom characters for the menu display
byte downArrow[8] = {
  0b00100, //   *
  0b00100, //   *
  0b00100, //   *
  0b00100, //   *
  0b00100, //   *
  0b10101, // * * *
  0b01110, //  ***
  0b00100  //   *
};

byte upArrow[8] = {
  0b00100, //   *
  0b01110, //  ***
  0b10101, // * * *
  0b00100, //   *
  0b00100, //   *
  0b00100, //   *
  0b00100, //   *
  0b00100  //   *
};

byte menuCursor[8] = {
  B01000, //  *
  B00100, //   *
  B00010, //    *
  B00001, //     *
  B00010, //    *
  B00100, //   *
  B01000, //  *
  B00000  //
};

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

// Setting the LCD shields pins
LiquidCrystal_I2C lcd(0x27, 20, 4);

void setup() {

  // Initializes serial communication
  Serial.begin(9600);

  // Initializes and clears the LCD screen
  lcd.begin(20, 4);
  lcd.init();
  lcd.backlight();
  lcd.clear();

  // Creates the byte for the 3 custom characters
  lcd.createChar(0, menuCursor);
  lcd.createChar(1, upArrow);
  lcd.createChar(2, downArrow);

}

void loop() {
  mainMenuDraw();
  drawCursor();
  inputAction();
}

// This function will generate the 2 menu items that can fit on the screen. They will change as you scroll through your menu. Up and down arrows will indicate your current menu position.
void mainMenuDraw() {
  Serial.print(menuPage);
  lcd.clear();
  lcd.setCursor(1, 0);
  lcd.print(menuItems[menuPage]);
  lcd.setCursor(1, 1);
  lcd.print(menuItems[menuPage + 1]);
  lcd.setCursor(1, 2);
  lcd.print(menuItems[menuPage + 2]);
  lcd.setCursor(1, 3);
  lcd.print(menuItems[menuPage + 3]);
  if (menuPage == 0) {
    lcd.setCursor(19, 3);
    lcd.write(byte(2));
  }
  else if (menuPage > 0 and menuPage < maxMenuPages) {
    lcd.setCursor(19, 3);
    lcd.write(byte(2));
    lcd.setCursor(19, 0);
    lcd.write(byte(1));
  }
  else if (menuPage == maxMenuPages) {
    lcd.setCursor(19, 0);
    lcd.write(byte(1));
  }
}

// When called, this function will erase the current cursor and redraw it based on the cursorPosition and menuPage variables.
void drawCursor() {
  for (int x = 0; x < 4; x++) {     // Erases current cursor
    lcd.setCursor(0, x);
    lcd.print(" ");
  }

  // The menu is set up to be progressive (menuPage 0 = Item 1 & Item 2, menuPage 1 = Item 2 & Item 3, menuPage 2 = Item 3 & Item 4), so
  // in order to determine where the cursor should be you need to see if you are at an odd or even menu page and an odd or even cursor position.
  if (menuPage == 0) {
    if (cursorPosition == 0) {  // If the menu page is even and the cursor position is even that means the cursor should be on line 1
      lcd.setCursor(0, 0);
      lcd.write(byte(0));
    }
    if (cursorPosition == 1) {  // If the menu page is even and the cursor position is odd that means the cursor should be on line 2
      lcd.setCursor(0, 1);
      lcd.write(byte(0));
    }
    if (cursorPosition == 2) {  // If the menu page is even and the cursor position is odd that means the cursor should be on line 2
      lcd.setCursor(0, 2);
      lcd.write(byte(0));
    }
    if (cursorPosition == 3) {  // If the menu page is even and the cursor position is odd that means the cursor should be on line 2
      lcd.setCursor(0, 3);
      lcd.write(byte(0));
    }
  }
  if (menuPage == 1) {
    if (cursorPosition == 0) {  // If the menu page is odd and the cursor position is even that means the cursor should be on line 2
      lcd.setCursor(0, 1);
      lcd.write(byte(0));
    }
    if (cursorPosition == 1) {  // If the menu page is odd and the cursor position is odd that means the cursor should be on line 1
      lcd.setCursor(0, 2);
      lcd.write(byte(0));
    }
    if (cursorPosition == 2) {  // If the menu page is odd and the cursor position is odd that means the cursor should be on line 1
      lcd.setCursor(0, 3);
      lcd.write(byte(0));
    }
    if (cursorPosition == 3) {  // If the menu page is odd and the cursor position is odd that means the cursor should be on line 1
      lcd.setCursor(0, 4);
      lcd.write(byte(0));
    }
  }
}

void inputAction() {
  int activeButton = 0;
  while (activeButton == 0) {
    int input;
    switch (input) {
    case 0: // When button returns as 0 there is no action taken
      break;
    case 1:  // This case will execute if the "forward" button is pressed
      input = 0;
      switch (cursorPosition) { // The case that is selected here is dependent on which menu page you are on and where the cursor is.
      case 0:
        menuItem1();
        break;
      case 1:
        menuItem2();
        break;
      case 2:
        menuItem3();
        break;
      case 3:
        menuItem4();
        break;

      }
      activeButton = 1;
      mainMenuDraw();
      drawCursor();
      break;
    case 2:
      input = 0;
      if (menuPage == 0) {
        cursorPosition = cursorPosition - 1;
        cursorPosition = constrain(cursorPosition, 0, ((sizeof(menuItems) / sizeof(String)) - 1));
      }
      if (menuPage % 2 == 0 and cursorPosition % 2 == 0) {
        menuPage = menuPage - 1;
        menuPage = constrain(menuPage, 0, maxMenuPages);
      }

      if (menuPage % 2 != 0 and cursorPosition % 2 != 0) {
        menuPage = menuPage - 1;
        menuPage = constrain(menuPage, 0, maxMenuPages);
      }

      cursorPosition = cursorPosition - 1;
      cursorPosition = constrain(cursorPosition, 0, ((sizeof(menuItems) / sizeof(String)) - 1));

      mainMenuDraw();
      drawCursor();
      activeButton = 1;
      break;
    case 3:
      input = 0;
      if (menuPage % 2 == 0 and cursorPosition % 2 != 0) {
        menuPage = menuPage + 1;
        menuPage = constrain(menuPage, 0, maxMenuPages);
      }

      if (menuPage % 2 != 0 and cursorPosition % 2 == 0) {
        menuPage = menuPage + 1;
        menuPage = constrain(menuPage, 0, maxMenuPages);
      }

      cursorPosition = cursorPosition + 1;
      cursorPosition = constrain(cursorPosition, 0, ((sizeof(menuItems) / sizeof(String)) - 1));
      mainMenuDraw();
      drawCursor();
      activeButton = 1;
      break;
    }
  }
}

void drawInstructions() {
  lcd.setCursor(0, 1); // Set cursor to the bottom line
  lcd.print("Use ");
  lcd.write(byte(1)); // Up arrow
  lcd.print("/");
  lcd.write(byte(2)); // Down arrow
  lcd.print(" buttons");
}

void menuItem1() { // Function executes when you select the Yellow item from main menu
  int activeButton = 0;

  lcd.clear();
  lcd.setCursor(3, 0);
  lcd.print("Yellow On");

  digitalWrite(13, HIGH);

  while (activeButton == 0) {
    int input;
    switch (input) {
    case 4:  // This case will execute if the "back" button is pressed
      input = 0;
      activeButton = 1;
      digitalWrite(13, LOW);
      break;
    }
  }
}

void menuItem2() { // Function executes when you select the Green item from main menu
  int activeButton = 0;

  lcd.clear();
  lcd.setCursor(3, 0);
  lcd.print("Green On");

  digitalWrite(12, HIGH);

  while (activeButton == 0) {
    int input;
    switch (input) {
    case 4:  // This case will execute if the "back" button is pressed
      input = 0;
      activeButton = 1;
      digitalWrite(12, LOW);
      break;
    }
  }
}

void menuItem3() { // Function executes when you select the Red item from main menu
  int activeButton = 0;

  lcd.clear();
  lcd.setCursor(3, 0);
  lcd.print("Red On");

  digitalWrite(11, HIGH);

  while (activeButton == 0) {
    int input;
    switch (input) {
    case 4:  // This case will execute if the "back" button is pressed
      input = 0;
      activeButton = 1;
      digitalWrite(11, LOW);
      break;
    }
  }
}

void menuItem4() { // Function executes when you select the Purple item from main menu
  int activeButton = 0;

  lcd.clear();
  lcd.setCursor(3, 0);
  lcd.print("Purple On");

  digitalWrite(3, HIGH);

  while (activeButton == 0) {
    int input;
    switch (input) {
    case 4:  // This case will execute if the "back" button is pressed
      input = 0;
      activeButton = 1;
      digitalWrite(3, LOW);
      break;
    }
  }
}

Ok this one displays the menu, but the buttons do nothing

Only read your first sketch,which seems quite complex.
Here:switch (int(inputAction))
inputAction is a function that requires a parameter, maybe that's your problem

lesept:
Only read your first sketch,which seems quite complex.
Here:switch (int(inputAction))
inputAction is a function that requires a parameter, maybe that's your problem

It's a combo of 2 menu examples; 1 menu example had efficient code and the other... the cursors, and switch statement.

-Cursor,switch statement

-Efficient code

switch (int (inputAction))
is being use in all switch statements, I can't use input from the first switch in the others due to the other switches being out of scope of the function / input not defined.

I super appreciate the reply, I will edit it right now and test.

Replacing the first 2 switch statement references from input to int(inputAction)
the menu is now blank but does print the menuCursor

I'm going to try to edit menuItem1,2,3,4 to menuItem1,2,3,4(int(input)) so I can have "input" as the reference in all switch statements and "input" is defined to menuItem1,2,3,4

I’m out of ideas, im back to the first sketch outcome, can only move down once or case1 executes and the screen says “Yellow On”

If I delete input = 0 inside case 1:

Instead of Yellow on, screen print’s “Green On”

int button = digitalRead(inputPins[3]);
switch (button) {

The problem seems to be the switch statement, I tried filling the brackets with 0,1,2,3. 1,2,3,4 5,4,3,2.
Different number arrangements effect the init menu.

it seems only with switch(input) the menu gets printed, just need the cursor to go all the way down and up + the switch statement to function properly

Can you explain what this is expected to do:

.
.
.
        switch (int(input)) 
        {
        case 0: // When button returns as 0 there is no action taken
            break;
            
        case 1:  // This case will execute if the "forward" button is pressed
            input = 0;
            switch (int(input)) { // The case that is selected here is dependent on which menu page you are on and where the cursor is.
            case 0:
                menuItem1();
                break;
            case 1:
                menuItem2();
                break;
            case 2:
                menuItem3();
                break;
.
.
.

Suppose "input" is 1 so the outer switch selects "case 1"; you then set input to 0 and immediately perform a switch on it. How would anything other than case 0 ever execute?

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

LiquidCrystal_I2C lcd(0x27, 20, 4);

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

void setup() {
  lcd.begin(20,4);
  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");
      lcd.setCursor(0, 2);
      lcd.print(" MenuItem3");
      lcd.setCursor(0, 3);
      lcd.print(" MenuItem4");
      break;
    case 2:
      lcd.clear();
      lcd.print(" MenuItem1");
      lcd.setCursor(0, 1);
      lcd.print(">MenuItem2");
      lcd.setCursor(0, 2);
      lcd.print(" MenuItem3");
      lcd.setCursor(0, 3);
      lcd.print(" MenuItem4");
      break;
    case 3:
      lcd.clear();
      lcd.print(" MenuItem1");
      lcd.setCursor(0, 1);
      lcd.print(" MenuItem2");
      lcd.setCursor(0, 2);
      lcd.print(">MenuItem3");
      lcd.setCursor(0, 3);
      lcd.print(" MenuItem4");
      break;
    case 4:
      lcd.clear();
      lcd.print(" MenuItem1");
      lcd.setCursor(0, 1);
      lcd.print(" MenuItem2");
      lcd.setCursor(0, 2);
      lcd.print(" MenuItem3");
      lcd.setCursor(0, 3);
      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);
}

I just need to edit the button pins, but I found another example and modified it. Should do exactly what I wanted the previous to do, but MUCH LESS complicated!

Blackfin:
Can you explain what this is expected to do:

.

.
.
        switch (int(input))
        {
        case 0: // When button returns as 0 there is no action taken
            break;
           
        case 1:  // This case will execute if the "forward" button is pressed
            input = 0;
            switch (int(input)) { // The case that is selected here is dependent on which menu page you are on and where the cursor is.
            case 0:
                menuItem1();
                break;
            case 1:
                menuItem2();
                break;
            case 2:
                menuItem3();
                break;
.
.
.




Suppose "input" is 1 so the outer switch selects "case 1"; you then set input to 0 and immediately perform a switch on it. How would anything other than case 0 ever execute?

You are correct, it seems input inside the case should not be equal to what it is, it really confused me which led me to find something I can put together in my head, should do exactly what I want after I test it, and it is much easier to understand.

I only wanted case 1 to execute if 1 of the 4 buttons was pressed, not just anyone, so you could go up and down the menu, when happy with whats currently selected hit the button that makes case1 execute, and then refer to that void.

Still a problem unfortunately!

I just dont get this.

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

LiquidCrystal_I2C lcd(0x27, 20, 4);

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

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

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

void updateMenu() {
  switch (menu) {
  case 0:
    menu = 1;
    break;
  case 1:
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(">MenuItem1");
    lcd.setCursor(0, 1);
    lcd.print(" MenuItem2");
    lcd.setCursor(0, 2);
    lcd.print(" MenuItem3");
    lcd.setCursor(0, 3);
    lcd.print(" MenuItem4");
    break;
  case 2:
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(" MenuItem1");
    lcd.setCursor(0, 1);
    lcd.print(">MenuItem2");
    lcd.setCursor(0, 2);
    lcd.print(" MenuItem3");
    lcd.setCursor(0, 3);
    lcd.print(" MenuItem4");
    break;
  case 3:
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(" MenuItem1");
    lcd.setCursor(0, 1);
    lcd.print(" MenuItem2");
    lcd.setCursor(0, 2);
    lcd.print(">MenuItem3");
    lcd.setCursor(0, 3);
    lcd.print(" MenuItem4");
    break;
  case 4:
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(" MenuItem1");
    lcd.setCursor(0, 1);
    lcd.print(" MenuItem2");
    lcd.setCursor(0, 2);
    lcd.print(" MenuItem3");
    lcd.setCursor(0, 3);
    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);
}

I’m sticking to this code, due to its simplicity. My problem is local to the loop statement.

If I swap downButton, menu-- for upButton menu++ the menu will automatically go down or stay at the top but only the selectButton works at the moment.

keyboardcowboy:
If I swap downButton, menu-- for upButton menu++ the menu will automatically go down or stay at the top but only the selectButton works at the moment.

You’re looking at the *current state *of the buttons. So, whendownButton is pressed the statements inside theifcurly braces will execute on *every scan * of the program. If you alter the button business so that you only act one time when the button state *goes *low things should get better. Check out IDE → file/examples/digital/state change detection & debounce.

Does this slightly different approach yield anything (compiles, not tested):

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

LiquidCrystal_I2C lcd(0x27, 20, 4);

char *pszMenuItems[] = 
{
    "MenuItem1",
    "MenuItem2",
    "MenuItem3",
    "MenuItem4"
};

void action1( void );
void action2( void );
void action3( void );
void action4( void );

typedef void (*myFunc)();
myFunc Functions[4] = 
{
    &action1,
    &action2,
    &action3,
    &action4
};

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

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

void loop() 
{
    static unsigned long
        timeButtonRead = 0;
    static byte
        lastupButton = 0xff,
        lastselButton = 0xff,
        lastdownButton = 0xff;
    byte
        currButton;
    unsigned long
        timeNow;

    //check buttons every 75mS
    timeNow = millis();
    if( timeNow - timeButtonRead < 75 )
        return;
    timeButtonRead = timeNow;

    //read the button...
    currButton = digitalRead(downButton);
    //...if it's state is not the same as last...
    if( currButton != lastdownButton )
    {
        //...save the new state
        lastdownButton = currButton;
        //if it's low indicating it has been pressed...
        if( currButton == LOW )
        {
            //process action; in this case, if menu is greater than 1...
            if( menu > 1 )
            {
                //...decrement it
                menu--;
                //and update the menu
                updateMenu();
                
            }//if
                
        }//if

    }//if

    //same comments for downbutton apply for up and select
    currButton = digitalRead(upButton);
    if( currButton != lastupButton )
    {
        lastupButton = currButton;
        if( currButton == LOW )
        {
            if( menu < 4 )
            {
                menu++;
                updateMenu();
                
            }//if
                
        }//if

    }//if

    currButton = digitalRead(selectButton);
    if( currButton != lastselButton )
    {
        lastselButton = currButton;
        if( currButton == LOW )
        {
            //call the function pointed to by menu in the Functions[] array
            Functions[menu]();
            //when it returns, update the menu
            updateMenu();
                
        }//if

    }//if

}//loop

void updateMenu() 
{
    for( int i=0; i<4; i++ )
    {
        lcd.clear();
        lcd.setCursor(0, i);
        //if menu line is selected, print a '>', otherwise a space
        if( i == (menu-1) )
            lcd.print( ">" );
        else
            lcd.print( " " );

        //print the text of the line item
        lcd.print( pszMenuItems[i] );
        
    }//for
        
}//updateMenu

void action1() 
{
    lcd.clear();
    lcd.print(">Executing #1");
    delay(1500);
}//action1

void action2() 
{
    lcd.clear();
    lcd.print(">Executing #2");
    delay(1500);
}//action2

void action3() 
{
    lcd.clear();
    lcd.print(">Executing #3");
    delay(1500);
}//action3

void action4() 
{
    lcd.clear();
    lcd.print(">Executing #4");
    delay(1500);
}//action4

Blackfin:
Does this slightly different approach yield anything (compiles, not tested):

#include <Wire.h>

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 20, 4);

char *pszMenuItems =
{
    “MenuItem1”,
    “MenuItem2”,
    “MenuItem3”,
    “MenuItem4”
};

void action1( void );
void action2( void );
void action3( void );
void action4( void );

typedef void (*myFunc)();
myFunc Functions[4] =
{
    &action1,
    &action2,
    &action3,
    &action4
};

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

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

void loop()
{
    static unsigned long
        timeButtonRead = 0;
    static byte
        lastupButton = 0xff,
        lastselButton = 0xff,
        lastdownButton = 0xff;
    byte
        currButton;
    unsigned long
        timeNow;

//check buttons every 75mS
    timeNow = millis();
    if( timeNow - timeButtonRead < 75 )
        return;
    timeButtonRead = timeNow;

//read the button…
    currButton = digitalRead(downButton);
    //…if it’s state is not the same as last…
    if( currButton != lastdownButton )
    {
        //…save the new state
        lastdownButton = currButton;
        //if it’s low indicating it has been pressed…
        if( currButton == LOW )
        {
            //process action; in this case, if menu is greater than 1…
            if( menu > 1 )
            {
                //…decrement it
                menu–;
                //and update the menu
                updateMenu();
               
            }//if
               
        }//if

}//if

//same comments for downbutton apply for up and select
    currButton = digitalRead(upButton);
    if( currButton != lastupButton )
    {
        lastupButton = currButton;
        if( currButton == LOW )
        {
            if( menu < 4 )
            {
                menu++;
                updateMenu();
               
            }//if
               
        }//if

}//if

currButton = digitalRead(selectButton);
    if( currButton != lastselButton )
    {
        lastselButton = currButton;
        if( currButton == LOW )
        {
            //call the function pointed to by menu in the Functions array
            Functionsmenu;
            //when it returns, update the menu
            updateMenu();
               
        }//if

}//if

}//loop

void updateMenu()
{
    for( int i=0; i<4; i++ )
    {
        lcd.clear();
        lcd.setCursor(0, i);
        //if menu line is selected, print a ‘>’, otherwise a space
        if( i == (menu-1) )
            lcd.print( “>” );
        else
            lcd.print( " " );

//print the text of the line item
        lcd.print( pszMenuItems[i] );
       
    }//for
       
}//updateMenu

void action1()
{
    lcd.clear();
    lcd.print(">Executing #1");
    delay(1500);
}//action1

void action2()
{
    lcd.clear();
    lcd.print(">Executing #2");
    delay(1500);
}//action2

void action3()
{
    lcd.clear();
    lcd.print(">Executing #3");
    delay(1500);
}//action3

void action4()
{
    lcd.clear();
    lcd.print(">Executing #4");
    delay(1500);
}//action4

First screen printed is executing #2 on line 0,0
Next, line 0,3 menuItem4

Only the button on pin 12 changes whats printed on line 0,3 printing executing#2 on line 0,0

Thank you very much trying to help!

Added some debug messages to the serial console, saw some goofy stuff. Try this:

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

LiquidCrystal_I2C lcd(0x27, 20, 4);

char *pszMenuItems[] = 
{
    "MenuItem1",
    "MenuItem2",
    "MenuItem3",
    "MenuItem4"
};

void action1( void );
void action2( void );
void action3( void );
void action4( void );

typedef void (*myFunc)();
myFunc Functions[4] = 
{
    &action1,
    &action2,
    &action3,
    &action4
};

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

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

void loop() 
{
    static unsigned long
        timeButtonRead = 0;
    static byte
        lastupButton = 0xff,
        lastselButton = 0xff,
        lastdownButton = 0xff;
    byte
        currButton;
    unsigned long
        timeNow;

    //check buttons every 75mS
    timeNow = millis();
    if( timeNow - timeButtonRead < 75 )
        return;
    timeButtonRead = timeNow;

    //read the button...
    currButton = digitalRead(downButton);
    //...if it's state is not the same as last...
    if( currButton != lastdownButton )
    {
        //...save the new state
        lastdownButton = currButton;
        //if it's low indicating it has been pressed...
        if( currButton == LOW )
        {
            //process action; in this case, if menu is greater than 1...
            if( menu > 1 )
            {
                //...decrement it                
                menu--;
                //and update the menu
                updateMenu();
                
            }//if
                
        }//if

    }//if

    //same comments for downbutton apply for up and select
    currButton = digitalRead(upButton);
    if( currButton != lastupButton )
    {
        lastupButton = currButton;
        if( currButton == LOW )
        {
            if( menu < 4 )
            {
                menu++;
                updateMenu();
                
            }//if
                
        }//if

    }//if

    currButton = digitalRead(selectButton);
    if( currButton != lastselButton )
    {
        lastselButton = currButton;
        if( currButton == LOW )
        {
            //call the function pointed to by menu in the Functions[] array
            Functions[menu-1]();
            //when it returns, update the menu
            updateMenu();
                
        }//if

    }//if

}//loop

void updateMenu() 
{
    lcd.clear();
    Serial.print( "\n\n\n\n" );
    for( int i=0; i<4; i++ )
    {
        lcd.setCursor(0, i);
        //if menu line is selected, print a '>', otherwise a space
        if( i == (menu-1) )
        {
            Serial.print( ">" );
            lcd.print( ">" );
        }
        else
        {
            Serial.print( " " );    
            lcd.print( " " );
            
        }//else
        
        //print the text of the line item
        Serial.println( pszMenuItems[i] );    
        lcd.print( pszMenuItems[i] );
        
    }//for
        
}//updateMenu

void action1() 
{
    lcd.clear();
    lcd.print(">Executing #1");
    Serial.println(">Executing #1");
    delay(1500);
}//action1

void action2() 
{
    lcd.clear();
    lcd.print(">Executing #2");
    Serial.println(">Executing #2");    
    delay(1500);
}//action2

void action3() 
{
    lcd.clear();
    lcd.print(">Executing #3");
    Serial.println(">Executing #3");    
    delay(1500);
}//action3

void action4() 
{
    lcd.clear();
    lcd.print(">Executing #4");
    Serial.println(">Executing #4");    
    delay(1500);
}//action4

Heres a I guess what you guys would call a fritzing pic of my buttons

Trying it right now BlackFin I really greatly appreciate your help and would love to be able to help you out with something in return.

If I understood it better I really wouldn't be trying to clutter this forum up with my posts, but am really appreciative of any assistance provided so I can do my best to learn this language.

Ooo so I make sure to pay very close attention to the screen as it uploads, first thing readable was on...
line 0,0- Executing #1
after which, the menu is printed.
The only button that works is at pin 12
which produce's the output of "Executing #1"

This is weird right?
I tried switching the input in pinmode to and from input_pullup while trying either HIGH or LOW inside the loop.
Also tried setting menu to different values inside case.

Should I maybe try to put the loop code in its own void and calling that in loop?

I do need to verify each button is working so im going to switch the pins/wiring between buttons to verify they each work and one isn't weird.

Change your switch wiring: connect one side of the switch to the Arduino pin. Connect the other side to GND so that when the switch is pressed the Arduino pin is grounded. You won't need any external pullups since the pinmodes are declared as INPUT_PULLUP.

keyboardcowboy:
Ooo so I make sure to pay very close attention to the screen as it uploads, first thing readable was on…
line 0,0- Executing #1
after which, the menu is printed.
The only button that works is at pin 12
which produce’s the output of “Executing #1

This is weird right?
I tried switching the input in pinmode to and from input_pullup while trying either HIGH or LOW inside the loop.
Also tried setting menu to different values inside case.

Should I maybe try to put the loop code in its own void and calling that in loop?

I do need to verify each button is working so im going to switch the pins/wiring between buttons to verify they each work and one isn’t weird.

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

LiquidCrystal_I2C lcd(0x27, 20, 4);

char *pszMenuItems[] =
{
    "MenuItem1",
    "MenuItem2",
    "MenuItem3",
    "MenuItem4"
};

void action1( void );
void action2( void );
void action3( void );
void action4( void );

typedef void (*myFunc)();
myFunc Functions[4] =
{
    &action1,
    &action2,
    &action3,
    &action4
};

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

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

void loop()
{
    static unsigned long
        timeButtonRead = 0;
    static byte
        lastupButton = 0xff,
        lastselButton = 0xff,
        lastdownButton = 0xff;
    byte
        currButton;
    unsigned long
        timeNow;

    //check buttons every 75mS
    timeNow = millis();
    if( timeNow - timeButtonRead < 75 )
        return;
    timeButtonRead = timeNow;

    //read the button...
    currButton = digitalRead(downButton);
    //...if it's state is not the same as last...
    if( currButton != lastdownButton )
    {
        //...save the new state
        lastdownButton = currButton;
        //if it's low indicating it has been pressed...
        if( currButton == LOW )
        {
            //process action; in this case, if menu is greater than 1...
            if( menu > 1 )
            {
                //...decrement it               
                menu--;
                //and update the menu
                updateMenu();
               
            }//if
               
        }//if

    }//if

    //same comments for downbutton apply for up and select
    currButton = digitalRead(upButton);
    if( currButton != lastupButton )
    {
        lastupButton = currButton;
        if( currButton == LOW )
        {
            if( menu < 4 )
            {
                menu++;
                updateMenu();
               
            }//if
               
        }//if

    }//if

    currButton = digitalRead(selectButton);
    if( currButton != lastselButton )
    {
        lastselButton = currButton;
        if( currButton == LOW )
        {
            //call the function pointed to by menu in the Functions[] array
            Functions[menu-1]();
            //when it returns, update the menu
            updateMenu();
               
        }//if

    }//if

}//loop

void updateMenu()
{
    lcd.clear();
    Serial.print( "\n\n\n\n" );
    for( int i=0; i<4; i++ )
    {
        lcd.setCursor(0, i);
        //if menu line is selected, print a '>', otherwise a space
        if( i == (menu-1) )
        {
            Serial.print( ">" );
            lcd.print( ">" );
        }
        else
        {
            Serial.print( " " );   
            lcd.print( " " );
           
        }//else
       
        //print the text of the line item
        Serial.println( pszMenuItems[i] );   
        lcd.print( pszMenuItems[i] );
       
    }//for
       
}//updateMenu

void action1()
{
    lcd.clear();
    lcd.print(">Executing #1");
    Serial.println(">Executing #1");
    delay(1500);
}//action1

void action2()
{
    lcd.clear();
    lcd.print(">Executing #2");
    Serial.println(">Executing #2");   
    delay(1500);
}//action2

void action3()
{
    lcd.clear();
    lcd.print(">Executing #3");
    Serial.println(">Executing #3");   
    delay(1500);
}//action3

void action4()
{
    lcd.clear();
    lcd.print(">Executing #4");
    Serial.println(">Executing #4");   
    delay(1500);
}//action4

It works, I had a f’d up button. I was really running out of ideas.
The initial output is Executing #2 then it prints menu with the cursor at menuItem2.

Last night I added a 4th button to my board as a test reference just in case it was a faulty button.

So this is solved, I had previously made a screen that prints out sensor info and would like those outputs to each be in there own menu and with the switch statement void’s that should be easy.

My desire is to learn the language while making something useful for someone else or myself, and it just had me confused after I really thought I had it.

Last thing I wanted to do was sign up on a forum and possibly get thrown further off track in my learning. I am really appreciative I took the risk, I thought it’d just sit around and people would be like well I understand it so you should and not offer any insight on the matter, when I am trying to learn.

This interactive programming makes me greater interested in learning as opposed to Python, it’s easier for me to view what I want and have better direction at figuring out as opposed to learning just the language.

Now I just want to read through the code and see the differences and where I overlooked so I can progress. Just hope to somehow return the favor of assistance to you, w/o you i’d be going hard at this and maybe confusing myself more.