Menu design problem ( temperature page + menu)

hi all,

I had a logger project which shown the temperature value on OLED (page 1), and if press any button, then go to setting page (page 2). ( I want to stay at page 2 ,until i exit the setting page...)

the problem facing is :

1.after pressing button, screen go to setting page( page2 ), then back to temperature page ( page 1) instantly

  1. I want the temperature update rate is 3 second, so I put the delay (3000) in loop ,
    however, it will also slow down the other function in loop, how to improve?

Many thanks.

void loop() {
 

  if ((!digitalRead(downButton)) || (!digitalRead(upButton)) || !digitalRead(selectButton)) {
    buttonaction();  // press any button, then go to setting page
  } else {
    sensorpage(); // if no button pressed , go to sensorpage
  }
}

void buttonaction() {                            //function that control menu 
  if (!digitalRead(downButton)) {
    updateMenu();
    menu++;
    delay(100);
    updateMenu();
    delay(100);
    while (!digitalRead(downButton));
  }
  if (!digitalRead(upButton)) {
    menu--;
    delay(100);
    updateMenu();
    delay(100);
    while (!digitalRead(upButton));
  }
if (!digitalRead(selectButton)) {
    executeAction();
    delay(100);
    updateMenu();
    delay(100);
    while (!digitalRead(selectButton));
  } 
}

void sensorpage()                    //drawing sensor page on OLED
{

  display.clearDisplay();
  display.setFont(&FreeSans9pt7b);

  display.drawLine ( 0, 20, 128, 20, WHITE);

  // RTC on top

  /* DateTime now = rtc.now();
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.setCursor(0, 0);
    display.print(now.day(), DEC);
    display.print("/");
    display.print(now.month(), DEC);
    display.print("/");
    display.print(now.year(), DEC);


  display.setCursor(0, 10);
  display.print(now.hour(), DEC);
  display.print(":");
  display.print(now.minute(), DEC);
  display.print(":");
  display.print(now.second(), DEC);*/

  // DIsplay temp at bottom

  int x1 = 45;
  int x2 = 105;

  int y1 = 40;
  int y2 = 60;


  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, y1);
  display.print("T1:");
  display.setTextSize(1);
  display.setCursor(x1, y1);
  display.print(thermocouple.readCelsius());
  display.setCursor(x2, y1);
  display.cp437(true);
  display.write(167);
  display.print("C");

  display.setCursor(0, y2);
  display.print("T2:");
  display.setCursor(x1, y2);
  // display.print(rtc.getTemperature());
  display.setCursor(x2, y2);
  display.cp437(true);
  display.write(167);
  display.print("C");
  display.display();


}

  
 
void updateMenu()     //function that control menu action
{

  display.setFont(&FreeSans9pt7b);
  display.setTextSize(1);


  switch (menu) {
    case -3:
      menu = 0;
      break;

    case -2:
      display.clearDisplay() ;
      display.display();


    case -1:
      menu = 0;
      break;

    case 0:
      sensorpage();
      break;



    case 1:
      display.clearDisplay();
      display.setTextColor(WHITE);
      display.setCursor(0, y);
      display.println("> Start Logging");
      display.setCursor(0, y2);
      display.println(" MenuItem2");
      display.display();
      break;
    case 2:
      display.clearDisplay();
      display.setTextColor(WHITE);
      display.setCursor(0, y);
      display.println("Start Logging");
      display.setCursor(0, y2);
      display.println("> MenuItem2");
      display.display();
      break;
    case 3:
      display.clearDisplay();
      display.setTextColor(WHITE);
      display.setCursor(0, y);
      display.println("> Display off");
      display.setCursor(0, y2);
      display.println(" Back");
      display.display();
      break;
    case 4:
      display.clearDisplay();
      display.setTextColor(WHITE);
      display.setCursor(0, y);
      display.println("Display off");
      display.setCursor(0, y2);
      display.println("> Back");
      display.display();
      break;
    case 5:
      menu = 4;
      break;
  }
}



Hi,
Have a look at: Arduino: Using millis() Instead of delay() - DZone IoT

Ok thanks.

Take a look at the State Change Detection example in the IDE (File->examples->02.digital->State Change Detection) to see how to detect when a button gets pressed, not if a button is pressed.

Then, set a state variable (e.g. state or inSettingsState) and then use that variable inside loop() to determine which state you are in and act accordingly... Something like this (not real code)

...
bool inSettingsState = false;

void loop() {
  if ( checkButtons() ) {
    inSettingsState = !inSettingsState;
  }

  if ( inSettingsState == true ) {
    // do Settings things
  }
  else {
    // do regular things
  }
}
...

:blush: thanks

Sometimes, it is also useful to distinguish between the first time to a menu (redraw everything) vs. returning to the same menu (only update what is needed). This is the approach of a finite state machine (google it, if interested) and then you get something more like

...
bool inSettingsState = false;

void loop() {
  if ( checkButtons() ) {
    inSettingsState = !inSettingsState;
    if ( inSettingsState == true ) {
      beginSettingsMenu();
    }
    else {
      beginRunMenu();
    }
  }

  if ( inSettingsState == true ) {
    // do Settings things
    updateSettingsMenu();
  }
  else {
    // do regular things
    updateRunMenu();
  }
}
...

Good to hear that, Let me study the coding first

Hi blh,

after reviewing the state change example, i still cant slove 1, 2 problem.

`
void loop() {
  BlynkEdgent.run ();
  timer.run();

  buttonState3 = digitalRead (selectButton);

  if ( buttonState3 != lastbuttonState3) {   //button press>  state change , go setting page
    if (buttonState3 == HIGH) {
      menu = 1 ;
      updateMenu();  // go to setting page
    }

  } else {
    sensorpage();               // need help.... after pressing select button, setting page
                                          // shown 1  second  then go to next function...
  }

  lastbuttonState3 = buttonState3;`

After pressing the select button , setting page shown for one second, then go to next function sensorpage() ,

how to stop looping for a while after entering setting page ?

it is very difficult to say without seeing an entire sketch...

please find the sketch below :slight_smile:

int upButton = 32;
int downButton = 33;
int selectButton = 25;
int menu = 0;
;
int buttonState3 = 0;  // button state for select buttom
int lastbuttonState3 = 0;

void loop() {
  BlynkEdgent.run ();
  timer.run();

  buttonState3 = digitalRead (selectButton);

  if ( buttonState3 != lastbuttonState3) {
    if (buttonState3 == HIGH) {
      buttonaction();                              //if pressed select button , start buttonaction function          
                                                             //and checking the button action> page select
    }

  } else {
    sensorpage();   //if button not pressed, go to sensorpage( temp page)
  }


  lastbuttonState3 = buttonState3;

}

void buttonaction() {                          //detect button action ,updating menu number and                  
                                                             //shown related page
  if (!digitalRead(downButton)) {
    menu++;
    delay(100);
    updateMenu();
    delay(100);
    while (!digitalRead(downButton));
  }
  if (!digitalRead(upButton)) {
    menu--;
    delay(100);
    updateMenu();
    delay(100);
    while (!digitalRead(upButton));
  }
  if (!digitalRead(selectButton)) {
    executeAction();
    delay(100);
    updateMenu();
    delay(100);
    while (!digitalRead(selectButton));
  }
}

void updateMenu()                      //menu display
{

  display.setFont(&FreeSans9pt7b);
  display.setTextSize(1);


  switch (menu) {
    case -3:
      menu = 0;
      break;

    case -2:
      display.clearDisplay() ;
      display.display();


    case -1:
      menu = 0;
      break;

    case 0:
      sensorpage();
      break;



    case 1:
      display.clearDisplay();
      display.setTextColor(WHITE);
      display.setCursor(0, y);
      display.println("> Start Logging");
      display.setCursor(0, y2);
      display.println(" MenuItem2");
      display.display();
      break;
    case 2:
      display.clearDisplay();
      display.setTextColor(WHITE);
      display.setCursor(0, y);
      display.println("Start Logging");
      display.setCursor(0, y2);
      display.println("> MenuItem2");
      display.display();
      break;
    case 3:
      display.clearDisplay();
      display.setTextColor(WHITE);
      display.setCursor(0, y);
      display.println("> Display off");
      display.setCursor(0, y2);
      display.println(" Back");
      display.display();
      break;
    case 4:
      display.clearDisplay();
      display.setTextColor(WHITE);
      display.setCursor(0, y);
      display.println("Display off");
      display.setCursor(0, y2);
      display.println("> Back");
      display.display();
      break;
    case 5:
      menu = 4;
      break;
  }
}


void sensorpage()     //temperature display page
{

  display.clearDisplay();
  display.setFont(&FreeSans9pt7b);

  display.drawLine ( 0, 20, 128, 20, WHITE);

  // DIsplay temp at bottom

  int x1 = 45;
  int x2 = 105;

  int y1 = 40;
  int y2 = 60;


  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, y1);
  display.print("T1:");
  display.setTextSize(1);
  display.setCursor(x1, y1);
  display.print(thermocouple.readCelsius());
  display.setCursor(x2, y1);
  display.cp437(true);
  display.write(167);
  display.print("C");

  display.setCursor(0, y2);
  display.print("T2:");
  display.setCursor(x1, y2);
  // display.print(rtc.getTemperature());
  display.setCursor(x2, y2);
  display.cp437(true);
  display.write(167);
  display.print("C");
  display.display();


}

////////////////////////

//menu action

void action1() {
  display.clearDisplay();
  display.setCursor(0, y2);
  display.print(">Executing #1");
  display.display();
  delay(1500);
}
void action2() {
  display.clearDisplay();
  display.setCursor(0, y2);
  display.print(">Executing #2");
  display.display();
  delay(1500);
}
void action3() {
  menu = -2;
}
void action4() {
  menu = 0;
}

Your logic appears off as well as what you are defining as a button press. Inside loop(), you read selectButton and then act upon it if it is HIGH. This demands there is an external pull-down resistor tied to that pin. Is the resistor present?

Then, inside buttonaction(), you test for selectButton being LOW

  if (!digitalRead(selectButton)) {

in order to do the executeaction() function.

So, follow the logic of the code.

  1. you press the selectButton, the state is not equal to the last state so you call buttonaction(). That function executes once and returns.
  2. you update lastbuttonState3
  3. you execute loop() again.
  4. buttonState3 is now equal to lastbuttonState3 so the else part gets executed which is sensorpage()

First off, how are your buttons wired up? This will dictate if they are HIGH or LOW when pressed. A typical schematic is one side of the button to ground and the other to the input pin with the pin declared as INPUT_PULLUP. It will read LOW when pressed.

Second, your buttonaction() function doesn't do anything if no buttons are pressed. They way you check buttons within the function needs to be the same state change detection example.

An alternative would be to use the Bounce2 library where you can define a button pin and it does all the state change and debouncing inside that library. It will make your life simplier.

Third, as I stated in reply #4, you need to keep track of what state your are in and then call the correct functions.

  1. Input pull up were used,
  2. Will try bounce 2 library
  3. Still not understand why using check state change to call function. Need more study.....