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:
- analogRead() and ADC
- PWM & analogWrite()
- delayMicroseconds()
- external interrupts
- UART serial communication

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 callingdigitalWrite(). - 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.
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 inputOnce 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 HIGHINPUT_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.
| Feature | INPUT | INPUT_PULLUP |
|---|---|---|
| Pin state without input | Floating, random | HIGH (stable) |
| External resistor needed | Yes | No (built-in) |
| Button wiring | Connect to GND, need resistor | Connect to GND only, simpler wiring |
| Risk of error | High (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.
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 13First 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
digitalRead() and digitalWrite() on analog pins?Yes! On most Arduino boards, analog pins (like A0–A5) can also function as digital pins. You can use them with pinMode(), digitalRead(), and digitalWrite(). Just remember that their pin numbers may differ depending on the board (e.g., A0 might be pin 14 on Arduino Uno).
INPUT for a button?This happens because the pin is floating—it doesn’t have a defined voltage when the button is not pressed. Using INPUT_PULLUP or adding an external pull-down resistor ensures stable readings.
digitalWrite() to dim an LED?Not directly. digitalWrite() only supports ON (HIGH) and OFF (LOW) states. To dim an LED, you need PWM pins and the analogWrite() function.
Both configure a pin to read an incoming signal, but they differ in default state. INPUT leaves the pin floating — with no connection, it can randomly read HIGH or LOW, causing unpredictable behavior. INPUT_PULLUP enables the Arduino's internal pull-up resistor, which holds the pin at HIGH by default. When the button is pressed and connects the pin to GND, it reads LOW. For buttons and switches, INPUT_PULLUP is almost always the right choice because it eliminates floating and removes the need for an external resistor.
The absolute maximum current per GPIO pin is 40 mA, but the safe recommended operating limit is 20 mA. The total current across all pins combined should not exceed 200 mA on an Arduino Uno. For components that need more current — DC motors, relays, solenoids, or high-power LEDs — always use an external driver such as a transistor, MOSFET, or relay module. Exceeding the pin current limit can permanently damage the microcontroller.
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.
Browse More Arduino Core Tutorials
Arduino ADC and analogRead() Explained: Complete Guide with Examples
Arduino I2C Tutorial: Wire Library, Master/Slave, Scanner & Troubleshooting
Arduino delayMicroseconds() Tutorial: Precise Timing, Pulses & Alternatives
Arduino PWM and analogWrite() Explained: Complete Guide with Examples
Arduino External Interrupts Tutorial: attachInterrupt(), ISR & Debounce
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.
Recommended Tools
Essential dev tools
Categories
Browse by platform


