debouncing an interrupt trigger

I have a button, linked to pin 2 of my arduino, to execute my interrupt service routine. My ISR increments a variable, which lets the rest of my function know what its doing.

My problem is that my buttons are bouncing horribly (damnably cheap buttons were salvaged from old 80's VCR!) Is there any way to debounce this switch in software, without using the delay() command? I tried using the Debounce library with no success, I presume it operates using delay() as well ...

Thank you :slight_smile:

1 Like

You could use an external RC combination to remove the de-bounce before it gets to the interrupt pin.

What does the rest of your code look like? I ask because if it were me I'd use the millis() function to produce some code that operated every milli second and use a simple statemachine to handle the reading and de-bouncing of the switch.

Regards,

Mike

BigMike's idea is a good one. Perhaps some variant like this would work?

void my_interrupt_handler()
{
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();
  // If interrupts come faster than 200ms, assume it's a bounce and ignore
  if (interrupt_time - last_interrupt_time > 200) 
  {
    ... do your thing
  }
  last_interrupt_time = interrupt_time;
}

Mikal

11 Likes

Using millis worked perfectly, thanks guys!

The rest of the program controls the PWM output of the arduino on pins 9, 10 and 11, to an RGB LED.

Cheers! :smiley:

I'm glad its all working.

However, I was actually thinking of doing that in the main loop, but as it is working, why not leave it there.

There is one problem - what happens when the value from millis() rolls over. I forget the numbers, but in older code the millis() function rolls over after about 9 hours. Currently the rollover occurs at about 50 days.

I think your button may stop working after the rollover. If your application won't be on for 50 days at a time this isn't a problem. If it will be then you may have a problem.

Regards,

Mike

1 Like

I think the battery for this project will last about 5 hours maximum given the number of LEDs it's powering.

BUT this millis() function returns the number of milliseconds elapsed from the beginning of the current function. If my ISR closes and re-opens, then won't the millis() function be reset, i.e. counting from the beginning when this particular instance of the ISR was called?

Millis counts from the time the sketch starts running (its set to zero just before setup is called).

Ahh, thanks for clearing that up :slight_smile:

So when millis() overflows, it resets back to zero, so that when the state machine checks against its previous state, a massive error value comes up.

It would be nice if a function could reset the millis() function back to zro (or for any other value, for that matter) so we could say:

val = millis();
if( val > 49 days) {
resetMillis();
}

Is this blue sky thinking, or could a function like this be implemented, feasibly?

The way my code works is that I could say:

val = millis();
if( val > 49 days) {
digitalWrite(resetPin, LOW);
delay(someArbitraryValue);
digitalWrite(resetPin,HIGH);
}

to reset the board, and then the millis() counter would be refreshed. For my particular product/toy, it doesn't matter so much if after 50 days of on-time, the product resets to its initial state.

Would that work around the problem? ...hypothetically? :slight_smile:

1 Like

A couple of salient points, AK:

So when millis() overflows, it resets back to zero, so that when the state machine checks against its previous state, a massive error value comes up.

Not necessarily. If you use the subtraction operator - to compare the "new" time with the "previous" time, as I did in reply #2, the overflow is perfectly harmless. This is because of the nature of unsigned arithmetic in C. Let's say the "previous" value of millis() you captured was 0xFFFFFFFF. 10ms later you check millis() and it's value has "rolled over" to 9. Well, good news! In C unsigned arithmetic 9 - 0xFFFFFFFF is 10, exactly what you were expecting!

Secondly, there is already a tidy way to write the resetMillis() function you propose. Unfortunately, it relies on undocumented system internals, so this (for now) only works in Arduino 0012:

void resetMillis()
{
  extern volatile unsigned long timer0_millis;
  timer0_millis = 0;
}

Mikal

1 Like

Wow I love that! It's nice how the system works out like that. Cheers :slight_smile:

Me too! :slight_smile:

Guy, I suggest a timer interrupt library: Arduino Playground - MsTimer2

I was having very much the same problem with my button bouncing and producing very strange results as the interrrupt was being called over and over on the button bounces. I tries Big Mike's idea with the code idea from mikalhart and it works great! Thanks alot guys I'm glad I found this thread!!!

1 Like

Rafael,

What do you propose with the timer interrupt library?

Fred

Hello! Let's go back to 2008...

BigMike's idea is a good one, but not perfect...

void my_interrupt_handler()
{
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();
  // If interrupts come faster than 200ms, assume it's a bounce and ignore
  if (interrupt_time - last_interrupt_time > 200)
  {
    ... do your thing
  }
  last_interrupt_time = interrupt_time;
}

Let's imagine that an interrupt occurs every 150ms constantly for 15 seconds. In such situation the interrupt routine wouldn't do anything, am I right? This is because the line which updates the "last interrupt time" variable doesn't depend on the result of "if". If we put the "last_interrupt_time = interrupt_time;" under the "if", so that it updates the "last interrupt time" only when the interrupt is succesfull, the hypothetical button will be debounced for 200 ms - button's second state change after 300 ms will be succesfull.

Sorry for poor English.

1 Like