Home / Codes / Debounce on Interrupt Handler

Debounce on Interrupt Handler

Using interrupts is a neat way to get your Arduino to react quickly to a signal, like a button press. However, the technique is still susceptible to debounce.

Image result for button on breadboard

Introduction to Debounce Interrupt

Debounce is a common issue in microcontroller programming. It is an effect where the state of the pin at which a button is connected becomes spurious after pressing the button.

Here is debounce as seen on an oscilloscope:

Related image

Naturally, such back and forth will result in a bug on the code.

Consider this code snippet:

void loop(){
  int buttonState = digitalRead(D1);
  if(buttonState == LOW){
     digitalWrite(LED_BUILTIN, HIGH);
  }else{
     digitalWrite(LED_BUILTIN, LOW);
  }
}

Here, the state of the builtin LED depends on the state of the button. If the button is pressed, the LED should turn on and turn off otherwise.  However, the part where the button is read is just one line:

int buttonState = digitalRead(D1);

If the microcontroller is executing any other line, then it will miss the time that the button is pressed. That’s why the only way for this code to work is for the user to press and hold the button.

Using External Interrupt

Using an interrupt will make the LED to turn on at the instant the button is pressed. This is now the modified sketch:

void setup(){
  pinMode(D2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(D2),handler,LOW);
}

void loop(){
  digitalWrite(LED_BUILTIN, LOW);
}

void handler(){
   digitalWrite(LED_BUILTIN, HIGH);
}

Here, an external interrupt is attached to D2 (only D2 and D3 pins are possible for this). Once this pin goes LOW, the code immediately goes to the interrupt service routine (named handler). The ISR turns on the LED. In the loop(), the LED is turned off.

While the code above looks good, it is susceptible to the effects of debounce. Once you press and depress a button, the pin where it is attached may read multiple states in a short amount of time.

The solution is to wait a certain amount of time before doing what the handler is supposed to do. But delay() doesn’t work inside an ISR! So this doesn’t work:

void handler(){
  delay(200);
  digitalWrite(LED_BUILTIN, HIGH);
}

Millis to the Rescue

Since delay() doesn’t work, we need to use an alternate way to wait for the button to settle down before reading its value. Here’s a good solution:

void handler()
{
 static unsigned long lastInterrupt = 0;
 unsigned long interruptTime = millis();
 if (interruptTime - lastInterrupt > 200)
 {
   digitalWrite(LED_BUILTIN, HIGH);
 }
 lastInterrupt = interruptTime;
}

In this code, we take note of the time when the interrupt is first triggered and when it was triggered again. If the difference between the first and second trigger is greater than 200 millisecond, then we are sure it’s not a debounce and proceed to turn on the LED.

Check Also

moving average filter

Implementing an 8-point Moving Average Filter

If you read sensors using microcontrollers before, you have dealt with data that is always …

Leave a Reply

Your email address will not be published. Required fields are marked *