Intended audience
This tutorial is intended for people who have mastered the basics of electronics and C/C++ programming. If you are a beginner and find the concepts difficult, please review the basic examples in the Arduino IDE.
In this tutorial BUTTON will be a generic term for any kind of switch or other input device with mechanical contacts.
Introduction
A common requirement in many projects is to have push buttons, switches or other electro-mechanical devices connected as inputs to an Arduino. This tutorial shows you how to connect a button and respond reliably to changes in the button's state.
Subjects covered
Part 1
- How to wire a push button switch to an input on the Arduino. Detect button operation and initiate actions.
- Code examples for above.
- Sample output on the serial monitor
Part 2
- The reason for debouncing the signal from any device with mechanical contacts
- Pull-up resistors, what they are and why they are required
- Pull-up vs pull-down
- State change detection
- Voltage, no voltage and 0v
Part 1
Single button input
The schematic shows a single button connected to an input on an Arduino Nano. On many Arduinos digital inputs 0 and 1 are used for the serial monitor. Digital input 2 is the first free input and is used in this example.
Here is what it looks like with a Nano Every on breadboard
Code for single button input to detect when the button becomes pressed
/* Simple debounce for a single push to make button wired between ground (0V) and buttonPin */
/* Tested on a Nano Every, should work on any Arduino */
const uint8_t BUTTONPIN = 2; // Input for button. On many Arduinos pins 0 and 1 are used for serial making pin 2 the first free pin.
void setup() {
Serial.begin(9600); // Start the serial monitor to see the results.
char fileName[] = {__FILE__};
Serial.println(fileName); // Prints the name of the file the location this sketch is in.
pinMode(BUTTONPIN, INPUT_PULLUP); // Make the button pin an input with the internal pull up resistor enabled.
}
void loop() {
Buttons(); // Calls the function to read the button.
// Your other code goes here, make sure it is non blocking (no delays, no loops that don't exit quickly)
}
/* This is the function that reads the state of the button, debounces it and prints to the serial monitor when it detects a press */
void Buttons() {
#define buttonPressed LOW // When the button is pressed the input will be low, this is to remove the confusion this migth cause.
uint32_t currentMillis = millis(); // Millis times uses to debounce the button
static uint32_t lastMillis; // Start of the debounce timeout
const uint32_t BOUNCETIMEOUT = 20; // Debounce time in milliseconds
bool currentButtonState = digitalRead(BUTTONPIN); // Reads the current state of the button and saves the result in a bool
static bool lastButtonState; // Holds the previous debounced state of the button
if (lastButtonState != currentButtonState) { // Checks to see if the button has been pressed or released, at this point the button has not been debounced
if (currentMillis - lastMillis >= BOUNCETIMEOUT) { // Checks to see if the state of the button has been stable for at least bounceTimeout duration
lastButtonState = currentButtonState; // At this point the button has been debounced, so save the last state
if (currentButtonState == buttonPressed) { // The button might have been pressed or released, this make sure only presses are acted on, not releases
Serial.println ("Button has been pressed"); // Here you put whatever code you want to take action when the button is pressed
}
}
} else {
lastMillis = currentMillis; // Saves the current value of millis in last millis so the debounce timer starts from current millis
}
}
This is what you can expect on the serial monitor