Language: EN

debounce-interrupciones-arduino

Read a pushbutton with Arduino with interrupts and debounce

In the previous post we saw what interrupts are and how to use them to respond to hardware events on pins.

We also made it clear that physical devices, such as pushbuttons, optical sensors, etc., present a bouncing effect that interferes with the use of interrupts, and that we need to eliminate it or we won’t be able to use interrupts with these devices.

The process of eliminating this bouncing is called “debounce”. In this post we will learn what bouncing is and how to eliminate it with hardware and software debounce.

What is debounce?

Electronic devices when changing state generate a signal that, while not perfectly square, is generally more or less “clean”. For example, let’s look at the signal that Arduino generates when changing the state of a digital output from HIGH to LOW.

arduino-sin-rebote

However, the real world is not as pretty. Many physical devices usually generate noise on the signal edges. For example, let’s look at the voltage variation that occurs when the change of state is generated by a pushbutton.

arduino-rebote

Notice the amount of noise that occurs after the edge. Essentially, within a range of a few microseconds, the signal is pure noise. All those peaks can trigger multiple interrupts.

TESTING THE BOUNCE

To test the bounce, we simply use a wire to connect Pin 2 and Ground (you can also use a pushbutton or a switch).

arduino-debounce-esquema

We activate the internal Pull UP resistor on Pin 2 and define an interrupt on the falling event on the PIN, and in the associated ISR function we simply increment a counter.

In the main loop, we check if the counter has been modified and if so, we display its value on the serial port.

const int intPin = 2;
volatile int ISRCounter = 0;
int counter = 0;

void setup()
{
  pinMode(intPin, INPUT_PULLUP);
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(intPin), debounceCount, FALLING);
}

void loop()
{
  if (counter != ISRCounter)
  {
    counter = ISRCounter;
    Serial.println(counter);
  }
}

void debounceCount()
{
  ISRCounter++;
}

When testing our setup and connecting PIN 2 to GROUND, we would expect the variable to increase by one each time. But we will see that in reality, it jumps several numbers each time (even several tens).

This is the effect of the bounce. The signal noise is generating multiple interrupts every time we connect the wire.

Eliminating the bounce

We have two ways to apply debounce. Adding electronic devices to filter the signal (hardware debounce) or modifying our code to eliminate the bounce (software debounce).

Hardware debounce

Applying hardware debounce has the advantage of not increasing the execution time of our code. In addition, generally, it is a more robust solution. On the other hand, it has the disadvantage of increasing the complexity of our setup.

The simplest way to apply hardware debounce is to place a capacitor in parallel with the device (pushbutton, switch, sensor…). A capacitor of the order of 1uF should be sufficient to filter out most of the noise.

The connection scheme is as follows.

arduino-debounce-hardware

In general, it is always advisable to add a hardware filter when using physical inputs with interrupts.

Software debounce

Software debounce has the advantage of not requiring additional components. We solve the bounce only by modifying the code of our program.

As a disadvantage, it slightly increases the execution time and the complexity of the code. In addition, if we do not apply the code correctly, we may ignore “true” interrupts.

The simplest way to apply software debounce is to check the time between interrupt triggers. If the time is less than a certain threshold (threshold), we simply ignore the interrupt. In short, we have defined a “dead zone” where we ignore the generated interrupts.

To apply software debounce, we modify the ISR function as follows.

const int timeThreshold = 150;
const int intPin = 2;
volatile int ISRCounter = 0;
int counter = 0;
long startTime = 0;

void setup()
{
  pinMode(intPin, INPUT_PULLUP);
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(intPin), debounceCount, FALLING);
}

void loop()
{
  if (counter != ISRCounter)
  {
    counter = ISRCounter;
    Serial.println(counter);
  }
}

void debounceCount()
{
  if (millis() - startTime > timeThreshold)
  {
    ISRCounter++;
    startTime = millis();
  }
}

A time of 100-200ms is correct for a pushbutton but in other cases, we must adjust the time to eliminate the bounce, but not ignore two possible nearby “true” events.

In a real setup, it is best to use a combination of both systems, while adjusting the value of the capacitor and the software filter times to adapt them to our system.

Download the code

All the code from this post is available for download on Github. github-full