I say: behind a button, unexpected things can hide. And within a program that does various things, handling a button can be tricky. The nice thing is that interesting functions can be built with a simple dumb button.
This tutorial will address these aspects:
- wiring and configuring pins, using pull-up/pull-down resistor,
- deglitching,
- detecting states versus events,
- detecting long presses,
- and some object-oriented programming.
The programming approach is based on polling, encouraged by the Arduino loop() principle, and which is perfectly acceptable for simple to moderately complex Arduino projects. We'll require the duration of each loop() execution to be "fairly" the same each time.
More advanced implementations, not covered here, may include the usage of interrupts and timers. They are more accurate, but also harder to understand.
This tutorial is intended to people with a basic first Arduino experience (i.e. with knowledge of the IDE, and of the compilation, flashing and running of sketches).
In the following ZIP file, the four sketches used in this tutorial can be found.
Remove these ads by
Signing UpStep 1Connecting the Button
This is a momentary switch, with one stable position (open) when no force is exerted, and conducting (closed) when pressed. It is one of the simplest electro-mechanical sensing device.
Connect the button like illustrated in the photo of this step.
(Don't be impressed by the size of my breadboard. A small one will be actually handier.)
The I/O Pin
The AVR (aka ATmega, i.e. the Atmel chip powering the Arduino board) has several I/O pins. I/O means that they can be freely configured by software as input or output.
Pin 2 will be a good choice for our example. It will be used to measure the state of the button: pressed or released.
Pull-up Resistor
The pin has to be connected to somewhere via the button. The question is: where.
A first idea would be to go to VCC. VCC is the usual denomination for the supply voltage, here 5V.
So when the button is pressed, the pin would be connected to VCC, and the software would read HIGH. But when the button is released, the pin is connected to nowhere, aka "floating", and will be exposed to noise, and the software will read HIGH and LOW in an erratic way.
So the solution is to use a so-called pull-up or pull-down resistor. Such a resistor ensures that the pin is always connected to GND or VCC, directly or via the resistor, depending on the button position.
Fortunately, the AVR chip has, internally, a 20 kOhm pull-up resistor that can be connected to the pin (internally). The pin must be configured as input, and its value, in this situation, tells whether the pull-up is connected (otherwise the value defines, when the pin is configured as output, its output state).
With this pull-up, we'll connect the pin to GND through the button, and have these situations when the button is released, respectively pressed:
Button not pressed:
VCC
|
20K | |
internal | |
pull-up |_|
|
| _____
input ––––*––––––o–––––––––o o––––– GND
pin released
button
Input is isolated from GND, so only connected to VCC via the resistor. No current flows.
Without the pull-up resistor, the input would be "floating".
Button pressed:
VCC
| :
20K | | :
internal | | :
pull-up |_| : some current flows
| `- - - - - - - - - ->
|
input ––––*––––––o–––––––––o–––––o––––– GND
pin pushed
button
Input is now directly connected to GND. Some current flows through the resistor.
In both cases, we now have a clearly defined situation.Consumption
When the button is pressed, the resistor gets a voltage difference equal to VCC, and a current I is flowing:
I = VCC / R
= 5 / 20,000 = 0.25 mA
Corresponding to consuming the power P:
P = VCC2 / R
= 52 / 20,000 = 1.25 mW
Polarity
Had we a pull-down at our disposal, we would have connected the pin to VCC instead of GND, and read HIGH upon press, which is more logical. But since we have a pull-up only, we'll have to reverse the polarity by software, at pin sampling.
For more about I/O pins, follow http://www.arduino.cc/en/Tutorial/DigitalPins.
Programming
The configuration of the AVR pin (as input and with pull-up enabled) is described in the code below.
Code
––––––––––8<––––––––––
#define BUTTON_PIN 2
void setup()
{
...
pinMode(BUTTON_PIN, INPUT);
digitalWrite(BUTTON_PIN, HIGH); // connect internal pull-up
...
}
void loop()
{
...
}
––––––––––>8––––––––––| « Previous Step | Download PDFView All Steps | Next Step » |














































////////////////////////////////////////////////////////////////////////////// // Arduino button tutorial 1. // // Demonstrates: // - detection of pressing state // // Push-button must be connected as follows: // __,__ // Pin2 ------o o------ GND // // (C) 2011 By P. Bauermeister // This example code is in the public domain. // ////////////////////////////////////////////////////////////////////////////// // Adapt these to your board and application timings: #define BUTTON_PIN 2 // Button #define DELAY 1000 // Delay per loop in ms #define LED_PIN 7 ////////////////////////////////////////////////////////////////////////////// void setup() { pinMode(BUTTON_PIN, INPUT); pinMode(LED_PIN, OUTPUT); digitalWrite(BUTTON_PIN, HIGH); // pull-up Serial.begin(9600); } boolean handle_button() { int button_pressed = !digitalRead(BUTTON_PIN); // pin low -> pressed return button_pressed; } void loop() { // handle button boolean button_pressed = handle_button(); // do other things if (button_pressed==0) { Serial.print("1"); digitalWrite(LED_PIN, HIGH); } else { digitalWrite(LED_PIN, LOW); Serial.print("2"); } //Serial.print(button_pressed ? "0" : "1"); // add newline sometimes static int counter = 0; if ((++counter & 0x3f) == 0) Serial.println(); delay(DELAY); }
http://www.arduino.cc/playground/Code/Bounce
But it does not handle the long press (which my initial goal, the debounce being just an extra bonus).
So if one just needs debouncing and edge detection, one should definitely use the bounce lib.
Thanks.
David