Connect with us

Menu code/buttons problems

Discussion in 'Microcontrollers, Programming and IoT' started by BlueObsecurit, May 2, 2021.

Scroll to continue with content
  1. BlueObsecurit

    BlueObsecurit

    26
    2
    Mar 24, 2021
    Hi.
    Got a music player project where I am using bitmaps to make an icon menu.
    I'm using a button library to handle button stuff, it seems to work if I make a simple code with just button inputs.
    I'm sure I'm missing something with the loops, something I haven't considered.

    The buttons works and it does reach the end of the if loop and switch case statements, but it is sporadic behaviour. Can't get it to go both left and right, sometimes freezes. I can't understand what it wrong. I'm using Seeeduino Xiao, pins are connected through button to ground. I'm posting part of the code that doesn't work, it handles only the main menu. This is to avoid overwhelming readers, I hope this will be enough, but if I missed including something let me know.

    Code:
    void loop() { //frame Coords: 0,0  ,  32,0   ,   64,0   ,   96,0    32 widht 21 length
    
    
      //add menuState 0 (music player default)
    
        //menuState 1, main menu
        if (menuState == 1) { //main menu, does not handle any commands to DFplayer
            u8g2.clearBuffer(); //this clears the buffer entirely, add the main menu bitmap, draws a frame around the first item then pushes it to screen.
            u8g2.drawXBMP(0, 0, 128, 32, mainMenu);
            //u8g2.drawFrame(0, 0, 32, 21);
            u8g2.sendBuffer();
            Serial.println("draw menu"); //debug
            //cursorPos = 0;
            Serial.println(cursorPos); //debug
           
           switch (cursorPos) { //each case instance handles removal and insertion of applicable frame
            case 0: //cursor is folders
                menuFrameClear(); //makes all frames transparent in buffer
                u8g2.drawFrame(0, 0, 32, 21); //add correct frame, push to screen
                u8g2.sendBuffer();
                Serial.println("frame drawn"); //debug
                while (!btnMenu.pressed() && !btnLeft.pressed() && !btnRight.pressed()){ //required to make code pause until input is received
                 
                if (btnMenu.pressed()) { //if menu button is pressed, enter folder menu
                    menuState = 2; //this changes the menu state. Program should then exit the parent if loop and proceed to next if loop (next menu). This rarely happens.
                    cursorPos = 0; //menuState 2 handles removal of previous menu. Cursor remains in 0 position.
                    Serial.println("menu case 0"); //debug
                   
                }
                if (btnRight.pressed()) {        
                    cursorPos = 1; //move cursor to right
                    Serial.println("right case 0"); //debug
                   
                }
                if (btnLeft.pressed()) {
               
                    cursorPos = 3; //loop around to the left
                    Serial.println("left case 0"); //debug
                   
                }
                }
            case 1: //cursor is at play mode
                menuFrameClear(); //remove all frames, add new one
                u8g2.drawFrame(32, 0, 32, 21);
                u8g2.sendBuffer();
                while (!btnMenu.pressed() && !btnLeft.pressed() && !btnRight.pressed()){
                 
                if (btnMenu.pressed()) {
                 
                    menuState = 3; //set menu to play mode, state 3 menu handles delete of previous screen
                    cursorPos = 0;
                    Serial.println("menu case 1");
                   
                }
                if (btnRight.pressed()) {
               
                    cursorPos = 2; //send cursor to the right
                    Serial.println("right case 1");
                   
                }
                if (btnLeft.pressed()) {
               
                    cursorPos = 0; //send cursor to the Left
                    Serial.println("left case 1");
                   
                }
                }
            case 2:
                menuFrameClear(); //remove all frames add new one
                u8g2.drawFrame(64, 0, 32, 21);
                u8g2.sendBuffer();
                while (!btnMenu.pressed() && !btnLeft.pressed() && !btnRight.pressed()){
             
                if (btnMenu.pressed()) {
                    menuState = 4; //set menu to EQ mode, state 4 menu handles delete of previous screen
                    cursorPos = 0;
                    Serial.println("menu case 2");
                   
                }
                if (btnRight.pressed()) {
                 
                    cursorPos = 3; //send cursor to the right
                    Serial.println("right case 2");
                   
                }
                if (btnLeft.pressed()) {
               
                    cursorPos = 1; //send cursor to the Left
                    Serial.println("left case 2");
                   
                }
                }
            case 3:
                menuFrameClear(); //remove all frames
                u8g2.drawFrame(96, 0, 32, 21);
                u8g2.sendBuffer();
                while (!btnMenu.pressed() && !btnLeft.pressed() && !btnRight.pressed()){
         
                if (btnMenu.pressed()) {
               
                    menuState = 5; //set menu to music mode, state 5 menu handles delete of previous screen
                    cursorPos = 0;
                    Serial.println("menu case 3");
                   
                }
                if (btnRight.pressed()) {
               
                    cursorPos = 0; //send cursor to the right
                    Serial.println("right case 3");
                   
                }
                if (btnLeft.pressed()) {
                 
                    cursorPos = 2; //send cursor to the Left
                    Serial.println("left case 3");
                   
                }
                }
    
            }
     
        } 
     
  2. Bluejets

    Bluejets

    5,135
    1,075
    Oct 5, 2014
    best if you post the full code and a diagram. You can be sure there are those here who will not be "overwhelmed" .
     
  3. Harald Kapp

    Harald Kapp Moderator Moderator

    11,801
    2,749
    Nov 17, 2011
    I think you're experiencing an issue with incomplete switch - case statements. Your code in short is like this:
    Code:
    switch (cursorPos) { //each case instance handles removal and insertion of applicable frame
            case 0: //cursor is folders
                {...
                }
            case 1: //cursor is at play mode
                {...
                }
            case 2:
                {...
                }
            case 3:
                {...
                }
    
            }
    This means that:
    • For cursorPos == 0 first the statements for case 0 are executed, then the statements for case 1, then case 2 and lastly case 3.
    • For cursorPos == 1 the statements for case 1 are executed, then the statements for case 2 and lastly case 3.
    • For cursorPos == 2 the statements for case 2 are executed, then the statements for case 3.
    • For cursorPos == 3 only the statements for case 3 are executed.
    In addition to this, you modify the state of cursorPos within the case statements, so when the code leaves one case section, it enters the next case section with a modified value of cursorPos.

    What you (usually) want to happen is that after executing the code for any one case the switch statement is terminated. To do this, you need to incorporate a "break;" statement:
    Code:
    switch (cursorPos) { //each case instance handles removal and insertion of applicable frame
            case 0: //cursor is folders
                {...
                break;
                }
            case 1: //cursor is at play mode
                {...
                break;
                }
            case 2:
                {...
                break;
                }
            case 3:
                {...
                break;
                }
    
            }
    See e.g. here how to use a "switch" statement in C.
     
  4. BlueObsecurit

    BlueObsecurit

    26
    2
    Mar 24, 2021
    Hi, thanks, this solved the logic. I did this very quickly, uploading the new code with break in it. Still some issues I will elaborate on.

    I note the request for full code and diagram, I'll do my best to draw one and fix the code ready for uploading.

    So the issues now are with the button behaviour and my theories on why it fails.

    * Button does not register - floating pin problem? But you'd need full code and diagram for this I suspect. Code problem? The way the code runs prevents event like registering the button from happening?

    * Button registers, but does not move the cursor. (The cursor redraws itself) This is probably because of the while statment in each case. The while statement ends because of button input, but the case runs through without registering a key press. Maybe this can be solved using pressed in the while statement and released in the if statement. Maybe it would be better to code something that behaves differently. As it stands, no option is a possible conclusion of a case, but it should always be right, left or menu. How can I do this?

    * Button left is clicked with no response. Button right is clicked with button left response. Something to do with the code, the left button is pressed and registered as pressed, while the right button ends the while statement. When this happens the if statement for left runs.

    All in all it seems I might want to modify the logic so that I don't require the while statement, then look for button presses. And also have some code where it can't exit the loop unless either left, right or menu is executed. How can I do something like that?
     
  5. Harald Kapp

    Harald Kapp Moderator Moderator

    11,801
    2,749
    Nov 17, 2011
    A specific button or all buttons? Always or only in some cases?
    In each case statement or only in some?
    Which response? The serial print or the cursor movement? Or both?
    Maybe start by telling us what you want to do? Analyzing your code to find out what's going on is a bit tedious.
    Also show us the schematic as requested. Without knowing how things are connected, it is only guesswork on our side to try to find out what's going on.

    Tip: Use enums instead of plain numbers for the menu states. That makes the code much better legible.
     
  6. BlueObsecurit

    BlueObsecurit

    26
    2
    Mar 24, 2021
    1. All buttons, "always" but they work as expected sometimes. when they do work, the logic (explained detailed below) works. (That means, if I press the button enough times I get the cursor to move to the right)

    2. Every case statement, but sometimes the button does not register, sometimes it does but does not move. I notice because the frame (explained below) redraws itself in the same position.

    3. Cursor movement, I haven't checked the serial (it is a bit tedious with this controller and I only had a few mins) I will do more troubleshooting after this post, where I'll also fix the code up for posting.

    Diagram attached, hope it is sufficient.

    What I have already posted is the main menu code. the initial setup of the code sets the menuState to 1 and cursorPos to 0, the first icon. 1st. It clears the buffer, draws a 4 icon bitmap. 2nd. Each case handles one of the 4 icon positions. Based on button input there are only three options in each case, move the cursor right, move the cursor left or enter the next sub menu. The cursor is a frame around the icon
     

    Attached Files:

  7. BlueObsecurit

    BlueObsecurit

    26
    2
    Mar 24, 2021
    Solved!
    Before I asked for help here I had break statements in the if statements, but like HaraldKapp said, I didn't also put them to close the case loops. I re-added the break statements properly both to the if and case statements and the code now works as expected. I also added an if/else statement to the bottom of the parent Menu if statement to stop it exiting the parent if loop entirely, speeding up the cursor change and preventing it from redrawing the bitmap needlessly.

    Also, the while statement needs to end on the basis of pressed button, while the changing of the cursor/menu needs to be on the basis of released button.

    I still have problems with buttons occationally not registering. They don't register in any way, including on the serial. Not entirely sure why that might be.

    Working code:
    Code:
     if (menuState == 1) { //main menu, does not handle any commands to DFplayer
            u8g2.clearBuffer(); //this clears the buffer entirely, add the main menu bitmap, draws a frame around the first item then pushes it to screen.
            u8g2.drawXBMP(0, 0, 128, 32, mainMenu);
            //u8g2.drawFrame(0, 0, 32, 21);
            u8g2.sendBuffer();
            Serial.println("draw menu"); //debug
            //cursorPos = 0;
            Serial.println(cursorPos); //debug
    
            cursorChange:
           switch (cursorPos) { //each case instance handles removal and insertion of applicable frame
            case 0: //cursor is folders
                menuFrameClear(); //makes all frames transparent in buffer
                u8g2.drawFrame(0, 0, 32, 21); //add correct frame, push to screen
                u8g2.sendBuffer();
                Serial.println("frame drawn"); //debug
                while (!btnMenu.pressed() && !btnLeft.pressed() && !btnRight.pressed()){ //required to make code pause until input is received
                  
                if (btnMenu.released()) { //if menu button is pressed, enter folder menu
                    menuState = 2; //this changes the menu state. Program should then exit the parent if loop and proceed to next if loop (next menu). This rarely happens.
                    cursorPos = 0; //menuState 2 handles removal of previous menu. Cursor remains in 0 position.
                    Serial.println("menu case 0"); //debug
                    break;
                }
                if (btnRight.released()) {         
                    cursorPos = 1; //move cursor to right
                    Serial.println("right case 0"); //debug
                    break;
                }
                if (btnLeft.released()) {
                
                    cursorPos = 3; //loop around to the left
                    Serial.println("left case 0"); //debug
                    break;
                }
                }
                break;
            case 1: //cursor is at play mode
                menuFrameClear(); //remove all frames, add new one
                u8g2.drawFrame(32, 0, 32, 21);
                u8g2.sendBuffer();
                while (!btnMenu.pressed() && !btnLeft.pressed() && !btnRight.pressed()){
                  
                if (btnMenu.released()) {
                  
                    menuState = 3; //set menu to play mode, state 3 menu handles delete of previous screen
                    cursorPos = 0;
                    Serial.println("menu case 1");
                    break;
                }
                if (btnRight.released()) {
                
                    cursorPos = 2; //send cursor to the right
                    Serial.println("right case 1");
                    break;
                }
                if (btnLeft.released()) {
                
                    cursorPos = 0; //send cursor to the Left
                    Serial.println("left case 1");
                    break;
                }
                }
                break;
            case 2:
                menuFrameClear(); //remove all frames add new one
                u8g2.drawFrame(64, 0, 32, 21);
                u8g2.sendBuffer();
                while (!btnMenu.pressed() && !btnLeft.pressed() && !btnRight.pressed()){
              
                if (btnMenu.released()) {
                    menuState = 4; //set menu to EQ mode, state 4 menu handles delete of previous screen
                    cursorPos = 0;
                    Serial.println("menu case 2");
                    break;
                }
                if (btnRight.released()) {
                  
                    cursorPos = 3; //send cursor to the right
                    Serial.println("right case 2");
                    break;
                }
                if (btnLeft.released()) {
                
                    cursorPos = 1; //send cursor to the Left
                    Serial.println("left case 2");
                    break;
                }
                }
                break;
            case 3:
                menuFrameClear(); //remove all frames
                u8g2.drawFrame(96, 0, 32, 21);
                u8g2.sendBuffer();
                while (!btnMenu.pressed() && !btnLeft.pressed() && !btnRight.pressed()){
          
                if (btnMenu.released()) {
                
                    menuState = 5; //set menu to music mode, state 5 menu handles delete of previous screen
                    cursorPos = 0;
                    Serial.println("menu case 3");
                    break;
                }
                if (btnRight.released()) {
                
                    cursorPos = 0; //send cursor to the right
                    Serial.println("right case 3");
                    break;
                }
                if (btnLeft.released()) {
                  
                    cursorPos = 2; //send cursor to the Left
                    Serial.println("left case 3");
                    break;
                }
                }
                break;
            }
          if (menuState != 1){
            
          }
          else {
            goto cursorChange;
          }
        } 
    Now, the change is still a bit slow. Any way I can do this better?
     
Ask a Question
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.
Electronics Point Logo
Continue to site
Quote of the day

-