Using interrupt to detect button being pressed

Using interrupts for a long time, 40 years, but in other environments, I started trying to do it on an UNO.
What I would like to gain is a flag set, in the ISR, when a button input goes from high to low. When loop picks up the flag it will reset the flag and execute a quite time consuming, seconds, task. Debouncing the button is considered not needed.

So faar I've not managed.

//testing interrupt on pin2, Arduino UNO Rev 3
const byte interruptPin = 2;
volatile bool state = LOW;


void setup() {
  pinMode(2, INPUT_PULLUP);
  Serial.begin(115200);
  Serial.println("Started");
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), ISR_button_pressed, LOW);
}

void loop() {

  if (state)//if an interrup has occured
  {
    Serial.print("Interrupt at time "); Serial.println(millis());
    delay(1000);//simulate task executing
    if (digitalRead(interruptPin))//if button is released let ISR set flag.
      state = false;//reset interrupt flag
  }
}



void ISR_button_pressed(void) {
  if (!state)//set flag to low if flag is true
    state = true;//set flag
}

It looks like the statement if (digitalRead(interruptPin)) does not read the ISR button.

A printout from monitor:

started
Interrupt at time 4696  First button press
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 4696
Interrupt at time 5548  Second button press
Interrupt at time 5548
Interrupt at time 5548
Interrupt at time 5548

What am I missing?

Don't you want FALLING mode, not LOW, based on your description?

Also why do you care about the input state after you've registered a high to low transition?

Try this:

//testing interrupt on pin2, Arduino UNO Rev 3
const byte interruptPin = 2;
volatile bool state = LOW;

void setup() 
{
    pinMode( interruptPin, INPUT_PULLUP );
    Serial.begin(115200);
    Serial.flush();
    Serial.println("Started");
    pinMode( interruptPin, INPUT_PULLUP );
    attachInterrupt(digitalPinToInterrupt(interruptPin), ISR_button_pressed, FALLING);
}

void loop() 
{
    if (state)//if an interrup has occured
    {
        Serial.print("Interrupt at time "); Serial.println(millis());
        delay(1000);//simulate task executing
        if (digitalRead(interruptPin))//if button is released let ISR set flag.
        {
            attachInterrupt(digitalPinToInterrupt(interruptPin), ISR_button_pressed, FALLING );
            state = false;//reset interrupt flag
        }
            
    }
}


void ISR_button_pressed(void) 
{
    if (!state)//set flag to low if flag is true
    {
        state = true;//set flag
        detachInterrupt( digitalPinToInterrupt(interruptPin) );
        
    }//if
}

aarg:
Don't you want FALLING mode, not LOW, based on your description?

Also why do you care about the input state after you've registered a high to low transition?
That is a remaining attempt to get the job done.

Thanks a lot! Haha. Late and trying to build a function for a Forum member I only remembered LOW, HIGH and CHANGE. Testing now works fine except for the start, reset. The button input is at PULLUP. An interrupt occurs and millis is printed as 0. If the button is pressed, active low and reset is pressed, no first interrupt arrives.

Why does reading the digital interrupt pin notbgive the state of the pin? Not allowed to read an interrupt pin?

Karma

@Blackfin
Thanks! A little bit more "complicated" but I will give it a checkup tomorrow.

Why does reading the digital interrupt pin notbgive the state of the pin? Not allowed to read an interrupt pin?

Thanks, I'm puzzled on this one. I always thought you could read it... I need to investigate. Maybe something to do with the timing of when you poll it?

But... why would you even want to read it? If the interrupt was triggered by a FALLING edge, you know the input must be LOW! Or... ??

Erik_Baas:
But... why would you even want to read it? If the interrupt was triggered by a FALLING edge, you know the input must be LOW! Or... ??

You only know that a negative flank passed. In case debouncing is needed reading a high is useful, button released. Else "autorepeat" will kick in.

Forget interrupts. No need for them. Use polling via the Bounce2 Library for de-bounce and handle it in loop.

1 Like

If interrupt it must be, you can debounce there, just save the value of millis() on every call, and use it as "previous millis" as in the polling version. The only (well, the main) drawback is that bounces will still trigger the execution of the ISR, so that adds overhead. In the polled version, the bounces can be completely ignored. The only overhead is a time stamp check every time through loop().

gfvalvo:
Forget interrupts. No need for them. Use polling via the Bounce2 Library for de-bounce and handle it in loop.

Not applicable. A time consuming execution has a loop time of several seconds.

aarg:
If interrupt it must be, you can debounce there, just save the value of millis() on every call, and use it as "previous millis" as in the polling version. The only (well, the main) drawback is that bounces will still trigger the execution of the ISR, so that adds overhead. In the polled version, the bounces can be completely ignored. The only overhead is a time stamp check every time through loop().

That sounds as the solution. During my tries the mills() returned the same !value for ever" and that puzzled me and made me hesitate. Never mind.
millis uses certain controller resources, likely a timer, maybe more. Some other day..

I'll use Your reply and test!

Railroader:
Not applicable. A time consuming execution has a loop time of several seconds.

That's a design problem in the loop itself.

And, your original post said "When loop picks up the flag..." So, there's no difference between running polling through Bounce2 and "picking up the flag".

gfvalvo:
That's a design problem in the loop itself.

And, your original post said "When loop picks up the flag..." So, there's no difference between running polling through Bounce2 and "picking up the flag".

Thanks for Your interest. You have read the original post. I've been programming, real time critical stuff for 40 years, I know that interrupt is not to be used by newbies. There is a reason to use it this time. A new member has managed to get his large and time eating project to work spending lots of his time wand helper time to get that faar. Instead of rewriting, redesigning his entire project I choose this solution. Agree?

Railroader:
Agree?

Doesn't matter. Sounds like you're on the hook to make it work.

A new member, using crutches, has managed to get his project almost working. We have been trying to trim it to decrease the loop time down from 3 seconds(!) but it's not good enough to pol a button.
Rather then redesigning his entire project, doing the coding myself, I choose the interrupt way.
In order to awoid another 50 #reply I took it on me to verify some pieces of code that I will deploy in his code. However the Arduino specials tricked me a bit.

The thing is, though, the problem mentioned in reply #12 will bite you when you try to do anything with the flag in that member's 3 second loop(). If you can only sample the flag every 3 seconds, it's not faster than sampling the pin every 3 seconds.

This phenomena is the secret reason why some people try to handle the event inside the ISR instead of using a flag (resulting in a mess because interrupts are disabled and so many things depend on them).

Yes, it's a code likely not done in the best way. Nested loops and delays for LEDs to change... Remaking the code is not an option. It took #50 replies to get this faar.

The problem is that pressing the button during that 3 seconds "dead window" is not noted. That's what I try to help that member to achieve. Press the button and the action will take place when that 3 second maraton has ended. It's no problem if the coin (button press) falls down after 3 seconds. That's okey.

aarg:
The thing is, though, the problem mentioned in reply #12 will bite you when you try to do anything with the flag in that member's 3 second loop(). If you can only sample the flag every 3 seconds, it's not faster than sampling the pin every 3 seconds.

This phenomena is the secret reason why some people try to handle the event inside the ISR instead of using a flag (resulting in a mess because interrupts are disabled and so many things depend on them).

It's getting very late here...
Trying Your tip I still experience the bounces when the button is released....

//testing interrupt on pin2, Arduino UNO Rev 3
const byte interruptPin = 2;
volatile bool state = LOW;
unsigned long lastISRmillis = 0L;

void setup() {
  pinMode(2, INPUT_PULLUP);
  Serial.begin(115200);
  Serial.println("Started");
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), ISR_button_pressed, FALLING);
}

void loop() {

  if (state)//if an interrup has occured
  {
    Serial.print("Interrupt at time "); Serial.println(millis());
    delay(1000);//simulate task executing
    //    if (digitalRead(interruptPin))//if button is released let ISR set flag.
    state = false;//reset interrupt flag
  }
}

void ISR_button_pressed(void) {
//  if ((millis() > lastISRmillis + 50) && digitalRead(interruptPin) == false) //50 mS debounce time
  if (millis() > lastISRmillis + 50)//50 mS debounce time
  {
    state = true;//set flag
    lastISRmillis = millis();
  }
}

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.