interrupt question

const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// variables will change:
volatile int buttonState = 0;         // variable for reading the pushbutton status

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
  // Attach an interrupt to the ISR vector
  attachInterrupt(0, pin_ISR, CHANGE);
}

void loop() {
  // Nothing here!
}

void pin_ISR() {
  buttonState = digitalRead(buttonPin);
  digitalWrite(ledPin, buttonState);
}

from what i can understand from this code it runs the function pin_ISR() when ever the button is pressed. but what does it do after that? does it start over from the top of the main loop or how does it continue? if i where to have some code running in the main loop and the intterupt was triggered would it just continue from the last point or would it start over?

i need the functionality where whenever someone lets go of a button it stops and start again from the beginning of the code.

Please look up interrupts on google. I don't want to begin to type what's already widely available.

You could go to the 3rd address in my sig space just below this message. It's a tutorial on the subject.

A human operated pushbutton switch is not an appropriate use of an interrupt (unless said human can press and release the button in less than a millisecond).

The planning and implementing a program tutorial shows how to organize your code into functions. When the button becomes pressed call the function that does something. When that function finishes it calls the begin again function.

groundFungus: A human operated pushbutton switch is not an appropriate use of an interrupt (unless said human can press and release the button in less than a millisecond).

The planning and implementing a program tutorial shows how to organize your code into functions. When the button becomes pressed call the function that does something. When that function finishes it calls the begin again function.

it needs to trigger on release so thats not a problem :)

GoForSmoke: Please look up interrupts on google. I don't want to begin to type what's already widely available.

You could go to the 3rd address in my sig space just below this message. It's a tutorial on the subject.

Im sorry to disturb you.

In your interrupt program, the following events occur when an IRQ-signal (interrupt request) is placed to the MCU via DPin-2 (INT0):

1. Having finished all the necessary initialization tasks in the setup function, the MCU enters into loop() function, and it is looping/waiting to receive an IRQ-signal. The loop() function could be taken as the Main Line Program (MLP) which the MCU is executing though there is nothing to execute except waiting.

2. When IRQ-signal arrives, the MCU enters into ISR, finishes the ISR, and then resumes the MLP from the label where it was interrupted. Let us assume that the loop() function contains the following instructions:

ML1: digitalWrite(13, HIGH);
ML2: delay(1000);
ML3: digitalwrite(13, LOW);
ML4: delay(1000);

Let us assume that the IRQ-signal arrived when the MCU was just executing instruction at label ML3. After finishing the ISR, the MCU will resume MLP execution from label ML4. This is the picture from high level point of view; the actual low level picture is a little bit different.

3. If you want that the MCU should resume MLP execution from top of loop() function (at label ML1), you have to manipulate the stack space to force the MCU to take ML1 as the return address rather than ML4. Manipulation of stack is easy when programming in assembly; but, I have no idea how difficlt it would be in high level environment.

GolamMostafa: 3. If you want that the MCU should resume MLP execution from top of loop() function (at label ML1), you have to manipulate the stack space to force the MCU to take ML1 as the return address rather than ML4. Manipulation of stack is easy when programming in assembly; but, I have no idea how difficlt it would be in high level environment.

That’s ridiculous. If you want the non-ISR code to do something different based on conditions detected in the ISR, then you set a flag which will be picked up by the main code. The main code should monitor the flag on every pass through loop() and act accordingly.

The flag needs to be of at least file-global scope and declared volatile.

Dennild: Im sorry to disturb you.

I'm sorry I tried to help you, I won't make that mistake again.

GolamMostafa: In your interrupt program, .....

This is too complicated - and I agree with @gfvalvo

Advice should ALWAYS be tailored to the level of knowledge and experience of the student.

...R

This is too complicated - and I agree with @gfvalvo

Advice should ALWAYS be tailored to the level of knowledge and experience of the student.

This is the beauty of the Forum that poster, reader, and critics are found together under the umbrella of a Moderator.

GolamMostafa: 3. If you want that the MCU should resume MLP execution from top of loop() function (at label ML1), you have to manipulate the stack space to force the MCU to take ML1 as the return address rather than ML4.

GolamMostafa: This is the beauty of the Forum that poster, reader, and critics are found together under the umbrella of a Moderator.

Yup. And this moderator is here to say that @gfvalvo and @Robin2 are wrong. "That's ridiculous" and "This is too complicated" are not even close to the core problem of your proposal. What you describe is guaranteed to corrupt the state of the application. Please do not dispense that suggestion again.

GolamMostafa: 2. When IRQ-signal arrives, the MCU enters into ISR, finishes the ISR, and then resumes the MLP from the label where it was interrupted. Let us assume that the loop() function contains the following instructions:

ML1: digitalWrite(13, HIGH);
ML2: delay(1000);
ML3: digitalwrite(13, LOW);
ML4: delay(1000);

Let us assume that the IRQ-signal arrived when the MCU was just executing instruction at label ML3. After finishing the ISR, the MCU will resume MLP execution from label ML4. This is the picture from high level point of view; the actual low level picture is a little bit different.

This is false, right? First, these are no single cycle instruction. And second, if it was inside digitalWrite, after the ISR it would continu inside digitalWrite and not go to ML4. At least this is what I thought was happening. If the interrupt happens, the programs stops, goes to the interrupt handler, executes and goes back to the program counter

Speklap:
This is false, right? First, these are no single cycle instruction. And second, if it was inside digitalWrite, after the ISR it would continu inside digitalWrite and not go to ML4.
At least this is what I thought was happening. If the interrupt happens, the programs stops, goes to the interrupt handler, executes and goes back to the program counter

You are pretty well correct.

Interrupts take place at the level of machine code instructions and implementing something like digitalWrite() needs a lot of machine code instructions. When an interrupt occurs the current machine code instruction completes and the ISR is called. When the ISR completes it returns control the next machine code instruction in the code that was being implemented - i.e.back to where the program counter had been when the ISR was called.

As you correctly surmise the ISR may well be called while the code is only part-way through the digitalWrite() function, and it will return and complete the function.

It is probably nit-picking on my part, but the program counter will also have been used in the execution of the code in the ISR so, technically, it does not go “back to the program counter”

…R

Yeah, indeed. Made that post a bit too quick. I thought he was wrong, but wanted confirmation since it wasn’t edited.

Should’ve added that after the interrupt occurence, the program counter gets placed on the stack and the ISR address gets loaded. Or just omitted that part.

After the interrupt occurrence the pushed registers are restored. But when you screw with the system at that level during the interrupt it makes the use of goto look smart.

OP, that half-baked road apple is a good route to a buggy mess that will have cross-effects as an added layer of unknowns to guess at what to try changing next.

GoForSmoke: After the interrupt occurrence the pushed registers are restored. But when you screw with the system at that level during the interrupt it makes the use of goto look smart.

OP, that half-baked road apple is a good route to a buggy mess that will have cross-effects as an added layer of unknowns to guess at what to try changing next.

Probably, so i will need to find a better solution for this, which is fine which is the reason i asked since i had no idea how it worked, Even from reading from the web page in your signature, which i did before i made the first post. I wasn't sure how they worked and therefor i asked here.

Does anyone have another idea then how to do this?

The code is gonna be used as control for water bottle rocket ramp . but due to safety reasons i need 2 buttons to be pressed for a certain amount of time and if those 2 buttons where to be released i need it to stop the firing sequence and start over when the buttons a pressed again. Also the idea was to have sound feedback while the buttons are pressed. like a bomb going off "- - - - -- -- -- --- ---- ---- -----------fires!" i have made it analog with logic gates and a binary counter but it takes to much space and if i decide to change the sound pattern i have to remake most if it every time.

i know how to do basic programming but i have no idea how to break out of a loop when one of the buttons are released and i thought that if i had the interrupt trigger on the button input that would be the best way to do so.

i need 2 buttons to be pressed for a certain amount of time and if those 2 buttons where to be released i need it to stop the firing sequence and start over when the buttons a pressed again.

Sounds like a state machine with 5 states

state 0 : system idle. Change to state 1 if button 1 becomes pressed or state 2 if button 2 becomes pressed

state 1 : only button 1 is pressed. Change to state 3 if button 2 becomes pressed. Change to state 0 if button 1 becomes released

state 2 : only button 2 is pressed. Change to state 3 if button 1 becomes pressed. Change to state 0 if button 2 becomes released

state 3 : countdown. Change to state 0 if either button becomes released. Time countdown using millis(). Change to state 4 when countdown ends

state 4 : Fire. Activate the rocket

Dennild: but due to safety reasons i need 2 buttons to be pressed for a certain amount of time and if those 2 buttons where to be released i need it to stop the firing sequence and start over

That sort of thing is straightforward with code something like this

buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) { // assumes HIGH = released
   startMillis = millis();    // restart the timer
}
if (millis() - startMillis >= safetyTime) {
   // button has been held continuously so do the stuff
}

...R

Dennild: from what i can understand from this code it runs the function pin_ISR() when ever the button is pressed. but what does it do after that? does it start over from the top of the main loop or how does it continue?

Your loop function is interrupted by the ISR. When the ISR terminates, the loop resumes doing whatever it was doing at the time.

So, if your loop is printing the values 1-1000 and the ISR gets triggered just as it is about to call Serial.print(67), the ISR runs, returns, and then the loop continues on and prints 67.

From the loop()'s point of view, the ISR calls happen invisibly and can happen at any time. You use volatile variables (usually) to communicate between the two.

Dennild: i know how to do basic programming but i have no idea how to break out of a loop when one of the buttons are released and i thought that if i had the interrupt trigger on the button input that would be the best way to do so.

The way to do that takes an approach that is not taught in standard beginner-intermediate courses.

It's just a different way that Arduino setup() and loop() make natural.

Whatever is inside of loop() runs over and over.

So you put a block of code in loop() to watch a button or buttons that updates a global variable when a button is pressed. It always runs with loop. It does not wait for the sketch to need to see a button press, it just runs.

And you put in another block of code that watches button status and acts when a button is indicated to have changed up/down.

All the blocks you put in get to run even if just to see whatever trigger they have has not been pulled. It is "event-driven code".

If you have no delays or blocking code, your void loop() can run 10's of times per milli. I am not joking, I've done examples doing as much as you've indicated that run at over 67000Hz on average. I know this because one block/task is a loop() counter that prints every second.

This works by the blocks using variables to control code execution instead of everything controlled through code structures. It allows breaking the job into tasks that "run concurrent" so quickly it's smooth.

You get multiple programs running at once with communications between, but only do as much as you write.

GoForSmoke: The way to do that takes an approach that is not taught in standard beginner-intermediate courses.

It's just a different way that Arduino setup() and loop() make natural.

Whatever is inside of loop() runs over and over.

So you put a block of code in loop() to watch a button or buttons that updates a global variable when a button is pressed. It always runs with loop. It does not wait for the sketch to need to see a button press, it just runs.

And you put in another block of code that watches button status and acts when a button is indicated to have changed up/down.

All the blocks you put in get to run even if just to see whatever trigger they have has not been pulled. It is "event-driven code".

If you have no delays or blocking code, your void loop() can run 10's of times per milli. I am not joking, I've done examples doing as much as you've indicated that run at over 67000Hz on average. I know this because one block/task is a loop() counter that prints every second.

This works by the blocks using variables to control code execution instead of everything controlled through code structures. It allows breaking the job into tasks that "run concurrent" so quickly it's smooth.

You get multiple programs running at once with communications between, but only do as much as you write.

thank you for that explanation it seems i have and idea of what todo now :)