Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple Arduino Interrupts on same pin

In the following code, why does ISR2 never run?

const int in = 19;
const int LED = 9;
int flag;
void setup() {
    pinMode(in, INPUT_PULLUP);
    pinMode(LED, OUTPUT);
    attachInterrupt(digitalPinToInterrupt(in), ISR2, RISING);
    attachInterrupt(digitalPinToInterrupt(in), ISR1, FALLING);

}
void  loop() {
    if (flag) {delay (100); flag = false;}// debounce
}
void ISR1(){
    digitalWrite(LED, LOW);
    // Turn Off the motor, since, Limit Switch was engaged
    flag = true;
}
void ISR2(){ // Limit Switch was disengaged. 
    digitalWrite(LED, HIGH);
    delay(100); // Debounce, so I do not receive spurious FALLING edges from this.
}

Does the Arduino not allow you to attach two interrupts on the same pin even if the interrupts are programmed for different events?

In my setup, pin 19 gets a signal from a limit switch used in a motion control setup. When the limit switch is engaged, the in pin gets LOW signal. Thus, I first see a FALLING edge followed by RISING edges and FALLING edges due to mechanical bounce. I handle the debouncing correctly in this case.

However, imagine the Limit Switch was sitting in engaged state for a while, and then I reverse the motor causing the Limit Switch to disengage, this will send a RISING edge followed by FALLING and RISING edges. I need to ignore these edges since nothing is in danger. The ISR2 was written with purpose of capturing the first RISING edge when the Limit switch disengages, and then debouncing it so that the following FALLING edges are ignored. But now that ISR2 never gets called, how can I deal with this situation?

P.S. My microcontroller is ATMEGA 2650, It's a Arduino Mega board.

like image 899
The Vivandiere Avatar asked Dec 18 '22 22:12

The Vivandiere


2 Answers

ISR2 never runs because there can be only one interrupt service routine for any interrupt source and you have replaced ISR2 with ISR1 as the sercice routine for this interrupt. If you reordered your code and attached ISR1 before ISR2 then you might see ISR2 run but not ISR1.

A typical microcontroller has an interrupt vector table that associates an interrupt service routine with each interrupt source. There can be only one service routine for each interrupt source. If you assign an new service routine then you're replacing the old service routine. There are not separate service routines for the rising and falling edges. Rising versus falling edge is a configuration setting for the interrupt source to determine when that interrupt should fire. The interrupt source cannot be configured to fire on both edges simultaneously.

However you may be able to reconfigure the interrupt for the other edge after you have received the interrupt for the first edge and debounced the transition. This way your code will ping-pong back and forth configuring for one ISR and then the other.

like image 141
kkrambo Avatar answered Jan 29 '23 05:01

kkrambo


Why are you saying that it never gets called? I think that it is called, but you don't notice it because the led does not change its state (because there are bounces).

Anyway, you are NOT debouncing it correctly. Let's do an example: you hit the endstop. ISR1 gets called, so flag is true. Ok, at next loop the motor will be stopped. But... Now the switch bounces. ISR2 gets called, and the delay function in it waits for 100ms before exiting the ISR. Result: you delayed the motor stop function by 100ms.

I suggest you to read my answer here, particularly the second case. And I suggest you to use my code instead of yours, since this way you will be able to IMMEDIATELY stop the motor, without bounces nor any other kind of problems.

like image 22
frarugi87 Avatar answered Jan 29 '23 03:01

frarugi87