Starts the loop then stops after one cycle

I have created a menu for the Adafruit RGB LCD display for my Arduino Uno. It’s coded so that the display turns on and prints some letters, then turns off while it waits for a button to turn it on. Once the button is pressed, it turns on and I’m able to choose my code then the display turns off after 15 seconds. My problem emerges when I choose a code for my LEDs that needs to loop multiple times. After selecting the function it’ll turn on the LEDs and run it, but when the display turns off it stops the function I chose and instead waits again for the button to be pushed. Here is my code for the wake-up, or turn on display, protocol;

 void onProtocol() {

  lcd.setCursor(1,0);
  lcd.print("Welcome");
  lcd.setCursor(3,1);
  lcd.print("LEDs Ready");
  delay(2000);
  lcd.clear();
  lcd.noDisplay();
  lcd.setBacklight(0);

 uint8_t buttons = lcd.readButtons();

  if (buttons) {
    switch (buttons & BUTTON_SELECT) {
      case 0:
        lcd.setBacklight(0);
        break;
      case 1:
        lcd.setBacklight(255);
        lcd.display();

        unsigned long startedWaiting = millis();
        while (millis() - startedWaiting <= 15000) {
          menuDraw();
        }
        lcd.setBacklight(0);
        lcd.clear();
        menuAddress = 0;
        mainPage = 0;
        break;
    }
  }

I’ve realized that the while() statement is the problem, but I don’t know of a way to keep the LEDs running while the display is in sleep mode. A buddy told me about interrupt() statements, but what I’ve read about them is that they’ll let the code run once, then revert back to what it’s supposed to be doing. Unless I’m wrong, but the interrupt() statement will put me in the same issue I am in right now where the code runs for a short time then turns off. Any help will be awesome.

You could set up a timer interrupt to run the display. They are a bit tricky, but well worth mastering, because they are very useful in many real-time applications.

Jrdoner

Please post a complete sketch that shows the issues. The problems are often in the code you are not showing.

Here a general observation and hint. You are trying to stay inside the onProtocol function with delay and while. This is usually not a good idea. Best is to avoid delay altogether and while if possible.

Try to write your software in a way that it is running trough everything all the time. Your Arduino is not a human and does not need vacation. The loop function should be executed as often as possible. Every time you run trough some function do as little as possible and then move on. This way your code stays responsive.

Have a look at the following example File → Examples → 02.Digital → BlinkWithoutDelay

You can use this to create different intervals in your loop. e.g.

  • every 10ms read the buttons and set some flags or counters

  • every 200ms check the relevant flags or counters and update LCD

Please post complete code.

       while (millis() - startedWaiting <= 15000) {
          menuDraw();
        }

Your use of millis() is wrong. Using millis() in a while-loop is basically the same as using delay().

You will need to implement a small statemachine. Below acts as a guide.

enum DISPLAYSTATES
{
  ST_WELCOME,
  ST_WELCOMEDELAY,
  ST_WELCOMECLEAR,
  ST_WAITBUTTON,
  ST_MENUDELAY,
  ST_MENUCLEAR,
};

void onProtocol()
{
  static DISPLAYSTATES currentState = ST_WELCOME;
  static unsigned long waitStartTime;

  uint8_t buttons; = lcd.readButtons();

  switch (currentState)
  {
    case ST_WELCOME:
      Serial.println("Entering ST_WELCOME");
      lcd.setCursor(1, 0);
      lcd.print("Welcome");
      lcd.setCursor(3, 1);
      lcd.print("LEDs Ready");
      // set the start time for the delay
      waitStartTime = millis();
      // next state / step
      currentState = ST_WELCOMEDELAY;
      Serial.println("Switching to ST_WELCOMEDELAY");
      break;
    case ST_WELCOMEDELAY:
      if (millis() - waitStartTime >= 2000)
      {
        currenState = ST_WELCOMECLEAR;
        Serial.println("Switching to ST_WELCOMECLEAR");
      }
      break;
    case ST_WELCOMECLEAR:
      lcd.clear();
      lcd.noDisplay();
      lcd.setBacklight(0);
      currentState = ST_WAITBUTTON;
      Serial.println("Switching to ST_WAITBUTTON");
      break;
    case ST_WAITBUTTON:
      buttons = lcd.readButtons();
      if (buttons)
      {
        switch (buttons & BUTTON_SELECT)
        {
          case 0:
            lcd.setBacklight(0);
            Serial.println("BTN = 0; stay in ST_WAITBUTTON");
            break;
          case 1:
            lcd.setBacklight(255);
            lcd.display();
            menuDraw();
            // set the start time for the delay
            waitStartTime = millis();
            // next state / step
            currentState = ST_MENUDELAY;
            Serial.println("BTN = 1; switching to ST_MENUDELAY");
        }
      }
      break;
    case ST_MENUDELAY:
      if (millis() - waitStartTime >= 15000)
      {
        currenState = ST_MENUCLEAR;
        Serial.println("Switching to ST_MENUCLEAR");
      }
      break;
    case ST_MENUCLEAR:
      lcd.setBacklight(0);
      lcd.clear();
      menuAddress = 0;
      mainPage = 0;
      currentState = ST_WAITBUTTON;
      Serial.println("Switching to ST_WAITBUTTON");
      break;
  }
}

I’ve broken it down in all the steps (states) that I saw; you probably can combine some. In loop(), you need to call it constantly; for it to work properly, no delay() and long for/while loops allowed.

void loop()
{
  onProtocol();

  ...
  ...
}

It’s not tested (nor compiled).

In the next step, you can dump the functionality of each state in its own function.