As a first project I plan on making a teensyduino ambient light with different light modes, which are checked in a big switch statement – now I want to switch from one mode to another by pressing a button.
googling lead me to using interrupts, but there is one point that is not clear – if I press the button during an expensive function, which takes long time and has many variables in use, what happens if i call the main loop from the interrupt, does the remaining state of remain in the ram and leads to a stackoverflow if I do switch too many times or is it cleared.
Here some code:
const int speed = 30 //milliseconds
const int modes = 11; //maximum number of modes
const int red = 15;
const int green = 14;
const int blue = 12;
volatile int mode = 0;
void setup() {
pinMode(red , OUTPUT);
pinMode(green , OUTPUT);
pinMode(blue , OUTPUT);
randomSeed(analogRead(0));
Serial.begin(9600);
attachInterrupt(0,incMode,CHANGE); // 0 -> digital pin 2
}
void loop() {
switch(mode){
case 0:{
Serial.println("powerdown");
setAll(0);
delay(1000);
break;
}
\\...
case modes:{
\\ expensive long function
}
}
}
void blinkAll(int times){
for(int i=1;i <= times;i++){
setAll(255);
delay(speed*17);
setAll(0);
delay(speed*17);
}
}
void setAll(int bright){
analogWrite(red , bright);
analogWrite(green , bright);
analogWrite(blue , bright);
}
void incMode(){
delay(speed);
blinkAll(2); //to indicate mode has changed
mode = (mode+1) % (modes+1); //switch starts with 0 so use "% modes+1"!
Serial.println("mode increased");
//--> loop();
//--> would resume the main loop but lead to a stackoverflow i presume
}
How would I break out of the running function without delay and stack pollution.
I know I could just set the mode and wait until the function has ended, but if I have a mode that takes minutes to end I want to be able to switch from it immediately.
PS.: Though I am using a teensyduino, I will use the arduino tag, and as I don’t know what language the arduinio uses the tags c/c++. Please change this if it is not appropriate.
You would eventually overflow the stack if you were to reenter main from the interrupt handler multiple times recursively. Additionally, since you’ll still be in the interrupt handler as far as the hardware is concerned, you’ll have all kinds of weirdness – in particular, interrupts are blocked when you’re already in an interrupt, which means
delay()won’t work andmillis()won’t count up, and various other things will be broken as well unless you figure out some way to manually re-enable interrupts.A better way to solve this would be to make your ‘expensive long function’ instead be a state machine driven by a cheap, short function that is called very frequently. Your interrupt handler can then simply set a flag that is checked on entry into this function, at which point the current mode (ie, current state machine) is changed.
This approach also makes it easier to define new lighting modes. For example, you could define something like this:
Now to define a new lighting mode you just need a new array of colors and times, rather than writing new code. Adding things like color ramps and other such effects is left as an exercise to the reader.