interrupts and debounce

Hello!

I've done everything I've encountered on internet about interrupts and debounce and what I prove doensn't work 100% efficiency.
Right now I have a 1uF capacitor on a button and in the software, I have a code that supposedly does the debounce.

void setup()
{

  pinMode(BlackButton, INPUT_PULLUP);     
  attachInterrupt(digitalPinToInterrupt(BlackButton), Debounce_interrupt_blackButton, FALLING);       

}

void loop()
{
  flag = false;
  pixels.neoPixelModo(modo);
}



//FUNCIONES

void Debounce_interrupt_blackButton()               //Sistema antirrebote de los pulsadores
{
  if (millis() - startTime > timeThreshold)
  {
    interrupt_blackButton();
    startTime = millis();
  }
}

void interrupt_blackButton()
{
  flag = true;
  pixels.fill(pixels.Color(0,0,0),0,numberLeds);
  pixels.show();
  modo++;
  if(modo > 5)
    modo = 1;
  Serial.println(modo);
}

When I press a button, the idea is that I will change the mode in the interrupt_blackButton() function just ONCE. What this function does is that some LED bars change the way they light up.

I need this part to be totally effective to make that button when I press twice consecutively do something else in the LED bars, for example to change color.

Any suggestions?

Thanks ^^

Can you use the millis() function in an ISR routine as the interrupts are globally disabled before the MCU enters into ISR; whereas, millis() function works on timer interrupt?

The millis() function returns the current time in milliseconds (1/1000th of a second) from when you powered up the board (or reset it). ... The millis() function is driven by a millisecond timer interrupt that increments an unsigned long every time it activates and just returns the value of that variable.

Interrupt is not the right thing for de-bouncing. Interrupts are for things that happen suddenly and need to be dealt with very quickly, by which I mean in time periods below about 1ms. A button press by a human is very slow in comparison. I suggest you poll the input every time around loop then time it (in milliseconds) to check that it stays active for more than, say, 20 milliseconds (play around with the time) and when it does count that as a valid input.

If you insist on doing it that way, just let the ISR set a flag that you can test from loop to do all this time consuming stuff.

Hmmm.....
I can see that being hard work to program for, especially for a beginner. Interrupt sets flag and exits. Code sees flag set and is in the middle of dealing with it when the button bounces and the interrupt interrupts and.... I don't know, it just seems a lot more likely to cause difficulties than polling the button.

Yes, you can use millis() in an interrupt. It only returns the current time value set by an interrupt. Millis() itself does not depend on an interrupt. So just like any other interrupt, be fast.

But the real issue is indeed, don't use a interrupt for a slow button :wink:

Kotito,
The more I think about it the more I think that not only is using interrupts to de-bounce a button the wrong thing to do I think it is going to be really difficult to get right.

As others have said, an interrupt needs to be really fast to stop it disrupting other code too much. It's not just that a button press is really slow compared to a properly functioning program but alto that a properly written interrupt is too fast for a bouncing button. You need time to check for bounce on a button, more time than should ever be allocated to an interrupt. If an ISR takes long enough to be sure a button as stopped bouncing then it is taking way too much time out of the code it has interrupted.

GolamMostafa:
Can you use the millis() function in an ISR routine as the interrupts are globally disabled before the MCU enters into ISR; whereas, millis() function works on timer interrupt?

You can, yes. the value of millis() won’t be updated but it’s the value it had when the ISR was triggered.

And would not make sense to have something needing to be stuck in an ISR for one millisecond (ie looping waiting for millis() to change) — so,most of the time it does not matter that millis() does not update

If you need smaller resolution you can also use micros()

But as said by everyone, not a good idea for a human operated button

This is a common subject on these forums, so I did some tests. I connected a simple, cheap push to make button to a resistor and a power supply and connected an oscilloscope across the button. With quick presses I typically measured a closed time for the button of around 150ms or more, with a bounce time of around 125μs. Maybe different people using different buttons will get different times, but I’ll go with what I have.
In detecting a button press you are looking for an event that lasts at least 150ms, this is an absolute age in terms of processor time. If you program is not getting completely round its loop in 10ms or less then you need to be asking why, and looking to either improve the code or using a faster processor. To be sure you are dealing with bounce you need to check the button input at least twice per press event; the first time you see it’s pressed, the second time you see it’s still pressed so you act on the press. 3 checks would be even better. So, given that a button press lasts at least 150ms, even if your code is rather slow and takes 50ms per loop, it is still going to be able to check the button input at least twice per loop, possibly 3 times.
An interrupt is what you use when you need something to be dealt with faster than your loop time. If you have an event that cannot wait 5ms or 10ms or 50ms or however long your loop takes THEN you use an interrupt. However, an interrupt is steeling time from your loop, so an interrupt has to be over and done very quickly, preferably in a time period measured in microseconds and quite possibly in less than the 125μs bounce I measured with my cheap button. Maybe another button will have even longer bounce. You should not have an interrupt taking this amount of time away from the loop. An interrupt is the wrong tool for button inputs and if you use an interrupt to detect and de-bounce a button press you are asking for trouble.
You can find a tutorial for de-bouncing at de-bounce tutorial, and, as you are reading this and have asked a question about using interrupts for button presses, I can only assume you haven't tried the example in the tutorial. Off you go…

Thanks guys for all your responses!!

I didn't have time to read all of this and you all have been writing a lot (=D)

Firstly I have understood about button and interruptions and I didn't know that heory about interrupts. In the beginning I was thinking that if I want to interrupt the program with a button and NOT WAIT for the loop to start again to read if I've already press a button or not, so obviously I had to put a button as a interruption. In that case the program didn't want to wait all the program to finish to start again.

The program I coded is just a LED bar iluminating in different ways. So if I wanted to change from one mode to another without waiting for the sequence to end , this was my best solution. Then I had to add the debounce.
Got it? =)

All of you have taugh me a important lesson about interruptions. I thank to Perry because now I could re-write my code and rethink it in another way.
I hope the idea you gave me, Perry, works =)

I wanted to change from one mode to another without waiting for the sequence to end.

You do this:

void loop() {
  //Do the light control stuff
  //Check the buttons
 }

You need to make sure the 'light control stuff' is written in such a way that it comes out every time round, and doesn't get stuck in an internal loop, so no delay(); and no while() unless it's really, really quick. Use the main loop to do any looping you need.

I hope the idea you gave me, Perry, works =)

Well it would if I did it! Oh! :o

uuis! if I do that code in my loop I'd have a problem perry =D

The first line takes like 10 seconds to accomplish, then arduino read my button. So if I press just as arduino are reading the first line, i'd have to wait 5 or 6 or 7,8,9 seconds to that line finishes.
that's why I need to interrupt the first line and start for the second 1.
yes? =D

Anyway, I have a slight idea on how to do it. ^^

And when it’s interrupted what do you do ? How is the information you in the ISR then injected in your 10 second wait/process?

And if you do anything to check what the isr has seen during your light animation, why wouldn’t you check the button there?

Could you post an schematic of your button debounce circuit?

Does it look like this?


or are you missing the resistor?

If I do that code in my loop I'd have a problem perry =D
The first line takes like 10 seconds to accomplish

You need to seriously re-think your code, no line of code should take 10 seconds, or even 1 second.

I've not had to de-bounce a button for years, not since I discovered Nextion displays. Here's something I put together to illustrate one way to approach it. I make no claims that it's the only or best way, just an idea to develop, improve or ignore as you see fit.

/* Simple button debounce. Increments a count and sends the updated count to the serial monitor once per button press */
/* Tested on an Uno */
/* Connect a simple push to make button between 0V and pin 2 */

const int buttonPin = 2;      // Connect the button between pin to and 0V
uint8_t pressedCount = 0;
uint8_t testCount = 0;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  uint32_t baudrate = 115200;
  Serial.begin(baudrate);
  Serial.println("");
  Serial.print("Serial port connected: ");
  Serial.println(baudrate);
  Serial.print("Testcount = ");
  Serial.println(testCount);
}

void loop() {
  debounce();
  delay(1);     //Your other code goes here instead of this delay. DO NOT leave this delay here, it's only for demonstration.
}

void debounce() {
  if (digitalRead(buttonPin)) {
    pressedCount = 0;
  }
  else {
    if (pressedCount < 4) {
      ++pressedCount;
      if (pressedCount == 3){
        ++testCount;
        Serial.print("Testcount = ");
        Serial.println(testCount);
      }
    }
  }
}