Yesterday the board output a signal. Today it reads one. Every project that reacts to the world — a doorbell, a tank float switch, a door sensor — starts with this.
What you need
- Arduino Uno or Nano, breadboard
- One 4-leg tactile push button (the small square kind in every kit)
- Two jumper wires
- Day 2’s LED on pin 13 can stay where it is — it will follow the L LED
Wiring
A 4-leg button is two pairs of legs joined inside. Pressing it connects one pair to the other. The legs that are always joined sit on opposite sides — which is why it goes across the middle gap of the breadboard, and why you use diagonally opposite legs: those two are only connected while you press.
| Button | Uno |
|---|---|
| one leg | pin 2 |
| the diagonally opposite leg | GND |
That’s all — no resistor.
Check before power: with the USB unplugged, both wires go to legs in different rows on different sides of the gap. If the button sits on one side only, or turned 90°, two of its joined legs share a row and it acts as if it’s always pressed.
Why INPUT_PULLUP?
An input pin that isn’t connected to anything floats: it picks up noise from your hand and the wires, and reads random HIGHs and LOWs. A pull-up resistor gently holds the pin HIGH until the button connects it to GND. The Uno has one built into every pin — pinMode(2, INPUT_PULLUP) switches it on.
The catch: the logic is upside down. Released reads HIGH, pressed reads LOW. That’s why the code checks digitalRead(BUTTON_PIN) == LOW.
Upload and count
Upload today’s code, open the Serial Monitor at 9600 baud and press the button three times. You should see:
Press the button...
Pressed 1 time
Pressed 2 times
Pressed 3 times
The L LED (and day 2’s LED) stays lit only while you hold the button.
How each press counts once
loop() runs hundreds of times a second, so a single press would otherwise be counted again on every pass. The sketch remembers the previous state in wasPressed and only counts the moment the button goes from released to pressed (pressed && !wasPressed).
The delay(20) at the end also hides contact bounce: when the metal contacts inside close, they chatter on and off for a few milliseconds, which looks like several quick presses.
Two experiments: see the problems for yourself
1. A floating pin. Change INPUT_PULLUP to INPUT and upload. Don’t touch the button — wave your hand near the wires or touch the pin 2 jumper. The count climbs by itself and the LED flickers. That’s noise on a floating pin. Change it back to INPUT_PULLUP.
2. Bounce. Change delay(20) to delay(0) and press the button 20 times. With most buttons, a few presses count as 2 or 3. Put delay(20) back.
Both bugs show up constantly in real projects, usually as “it counts wrong sometimes”. Now you know what they look like.
Try it: make it a toggle
Change the sketch so each press toggles the LED — on, then off at the next press — instead of lighting only while held.
Hint: add bool ledOn = false; next to wasPressed. Inside the if (pressed && !wasPressed) block, add ledOn = !ledOn; (the ! means “not”). Then change the digitalWrite line to use ledOn instead of pressed.
Done early? Add a second button on pin 3 (diagonal leg to GND) that sets presses back to 0 and prints Reset.
Common mistakes
- LED always on, count stuck at 1: the button is turned 90° or not across the gap.
- Nothing happens when pressed: the second wire goes to 5V instead of GND. With a pull-up, the pin is already HIGH, so connecting it to 5V changes nothing.
- Counts jump by 2 or 3: bounce — check the
delay(20)is still there. if (digitalRead(2) = LOW)— one=sets a value,==compares. The compiler may only warn you.
You’re done when…
- Each press adds exactly one to the count in the Serial Monitor.
- You saw the count climb on its own with
INPUT, and fixed it withINPUT_PULLUP. - Your toggle version switches the LED on with one press and off with the next.
- You can say why a pressed button reads
LOWhere.
Tomorrow: inputs that aren’t just on or off.
Today's code
// Day 3 — Buttons and INPUT_PULLUP (Arduino Uno / Nano)
// Wire a push button between pin 2 and GND. No resistor needed: INPUT_PULLUP turns on
// the chip's internal pull-up, so the pin reads HIGH when released and LOW when pressed.
const int BUTTON_PIN = 2;
const int LED_PIN = 13; // the on-board "L" LED
int presses = 0;
bool wasPressed = false;
void setup() {
Serial.begin(9600);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
Serial.println("Press the button...");
}
void loop() {
bool pressed = digitalRead(BUTTON_PIN) == LOW; // LOW = pressed with a pull-up
digitalWrite(LED_PIN, pressed ? HIGH : LOW);
if (pressed && !wasPressed) { // count each press once, not every loop
presses++;
Serial.print("Pressed ");
Serial.print(presses);
Serial.println(presses == 1 ? " time" : " times");
}
wasPressed = pressed;
delay(20); // a short wait also hides contact bounce
}// Day 3 — Buttons and INPUT_PULLUP (Arduino Uno / Nano)
// Wire a push button between pin 2 and GND. No resistor needed: INPUT_PULLUP turns on
// the chip's internal pull-up, so the pin reads HIGH when released and LOW when pressed.
const int BUTTON_PIN = 2;
const int LED_PIN = 13; // the on-board "L" LED
int presses = 0;
bool wasPressed = false;
void setup() {
Serial.begin(9600);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
Serial.println("Press the button...");
}
void loop() {
bool pressed = digitalRead(BUTTON_PIN) == LOW; // LOW = pressed with a pull-up
digitalWrite(LED_PIN, pressed ? HIGH : LOW);
if (pressed && !wasPressed) { // count each press once, not every loop
presses++;
Serial.print("Pressed ");
Serial.print(presses);
Serial.println(presses == 1 ? " time" : " times");
}
wasPressed = pressed;
delay(20); // a short wait also hides contact bounce
}