The site for those who love tinkering with Arduino, Raspberry Pi & Co.

Arduino and Button Boucing: a possible solution

by

In our previous article "Arduino digitalRead, digital input and buttons" we saw how the digitalRead function works and how it works.

In that article we ignored some issues that the button can give us.

In our projects, especially if we do not come from the electronic world, we think that if there is an error it is the software's fault.

This is perfectly normal, since for someone from the world of computer programming like me, it has to do with ultra-tested hardware.

Furthermore, we often forget (or at least it often happens to me) that with arduino we are literally programming the hardware while in a PC, generally, an abstraction is programmed (of a more or less low level).

This abstraction allows us to focus only on the software and completely ignore what machine our program works on.

All this speech was made to tell you that there can also be errors in the electronics of our project. One mistake we will talk about today, in particular, is the problem that plagues all buttons, especially if they come with fury from china! This problem is known as “Button Boucing” which means button bouncing.

This error can be noticed a lot when we work with event-generated interrupts. The dynamics of this type of error is very simple, when we press the button and then release it, internally, the button begins to bounce. This generates an additional signal which is detected by our board and which could compromise the operation of the project.

Problem analysis

Let's analyze the problem by testing! Let's pretend we're unprepared for boucing and take:

  1. The Arduino board (Click to see which pins of your board accept Interrupts);
  2. One button;
  3. A 10 Kohm resistor
  4. A breadboard
  5. Wires

Once all the material is taken, we replicate the following pattern.

Now let's run our apparently correct code!

#define INTERRUPT_PIN 2
#define BOUNCE_DELAY 50

/ * volatile is a variable qualifier that is used to tell the compiler 
 * that every time the variable is used, it is taken from RAM and not
 * from the registers.
 * /
volatile byte val = 0;
unsigned long lastTime = 0;

/ * Function that is re-called every time a 
 * rising edge of the signal
 * /
void count () {
  val ++;
}

/ * attachInterrupt (): The function executes the function registered on its event
 * in our case, the function started is called count, the event is an edge of 
 * rising signal on pin 2.
 *  
 *  CAUTION! Not all pins on the board can be used for managing
 * events, in the case of the Arduino Uno board these events can be recorded on the pin
 * 2 and 3 but on other cards these pins may be different
 * /
void setup () {
  pinMode (INTERRUPT_PIN, INPUT_PULLUP);
  Serial.begin (9600);
  attachInterrupt (digitalPinToInterrupt (INTERRUPT_PIN), count, RISING);
}

void loop () {
  Serial.println (val);
}

The code described above increases the counter by 1 every time our button is pressed. As we can see, this does not happen, since due to the bounce of the button, the variable is incremented by more than a single unit.

This problem can be solved in two different ways: the first is to buy a more reliable component (ATTENTION, reliability does not last over time) but we don't like this!

I know what you like! You like to fix this quickly and inexpensively, so we'll have to write some code that takes that into consideration too!

Solution of the problem

Since these bounces generally last between 20 and 30 milliseconds, then a possible solution could be to ignore all the events coming from the button at that moment. In fact, looking at the new function count () we can see that a control has been added that has just this task.

#define INTERRUPT_PIN 2
#define BOUNCE_DELAY 50

/ * volatile is a variable qualifier that is used to tell the compiler 
 * that every time the variable is used, it is taken from RAM and not
 * from the registers.
 * /
volatile byte val = 0;
unsigned long lastTime = 0;

/ * millis () returns the time in milliseconds that has elapsed since the moment
 * when the card is switched on.
 * /
void count () {
  if ((millis () - lastTime)> BOUNCE_DELAY) {
    val ++;
    lastTime = millis ();
  }
}

/ * attachInterrupt (): The function executes the function registered on its event
 * in our case, the function started is called count, the event is an edge of 
 * rising signal on pin 2.
 *  
 *  CAUTION! Not all pins on the board can be used for managing
 * events, in the case of the Arduino Uno board these events can be recorded on the pin
 * 2 and 3 but on other cards these pins may be different
 * /
void setup () {
  pinMode (INTERRUPT_PIN, INPUT_PULLUP);
  Serial.begin (9600);
  attachInterrupt (digitalPinToInterrupt (INTERRUPT_PIN), count, RISING);
}

void loop () {
  Serial.println (val);
}

Obviously this solution like all the solutions we can take, does not completely eliminate this problem but reduces it to a minimum. It is necessary to experiment and test the program in order to find an optimal BOUNCE_DELAY, which is neither too big (risk of loss of events) nor too small (risk that not all bounces are ignored).

As always, I invite you to write comments if you have any problems or doubts and to let me know if you have removed all the bounces from your projects.

Ti è rimasta una domanda o un dubbio?

Iscriviti e chiedi nella community

Leave a Reply

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