Arduino digitalRead Tutorial

Introduction

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.

How to solve switch bounce problems

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.

arduino 2leds with button layout with breadboard
Diagram using fritzing

The schematic shows the pin connections and components.
arduino 2leds with button schematic
Diagram using fritzing

Using Arduino digitalRead

There are two elements to using a pin and reading its value:

  1. You need to tell the microcontroller that the pin is to be an input (they can be input, output or "input - pulled-up").
  2. 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;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
}

void loop() {

  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:

different switches

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

const int buttonPin = 2;
const int ledPin1 = 7;
const int ledPin2 = 8;

int buttonState = 0;
int previousButtonState = 0;
int ledState = 0;

unsigned long buttonPressTime = 0;
const unsigned long debounceDelay = 50;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
}

void loop() {

  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.
    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-debounced-delay.ino

Arduino digitalRead: Code Explanation Ex2

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():

  1. Read button pin twice with 50ms delay.
  2. If readings match, it's stable - assign to buttonState.
  3. Check if buttonState is HIGH and previous was LOW, indicating a press.
  4. If pressed, toggle LED state by changing digitalWrite values.
  5. 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:

Information page "easy-switch-debounce".
Information page "arduino-millis".
A related page is: "Arduino Toggle Switch" (uses push button as a toggle).




Written by John Main who has a degree in Electronic Engineering.

Note: Parts of this page were written using claude-instant as a research assistant.


B2


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.



Privacy Policy | Contact | About Me

Site Map | Terms of Use