One-sentence summary
Digital output lets us control a part such as an LED by turning a pin on and off, and digital input lets us read whether a button is pressed; combining these two ideas lets the Arduino make decisions like "turn on the light when the button is pressed."
Why does it matter?
In the Blink lesson we turned an LED on and off. But that LED did not hear anything from us; it just blinked for the time we wrote in the code. Real devices listen to their surroundings: you press a button and a light turns on; you touch a key and a door opens.
In this lesson we meet the two directions of an Arduino. Digital output is the Arduino sending something to the world: it turns a pin on (5 volts) or off (0 volts). Digital input is the Arduino listening to the world: it checks whether there is a signal on a pin.
The word "digital" here simply means there are only two values: on or off, 1 or 0. There is nothing in between. For a button this fits perfectly; a button is either pressed or it is not. This two-value logic is the foundation of every computer.
Digital output: controlling a pin
You may remember from the Blink lesson that the digitalWrite command sets a pin to HIGH (about 5 volts, on) or LOW (0 volts, off). When we connect an LED to that pin through a resistor, the LED lights up when the pin turns on.
Wiring
- The long leg of the LED (positive, anode) connects to a resistor.
- The resistor (220–330 ohm) goes to pin 8.
- The short leg of the LED (negative, cathode) connects to GND.
The resistor is essential. Without it, too much current flows through the LED and the LED (and sometimes the pin) can be damaged. Think of the resistor as a narrowing in a water pipe: it keeps the flow at a safe level.
The code
int ledPin = 8;
void setup() {
pinMode(ledPin, OUTPUT); // pin 8 will be an output
}
void loop() {
digitalWrite(ledPin, HIGH); // turn the LED on
delay(1000);
digitalWrite(ledPin, LOW); // turn the LED off
delay(1000);
}
This is the same as Blink, except we stored the pin number in a variable. The line pinMode(ledPin, OUTPUT) tells the Arduino "I will send a signal out of this pin." If we forget to set a pin as an output, digitalWrite will not work properly.
Digital input: reading a button
Now we want the Arduino to listen. We read the state of a button with the digitalRead command. This command returns HIGH or LOW.
Why do we need INPUT_PULLUP?
When you leave a button pin unconnected, a strange problem appears: the pin is neither on nor off, it picks up electrical noise from the air and reads a random HIGH or LOW. This is called a "floating input."
The fix is to pull the pin to a fixed value with a resistor. The Arduino can do this for us internally: when we write pinMode(pin, INPUT_PULLUP), the pin is pulled to HIGH through a built-in resistor. So when the button is not pressed, digitalRead reads HIGH.
We connect the other leg of the button to GND. When you press the button, the pin is connected to GND and reads LOW. This can feel backwards: pressed = LOW, released = HIGH. But not needing an external resistor makes it worth it.
Wiring
- One leg of the button to pin 2.
- The other leg of the button to GND.
- The LED still on pin 8, with a resistor (as above).
Watching the button with Serial
First let us see what the button reads with our own eyes. Serial lets us send messages from the Arduino to the computer.
int buttonPin = 2;
void setup() {
Serial.begin(9600);
pinMode(buttonPin, INPUT_PULLUP);
}
void loop() {
int state = digitalRead(buttonPin);
Serial.println(state); // pressed=0, released=1
delay(200);
}
When you upload the code and open the Serial Monitor, you see 1 (HIGH) when the button is not pressed and 0 (LOW) when you press it. This is how we read the invisible language of electricity.
Combine the two: control an LED with a button
Now for the real goal: the LED lights up when the button is pressed and turns off when you release it. We combine input and output in one program.
int buttonPin = 2;
int ledPin = 8;
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}
void loop() {
if (digitalRead(buttonPin) == LOW) { // pressed
digitalWrite(ledPin, HIGH); // turn LED on
} else {
digitalWrite(ledPin, LOW); // turn LED off
}
}
The program keeps looping inside loop. On every turn it reads the button. If it is pressed (LOW) it turns the LED on, otherwise it turns it off. This is the condition structure from the Algorithms lesson, now working on real hardware: "If the button is pressed, turn on the light."
Two everyday examples
A doorbell. A bell button works with exactly this logic. When you press it the circuit closes and the sound inside turns on; when you release it, it goes quiet. Our button-and-LED is a tiny doorbell; it just gives light instead of sound.
A fridge light. When you open the door the light turns on, when you close it the light turns off. A small switch at the edge of the door feeds a digital input. While the door is closed the switch is pressed (light off); when it opens the switch is released (light on). It is the same "read the input, decide the output" idea.
Mini practice
Build and run the button-and-LED circuit above. Then change the code so that each press of the button toggles the LED (if it is on, turn it off; if it is off, turn it on) — just like a real room light switch.
Hint: Keep the LED's state in a variable. To catch the moment the button is pressed, also store the previous reading.
int buttonPin = 2;
int ledPin = 8;
bool ledOn = false;
int previousState = HIGH;
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}
void loop() {
int state = digitalRead(buttonPin);
if (previousState == HIGH && state == LOW) { // new press
ledOn = !ledOn;
digitalWrite(ledPin, ledOn);
delay(50); // reduce bounce
}
previousState = state;
}
Run it and observe: sometimes a single press seems to toggle twice. We explain why in the "Common mistakes" section.
Common mistakes
Forgetting the pinMode line
If you do not set the pin type, input and output will not behave as expected. Set the button to INPUT_PULLUP and the LED to OUTPUT inside setup.
Connecting an LED without a resistor
If you plug the LED directly into a pin, too much current flows. The LED can burn out or the pin can be damaged. Always connect it through a 220–330 ohm resistor.
Getting the INPUT_PULLUP logic backwards
With INPUT_PULLUP a button reads HIGH when released and LOW when pressed. If you write == HIGH instead of == LOW, the LED behaves the opposite way.
Button bounce (debounce)
Buttons work with metal contacts; the moment you press, the contact jitters for a few milliseconds. The Arduino may read this as several presses. A small delay(50), or a wait built with millis, smooths out this bounce.
Safety note
- In this lesson we use only low voltage: the 5 volts the Arduino gets from USB or a battery pack. Never experiment with mains electricity (wall sockets).
- Always connect an LED through a current-limiting resistor. A connection without a resistor can heat parts up.
- When you change wiring, unplug the Arduino's USB cable; build and check the circuit, then plug it back in.
- If you want to run a motor, pump, or a strong load, do not do it directly from an Arduino pin. Motors need a motor driver board and a separate power source; otherwise the Arduino can be damaged. Remember to start motors at low speed.
- Build your first circuit together with an adult. If you are unsure about a connection, do not power it up before asking.
Lesson summary
- Digital output (
digitalWrite) controls parts such as LEDs by setting a pin toHIGHorLOW. - Digital input (
digitalRead) reads whether a pin isHIGHorLOW; this is how we learn a button's state. INPUT_PULLUPprevents a floating input: the button readsHIGHwhen released andLOWwhen pressed.- By combining input and output with an
ifcondition, we build decisions like "turn on the light when the button is pressed." - Always connect an LED through a resistor and work only with low voltage.
Check questions
- What does the command
digitalWrite(8, HIGH)do? - Which command do we use to read the state of a button?
- With
INPUT_PULLUP, what doesdigitalReadreturn when the button is released:HIGHorLOW? - What can happen if we connect an LED without a resistor?
- To turn the LED on when the button is pressed, how do we write the
ifcondition asdigitalRead(buttonPin) == ?(with INPUT_PULLUP)?
Answers
- It sets pin 8 to
HIGH(about 5 volts); if an LED is connected to that pin through a resistor, it lights up. - We use the
digitalReadcommand; it returnsHIGHorLOW. - It returns
HIGH.INPUT_PULLUPpulls the pin toHIGHthrough a built-in resistor; when the button is pressed the pin connects to GND and becomesLOW. - Too much current flows through the LED; the LED can burn out or the Arduino pin can be damaged. This is why we use a 220–330 ohm resistor.
- We write
if (digitalRead(buttonPin) == LOW). Because withINPUT_PULLUPa pressed button readsLOW.
Source and verification note
For “Digital Input and Output”, verification focuses on whether the relationship between Digital output: controlling a pin and The code remains consistent across examples. Pin, voltage and current limits can differ between Arduino-compatible boards. Compiling code does not guarantee a safe circuit; loads such as motors and servos require a suitable driver and external power where appropriate.
Next lesson
Analog Read: A pin can read not just on/off but many values in between. With analogRead we will read a potentiometer or a light sensor and turn it into numbers from 0 to 1023.