After reading this tutorial, you will understand the basic of Arduino digital pins: What they are, how to configure them as input or output, how to digitalRead, and how to digitalWrite. Also we present, briefly, the concepts of debouncing, and pull-up & pull-down resistors.

Digital Inputs

Arduino digital pins know only two states: HIGH voltage (1’s) and LOW voltage (0’s), where 1 corresponds to a voltage of 5 volts and 0 to a voltage of 0 volts. The signals to be read in at the digital inputs come from other digital circuits such as push-button or limit switch, or sensors with digital outputs.

pinMode input

The digital pins of the Arduino microcontroller are programmed as inputs by default and have a high input impedance. No configuration needs to be done for an input. In most programs, however, inputs are defined with the pinMode().

As already explained in Arduino Sketch, the configuration is done in the setup() function.

void setup()
{
  pinMode(12, INPUT); // Set pin 12 as input
}

Pull-up and Pull-down Resistors

A pullup or pulldown resistor is used to provide a clearly defined signal (LOW or HIGH) at the input pin. Without a pullup or pulldown resistor, noise on an open input pin can cause Distortion so that false signals are detected by the microcontroller.

If you want to read the status of a switch, for example, a limit switch from a robot, the pullup or pulldown resistor should be connected. This is necessary so that the input has a fixed potential if the switch is not activated, to avoid the so-called floating state, where the actual voltage is not recognized as high nor low.

Pull-up Resistor

The figure below shows the connection of an Arduino input pullup resistor. If the 10kΩ resistor were replaced with wire, there would be a short circuit between 5V and GND pins when pressing the switch. In addition, the signal could no longer be determined correctly due to interference. The pullup resistor ensures that the signal is “pulled up” to VCC.

Pull-up Resistor

Internal Pull-up Resistor

Instead of connecting a pullup resistor, an internal pull-up can be enabled. This configuration is then done in the setup() using the pinMode function by passing the parameter INPUT_PULLUP. The next figure represents the Arduino internal pullup resistor.

void setup()
{
  // Set Port 2 as input and enable pullup resistor 
  pinMode(2, INPUT_PULLUP); 
}
Internal Pull-up Resistor

Pull-down Resistor

The figure below shows the connection of the Arduino input pulldown. It has the same concept as the pull up resistor, except that the read value is 0 V when the switch is not pressed. The pulldown resistor ensures that the signal is “pulled down” to GND.

Pull-down Resistor

digitalRead

Reading the value for a digital input is done using digitalRead(PinNumber). The read result is always a value HIGH or LOW. The Arduino Uno digital pins are in the range from 0 to 13.

int switchVal;           // variable for switch

void setup()
{
  pinMode(12, INPUT); // Set pin 12 as input
}

void loop()
{
  switchVal = digitalRead(12);     // Read pin 12
}

The PinNumber can be passed directly as a number in the pinMode function or passed as a Define or variable initialized at the beginning of the Arduino Sketch.

#define SWITCH_PIN   2   // Define input pin
int switchVal;           // variable for switch

void setup()
{
  pinMode(SWITCH_PIN, INPUT); // Set SWITCH_PIN as input
}

void loop()
{
  switchVal = digitalRead(SWITCH_PIN); // Read switch state
}

Debouncing

When reading digital signals from switches or push-buttons, it often happens that several signals with HIGH and LOW are read when the button is pressed. This behavior is called “bouncing”. As a result, the Arduino thinks that the switch is pressed several times.

The bouncing behavior can be suppressed by means of debouncing. The debouncing can be done on

  • hardware level (debouncing circuit)
  • software level (debouncing code)
Debouncing circuit

One of the debouncing circuits is the RC circuit, which consists of resistor (R) and capacitor (C). Here R2 and C1 act as a so-called low pass filter. The resistor R1 is the pull-up resistor.

RC Circuit
Debouncing code

Instead of using extra components for the debouncing circuit, the bouncing issue can be solved using the software. The simplest way is to use a small delay after the digitalRead as below. Choose a value between 10 and 50 ms.

  // read button state
  buttonSt = digitalRead(BUTTON_PIN);
  // Delay 50 ms for debouncing
  delay(50);

A more robust way is to use Arduino debounce code, available in the Arduino IDE under File/Examples/02.Digital/Debounce.

This example implements the hysteresis by using the millis() function to update the button state after milliseconds since the last time the push-button pressed. It reverts the LED state each time the button is pressed.

Digital Outputs

The digital outputs of the Arduino are the signal transmitters to the outside world, which control LEDs, relays, etc. The outputs provide digital signals, i.e. 1 and 0 or HIGH and LOW. The voltage levels are 5 volts for HIGH and 0 volts for LOW. Of course, for 3.3 V Arduino, the output signals at signal HIGH are 3.3 volts.

The Arduino Uno maximum current for digital I/O is 40 mA. This current allows the direct control of an LED with a series resistor. The control of components such as relays, lamps, or motors requires an additional driver circuit that uses transistors or driver IC.

Arduino digitalWrite

Any of the Arduino Uno digital pins (0 to 13) can be initialized as output or input. An output pin must be initialized as output in the setup(). The output voltage is set to HIGH or LOW in the loop() for the application use, as shown in the blinking LED sketch.

Arduino read digital output

In some applications, we would like to read the current state of a specific digital output pin. One solution is to connect another input port to the output port we want to check. However, this solution requires reserving additional digital ports for this simple check!

A better solution to read the output pin with digitalRead(), although it is defined as an output. We wrote the sketch below to present this concept. The LED 1 follows the state of the push button. Next, the program waits 1 second. Subsequently, we read the actual state of LED 1 using ledSt = digitalRead(LED_PIN1) and pass it to LED 2 using digitalWrite(LED_PIN2, ledSt).

#define BUTTON_PIN  2    // Push-button pin
#define LED_PIN1   12    // LED 1 pin
#define LED_PIN2   13    // LED 2 pin

int ledSt = LOW;          // Current LED state
int buttonSt;             // Current button state

void setup()
{
  // Set LED 1 and 2 as outputs
  pinMode(LED_PIN1, OUTPUT);
  pinMode(LED_PIN2, OUTPUT);
  // Initialize pin 12 and 13 as low
  digitalWrite(LED_PIN1, LOW);
  digitalWrite(LED_PIN2, LOW);
}

void loop()
{
  // read button state
  buttonSt = digitalRead(BUTTON_PIN);
  // Delay 10 ms for debouncing
  delay(10);

  // Set LED 1 as button state
  digitalWrite(LED_PIN1, buttonSt);
  
  // Dealy 1000 ms
  delay(1000);
  // Read LED 1 state
  ledSt = digitalRead(LED_PIN1); 
  // Set LED 2 as LED 1
  digitalWrite(LED_PIN2, ledSt); 
}