Hi,
I'm fairly new to Arduino programming. Currently I'm building a project to trigger an 'alarm' when a certain button is pushed.
I decided to use a 'state machine' using a switch/case loop. However, on debugging I came into a weird problem.
The code below works fine: the loop starts in the S_IDLE state and on pushing the button it switches to the S_ALARMTRIG state which then enters the S_LEDON state to flash the LED.
#define S_IDLE 8
#define S_LEDON 3
#define S_WAITON 4
#define S_LEDOFF 5
#define S_WAITOFF 6
#define S_TURNOFF 7
#define S_ALARMTRIG 9
const int buttonPin = 4;
const int ledPin = 13;
int ledState = LOW;
int buttonState;
int lastButtonState = LOW;
static int state = S_IDLE;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
void setup()
{
Serial.begin(9600);
Serial.println("Setup-loop");
pinMode(buttonPin, INPUT);
pinMode(ledPin, OUTPUT);
Serial.println("Setup-loop ran - starting main looop");
}
void loop()
{
static unsigned long ts; // om de huidige tijd voor pauzes in te bewaren
switch (state)
{
case S_LEDON:
Serial.println(state);
digitalWrite(ledPin, HIGH); // schakel LED in
ts = millis(); // noteer de huidige tijd
state = S_WAITON; // ga naar de volgende state
break;
case S_WAITON:
Serial.println(state);
if (millis() > ts + 1000)
{
state = S_LEDOFF;
}
break;
case S_LEDOFF:
digitalWrite(ledPin, LOW); // schakel LED uit
ts = millis(); // noteer de huidige tijd
state = S_WAITOFF;
break;
case S_WAITOFF:
Serial.println(state);
// zodra er 1 seconde verstreken is , ga naar terug naar fase S_LEDON
if (millis() > ts + 1000)
{
state = S_LEDON;
}
break;
case S_TURNOFF:
ledState = LOW;
state = S_IDLE;
break;
case S_ALARMTRIG:
state = S_LEDON;
break;
case S_IDLE:
Serial.println(state);
int reading = digitalRead(buttonPin);
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != buttonState) {
buttonState = reading;
if (buttonState == HIGH) {
ledState = !ledState;
state = S_ALARMTRIG;
}
}
}
digitalWrite(ledPin, ledState);
lastButtonState = reading;
break;
default:
state = S_IDLE;
break;
}
}
However, the code below doesn't work because it hangs on pressing the button, although it is EXACTLY the same, apart from the position of the case S_IDLE (which is now in the beginning of the switch() statement rather than the end).
#define S_IDLE 8
#define S_LEDON 3
#define S_WAITON 4
#define S_LEDOFF 5
#define S_WAITOFF 6
#define S_TURNOFF 7
#define S_ALARMTRIG 9
const int buttonPin = 4;
const int ledPin = 13;
int ledState = LOW;
int buttonState;
int lastButtonState = LOW;
static int state = S_IDLE;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
void setup()
{
Serial.begin(9600);
Serial.println("Setup-loop");
pinMode(buttonPin, INPUT);
pinMode(ledPin, OUTPUT);
Serial.println("Setup-loop ran - starting main looop");
}
void loop()
{
static unsigned long ts; // om de huidige tijd voor pauzes in te bewaren
switch (state)
{
case S_IDLE:
Serial.println(state);
int reading = digitalRead(buttonPin);
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != buttonState) {
buttonState = reading;
if (buttonState == HIGH) {
ledState = !ledState;
state = S_ALARMTRIG;
}
}
}
digitalWrite(ledPin, ledState);
lastButtonState = reading;
break;
case S_LEDON:
Serial.println(state);
digitalWrite(ledPin, HIGH); // schakel LED in
ts = millis(); // noteer de huidige tijd
state = S_WAITON; // ga naar de volgende state
break;
case S_WAITON:
Serial.println(state);
if (millis() > ts + 1000)
{
state = S_LEDOFF;
}
break;
case S_LEDOFF:
digitalWrite(ledPin, LOW); // schakel LED uit
ts = millis(); // noteer de huidige tijd
state = S_WAITOFF;
break;
case S_WAITOFF:
Serial.println(state);
// zodra er 1 seconde verstreken is , ga naar terug naar fase S_LEDON
if (millis() > ts + 1000)
{
state = S_LEDON;
}
break;
case S_TURNOFF:
ledState = LOW;
state = S_IDLE;
break;
case S_ALARMTRIG:
state = S_LEDON;
break;
default:
state = S_IDLE;
break;
}
}
Can anyone clear this up for me? I really don't understand how only the position of the case S_IDLE statement can make a difference in this case...