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();
}
2 Answers 2
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– Vincent Labrecque2020年01月13日 16:54:43 +00:00Commented Jan 13, 2020 at 16:54
-
Nevermind, I made it work with a dummy boolean variable. BlinkWithoutDelay was the way to go. Thank you!Vincent Labrecque– Vincent Labrecque2020年01月13日 17:14:32 +00:00Commented Jan 13, 2020 at 17:14
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– Vincent Labrecque2020年01月13日 17:05:50 +00:00Commented Jan 13, 2020 at 17:05
-
I forgot the semi colon after the second enum. I don't have a compiler at handMichel Keijzers– Michel Keijzers2020年01月13日 17:08:53 +00:00Commented Jan 13, 2020 at 17:08
-
You also should get rid of the while statement. Don't block your code for long or indetermined time.Michel Keijzers– Michel Keijzers2020年01月13日 17:10:29 +00:00Commented Jan 13, 2020 at 17:10