Debouncing buttons in AVR C++
On the face of it, reading the open/closed state of a button should be straightforward. You would just wire up the button circuit and tap the current flow into one of the Arduino digital pins configured for input.
Unfortunately you will soon discover that it’s just not that simple. At the point when a button’s contacts are being physically closed or opened the state of the electrical circuit is momentarily noisy. This means that your program will receive a rapid sequence of random HIGH/LOW signals which will certainly confuse it.
You could spend money and solve the problem in hardware with some circuitry around your buttons but it’s far easier to just write some code to do it. The technique is straightforward enough; when a button state change is detected we do not act upon it unless the state change lasts for longer than a preset short period of time, known as the debounce delay.
A C++ class solves the problem
I’ve written a reusable C++ class to do the debouncing for you. Here’s the header file.
#ifndef __99AC969B_B0C0_4ddb_BEDD_BF59AA339234
#define __99AC969B_B0C0_4ddb_BEDD_BF59AA339234
#include <stdint.h>
//
// Button implementation that does software debouncing
//
class DebouncedButton
{
private:
// time to wait for bounce to clear
static const uint32_t DEBOUNCE_DELAY_MILLIS=50;
// Internal button state
enum InternalState
{
Idle, // nothing happening
DebounceDelay, // delaying...
};
// The digital pin where the button is connected
uint8_t _digitalPin;
// The pressed state (HIGH/LOW)
uint8_t _pressedState;
// Internal state of the class
InternalState _internalState;
// The last time we sampled our button
uint32_t _lastTime;
public:
// Possible button states
enum ButtonState
{
NotPressed, // button is up
Pressed, // button is down
};
// Setup the class
void setup(uint8_t digitalPin_,uint8_t pressedState_);
// Get the current state of the button
ButtonState getState();
};
#endif
DebouncedButton.h
To use this class you must first declare an instance of DebouncedButton for each button in your project. For example:
DebouncedButton theButton; theButton.setup(2,HIGH);
This would declare a button to be on digital pin 2 and that its pressed state reads HIGH. This feature allows you to handle normally open and normally closed buttons in this same class.
Next you simply poll the class whenever you want to know the current state of the button, for example:
if(theButton.getState()==DebouncedButton::Pressed)
{
// do something
}
The getState() member function is asynchronous and will not block the caller at all, even for the duration of the debounce delay.
Source Code
Here’s the full source code to DebouncedButton.cpp so you can just copy and paste into your own project:
#include <wiring.h>
#include "DebouncedButton.h"
/*
* Setup the class
*/
void DebouncedButton::setup(
uint8_t digitalPin_,uint8_t pressedState_
)
{
_digitalPin=digitalPin_;
_pressedState=pressedState_;
_internalState=Idle;
// set up the pin
pinMode(digitalPin_,INPUT);
// activate the internal pull-up resistor
digitalWrite(digitalPin_,HIGH);
}
/*
* Get the current state
*/
DebouncedButton::ButtonState DebouncedButton::getState()
{
uint32_t newTime;
uint8_t state;
// read the pin and flip it if this switch reads high when open
state=digitalRead(_digitalPin);
if(_pressedState==LOW)
state^=HIGH;
// if state is low then wherever we were then
// we are now back at not pressed
if(state==LOW)
{
_internalState=Idle;
return NotPressed;
}
// sample the clock
newTime=millis();
// act on the internal state machine
switch(_internalState)
{
case Idle:
_internalState=DebounceDelay;
_lastTime=newTime;
break;
case DebounceDelay:
if(newTime-_lastTime>=DEBOUNCE_DELAY_MILLIS)
{
// been high for at least the debounce time
return Pressed;
}
break;
}
// nothing happened at this time
return NotPressed;
}
DebouncedButton.cpp
Test Project
For our test, let’s wire up the following simple circuit.

On the breadboard it looks like this. The red wire goes to +5V, blue to Arduino digital #2 and the 10K resistor is going to ground. This breadboard connects horizontal holes together as a strip.
Here’s some test code to demonstrate the button class. This example will flash the LED on the Arduino pin 13 when the button is pressed. The layout of this code is designed for Eclipse users. If you are using the Arduino IDE then you should just be able to copy and paste the setup() and loop() functions into the IDE Window.
#include <wiring.h>
#include <avr/wdt.h>
#include "DebouncedButton.h"
// Compatibility stub for undefined pure virtual
extern "C" void __cxa_pure_virtual() { for(;;); }
// the button class
DebouncedButton theButton;
/*
* Main entry point
*/
int main(void)
{
init();
setup();
for(;;)
loop();
}
/*
* Setup before loop
*/
void setup()
{
// setup the LED
pinMode(13,OUTPUT);
digitalWrite(13,LOW);
// setup the button on pin 2 (active LOW)
theButton.setup(2,HIGH);
}
/*
* Main loop
*/
void loop()
{
uint8_t i;
// check if the button is pressed
if(theButton.getState()==DebouncedButton::Pressed)
{
// flash it 3 times
for(i=0;i<=6;i++)
{
digitalWrite(13,i & 1);
delay(200);
}
}
}
main.cpp
Download the test project
The above test project is available for download, click here to go to the downloads page to get it.
The test project has a dependency on the Arduino libraries for Eclipse that you can also get from my downloads page. You may have to adjust the Eclipse compiler C++ include and link settings to reflect the location of the Arduino libraries on your PC.




