HomeArduinoCore TutorialsdigitalWrite() and digitalRead()

Arduino digitalWrite() and digitalRead(): Complete Guide with Examples

digitalWrite() and digitalRead() are the two functions you’ll use in almost every Arduino project. One controls outputs — LEDs, buzzers, relays, motors. The other reads inputs — buttons, switches, sensors. Together they are the foundation of all Arduino GPIO interaction.

In this tutorial you’ll learn exactly how both functions work, what pinMode() does and why it must be called first, when to use INPUT_PULLUP instead of plain INPUT (and why it matters), and how to combine both functions in a real working example — a button that controls an LED. Wiring diagrams, full code with line-by-line explanation, and tested results are all included. The project is available to download at the bottom of the page.

This is part of the Arduino Core Tutorials series. If you’re new to Arduino I/O, start with the following:

Arduino digitalWrite() and digitalRead() Tutorial

Arduino digitalWrite(): Controlling Digital Output

The Arduino GPIO pins can work as either inputs or outputs. When you set a pin as an output, you can use it to control devices like LEDs, buzzers, motors, or relays. To configure a pin as an output, you need the pinMode() function.

For example, if you want to set pin 13 as an output, the code looks like this:

pinMode(13, OUTPUT);

Once the pin is configured, you can use the digitalWrite() function to set it either HIGH (ON) or LOW (OFF). This makes it easy to control connected components.

pinMode() and Output Configuration

void setup() {
  pinMode(13, OUTPUT);       // Set pin 13 as output
  digitalWrite(13, HIGH);    // Set pin 13 as HIGH (5V or 3.3V)
}
void loop(){
}

setup() runs once when the Arduino starts. pinMode(13, OUTPUT) will set the pin 13 as an output pin and digitalWrite(13, HIGH) will pull the pin to HIGH (5V or 3.3V). If you connect a voltmeter to measure the voltage of this pin, you should be able to see how much your Arduino outputs.

Key Points to Remember

  • Always set the pin as OUTPUT using pinMode() before calling digitalWrite().
  • HIGH = ON (5V or 3.3V), LOW = OFF (0V).
  • Use resistors when connecting LEDs to protect the pin.
  • Do not connect high-current devices directly; instead, use a relay, transistor, or MOSFET.

Output Voltage and Current Limits

Output Voltage

On most Arduino boards, the digital output voltage is:

  • HIGH = 5V (or 3.3V on some boards)
  • LOW = 0V (Ground)

Important: Never connect one Arduino output pin directly to another output pin, or to the output of a sensor or IC. If two outputs with different voltages are connected, a large current may flow, which can damage the Arduino pin permanently.

Each GPIO pin also has protection diodes that help prevent damage from small voltage spikes. Still, it’s best to always match the voltage levels of your components. If you’re using a mix of 3.3V and 5V devices, you should use a level shifter for safety.


Output Current

Every Arduino digital pin can supply or receive a small amount of current.

  • The maximum current per pin is 40 mA, but this is the absolute limit.
  • The safe recommended current is about 20 mA per pin.

This is enough for driving small components like LEDs (with a resistor) or buzzers. But if you need to control devices that require more current—like motors, relays, or high-power LEDs—you must use an external driver circuit, transistor, or relay module.


Wiring an LED to Arduino Pin 13

The image below shows how the LED is connected to the Arduino Uno.

Arduino Uno wiring diagram — LED connected to pin 13 via 330Ω resistor with cathode to GND

Even though Arduino already has an onboard LED connected to pin 13, I have added an external LED as well to demonstrate how we can connect an LED to the Arduino.

  • Connect the anode (long leg) of the LED to digital pin 13 of the Arduino through a 330 Ω resistor.
    • The resistor is used to limit the current and protect the LED from burning out.
  • Connect the cathode (short leg) of the LED directly to the GND pin of the Arduino.

LED Blink Code with digitalWrite() — Line by Line

Now that the LED is connected to the Arduino Uno, we will write a code to blink this LED at a defined rate. The digitalWrite function can only Set or Reset the pins, therefore, we will add a small delay between the Setting and Resetting of the pin to have a blinking effect.

The code below blinks the LED every 1 second.

#define LED_PIN 13  // LED is connectde to Pin 13

void setup() {
  pinMode(LED_PIN, OUTPUT);       // Set LED Pin as output
}

void loop() {
  digitalWrite(LED_PIN, HIGH);    // Set Led Pin High to turn the LED ON
  delay(1000);              // Wait 1 second (1000ms)
  digitalWrite(LED_PIN, LOW);     // Reset Led Pin to Low to turn the LED OFF
  delay(1000);              // Wait 1 second (1000ms)
}

Let’s break down this code in small parts to understand it better.

Pin Definitions

#define LED_PIN 13

#define LED_PIN 13 tells the Arduino that LED_PIN is just another name for pin 13. This makes your code easier to read. If you later move the LED to pin 12, you just change this line.

setup () function

void setup() {
  pinMode(LED_PIN, OUTPUT);       // Set LED Pin as output
}

setup() runs once when the Arduino starts. pinMode(LED_PIN, OUTPUT) tells Arduino: “Pin 13 will send out voltage, not read it.” Since an LED lights up when voltage flows through it, this pin needs to be an output.

loop () function

void loop() {
  digitalWrite(LED_PIN, HIGH);    // Set Led Pin High to turn the LED ON
  delay(1000);              // Wait 1 second (1000ms)
  digitalWrite(LED_PIN, LOW);     // Reset Led Pin to Low to turn the LED OFF
  delay(1000);              // Wait 1 second (1000ms)
}

The loop() function runs forever. Inside this function, we will set the LED_PIN (Pin 13) HIGH and LOW after every 1 second. This will have a blinking effect on the LED connected to the this pin. The LED will keep blinking forever as long as the Arduino is connected to the power supply.


LED Blink Test Results

After uploading the example code to your Arduino, here’s what you should observe:

The LED connected to pin 13 turns ON for 1 second, then OFF for 1 second. This cycle repeats continuously, showing that the digital output pin is working correctly. This confirms that your pin has been correctly configured as OUTPUT using pinMode().

Arduino digitalRead(): Reading Digital Input

Just like Arduino pins can act as outputs, they can also work as digital inputs. In this mode, the pins are used to read signals from external devices such as buttons, switches, and digital sensors. With digital input, Arduino can detect whether a pin is receiving a HIGH (ON) signal or a LOW (OFF) signal, which makes your projects interactive.

To use a GPIO pin as an input, you need the pinMode() function. For example, if you want to set pin 2 as an input:

pinMode(2, INPUT);  // Set pin as input

Once the pin is configured, you can use the digitalRead() function to Read it.

pinMode() and Input Configuration

void setup() {
  pinMode(2, INPUT);  // Set pin as input
}
void loop(){
  int buttonState = digitalRead(2);
}

The setup()function runs once when the Arduino starts. pinMode(2, INPUT) will set the pin 2 as an input pin. We can read the state of this pin inside the loop(), which runs forever. The current state of the Pin 2 will be stored in the buttonState variable.

  • If the pin is receiving voltage, digitalRead() will return HIGH.
  • If the pin is connected to ground, it will return LOW.

Problem: If nothing is connected to the pin, it “floats”, meaning it can randomly read HIGH or LOW. This can make your program behave unpredictably.


INPUT vs INPUT_PULLUP: When to Use Each

Arduino also provides an internal pull-up resistor that can be activated using:

pinMode(2, INPUT_PULLUP);  // set input with default state as HIGH

INPUT_PULLUP also sets the pin to read voltage, but it turns on a built-in pull-up resistor. This means the pin is internally connected to 5V (HIGH) through a resistor, so it stays HIGH when the button is not pressed.

When you press the button and connect the pin to GND, it reads LOW. This feature reduces wiring complexity because you don’t need an external resistor.

FeatureINPUTINPUT_PULLUP
Pin state without inputFloating, randomHIGH (stable)
External resistor neededYesNo (built-in)
Button wiringConnect to GND, need resistorConnect to GND only, simpler wiring
Risk of errorHigh (false reads)Low (stable, predictable)

Input Voltage, Current & Common Use Cases

The Arduino reads digital inputs as either:

  • HIGH = 5V (or 3.3V on some boards)
  • LOW = 0V (GND)

Never apply voltage higher than the board’s rated voltage to an input pin, as this can permanently damage the Arduino.

Arduino input pins draw a very small current (microamps), which is safe to connect to switches, sensors, and buttons directly. The pin only “listens” to the voltage and does not supply power.

Digital input is the basis of many Arduino projects. Some common examples include:

  • Buttons and Switches → Detecting user input
  • Motion Sensors (PIR) → Detecting movement
  • IR Sensors → Reading obstacle detection signals
  • Limit Switches → Used in robotics and CNC machines

Wiring a Button to Arduino Pin 2

The image below shows how a button can be added to the Arduino Uno.

Arduino Uno wiring diagram — push button on pin 2 using INPUT_PULLUP and LED on pin 13 as output

We are going to use the INPUT_PULLUP mode for reading the Pin 2. This means that the pin will be HIGH in the default state. The button the connected between the Pin 2 and ground of Arduino.

When the button is pressed, the Pin 2 will connect to the ground and the the pin state will change to LOW.


Button Read Code with digitalRead() — Line by Line

Before reading a pin, you must configure it as an input using pinMode(). You can also use INPUT_PULLUP to enable the internal pull-up resistor, which is useful for buttons.

const int buttonPin = 2;   // Button connected to pin 2
const int LED_PIN = 13;    // LED connected to pin 13

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);    // Button pin uses internal pull-up
  pinMode(LED_PIN, OUTPUT);            // LED pin is output
}

void loop() {
  int buttonState = digitalRead(buttonPin);  // Read button state

  if (buttonState == LOW) {                 // If button is pressed
    digitalWrite(LED_PIN, HIGH);           // Turn LED ON
  } else {                                  // If button is not pressed
    digitalWrite(LED_PIN, LOW);            // Turn LED OFF
  }
}

Let’s break down this code in small parts to understand it better.

Pin Definitions

const int buttonPin = 2;   // Button connected to pin 2
const int LED_PIN = 13;     // LED connected to pin 13

First define the pins used by the button and LED. This make it easier for us to change them later.

setup() Function

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);    // Button pin uses internal pull-up
  pinMode(LED_PIN, OUTPUT);            // LED pin is output
}

The setup() runs once when the Arduino starts. Here we will configure the buttonPin as Input with internal Pull-Up resistor and the LED pin as output. The Internal Pull-Up will keep the button state HIGH while the button is not pressed.

loop() Function

  int buttonState = digitalRead(buttonPin);  // Read button state

  if (buttonState == LOW) {                 // If button is pressed
    digitalWrite(LED_PIN, HIGH);           // Turn LED ON
  } else {                                  // If button is not pressed
    digitalWrite(LED_PIN, LOW);            // Turn LED OFF
  }

The loop () function runs forever. Here we will continuously read the state of the buttonPin using the function digitalRead(). Since this pin is connected to the 5V (or 3.3V) using the internal Pull-UP, the pin will read HIGH by default. In this situation the LED will be turned OFF.

When the button is pressed, the pin is pulled LOW to the ground and the function digitalRead()will also return LOW. At this point we will turn the LED ON.


Button Read Test Results

After uploading the example code to your Arduino, here’s what you should observe:

As you can see in the video, the LED is OFF by default. When the button is pressed, the LED turns ON and it stays ON as long as the button is pressed. On realeasing the button, the LED turns OFF again. This confirms that our code is working well, just as we programmed it.

Arduino digitalWrite() and digitalRead(): FAQ

Conclusion

digitalWrite() and digitalRead() are simple functions with a lot of depth once you understand what's happening underneath — why floating pins cause random reads, why INPUT_PULLUP is almost always the right choice for buttons, and why a 330 Ω resistor is required before connecting an LED to any output pin.

From here, the direct next step is PWM and analogWrite() — which builds on the same output pins to give you variable control over brightness and speed rather than just ON/OFF. If your project needs to react to events without blocking the main loop, external interrupts is how you handle button presses without polling inside loop(). And when you need to read analog signals from sensors like potentiometers or temperature sensors, analogRead() and ADC covers the other half of Arduino's I/O system.

Download Arduino digitalWrite() and digitalRead() Project Files

Complete Arduino sketch with LED blink using digitalWrite() and button-controlled LED using digitalRead() with INPUT_PULLUP — ready to upload and test. Free to download — support the work if it helped you.

Arduino sketch digitalWrite + digitalRead Button + LED example

Browse More Arduino Core Tutorials

About the Author
Arun Rawat
Arun Rawat
Embedded Systems Engineer · Founder, ControllersTech

Arun is an embedded systems engineer with 10+ years of experience in STM32, ESP32, and AVR microcontrollers. He created ControllersTech to share practical tutorials on embedded software, HAL drivers, RTOS, and hardware design — grounded in real industrial automation experience.

Subscribe
Notify of

0 Comments
Newest
Oldest Most Voted
×

Don’t Miss Future STM32 Tutorials

Join thousands of developers getting free guides, code examples, and updates.