Overview
INPUT_PULLUP enables a resistor inside the chip that holds the pin HIGH. Wire
the button from the pin to GND and you need no extra parts. The catch is contact bounce: a mechanical switch
chatters for a few milliseconds when pressed, which a fast loop sees as several presses.
You will need
- Arduino Uno R3
- Momentary pushbutton
- Jumper wires
Wiring
| Uno pin | Connects to | Notes |
|---|---|---|
| 2 | Button, one side | INPUT_PULLUP: reads LOW when pressed (active-low) |
| GND | Button, other side |
Diagram
The sketch
const int BUTTON_PIN = 2;
const unsigned long DEBOUNCE_MS = 30;
int stableState = HIGH; // debounced state (HIGH = released)
int lastReading = HIGH; // raw reading from the previous loop
unsigned long lastChangeMs = 0;
bool ledOn = false;
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
int reading = digitalRead(BUTTON_PIN);
if (reading != lastReading) { // raw input changed: restart the timer
lastChangeMs = millis();
lastReading = reading;
}
if (millis() - lastChangeMs >= DEBOUNCE_MS && reading != stableState) {
stableState = reading; // stable long enough: accept it
if (stableState == LOW) { // a new press
ledOn = !ledOn;
digitalWrite(LED_BUILTIN, ledOn ? HIGH : LOW);
}
}
}How the code works
The sketch accepts a new state only after the raw reading has stayed the same for 30 ms,
and acts only on the change from released to pressed. Unlike a delay()-based debounce, the loop
never stops, so it can do other work at the same time. The workshop button projects use the simpler
blocking approach, which is fine when the button is the only thing the sketch watches.
What you should observe
- Each press toggles the L LED exactly once.
- Set
DEBOUNCE_MSto 0 and some presses will toggle twice (the LED appears not to change).