I have used attachInterrupt()
to reset my program to the beginning. It actually interrupts while running the 3 states as shown below inside of the if
statement but when I press the actual button it does not exit, it goes to the function and continuing to the next state. It only works (means exiting/resetting) after all three states have executed completely.
if(buttoncount<2){
originalstate();
alertstate();
evacuationstate();
I would like to make a button to stop the program while running in the middle and start again.
Code:
// Declaring pins
// Input pins
const int sensor1button_pin = 6;
const int sensor2button_pin = 3;
const int sensor3button_pin = 4;
const int sensor4button_pin = 5;
const int sensor5button_pin = 2;
const int sensor6button_pin = 15;
const int sensor7button_pin = 15;
// Output pins
const int led1_pin = 8;
const int led2_pin = 9;
const int led3_pin = 10;
const int led4_pin = 11;
const int buzzerpin = 15;
// Initialy buzzer at false mode
boolean flag1;
boolean flag2;
int flag3 ;
// for leds
int ledState1 = LOW; // Original
int ledState2 = LOW; // Alert
int ledState3 = LOW; // Evacuate
int ledState4 = LOW; // Isolate
// Buttons
int button1_state = LOW;
int button2_state = LOW;
int button3_state = LOW;
int button4_state = LOW;
int button6_state = LOW;
int button7_state = LOW;
int button5_state = LOW;
// Other variables
int buttoncount = 0;
int reset_switch=0;
void setup() {
// INPUT pins
pinMode(sensor1button_pin, INPUT);
pinMode(sensor2button_pin, INPUT);
pinMode(sensor3button_pin, INPUT);
pinMode(sensor4button_pin, INPUT);
pinMode(sensor5button_pin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(sensor5button_pin), clearreset, CHANGE);
pinMode(sensor6button_pin, INPUT);
pinMode(sensor7button_pin, INPUT);
// OUTPUT pins
pinMode(buzzerpin, OUTPUT);
pinMode(led1_pin, OUTPUT);
pinMode(led2_pin, OUTPUT);
pinMode(led3_pin, OUTPUT);
pinMode(led4_pin, OUTPUT);
Serial.begin(9600);
}
void loop() {
button1_state = digitalRead (sensor1button_pin);
button2_state = digitalRead (sensor2button_pin);
button3_state = digitalRead (sensor3button_pin);
button4_state = digitalRead (sensor4button_pin);
button5_state = digitalRead (sensor5button_pin);
button6_state = digitalRead (sensor6button_pin);
button7_state = digitalRead (sensor7button_pin);
Serial.println(digitalRead (sensor5button_pin));
if( button1_state == HIGH || button2_state == HIGH || button3_state == HIGH || button4_state == HIGH) {
delay(280);
buttoncount = buttoncount + 1;
}
if (button1_state == HIGH || button2_state == HIGH || button3_state == HIGH || button4_state == HIGH) {
if(buttoncount<2){
originalstate();
alertstate();
evacuationstate();
}
}
}
// LED lighting arrangements
void originalstate() {
digitalWrite(led1_pin, HIGH);
digitalWrite(led2_pin, LOW);
digitalWrite(led3_pin, LOW);
digitalWrite(led4_pin, LOW);
delay(1500);
}
void alertstate() {
digitalWrite(led1_pin, LOW);
digitalWrite(led2_pin, HIGH);
digitalWrite(led3_pin, LOW);
digitalWrite(led4_pin, LOW);
delay(1500);
}
void evacuationstate() {
digitalWrite(led1_pin, LOW);
digitalWrite(led2_pin, LOW);
digitalWrite(led3_pin, HIGH);
digitalWrite(led4_pin, LOW);
delay(1500);
}
void isolatestate() {
digitalWrite(led1_pin, LOW);
digitalWrite(led2_pin, LOW);
digitalWrite(led3_pin, LOW);
digitalWrite(led4_pin, HIGH);
}
// Clear or reset back to the begin
void clearreset() {
button1_state = LOW;
button2_state = LOW;
button3_state = LOW;
button4_state = LOW;
button5_state = LOW;
button6_state = LOW;
button7_state = LOW;
digitalWrite(led1_pin, LOW);
digitalWrite(led2_pin, LOW);
digitalWrite(led3_pin, LOW);
buttoncount = 0;
exit;
}
3 Answers 3
You need non-blocking code in combination with a finite state machine:
1. Non-blocking code: You should not use delay()
, since it is just busy waiting. Instead use the millis()
function to measure the time distance between the last execution of the code part and the current time. If it has reached a certain level (like 1500ms), execute the code and save the current time in a timestamp as a reference for the next execution. Refer to the BlinkWithoutDelay
example of the Arduino IDE. There are also many tutorials for that on the internet, so I will not explain this further here.
2. Finite state machine: Here your loop()
function contains of a switch
statement with a (mostly numerical) state variable as parameter. Every case contains only the code for its special case. To get from one state to another you would just change the state variable to the corresponding value. You can also do this in an ISR (if you set the state variable as volatile
). If you non-blocking code as described above, the loop()
function is executed very fast, so that the change of the state variable inside the ISR takes effect almost immediately (delay will not be sensable by a human). Something like this:
volatile int state=0;
void isr_function(){
state++;
if(state>1) state=0;
}
void loop(){
switch(state){
case 0: // state 0
do_something();
break;
case 1: // state 1
do_another_thing();
break;
}
}
Note: Depending in your target you may want to add code for button debouncing, so that one button press is really sensed as one press, not more. This is relevant most times you have non-blocking code. Debouncing has been described many times in the internet, so just Google it
You should enable verbose compilation in the IDE. You will then have a chance to see this compiler warning:
warning: statement is a reference, not call, to function ‘exit’
exit;
^
warning: statement has no effect
Naming a function without calling it is a way to get a pointer to the
function. It's equivalent to &exit
. But since you do nothing with that
pointer, the statement has no effect, and that's exactly what the
compiler is warning you about.
You presumably want to call the exit()
function, like in:
exit(0);
Edit: That being said, exit()
is probably not what you want.
This function just stops your program by putting it in an infinite loop.
If you want it to restart from scratch, you can first declare
extern "C" void __init();
then, instead of exit(0);
call __init();
. This will send your
program to the beginning of the initialization code from the C runtime,
which is responsible of resetting the stack and initializing the memory
(.data and .bss sections). Note that this is not equivalent to a
hardware reset because:
- doing this does not run the bootloader
- more importantly, it doesn't reset the IO registers of the peripherals to their default reset state.
... .any way, I can interrupt the program while running and change to any other function of the program. such as when we press the reset button it goes to reset, if we press a push button it goes to some any other function.
Interrupt will not help you achieve your requirement. You want to 'reset the state' of your running sketch. But after the interrupt the MCU returns in the code where it was before interrupt and continues.
You should implement the 'reset of the state' in your algorithm. In a loop of a non-blocking sketch you can check the button and if it is pressed, then 'reset the state' of the sketch.
-
Did you read my answer?
__init()
completely resets the state of the program. There is no "after the interrupt": since__init()
does not return, the followingreti
(return from interrupt) instruction will never be executed. And there is no "state where it was before interrupt": that state was on the stack, and the stack is reset by__init()
.Edgar Bonet– Edgar Bonet2018年05月25日 12:47:25 +00:00Commented May 25, 2018 at 12:47 -
@EdgarBonet, I did read your answer and it is correct. I answer other point of view, not what he coded, but what he wants to achieve (second comment). He doesn't want to reset the program, only the 'state of the program'.2018年05月25日 12:53:01 +00:00Commented May 25, 2018 at 12:53
-
Then you should clarify your answer, say that you are proposing a different approach (the OP specifically asked to "stop the program [...] and start again"), adjust the wording accordingly ("must" → "should"), tell if/how the proposed approach is better, and maybe explain how resetting the "state of the program" (whatever you mean by that) is different from resetting the program itself.Edgar Bonet– Edgar Bonet2018年05月25日 13:43:10 +00:00Commented May 25, 2018 at 13:43
set
aflag
variable in the interrupt service function ... check the flag at the beginning of each state function and skipdigitalWrite()
anddelay()
commands if the flag is setstate
variable and call the state functions depending on its value .... use the interrupt to set the state variable to a specific valueif
statements one after another .... merge the contents into one