In this beginner "Arduino digitalRead" project, you will learn how to use
digitalRead to read an input button correctly and control two LEDs. In a
previous tutorial project - "Arduino LED with button" -
showed you how control a single LED using an input button.
However, there is one big problem with that project - it does
work, but it ignores a very important and very subtle problem - which
we'll explore in this tutorial.
The new circuit will allow you to switch between two lit LEDs, by simply pressing a button connected to your
Arduino board.
By the end of this tutorial, you will understand how to build the
circuit on a breadboard, write the code to sense button presses and
drive the LED accordingly, but in addition you will understand the problem of switch bounce.
Arduino digitalRead
The digitalRead function allows you to read the value on an Arduino's
digital pins configured as inputs. It returns either a HIGH or LOW value
indicating if the pin is getting voltage or not. This lets us sense the
state of buttons, switches or sensor outputs in code.
Note that microcontrollers operate on zeros and ones but at the input
you have high or low voltage, usually 5V or 0V where 5V is the
operational voltage required by your microcontroller. The digitalRead
function translates these voltages into digital "1" and "0" so that the
information can be used within a program.
Note also that the HIGH or LOW, that you can write in Arduino code, are
translated to values 1 and 0 respectively i.e. they have corresponing
numbers that the microcontroller can use.
Required Components
Arduino Uno board
2x LEDs (any color)
2x 1k ohm resistor
Push button
Breadboard
Jumper wires
Circuit Diagram :Arduino LED with button
The layout diagram shows how to place components on the breadboard.
Note that you have to place the LED the right way round -the flat side
of the LED (cathode - or negative side) connects to ground (GND or 0V).
Ground (0V) and supply voltage (5V) are connected from pins in the
lower pin header of the Arduino Uno, while control pins 2 and 7 are
connected from the
top connector.
Diagram using fritzing
The schematic shows the pin connections and components.
Diagram using fritzing
Using Arduino digitalRead
There are two elements to using a pin and reading its value:
You need to tell the microcontroller that the pin is to be an input (they can be input, output or "input - pulled-up").
You then read the pin using the digialRead function.
We'll configure the pin as an input by calling pinMode and specifying the pin and INPUT as arguments. Here we are using pin 2 as the button input pin.
To use digitalRead, we pass it the number of the digital pin we want to
read as a parameter. It returns either HIGH or LOW, which we can assign
to a variable or use directly in logic.
For example, we can declare a variable and assign the pin read:
pinMode(2, INPUT);
int buttonState = digitalRead(2);
Now buttonState will be either 1 or 0 depending on the button state.
Uploading the Code
For the following sketches below:
There are a few steps to uploading the code using the Arduino IDE:
Connect the Arduino Uno to the PC with a USB cable.
Select the Arduino Uno hardware.
Open a new sketch.
Paste the code above into the new page (overwrite everything).
Press the upload button (right arrow at top).
You can find a more detailed tutorial on the Arduino IDE page.
Arduino digitalRead: Example Sketch
For the code, we'll switch between lighting each LED in turn when the
button is pressed - and actually do the update on button release.
Copy and paste the code below into the Arduino IDE (in a new
sketch) replacing everything that is in the new sketch window (See "Uploading the code" below).
// Button is connected to pin 2
// LED 1 is connected to pin 7
// LED 2 is connected to pin 8
const int buttonPin = 2;
const int ledPin1 = 7;
const int ledPin2 = 8;
int buttonState = 0;
int previousButtonState = 0;
int ledState = 0;
voidsetup(){
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
}
voidloop(){
buttonState = digitalRead(buttonPin);
if(buttonState != previousButtonState &&
previousButtonState == LOW){
if(ledState == 0){
digitalWrite(ledPin1, HIGH);
digitalWrite(ledPin2, LOW);
ledState = 1;
}
else{
digitalWrite(ledPin1, LOW);
digitalWrite(ledPin2, HIGH);
ledState = 0;
}
}
previousButtonState = buttonState;
}
sketch arduino-2leds-with-button
Arduino digitalRead: Code Explanation Ex1
The main difference in this code to the tutorial code in "Arduino LED with button"
is that a state variable is introduced to store the "fact" that the
button has been pressed (and released). So the code does not simply transfer the button press information directly to
the led, it waits for the button to change state but only if the previous state was LOW.
In this way the code detects when the button state goes from low to
high. (we don't want it to change the LEDs as soon as you press the
button, but only when you release the button).
Detailed Code Explanation Ex1
The button is connected to pin 2 and defined as input variable buttonPin.
LED1 is connected to pin 7 and LED2 to pin 8, defined as output variables ledPin1 and ledPin2.
buttonState reads the current button input value on pin 2.
previousButtonState stores the previous button state reading.
ledState tracks which LED is on (0 = LED1, 1 = LED2).
In setup(), the pins are configured as inputs and outputs.
In loop():
buttonState is read from the button pin.
It only checks if buttonState is different than previousButtonState AND previousButtonState was LOW.
This ensures a state change from LOW to HIGH is detected, ignoring repeated HIGH or LOW readings.
If ledState is 0, it turns on LED1 and off LED2, sets ledState to 1.
Otherwise it turns on LED2 and off LED1, sets ledState to 0.
previousButtonState is updated with the current buttonState.
This toggles the LED states each time the button is pressed.
So in summary, it uses button input and ledState variable to toggle two LEDs on button press-and-release .
The hidden problem : Bounce
When a button or switch changes state physically, the electrical signal
may bounce rapidly between on and off multiple times as the contacts
settle. This can cause missed or extra readings.
To get this effect with the micro switch you may have to hit the
button quite a few times at different speed as that switch is better
behaved than others. Eventually you'll see a missed transition - a rapid
jab causes problems for the code!
When you try the code above you will see that sometimes everything works as expected but sometimes:
The LED flickers but immediately returns the to original LED.
The button press is ignored.
For the last case, in fact the second LED is probably switching on
but the rapid bounce signal immediately returns to the first LED.
The other thing to note is that the micro-switch is a lot better that
other switches for bouncing - because it is physically small. If you
have one try one that looks like the red one below (or any other large
switch) and you'll really get some random behavior:
When you try the program above you will find it difficult to change the
LEDs reliably for each button press. This is because the bouncing in the
button causes multiple button presses, so the LEDs switch state
randomly and there's no reliable way to select the next LED.
Note: If you don't address this bouncing switch input then you have a totally unreliable design!
The solution is to debounce the switch and there are several ways to do it but a simple method is to wait a short time, like 10-50ms, between
readings to allow any bouncing to complete. Adding the delay function
inside the reading loop fixes this issue reliably.
Example Sketch: Arduino digitalRead with Debounce
You can copy and paste the code below into the Arduino IDE (in a new
sketch) replacing everything that is in the new sketch window (See "Uploading the code" below).
// Button is connected to pin 2
// LED 1 is connected to pin 7
// LED 2 is connected to pin 8
constint buttonPin = 2;
constint ledPin1 = 7;
constint ledPin2 = 8;
int buttonState = 0;
int previousButtonState = 0;
int ledState = 0;
unsignedlong buttonPressTime = 0;
constunsignedlong debounceDelay = 50;
voidsetup(){
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
}
voidloop(){
int reading1 = digitalRead(buttonPin);
delay(50);
int reading2 = digitalRead(buttonPin);
// Detect stable press/release
if(reading1==reading2){ // Press or release is same as 50ms ago.
buttonState = reading1;
if(buttonState == HIGH && // Update on correct transition.
The difference in this code to Ex1 code, is that two readings are
taken separated by 50ms in time. If the readings match then the bouncing
has stopped and the signal level is taken as stable and then used in
the following code.
In this way the unreliable switch bounce operation is eliminated.
Note: You may need to choose longer than 50ms - this depends on the switch characteristics.
Now the LEDs light alternately in the correct way.
Detailed Code Explanation Ex2
The following variables are declared:
const int buttonPin = 2; - Pin number for button.
const int ledPin1 = 7; - Pin number for LED 1.
const int ledPin2 = 8; - Pin number for LED 2.
int buttonState = 0; - Stores current button reading.
int previousButtonState = 0; - Stores last button reading.
int ledState = 0; - Tracks which LED is on (0 or 1).
unsigned long buttonPressTime = 0; - Stores button press time.
const unsigned long debounceDelay = 50; - Debounce delay value.
Setup Function
The setup function configures the pins:
Sets button pin to INPUT_PULLUP to enable internal pull-up resistor.
Sets LED pins to OUTPUT to control them.
Loop Function
The main code is in loop():
Read button pin twice with 50ms delay.
If readings match, it's stable - assign to buttonState.
Check if buttonState is HIGH and previous was LOW, indicating a press.
If pressed, toggle LED state by changing digitalWrite values.
Update previousButtonState for next loop.
By debouncing with a delay, only stable presses are detected to avoid
errors from bounce. The LEDs toggle on each press of the button.
Conclusions
Even though the circuit is simple, using buttons has the compilation
of dealing with switch bounce. This tutorial showed you how to use
digitalRead to read the value of an external push button. This was achaived by employing the
internal pull up resistor in the connected microcontroller pin. It also
demonstrates one method of overcoming switch bounce.
You should be aware that, although this debounce method does work,
for a high performance system the delay() function should not be used
(as it stops the processor during the delay() operation).
Instead, a delay calculating method should be used that uses the
millis() function. It was not shown in this tutorial as delay() is the
easier method to understand and does work well.
To find out more about the correct delay timing method using millis() you should look at these resources:
How to get accurate DHT22 digital humidity sensor readings with an Arduino. Did you know it also measures temperature as Well? Find out why, in this page...
A PIR sensor lets your Arduino sense movement without contact. This tutorial covers PIR sensor basics, connecting one to an Arduino board and coding a motion detector.
Arduino Hall Effect Sensor: Add magnetic sensing superpowers to your Arduino projects with an easy-to-use hall effect sensor. With full code and layout...
Comments
Have your say about what you just read! Leave me a comment in the box below.
Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.