Electronic – arduino – How to debounce a switch on both positive and negative-going edges

arduinodebounceinterrupts

I would like to connect a mechanical switch to an interrupt pin on an Arduino Uno processor where the interrupt is configured for CHANGE interrupts (i.e., triggers on either a positive-going or negative-going signal).

I've found numerous approaches for implementation of debounce circuitry for positive or negative going signals, but I have not found suggestions for circuitry that can debounce either positive-going or negative-going signals.

Essentially, I want to use a single interrupt pin that can detect the opening or closing of an external switch, and I'd like to debounce the input using a hardware approach.


To be a bit more specific, the switch in question will open and close up to 200 times per second and I'd like to determine the amount of time it is closed each time it goes through an on/off cycle. I.e., I'm not talking about a button pushed by the user.

Best Answer

To debounce either edge of a changing signal, use hysteresis. Many debouncing algorithms assume an active high or active low signal, but you need to detect both.

Here is the essence of the hysteresis algorithm:

    bool input_state = digitalRead(INPUT_PIN);
    unsigned long current_ms = millis();

    edge = rise = fall = false;

    // Hysteresis:
    //   If there is no change, reset the debounce timer.
    //   Else, compare the time difference with the debounce delay.
    if (input_state == output_state)
    {
      last_ms = current_ms;
    }
    else
    {
      if ((current_ms - last_ms) >= DEBOUNCE_DELAY_ms)
      {
        // Successfully debounced, so update the outputs.
        is_debounced = true;
        rise = input_state && !output_state;
        fall = !input_state && output_state;
        edge = rise || fall;
        output_state = input_state;
      }
      else
      {
          is_debounced = false;
      }
    }

This could be called from an interrupt service routine something like this:

ISR(TIMER0_COMPA_vect)
{
  static Debouncer button1(BUTTON_PIN, DEBOUNCE_DELAY_ms);
  static bool led_state = false;
  
  button1.UpdateISR();
  
  // Toggle the LED on either edge of the debounced signal.
  if (button1.Edge())
  {
    led_state = !led_state;
    digitalWrite(LED_PIN, led_state);
  }
}

Here is a link the full code of the hysteresis debouncer on GitHub which uses the millis() timer, but you might need to change it to use the micros() timer and possibly increase the interrupt frequency for greater accuracy in your application. You also need to figure out the length of DEBOUNCE_DELAY. Use an oscilloscope to see what the switch bounce noise looks like.