Trouble with switch case execution

Hello. I'm working on a temperature controller program. I'm playing around with menus and trying to find a good and clear way to handle my menus. I had something that worked but I wanted to try doing it with switch cases to hopefully make it easier for me to think about and program.

I'm missing something about how I have the switch case set up. I have an enum for the menu pages and I'm testing those and using the logic to then advance through the menu pages based on a cursor position that is increased or decreased with buttons. An enter button advances the menu page.

If I have just the first switch case ROOT, all my options appear to work. When I add the next case GLYCOL_T, the code seems to go there even when currMainPage is still at 0. It looks like it's evaluating the switch inside the GLYCOL_T case and locking my cursor between 1 and 3. I'm really not sure what I'm missing.

Thanks for the help. My code is below. I have a custom button library that works fine. I'm including it as well if it's needed.

#include <Arduino.h>
#include <LiquidCrystal_I2C.h> // Library for LCD
#include <Button.h>

// Project defines


// Project structures
struct tempCtrl{
  const String label; // Temperature control label
  float tempF; // Measured temperature (F)
  float tempF_SP; // Temperature setpoint (F)
  u_int8_t hyst; // Hysteresis for temperature control (F)
  boolean heatEnbl; // Enable heating control
  boolean coolEnbl; // Enable cooling control
  u_int8_t heatDelay; // Heating control cycle delay (min)
  u_int8_t coolDelay; // Cooling control cycle delay (min)
  u_int8_t switchDelay; // Heating/Cooling switchover delay (min)
};

LiquidCrystal_I2C lcd(0x27, 20, 4); // I2C address 0x27, 20 columns and 4 rows

// Configure input button pins
const byte BTN_ENTER = 25;
const byte BTN_INC = 26;
const byte BTN_DEC = 27;

// Menu constants and variables
const String menuLabel[4] = {"(0)Temperatures:", "(1)Temp SP Config", "(2)Temp Hyst Config", "(3)Temp Delay Config"};
const String posLabel[3] = {"Glycl", "Ferm1", "Ferm2"};
float tempValue[3] = {49.2, 66.7, 68.3};
float tempSP[3] = {50, 68, 68};
float hyst[3] = {5, 1, 1};
float delaySP[3] = {10, 1, 1};
const u_int16_t buttonEnterDelay = 2000;
const u_int16_t menuTimeOutDelay = 20000;
u_int8_t menuPos = 0; // Initialize menu position
u_int8_t menuCursorPos = 0; // Initialize menu position
boolean updateDisplay = true; // Update the display

// Temperature control variables

tempCtrl glycol, ferm1, ferm2;

// Menu structure
enum menuPage {
  ROOT, // Root menu
  GLYCOL_T, // Glycol temperature menu
  GLYCOL_C, // Glycol cooling menu
  GLYCOL_H, // Glycol heating menu
  FERM1_T, // Fermenter 1 temperature menu
  FERM1_C, // Fermenter 1 cooling menu
  FERM1_H, // Fermenter 1 heating menu
  FERM2_T, // Fermenter 1 temperature menu
  FERM2_C, // Fermenter 1 cooling menu
  FERM2_H // Fermenter 1 heating menu
};
enum menuPage currMainPage = ROOT; // Initialize menuPos to the root menu

enum menuCursor {
  POS_0, // Position 0
  POS_1, // Position 1
  POS_2, // Position 2
  POS_3 // Position 3
};
enum menuCursor cursorPos = POS_0;

// Function forward declarations

Button btnEnter(BTN_ENTER, buttonEnterDelay);
Button btnInc(BTN_INC, buttonEnterDelay);
Button btnDec(BTN_DEC, buttonEnterDelay);

void menuNavigation();

void setup() {
  Serial.begin(115200);     // Initialize serial

  btnEnter.Begin();
  btnInc.Begin();
  btnDec.Begin();
  
  lcd.init();               // Initialize LCD
  lcd.backlight();          // Turn on LCD backlight
  lcd.clear();              // Clear LCD

 
}

void loop() {
   
  btnEnter.Pressed(); // Read enter button
  btnInc.Pressed(); // Read increase button
  btnDec.Pressed(); // Read decrease button

  menuNavigation(); // Menu navigation



  
  //if (updateDisplay) {lcd.clear();}
  lcd.setCursor(0,0);
  lcd.print(currMainPage);
  lcd.setCursor(0,1);
  lcd.print(menuCursorPos);
  //lcd.setCursor(0,2);
  //lcd.print(btnDec.btnState, HEX);
  //lcd.setCursor(0,3);
  //lcd.print(btnEnter.longPress);

  updateDisplay = false;

    
 
}

void menuNavigation(){
  static u_int8_t menuUnit = 0; // Menu unit (0-3)



  // Increase/Decrease button scrolling through sub menu positions and roll around when at ends
  if (btnInc.shortPress | btnInc.longPress) {
    if (menuCursorPos == 3) {menuCursorPos = 1;}
    else {menuCursorPos++;}
    updateDisplay = true;
  }
  if (btnDec.shortPress | btnDec.longPress) {
    if (menuCursorPos <= 1) {menuCursorPos = 3;}
    else {menuCursorPos--;}
    updateDisplay = true;
  }
  


  switch (currMainPage) {
    case ROOT:
      switch (menuCursorPos) {
        case 0:
          break;
        case 1:
          if (btnEnter.shortPress) {currMainPage = GLYCOL_T; menuCursorPos = 1;}
          if (btnEnter.longPress) {/* change SP */}
          break;
        case 2:
          if (btnEnter.shortPress) {currMainPage = FERM1_T; menuCursorPos = 1;}
          if (btnEnter.longPress) {/* change SP */}
          break;
        case 3:
          if (btnEnter.shortPress) {currMainPage = FERM2_T; menuCursorPos = 1;}
          if (btnEnter.longPress) {/* change SP */}
          break;   
      }

    case GLYCOL_T:
      if (btnEnter.shortPress) {currMainPage = GLYCOL_C; menuCursorPos = 1;}
      switch (menuCursorPos) {
        case 0: menuCursorPos = 3; break;
        case 1: if (btnEnter.longPress) {/* change SP */} break;
        case 2: if (btnEnter.longPress) {/* change SP */} break;
        case 3: if (btnEnter.longPress) {/* change SP */} break;
        case 4: menuCursorPos = 1; break;  
      } 

    
  }
  
  
  /*
  // Set cursor position enumerations
  switch (menuCursorPos) {
    case 0: cursorPos = POS_0; break;
    case 1: cursorPos = POS_1; break;
    case 2: cursorPos = POS_2; break;
    case 3: cursorPos = POS_3; break;
    default: cursorPos = POS_0; break;
  }
  
  // Scroll through main menu positions and roll around when at end

  if (cursorPos != POS_0 && btnEnter.shortPress) {
    if (menuPos == 0) {menuUnit = menuCursorPos;}
    menuPos++;
    if (menuPos == 4) {menuPos = 0; menuCursorPos = 0; menuUnit = 0;}
    updateDisplay = true;
  }
  */
  /*
    (M)	      (CP)	  (M)   	(CP)		  (M)	    (CP)	    (M)   	(CP)
    (0)ROOT-POS_0	    (0)ROOT-POS_1	  	(0)ROOT-POS_2		  (0)ROOT-POS_3

		                  (1)GLYCOL_T-POS_1	(1)FERM1_T-POS_1	(1)FERM2_T-POS_1

		                  (2)GLYCOL_C-POS_1	(2)FERM1_C-POS_1	(2)FERM2_C-POS_1

		                  (3)GLYCOL_H-POS_1	(3)FERM1_H-POS_1	(3)FERM2_H-POS_1
  */

  // Set menu page enumerations
  /*
  switch (menuUnit) {
    case 0: currMainPage = ROOT; break;
    case 1:
      switch (menuPos) {
        case 0: currMainPage = ROOT; break;
        case 1: currMainPage = GLYCOL_T; break;
        case 2: currMainPage = GLYCOL_C; break;
        case 3: currMainPage = GLYCOL_H; break;
      }
      break;
    case 2:
      switch (menuPos) {
        case 0: currMainPage = ROOT; break;
        case 1: currMainPage = FERM1_T; break;
        case 2: currMainPage = FERM1_C; break;
        case 3: currMainPage = FERM1_H; break;
      }
      break;
      case 3:
      switch (menuPos) {
        case 0: currMainPage = ROOT; break;
        case 1: currMainPage = FERM2_T; break;
        case 2: currMainPage = FERM2_C; break;
        case 3: currMainPage = FERM2_H; break;
      }
      break;
  }
  */

  // Reset button press flags
  btnEnter.ResetPressed();
  btnInc.ResetPressed();
  btnDec.ResetPressed();

  return;

}

button.h

#ifndef Button_h
#define Button_h
#include <Arduino.h>

/*
* @breif Mutli-function and debounce button object
*/

class Button {

    private:
        byte _pin;
        u_int16_t _LONG_PRESS_MS; // Long press delay Ms
        u_int32_t _btnReadPrevMs = 0; // Previous button read Ms
        u_int32_t _pressedPrevMs = 0; // Previous button pressed Ms
        u_int32_t _currMs;
        u_int8_t _state = 0xFF; // Initial state of button captures
            
    public:
        Button(byte pin, u_int16_t LONG_PRESS_MS);
        boolean isPressed = false; // Button is currently pressed
        boolean isLongPress = false; // Button is current pressed for > long time
        boolean longPress = false; // Button was released - Press was short
        boolean shortPress = false; // Button was released - Press was long
        u_int8_t btnState = 0; // Button state
        void Begin(); // Setup hardware input pin
        void Pressed(); // Button function
        void ResetPressed(); // Reset button press triggers
};

#endif

button.cpp

#include "Arduino.h"
#include "Button.h"

Button::Button(byte pin, u_int16_t LONG_PRESS_MS){
    _pin = pin;
    _LONG_PRESS_MS = LONG_PRESS_MS;  
}

void Button::Begin(){pinMode(_pin, INPUT_PULLUP);}

void Button::Pressed(){
    _currMs = millis(); // Current Ms
    
    if (_currMs - _btnReadPrevMs > 5) { // Run debounce routine every 5ms
        _btnReadPrevMs = _currMs;
        _state = (_state<<1) | digitalRead(_pin); // Left shift state OR in current input OR mask out higher byte
        btnState = _state;
        
        if (_state == 0x00) { // Set pressed state if button accumulator is all 0's
            isPressed = true;
            if (_currMs - _pressedPrevMs > _LONG_PRESS_MS) { // Set long pressed if button pressed for > long time
            _pressedPrevMs = _currMs;
            isLongPress = true;
            }
        }
    }

    if (isPressed && !isLongPress && _state == 0xFF) {shortPress = true;} // Set short press when button released < long time
    if (isPressed && isLongPress && _state == 0xFF) {longPress = true;} // Set long press when button released > long time

     
    if (_state == 0xFF) {isPressed = false; isLongPress = false; _pressedPrevMs = _currMs;} // Reset button pressed states                   
                                                    
}

void Button::ResetPressed() {
    shortPress = false;
    longPress = false;
    
}

Should be:

uint8_t heatDelay;  // only 1 underline, before the t

etc.

Well that would do it! Without that break the program just continues down the line to my next set of cursor cases. I really appreciate it. I couldn’t see that to save my life.

Check your 'compiler warning' setting in 'preferences'. If set to 'all' the compiler should flag that with a "this may fall through" message.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.