Basics · 3 min read

How to Connect a Push Button to Arduino: Pull-up, Pull-down and Debounce

How do you connect a push button to Arduino? The inside of a 4-leg button, pull-up and pull-down resistors, INPUT_PULLUP, debounce and an example that toggles an LED.

A button is the simplest part for bringing a user's touch into an Arduino project. Pressed, it joins two contacts; released, it separates them. Simple as it looks, wired wrongly it reads random values or counts one press several times. In this guide we cover how to connect and read a button correctly.

Push button
4-leg tactile switch. The legs are connected internally in pairs.

Inside a 4-leg button

The 6×6 mm tactile button you'll use most on a breadboard has 4 legs but only 2 connection points: opposite leg pairs are already connected inside. Pressing the button joins the two pairs. If you seat the button across the center channel of the breadboard, each pair lands in separate rows and the right orientation is easy.

If you're unsure of the orientation, set your multimeter to continuity: legs that beep without pressing are an already-connected pair. Legs that beep only when pressed are the ones the button switches.

Why do you need a pull-up or pull-down resistor?

When the button isn't pressed, the Arduino's input pin isn't connected to anything; this is called a floating input. Such a pin picks up electrical noise and reads random HIGH or LOW values. The fix is to pull the pin to a fixed level through a resistor:

MethodWiringNot pressedPressed
Pull-down10 kΩ pin → GND, button pin → 5VLOWHIGH
Pull-up (external)10 kΩ pin → 5V, button pin → GNDHIGHLOW
INPUT_PULLUP (internal)Button pin → GND, no resistor neededHIGHLOW

The most practical way is pinMode(pin, INPUT_PULLUP): the Arduino's internal resistor of about 20–50 kΩ is enabled and you just connect the button between the pin and GND. The only difference is that the logic is inverted: a press reads LOW.

Debounce: why does one press count several times?

The moment the button's metal contacts touch, they vibrate for a few milliseconds and the circuit opens and closes many times. Because the Arduino reads so fast, it can see one press as 3–5 presses. This is called contact bounce. To fix it in software, new changes are ignored for about 50 ms after the last change.

const int BUTTON_PIN = 2;   // buton pin ile GND arasında / button between pin and GND
const int LED_PIN = 13;     // karttaki LED / onboard LED

bool ledOn = false;
int lastReading = HIGH;
int stableState = HIGH;
unsigned long lastChange = 0;

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP); // dahili pull-up / internal pull-up
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  int reading = digitalRead(BUTTON_PIN);
  if (reading != lastReading) lastChange = millis();   // değişti / changed
  if (millis() - lastChange > 50 && reading != stableState) {
    stableState = reading;                              // 50 ms kararlı / stable for 50 ms
    if (stableState == LOW) {                           // basıldı / pressed
      ledOn = !ledOn;                                   // LED'i değiştir / toggle LED
      digitalWrite(LED_PIN, ledOn ? HIGH : LOW);
    }
  }
  lastReading = reading;
}

This code toggles the LED once per press; holding the button doesn't keep toggling it. Because it uses millis() instead of delay(), the loop never waits and can do other jobs at the same time.

Common mistakes

  • Inserting the button the wrong way: if you use an already-connected pair of legs, the button always reads as pressed. Turn it 90°.
  • Not using a resistor: without a pull-up or pull-down the reading changes randomly.
  • Expecting the wrong logic with INPUT_PULLUP: a press reads LOW, not HIGH; write your conditions accordingly.
  • Using a long delay() for debounce: the program can't do anything during that time; timing with millis() is better.
  • Using pins 34–39 on an ESP32: these pins have no internal pull-up; add an external resistor or pick another pin.

To place the button and resistor correctly on a breadboard, see What Is a Breadboard?, and to understand pull-up resistor values, What Is a Resistor?.

Frequently asked questions

What resistor do I need for a button?

10 kΩ is standard for a pull-up or pull-down. With INPUT_PULLUP you don't need an external resistor at all.

Why does the button read LOW when pressed?

With INPUT_PULLUP or an external pull-up, the pin is normally HIGH; the button connects it to GND, so it reads LOW when pressed. That's the expected behavior.

How long should the debounce time be?

20–50 ms is enough for most buttons. Old or low-quality buttons may need 80–100 ms.

How do I read several buttons?

Connect each button to its own pin and set them all to INPUT_PULLUP. For many buttons, use a keypad or read them on a single analog pin with different resistors.

See all projects
Led Burning with Push Button (Push)
#9Beginner

Led Burning with Push Button (Push)

Push control project that turns on the LED when the button is pressed and turns it off when it is released. Teaches button reading and conditional expression usage with digitalRead.

4.9(110)
176
Led Burning with Button (On Off)
#10Beginner

Led Burning with Button (On Off)

A toggle project that changes the state of the LED (on/off) with each button press. Teaches state variable and debounce logic.

4.8(100)
157
Simple Piano with Buzzer and Button
#26Advanced
Premium

Simple Piano with Buzzer and Button

Simple piano project with 8 buttons and buzzer to play notes from C to high C. Teaches how to simulate a musical instrument by assigning different frequencies to each button.

4.9(66)
87
7 Segment Display and Counter with Button
#43Advanced
Premium

7 Segment Display and Counter with Button

Counter project that increases, decreases and resets the number on the 7 segment display with 3 buttons. Teaches boundary control and user interactive counter logic.

4.6(35)
46
ESP32 LED Control with Push Button (Push)
#104Beginner

ESP32 LED Control with Push Button (Push)

The LED lights up when the button is pressed and turns off when released. Shows how the ESP32's digital input pin and internal pull-up resistor are used. The INPUT_PULLUP mode eliminates the need for an external resistor.

4.6(36)
55
ESP32 LED Control with Pushbutton (Toggle)
#105Beginner

ESP32 LED Control with Pushbutton (Toggle)

Each time the button is pressed the state of the LED changes: if it is on it turns off, if it is off it turns on. Classic toggle pattern. With debounce we clean up the mechanical noise of the pushbutton to ensure a single toggle with a single press.

4.6(39)
56
Raspberry Pi Pico Button Toggle LED (GP14 + GP2)
#156Beginner
Premium

Raspberry Pi Pico Button Toggle LED (GP14 + GP2)

Button + LED — next level! 🔁 Unlike #155, no need to hold the button. Press and release → LED on. Press and release again → LED off (toggle). Same circuit as #155 (LED GP14, Button GP2), but big code difference. Learn **edge detection** (capturing the 1→0 falling moment), **state tracking**, **debounce** (mechanical bounce filter). MicroPython's `led.toggle()` swaps state in one line. Foundation of all interactive button projects (mode switcher, IRQ, double-click).

0.0(0)
Raspberry Pi Pico Button Debounce: IRQ vs Software Polling (GP5 + GP4)
#159Intermediate
Premium

Raspberry Pi Pico Button Debounce: IRQ vs Software Polling (GP5 + GP4)

Press a button once, code counts 3-4? That is **contact bounce** — metal contacts oscillate for microseconds! 🔁 Compare 2 counting methods side-by-side in Serial: **RAW polling** (catches bounce, over-counts) vs **IRQ + software debounce** (accurate). Learn contact bounce physics, software debounce (`ticks_diff() > 50ms`), **Pin.irq()** interrupt registration, **IRQ_FALLING** trigger, ISR handlers, `global` + ISR safety. LED toggles via IRQ (visual feedback). Serial shows both counters per press

0.0(0)

Learn why a button reads unreliably on its own, what a pull-up resistor does, how to use INPUT_PULLUP and how debounce makes presses count correctly.

How to Connect a Push Button to Arduino: Pull-up, Pull-down and Debounce | BlueGrays