0

I can't seem to be able to escape a while loop using a keypad button. I've tried the solution from this thread: https://forum.arduino.cc/index.php?topic=79932.0

Here's my code:

void alarm(){
  char customKey = customKeypad.getKey();

  while (customKey == NO_KEY){
    customKey = customKeypad.getKey();
    lcd.noDisplay();
    delay(750);// change for faster flash
    lcd.display();
    delay(750);// change for faster flash
  }
  lcd_home_screen();
}

I tried both == and != for the while (customKey == NO_KEY)

Additional info: I am calling this alarm function from another function inside my Loop. Here's the complete code:

void loop() {
  // keypad
  char customKey = customKeypad.getKey();    
  if (customKey == 'A'){
    main_program(5);
  }
}

int main_program(int duration){
  timer(duration);
  alarm();
}
1

Because you're using delay() within your while loop you have to ensure that you are pressing the key at the precise moment it is read.

You should not use delay().

Instead take a look at the BlinkWithoutDelay example in the IDE. And also consider implementing a Finite State Machine to know both if you're blinking and what state you're blinking currently is in.

  • Your solution of BlinkWithoutDelay makes a lot of sense and is more reachable for my level of knowledge, thank you. My blockage now is the problem that I cannot bool the lcd.Display and noDisplay functions. In the BlinkWithoutDelay example, the code checks for low or high pin output, but in my case I have to check if my lcd is on Display or noDisplay. How can i check that? I'll post the new code if what I just wrote is not clear. – Vincent Labrecque Jan 13 at 16:54
  • Nevermind, I made it work with a dummy boolean variable. BlinkWithoutDelay was the way to go. Thank you! – Vincent Labrecque Jan 13 at 17:14
0

To elaborate on Majenko's answer, you can create some enumeration types for the states, e.g.

enum EAlarmState 
{
   On,
   Off
};

EAlarmState _alarmState = EAlarmState::Off;

enum EBlinkState
{
    BlinkOn,
    BlinkOff,
};

EBlinkState _blinkState = EBlinkState::BlinkOff;

unsigned int long _lastBlinkTime = 0;

The _blinkState and _lastBlinkTime state will not be checked when _alarmState is off.

Now you can use something like this to check the states and the keypad (pseudo code):

void loop()
{
    checkKeypad();

    switch (_alarmState)
    {
    case EAlarmStateOn:
       if (millis() - _lastBlinkTime) >= 750)
       {
          `Blink off code`
          switch(_blinkState)
          {
          case EBlinkStateOn:
             _lastBlinkTime = millis();
             'Blink off code'
             _blinkState = EBlinkState::Off;
             break;

          `same for case EBlinkStateOff'
             break;

          default: // Error
             break;
          }
       }

And also create state checking and changing for the alarm itself.

It looks like a lot of code (and it will be), so split it in sub functions. But the most important is that the code is fairly easy to read (and thus maintain).

  • I tried to copy/paste your code, but since I don't understand what is going on, I could not make it work. I pasted the top part of your code before the Setup() function, and the bottom part in the while loop inside my alarm() function. I now face the following error msg "expected initializer before '_blinkState' – Vincent Labrecque Jan 13 at 17:05
  • I forgot the semi colon after the second enum. I don't have a compiler at hand – Michel Keijzers Jan 13 at 17:08
  • You also should get rid of the while statement. Don't block your code for long or indetermined time. – Michel Keijzers Jan 13 at 17:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.