Case menu structure assistance needed

Hello everyone

I've been coding for the past couple of days and I seem to be stuck and can't seem to see the light. Your assistance in pointing me in the correct direction will be greatly appreciated. :smiley:

I've coded a menu using the case statement and loads of functions to make it look nice and pretty. The main menu screen works fine (I think it works fine since the loop is only looping back to this menu) but as soon as I try to go into the sub menu I run into trouble. I've setup a counter to count my enter and escape button presses to go in and out of the sub menu and this works but the problem is that if I use a if statement to test the counter and to go to the sub menu then the screen toggles between the main menu and the sub menu constantly. When I press the ESC button it works nicely and goes back to the main menu. I'm not sure how to get around this but I've tried changing the if statement to a while statement which works wonderfully but when I call the functions to test the button presses while using the while it is unresponsive.

The problem area is found in the void loop, if statement.

Your feedback will be greatly appreciated as I'm at the stage of pulling out some hair here :~

Code as follows:

  #include <glcd.h>                // include the library header
  #include <fonts/allFonts.h>      // include the Fonts
  
  const int ESC_Button   = 2;
  const int UP_Button    = 3;
  const int DWN_Button   = 12;
  const int ENT_Button   = 13;

  const int ledPin =  13;      // the number of the LED pin
  
  int ESC_Button_State   = 0;
  int UP_Button_State    = 0;
  int DWN_Button_State   = 0;
  int ENT_Button_State   = 0;
  
  int UP_DOWN_Selector            = 1;
  int ENT_ESC_Selector            = 1;

  void setup() 
  {
    GLCD.Init(NON_INVERTED);     // Initialize the GLCD 
    GLCD.ClearScreen(); 
    GLCD.Init();
    
    pinMode ( ESC_Button, INPUT );
    pinMode ( UP_Button,  INPUT );
    pinMode ( DWN_Button, INPUT );
    pinMode ( ENT_Button, INPUT );
    
    pinMode(ledPin, OUTPUT);
  
  }

  void loop()
  {        

    ESC_Button_State   = digitalRead(ESC_Button);
    UP_Button_State    = digitalRead(UP_Button);
    DWN_Button_State   = digitalRead(DWN_Button);
    ENT_Button_State   = digitalRead(ENT_Button);  
      
        Draw_Menu_Blocks();
        
        Test_UP_DOWN_Counter();
        Test_ENT_ESC_Counter_Value();
        
        
        Main_Menu_Case_Switch();
    
    
   /*     if( ENT_ESC_Selector  == 2 )
        {
          GLCD.ClearScreen(); 
        }    
     */   
        if( ENT_ESC_Selector  == 0 )   // tried to use a while here as well.
        {
          UP_DOWN_Selector = 1;
            
          Test_UP_DOWN_Counter();
          Test_ENT_ESC_Counter_Value();
            
          Sub_Menu1_Case_Switch();            
        }      
  }


  /****************************************************************************************************************************************************************************
  **************************************                    Menu Case Switch - Used to draw sub menu                   ********************************************************
  ****************************************************************************************************************************************************************************/ 


  void Main_Menu_Case_Switch() 
  {
    switch ( UP_DOWN_Selector )
    {
        case 1:
          Menu_Line1_Highlighted();  
          Menu_Line2_Not_Highlighted(); 
          Menu_Line3_Not_Highlighted(); 
          Menu_Line4_Not_Highlighted(); 
          break;                                                 // Break used to break main menu          
                 
        case 2:
          Menu_Line1_Not_Highlighted();  
          Menu_Line2_Highlighted(); 
          Menu_Line3_Not_Highlighted(); 
          Menu_Line4_Not_Highlighted();   
          break;  
          
        case 3:
          Menu_Line1_Not_Highlighted();  
          Menu_Line2_Not_Highlighted(); 
          Menu_Line3_Highlighted(); 
          Menu_Line4_Not_Highlighted();   
          break;  
                
        case 4:
          Menu_Line1_Not_Highlighted();  
          Menu_Line2_Not_Highlighted(); 
          Menu_Line3_Not_Highlighted(); 
          Menu_Line4_Highlighted();   
          break;            
    }  
  }
  

  /****************************************************************************************************************************************************************************
  **************************************                Sub Menu1 Case Switch - Used to draw sub menu                  ********************************************************
  ****************************************************************************************************************************************************************************/  
  
  
  void Sub_Menu1_Case_Switch()
  {
    switch ( UP_DOWN_Selector )
    {
       case 1:
         Sub_Menu1_Line1_Highlighted();  
         Sub_Menu1_Line2_Not_Highlighted(); 
         Sub_Menu1_Line3_Not_Highlighted(); 
         Sub_Menu1_Line4_Not_Highlighted();            
         break;
                                                    
               
       case 2:
         Sub_Menu1_Line1_Not_Highlighted();  
         Sub_Menu1_Line2_Highlighted(); 
         Sub_Menu1_Line3_Not_Highlighted(); 
         Sub_Menu1_Line4_Not_Highlighted();                
         break;               
                
       case 3:
         Sub_Menu1_Line1_Not_Highlighted();  
         Sub_Menu1_Line2_Not_Highlighted(); 
         Sub_Menu1_Line3_Highlighted(); 
         Sub_Menu1_Line4_Not_Highlighted();                
         break;
                
       case 4:
         Sub_Menu1_Line1_Not_Highlighted();  
         Sub_Menu1_Line2_Not_Highlighted(); 
         Sub_Menu1_Line3_Not_Highlighted(); 
         Sub_Menu1_Line4_Highlighted();                
         break;                
    }
  }
  
    
  /****************************************************************************************************************************************************************************
  **************************************                       Code to draw up the menu                                ********************************************************
  ****************************************************************************************************************************************************************************/  
  
  
  void Draw_Menu_Blocks()
  {
    // Part above menu   
   
    GLCD.DrawRect( 0,  0, 127, 63);  // draw an open rectangle that spans the extremties of the LCD
    
    GLCD.FillRect( 47,  2,   2,  8);  // Klein reg hoek om die Text beter te laat lyk, aan die linker kant
    GLCD.DrawLine( 49,  2,  79,  2);  // Lyn bo die text om dit beter te laat lyk
    GLCD.DrawLine( 0, 12, 126, 12);  // Lyn om 'n blokkie te maak
    
    GLCD.SelectFont(System5x7, WHITE);                                                                       
    GLCD.CursorToXY(GLCD.Width/2 - 14, 3);
    GLCD.print("MENU:");   
    
    GLCD.DrawLine( 0, 51, 126, 51);  // Lyn om 'n blokkie te maak 

    //****************************************************************************************************************************************************************************    
    //Call menu line functions
  
    

        
    
    //****************************************************************************************************************************************************************************
    // Part below menu    
  
    GLCD.DrawLine( 31, 52,  31, 62);    // Lines to draw four blocks at the bottom.
    GLCD.DrawLine( 63, 52,  63, 62);
    GLCD.DrawLine( 94, 52,  94, 62); 
  
    // Menu buttons at the bottom of the display. 
  
    GLCD.SelectFont(System5x7, BLACK);                                                                       
    GLCD.CursorToXY(8, 54);             // Write ESC in the first block
    GLCD.print("ESC");  
         
    GLCD.DrawLine( 47, 54,  47, 60);    // Draw Up arrow in second block from left
    GLCD.DrawLine( 46, 55,  48, 55);
    GLCD.DrawLine( 45, 56,  49, 56);
    
    GLCD.DrawLine( 78, 54,  78, 60);    //  Draw Down arrow in third block from left
    GLCD.DrawLine( 77, 59,  79, 59);
    GLCD.DrawLine( 76, 58,  80, 58);
  
    GLCD.CursorToXY(103, 54);            // Write ENT in thte last block
    GLCD.print("ENT");   
  
  }

code from the end of the previous code:

/****************************************************************************************************************************************************************************
  ****************************     Test_ENT_ESC_Counter_Value to determine whether ENT or ESC was pressed to use in case function    ********************************************
  ****************************************************************************************************************************************************************************/  
  
  
  void Test_ENT_ESC_Counter_Value ()
  {
    if ( ESC_Button_State == HIGH ) 
    {
      Highlighted_Escape_Button();
      delay(150); 
      digitalWrite(ledPin, HIGH); 
      ENT_ESC_Selector--;
      
      if ( ENT_ESC_Selector < 0 )
      {
        ENT_ESC_Selector = 0;
      }
    }
      
    ESC_Button_State   = 0;
    digitalWrite(ledPin, LOW); 
    Not_Highlighted_Escape_Button();
  
    if ( ENT_Button_State == HIGH )
    {
        Highlighted_Enter_Button();
        delay(150); 
        digitalWrite(ledPin, HIGH); 
        ENT_ESC_Selector++;
        
        if (ENT_ESC_Selector > 2 )
        {
          ENT_ESC_Selector = 2;
        }
    }
        
    ENT_Button_State   = 0;
    digitalWrite(ledPin, LOW); 
    Not_Highlighted_Enter_Button();
  }
 
 
  /****************************************************************************************************************************************************************************
  ****************************     Tests Main Menu Line Counter Value to determine which line in the menu should be highlighted    ********************************************
  ****************************************************************************************************************************************************************************/  
 
  
void Test_UP_DOWN_Counter ()
  {       
    if ( UP_Button_State == HIGH )
    {
        Highlighted_Up_Button();
        delay(150); 
        digitalWrite(ledPin, HIGH); 
        UP_DOWN_Selector--;
        
        if (UP_DOWN_Selector < 1 )
        {
          UP_DOWN_Selector = 4;
        }
    }
    
    UP_Button_State   = 0;
    digitalWrite(ledPin, LOW); 
    Not_Highlighted_Up_Button();  
    
    if (DWN_Button_State == HIGH )
    {
        Highlighted_Down_Button();
        digitalWrite(ledPin, HIGH); 
        delay(150); 
        UP_DOWN_Selector++;
        
        if (UP_DOWN_Selector > 4 )
        {
          UP_DOWN_Selector = 1;
        }
    }    
        
    DWN_Button_State   = 0;
    digitalWrite(ledPin, LOW); 
    Not_Highlighted_Down_Button();        
  }

 
  /****************************************************************************************************************************************************************************
  **************************************                           Highlighted Buttons                                 ********************************************************
  ****************************************************************************************************************************************************************************/  

  
  void Highlighted_Escape_Button() 
  {
  
    GLCD.SelectFont(System5x7, WHITE);      // Highlighteds Escape button when pressed.
    GLCD.CursorToXY(8, 54);                 // Write ESC in the first block
    GLCD.print("ESC");    
    GLCD.DrawRoundRect( 5, 53, 21, 8, 2);   // rounded rectangle around text area    
    GLCD.DrawLine( 7, 54, 7, 60); 
    GLCD.DrawLine( 6, 54, 6, 60); 
    
  }
   
  void Highlighted_Up_Button() 
  {
    
    GLCD.DrawRoundRect( 37, 53, 21, 8, 2);  // rounded rectangle around text area    
    GLCD.FillRect( 38, 54, 19, 7 );
    GLCD.DrawLine( 47, 54,  47, 60, WHITE);    // Draw Up arrow in second block from left
    GLCD.DrawLine( 46, 55,  48, 55, WHITE);
    GLCD.DrawLine( 45, 56,  49, 56, WHITE);
    
  }
  
  void Highlighted_Down_Button()
  {
    
    GLCD.DrawRoundRect( 68, 53, 21, 8, 2);  // rounded rectangle around text area    
    GLCD.FillRect( 69, 54, 19, 7 );
    GLCD.DrawLine( 78, 54,  78, 60, WHITE); //  Draw Down arrow in third block from left
    GLCD.DrawLine( 77, 59,  79, 59, WHITE);
    GLCD.DrawLine( 76, 58,  80, 58, WHITE);
  
  }
  
  void Highlighted_Enter_Button()
  {
    
    GLCD.SelectFont(System5x7, WHITE);      // Highlighteds Enter button when pressed.
    GLCD.CursorToXY(103, 54);               // Write ENT in thte last block
    GLCD.print("ENT");  
    GLCD.DrawRoundRect( 100, 53, 21, 8, 2); // rounded rectangle around text area    
    GLCD.DrawLine( 101, 54, 101, 60); 
    GLCD.DrawLine( 102, 54, 102, 60); 
  
  }

The rest of the code is drawing functions used highlight buttons and menu lines as I push a button or scroll through the menu etc. Let me know if anyone needs to see this.

The problem area is found in the void loop, if statement.

The problem might be found in the loop function, not in the void loop.

There are two if statements in loop(). One is commented out. Which one do you think is causing the problem?

Using fewer global variables would be a good thing. Some of your functions need to return values, not set global variables.

Describing the exact sequence of events that causes the problem would be good.

Hello Paul

Please ignore the if statement that is greyed out. Detailed description:

I've coded a main menu and a sub menu and want to test moving from the main menu to the sub menu using the enter and escape buttons. The up and down buttons should also work in both the main menu and the sub menu.

Your correct in saying that the loop function is the problem. When I call my main menu function in void loop, the function goes through all the commands and then loops around, being one menu it's not a problem.

When I choose to go to the sub menu i.e. call the sub menu function then the void loop goes through the sub menu function and reaches the end of the loop and then rolls back to the start running through the main menu function and going through the sub menu function again etc.

So what is happening is that its showing the main menu for a few milli seconds and then the sub menu for a few milli seconds so no usable interface in other words.

Thanks for the tip on returning some variables, I'm a bit rusty with my programming and am just getting back into it, but will look into it.

I also just noticed that I've made a mistake with the code that I've posted

"ENT_ESC_Selector == 0" in the if statement should be "ENT_ESC_Selector == 2" to be able to relate to the ENT button and not to the ESC button but this doesn't change anything with the problem I'm experiencing.

Solved it!!! Yeay

I had to use while statements but I didn't read my inputs again in the sub menu so this fixed it.

  void loop()
  {          
          
 
       Read_Buttons();        
       Draw_Menu_Blocks();
        
        Test_UP_DOWN_Counter();
        Test_ENT_ESC_Counter_Value();
        
        if( ENT_ESC_Selector  <= 1 )
        {
          ENT_ESC_Selector = 1;
        }        
                
        Main_Menu_Case_Switch();
      
        if( ENT_ESC_Selector  == 2 )
        {
          UP_DOWN_Selector = 1;
        }
        
        while( ENT_ESC_Selector  == 2 ) 
        {
          

          Read_Buttons();    
          
          Test_UP_DOWN_Counter();
          Test_ENT_ESC_Counter_Value();
            
          Sub_Menu1_Case_Switch();            
        }  
    
  }

  /****************************************************************************************************************************************************************************
  ****************************                                            Read Button Inputs                                       ********************************************
  ****************************************************************************************************************************************************************************/  

  
  void Read_Buttons()
  {  
    ESC_Button_State   = digitalRead(ESC_Button);
    UP_Button_State    = digitalRead(UP_Button);
    DWN_Button_State   = digitalRead(DWN_Button);
    ENT_Button_State   = digitalRead(ENT_Button);  
  }

Can I suggest that you make these functions (which you have not included in the code posted), into one function with a parameter for the line to be highlighted.

    Menu_Line1_Highlighted();  
    Menu_Line2_Not_Highlighted(); 
    Menu_Line3_Not_Highlighted(); 
    Menu_Line4_Not_Highlighted();

perhaps

    Menu_Line_Highlighted(1);

There is no need to indicate those that should not be highlighted as, by definition, there will only be one line highlighted at any one time.

I am not sure what else you intend to do in the Main_Menu_Case_Switch() function but as you will see, the case number equates to the menu line to be highlighted, so you could eliminate the switch/case structure as it currently stands and substitute a single call to Menu_Line_Highlighted(UP_DOWN_Selector).