External Interrupt - need to stop execution or jump to another

Hey boys and girls,

I've an program modelling problem. Imagine there is a loop-function i.e that:

const int PIN_INTERRUPT_0 = 0;
volatile boolean interrupted = false;

void setup()
{
	Serial.begin(115200);
	attachInterrupt(PIN_INTERRUPT_0, onInterrupt0, RISING);
}

void loop()
{
	if (!interrupted)
	{
		//do sth. which takes long time. i.e. one minute delay
		delay(60000);
	}else{
		//i can't do sth. because i was interrupted, so i'm gonna do nothing
	}
}

void onInterrupt0()
{
	interrupted = true;
}

if i press a button while delaying the 60 seconds the code is interrupted. but after the interrupt event the delayfunction will finish. is there a possibility to immediately stop the execution of the program, where the interrupt event occured? for example i want to change a program state by an interrupt and stop current execution and jump to the beginning of the loop function, where an decision is done. something like this:

const int PIN_INTERRUPT_0 = 0;
volatile int state = 1;

void setup()
{
	Serial.begin(115200);
	attachInterrupt(PIN_INTERRUPT_0, onInterrupt0, RISING);
}

void loop()
{
	switch(state){
		case 1:
			//do more or less complex jobs for state 1
			break;
		case 2:
			//do more or less complex jobs for state 2
			break;
		case 3:
			//do more or less complex jobs for state 3
			break;
	}
}

void onInterrupt0()
{
	//switch to another state, i.e.
	state = 3;
	//an now the current task should stop and the program should jump to the bginning of loop
}

i need this interrupt approach. It is important, because it should act like a kill switch, for stopping motors. any ideas

Given that you have to poll the "interrupted" flag anyway I see little difference between using an interrupt and just polling a pin.

If you seriously need to kill the machine on a button press the actual ISR should halt the processor, maybe with a while(1) after cleaning up any mess.


Rob

thanks, finally i don't want to use an interrupt where i could use polling a pin. this first snippet is only for demonstrate my problem by focusing on the interruption while the delay-function (placeholder for other processor load) is executed. your second answer is ittle more helpful idea. but the problem is, if i hang the processor by using infinite while loop inside the ISR makes my arduino program dead. That isn't what i want to do, because i've to communicate with a computer for inform it about my emergency state and change the arduino program state. but i don't know how to accomplish that without executing the program at the last execution point.
any other suggestions?

communicate with a computer for inform it about my emergency state and change the arduino program state

==

after cleaning up any mess.

You don't have to hang after that, you can return to where you came from but such error recovery is not easy to get right.

You can do anything in an ISR that you can do outside it, generally we say "keep it short" but in this case the crap has hit the fan and you don't care if millis() counts properly or anything. You have full control, do what you gotta do. That said you won't be able to use some of the Arduino functions, for example Serial.print(), unless you re-enable interrupts and if you do that you better make sure the system is stable before you do. You can still use the UART, just write a polled version, so you can tell the host PC what's happening, clean up stuff etc.

The hard part is returning, where do you return to? Presumably not back to what was running at the time. Things like goto and longjmp are used for error recovery, so you could goto a known location but that will leave a stack frame on the stack, one or two won't do any harm but this is a memory leak. If you know your assembly language you could clean up the stack before the goto.

Longjmp is similar, I can't remember but I think it will have the same stack issue.

Another possibility is to set a flag in EEPROM and reset yourself with the watchdog timer or a jmp(0); (yes I know that's not a real reset, but it's often all you need), then in setup() you test that flag and act accordingly.

Real error recovery is not easy.

At this point I have to ask what the application is, if it's just to stop your 1kg robot from knocking over the furniture that's one thing, if it's for a 10-tonne industrial people-carrying machine that's quite another and this forum is not a suitable venue to be getting ideas from :slight_smile:


Rob

Thanks for your extensive answer.
First of all - no - the project is not based on dangerous huge machines which could injure human, plants or animals. The Safety is needed for pieces of hardware.
Well, i'm interested in your second approach:

Another possibility is to set a flag in EEPROM and reset yourself with the watchdog timer or a jmp(0); (yes I know that's not a real reset, but it's often all you need), then in setup() you test that flag and act accordingly.

Does that cause memory leaks too? would it be possible that you could provide a small snippet with comments? based on your idea Ive another idea, too. inside ISR i could set an EEPROM flag, which is interpretetd on arduino startup, "cleaning up any mess" and than hardware-reset the arduino (connect digout pin and reset pin). what do you think is the cleaner approach?

best albrecht

You can't use interrupts in this way! It's not what they are intended for. Any attempt to "jump" out if the ISR will scramble your program. Learn to do things correctly - see blinkwithout delay.

Mark

by which way your suggestion (BlnikWithoutDelay sketch) is helpful? tell me a way of reacting anytime regardless the used current execution constructs without interrupts. polling is no solution, if i use while-loops or delay-functions. i cant model any scenario with the approch from the example sketch. would I be mistaken in expecting this?

i've found a very useful link which describes possibilities for resetting the arduino. i think two of them are the equivalent, of what Graynomad meant. http://www.xappsoftware.com/wordpress/2013/06/24/three-ways-to-reset-an-arduino-board-by-code/

The point is - forget interrupts, and forget about resetting. It is a very common "newbie" mistake to imagine that "interrupts" have a purpose to "interrupt" the execution of your main program. Absolutely not the case!

Just write proper code! Proper code solves everything. Proper code retains control within the main program "loop".

If there is an event of importance, then part of the main "loop" is checking for it and taking the appropriate action.

What is important, is to code things in the loop so that none of them ever delays. You need to start by writing code to perform the individual parts of your task within the"loop" framework. This means you do not use the "delay()" function, nor do you ever use a "while" loop. Every action must complete (almost) immediately and proceed through the "loop". All "waits" are implemented by time comparisons in the general manner of the oft-cited "Blink without Delay" example.

Once you have the pieces working, they simply cascade within the loop, one after another. Since nothing unduly delays the constant circulation of the loop, the part which polls for your critical event is executed frequently, (hundreds of times per second) and able to take the necessary action.

Look at what is written in blink without delay

Is says :-
if the led is on and its time to turn it off do so
if the led is off and its time to turn it on do so

What we have are a number of short simple slices of code. The slices of code should avoid any blocking function. You simply combine the concept of the thin slice with one or more FSM's and you can buildup any program you need.

Mark

I recently wrote a demo sketch to show a more advanced use of the blink without delay concept to control several things at the same time. It includes reading a button in a way that could easily be modified to stop your process.

http://forum.arduino.cc/index.php?topic=223286.0

...R

my first intention was to write only a few lines. i wanted keep it simple at all costs.
but you collectively say that the polling approach is the proper way.
So i will reconsider my kill-the-program-approach an dive into the magic of doing it the correct way :slight_smile:

thanks for your qualified answers.

albrecht

thanks for reply....
i am dealing with 5v max not more than that...
what is polling by the way!!!

kazmi:
thanks for reply....
i am dealing with 5v max not more than that...
what is polling by the way!!!

Have you posted this in the wrong Thread?

"Polling" is when the program regularly checks the value of something. Imagine looking at the clock every few minutes so you will know when it is 6pm.

In contrast, if you use an interrupt the program continues doing other stuff unless an "interrupt" interrupts it. Imagine having someone else tap you on the shoulder when it is 6pm.

...R

i wanted keep it simple at all costs

The words "interrupt" and "simple" don't often sit easily in close proximity.

AWOL:
The words "interrupt" and "simple" don't often sit easily in close proximity.

Words of wisdom.

...R

I'm paraphrasing a book I first read in the late 1970s.
I'd love to see the original quote again, but it went something like "Interrupts are difficult and dangerous; their use by beginners is to be discouraged"

Robin2:

kazmi:
thanks for reply....
i am dealing with 5v max not more than that...
what is polling by the way!!!

Have you posted this in the wrong Thread?

Clearly, he had!

Robin2:
"Polling" is when the program regularly checks the value of something. Imagine looking at the clock every few minutes so you will know when it is 6pm.

In contrast, if you use an interrupt the program continues doing other stuff unless an "interrupt" interrupts it. Imagine having someone else tap you on the shoulder when it is 6pm.

Or setting an alarm. It is much more difficult to ignore an alarm, than a tap on the shoulder. :wink:

The problem with this comparison, is that it suggests to people that it is tedious to repeatedly look at the clock. In microprocessor terms, it is anything but - the microprocessor spends the majority of the time literally "twiddling its thumbs", its ability to execute millions of operations per second means that you are mostly looking for extra tasks in order to keep it occupied.

If power consumption is a concern, you can put it to "sleep" and use an interrupt to wake it again, but in fact even for this there is no need for it to perform an interrupt service routine; the interrupt need only cause it to resume after the sleep instruction.

Paul__B:
The problem with this comparison, is that it suggests to people that it is tedious to repeatedly look at the clock.

I guess I had in mind a program (written using Blink Without Delay concepts!) that was doing stuff and had to "disturb itself" to do the polling in the same way that glancing at a clock disturbs you if you are reading a book.

Many newbies seem to have a problem grasping how polling can be integrated into a program.

...R

Robin2:
I had in mind a program ... had to "disturb itself" to do the polling in the same way that glancing at a clock disturbs you if you are reading a book.

But of course, if you are reading a book (or in my case, playing Spider), you simply don't look at the clock! XD

(Except at the end of the game/ book/ chapter maybe.)