Hi,
I understand that when a function is called via its attached interrupt, the program will continue exactly where it left off after the interrupt function is completed. But what if I want the program to just go back to the beginning of loop() instead?
Lets say for example a function called MyInterrupt() is attached to an interrupt.... While another random function, lets call it My RandomFunction() is running, the user triggers MyInterrupt(). Normally the program would jump right back into MyRandomFunction() where it left off when the user triggered the interrupt. What if I wanted the program to break out of that function and instead just return back to the beginning of loop() after the interrupt was triggered?
Well, you can't. The interrupt function will return to the place where it was called from.
One thing you can do, is have the interrupt function set a flag ( which must be declared volatile ), and then check the status of that flag in the other function, which will tell you if an interrupt has just occured, and then you can do whatever you like if the flag is set, including aborting the current iteration of loop( ), which you can do with a return statement.
The other thing you could do, is set up some scheme so that the interrupt routine can figure out exactly where is was called from, and delete some information from the stack, and then make a jump using machine language to a particular location in the program. But I really don't recommend this unless you know exactly what you are doing.
moses1592:
What if I wanted the program to break out of that function and instead just return back to the beginning of loop() after the interrupt was triggered?
Then an interrupt is probably not what you need. Most likely, the reason you think you need an interrupt is because you have not designed the sketch so that it can handle multiple things at once (such as respond to a button press while it is in the middle of some other sequence of actions). If you explain what your underlying objective is, perhaps somebody can suggest the most sensible way to implement it.
As peterH says this normal a problem with the design. Start by looking at blink without delay and at finite state machines in the playground.
Mark
The reason I wanted to don this is because, in my example above, the MyRandomFunction() already uses a millis() timer loop... Everything within that function is nested in the timer loop. Where it becomes a bit tricky is, the main timer loop is there to make sure all inputs are idle for three minutes, and if so, triggers another timer within the initial loop that pulses a relay on for 250mils, then off for 3000mils, and does this ten times. This sequence of ten pulses on that relay happens only once when MyRandomFunction() is called and inputs are idle for 3 minutes. If things get this far with all inputs still remaining idle and three more minutes pass, then every 5 minutes until an input is detected, the program pulses a different relay on and off for 200mils, thirty times, waits another 2 minutes, then repeats those 200mils pulses on that relay indefinitely every two minutes until an input is detected. This sound very confusing to type, but its actually very easy to code using one main millis() timer and embedded delay()'s inside. I know this can all be done through nesting millis() while loops and omitting delay()'s but code will be much more complex. Furthermore, at any point in any of this mess, whenever an input is detected, the program needs to detected it, exit MyRandomFunction() and start in loop() again. The problem is that if an input is triggered by the user while the code hangs on one of the many delay()'s, it wont be detected unless Its thru an interrupt. If I could make the interrupt's function return to loop() then all would be fine, but since that's not possible I guess I'm going to have to re-code with nested millis() timers and omit all of the delay()'s.
BTW, this code is controlling a pinball machine. If a game is started and the player walks away and the machine is idle for three minutes, the code uses a relay to trigger the end-of-ball switch several times to put the pinball machine in game-over mode. Furthermore, I added additional flasher-bulb circuits, and general illumination lighting and controlled by the arduino. To add to that, the arduino controls all four solenoids in the machine, disables them in game-over mode, and enters 'attract mode' when idle for 6 minutes, where it will systematically pulse the flasher bulb circuit and GI lighting, and is responsible for triggering (via a relay), the start game switch on the machines internal driver board. All of this works perfectly except for the 'attract mode' code, which I am trying to code now.
So loop() looks something like (pseudo code).
void loop(){
if (no inputs for 3mins or more){
machineIdle();
} else {
machineIsIdle = false;
gameOn();
}
}
void machineIdle(){
If (machineIsIdle == false){
machineIsIdle = true;
idleState=0; // the 3 mins of idle time are up
}
switch/case to implement the state machine
}
I will leave filling out the rest to you. But I'd look at another state machine for the game play (may be more than one). Don't use delay or anything like it any where in the code. Use the timing method shown in blink with out delay.
Mark
I guess I'm going to have to re-code with nested millis() timers and omit all of the delay()'s.
Yep. Which is why we advise not using delay() in the first place.
moses1592:
This sound very confusing to type, but its actually very easy to code
Even quite complex behaviour can be achieved quite easily using a simple state machine for each independent thing you want to control. I suspect you will find that you can implement the behaviour you describe just as easily using a non-blocking approach as with your current blocking version.