~90 min. Wire a pushbutton to a digital input pin; read it with digitalRead; toggle an LED when the button is pressed; add debouncing.
Goal: complete a full input-output loop in software; understand active-low logic and debouncing
Estimated time: 90 minutes
Prerequisites: lab 7.1 + 7.2 complete
Steps
Step 1: Wire the button (15 min)
Pushbutton on the breadboard, spanning the central gap (so its two sides are on different tie-strips). One side: connect to pin 2. Other side: connect to GND
That's it. With INPUT_PULLUP, you don't need an external resistor; the Arduino provides an internal one. The button shorts pin 2 to ground when pressed; pin 2 reads HIGH (5 V through pullup) when released and LOW (~0 V) when pressed
Wire an LED + resistor on pin 8 as in lab 7.2 (so you have something to control)
Step 2: Read the button (20 min)
Write a sketch:
void setup() {
pinMode(2, INPUT_PULLUP);
pinMode(8, OUTPUT);
Serial.begin(9600);
}
void loop() {
int state = digitalRead(2);
Serial.println(state);
delay(100);
}
Upload. Open Serial Monitor (Tools → Serial Monitor; baud 9600). You should see "1" when the button is released and "0" when pressed. The "0" is LOW (button pulls pin to ground); the "1" is HIGH (pullup keeps pin at 5 V when button is released)
Step 3: Drive LED from button (10 min)
Modify the sketch:
void loop() {
int state = digitalRead(2);
if (state == LOW) {
digitalWrite(8, HIGH); // pressed = LED on
} else {
digitalWrite(8, LOW); // released = LED off
}
}
Upload. Verify: hold the button = LED on. Release = LED off
Step 4: Implement a toggle (20 min)
A "toggle" means the LED state changes once per button PRESS (not on each loop iteration the button is held). Add state tracking:
int lastState = HIGH;
int ledState = LOW;
void loop() {
int state = digitalRead(2);
if (state == LOW && lastState == HIGH) {
// edge: button just pressed
ledState = !ledState;
digitalWrite(8, ledState);
}
lastState = state;
}
Upload. Each press toggles the LED. The LED stays in its new state until the next press
Step 5: Add debouncing (25 min)
Without debouncing, one press registers as several (mechanical bounce). Add a 20 ms confirmation:
int lastState = HIGH;
int ledState = LOW;
unsigned long lastChange = 0;
void loop() {
int state = digitalRead(2);
if (state != lastState) {
lastChange = millis(); // start timer on any change
}
if ((millis() - lastChange) > 20 && state != lastState) {
// state has been stable for 20ms; accept
lastState = state;
if (state == LOW) {
ledState = !ledState;
digitalWrite(8, ledState);
}
}
}
(This is one common debouncing pattern; there are others. Read the Arduino "Debounce" example if you want more depth.)
Upload. Test by pressing slowly and rapidly. The LED should toggle exactly once per press, even on fast presses
Expected output
- Working button-toggles-LED with debouncing
- Serial Monitor showing the button state in real time
- Notebook reflection on why debouncing matters
Common pitfalls
- Missing pinMode(2, INPUT_PULLUP): without it, pin 2 floats and reads garbage
- Wiring the button to +5V instead of GND: with pullup, the button SHORTS TO GROUND when pressed. Wiring to +5V means the button does nothing (already pulled high; pressing just confirms it)
- No debouncing: a single press registers as 2-5 toggles. The lab works without debouncing; debouncing is the next-level polish
Stretch (optional)
- Add a second button on pin 3 that controls a second LED on pin 9. Both buttons work independently
- Make the LED blink (not just toggle) when the button is pressed: press = start blinking; press again = stop. This requires a state machine: idle / blinking
- Replace
Serial.println(state)with a count: print "button pressed N times" for each accepted press
Lab 8.1 v0.1. The first input + output Arduino lab. Pattern used in dozens of weeks ahead.