5

I've been using a button to interact with a sketch (on my Uno), and it's mostly working fine. However, sometimes it seems to be detecting multiple presses when it's only pressed once.

It's a small circuit-mounted momentary button, which is normally open. It's connected from +5V directly to an input pin. I've also added a 10K pull-down resistor on the pin to make sure the input isn't left floating.

Here's a test sketch I've been using, which reports the number of presses to the serial monitor:

    int oldState = LOW;
    int numPresses = 0;
void setup()
{
    pinMode(5, INPUT);
    Serial.begin(9600);
}

void loop()
{
    const int newState = digitalRead(5);

    if (newState != oldState) {
        if (newState == HIGH) Serial.println(++numPresses);
        oldState = newState;
    }
}

Sometimes when I press the button once, the serial monitor shows two presses in a row. It sometimes even reports a press when I release the button.

Is it possible to fix this? Or do I just have a faulty button or pin or something?

Rohit Gupta
  • 618
  • 2
  • 5
  • 18
Peter Bloomfield
  • 10,982
  • 9
  • 48
  • 87

3 Answers3

11

Contact Bounce

This is known as contact bounce and happens when the metal contacts in the button or switch bounce against each other when you push it. The microcontroller is fast enough to pick up these bounces and, as far as it's concerned, you're toggling the switch many times in as much as 10 milliseconds of time.

Different switches and buttons will have a different amount of contact bounce, and even one switch will behave differently between two presses.

Here's a button press captured on a scope (image from Maxim):

enter image description here

At 2ms/div we don't see a stable signal until 6ms after initial contact!

Solutions

Add a delay

The absolute simplest solution is to introduce a short delay after you read the button input. This will prevent the code from picking up any bounces and when it resumes, the signal should be stable.

if (digitalRead(A3) == 0) {
    // do something here
    delay(500);
}

In the example above, I delay 500ms after reading the state of the pin. The button is normally high so when I press it down, the state of the pin goes to logic 0. I pick that up in the code and do something and then wait at least 500ms before continuing.

Obviously, this code will just halt for half a second every time you push a button, which may or may not be acceptable in your application. You can decrease the amount of delay depending on the contact bounce time of your switch, too, but I play it safe here.

Ignore button presses too close to each other

Similar to the solution above but instead of adding a hard delay, you use the millis() function to keep track of when the last time the switch was triggered. Every time you see a switch trigger, you compare against the time and, if not enough time has elapsed (say like 500ms in my previous example), you ignore it.

This solves the problem of having to use delay() in your code.

Switch debouncer IC

There are things like the MAX6816 which is an IC that you put in between your switch and microcontroller input. It will denounce the signal for you. At a price of $1.62 @1k you'll probably never use this.

Other

There are many solutions to this problem... I always do it in software, but some others include using a latch or capacitor.

Debounce Code – one post to rule them all

sachleen
  • 7,565
  • 5
  • 40
  • 57
4

The button contacts themselves are probably bouncing in and out of contact, which is causing the circuit to open and close multiple times, even though the button position isn't changing.

It's a common problem with buttons and would be the first thing I would check. In order to fix this, you need to de-bounce the button. There are various ways in which to accomplish this, some of which can be done in the sketch itself.

A good solution is code that measures the duration of each button state and only registers a change in state if the current duration is greater than the desired duration. That option should be used for more complex projects. The code for it will be project specific and likely use sketch defined variables, but an example of what needs to be done can be found here.

If the sketch is very basic or you just want to make sure that bounce is the problem, you can add a short delay after the button state changes. For example:

void loop()
{
    const int newState = digitalRead(5);

    if (newState != oldState) {
        if (newState == HIGH) Serial.println(++numPresses);
        oldState = newState;
        delay(10) //Adjust the delay length to be as short as possible without triggering errors
    }
}    
jlbnjmn
  • 978
  • 2
  • 9
  • 15
3

This is your button bouncing which is quite usual behavior; it has nothing to do with button quality.

There are 2 ways to "debounce" a button: by hardware or by software.

Personally, I prefer by hardware; just google for button debouncing circuit and you should find many examples.

If you don't have the necessary components available, you can use software debouncing.

By software, you have an example here on Arduino web site.

jfpoilpret
  • 9,162
  • 7
  • 38
  • 54