Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

Push button with ESP32 DevKit V1 — INPUT_PULLUP and debounce

Wire a push button between GPIO32 and GND on an ESP32 DevKit V1, use the internal pull-up, debounce in software and tell short presses from long ones.

Arduino C++Verified — core esp32 3.3.12, 3 Nov 2026Compile-only

Community draft — report a mistake

A push button is the first input every project needs, and the ESP32 makes it easy: every output-capable pin has an internal pull-up, so the button goes straight from the GPIO to GND with no resistor.

The DevKit V1 has two traps. GPIO34–39 have no pull-ups, and the strapping pins (D2, D12, D15) change how the board boots if the button is held at reset. GPIO32 avoids both. The sketch debounces in software and reports each press as short or long, which is how one button can do two jobs.

Wiring

ESP32 DevKit V1Only the pins used are shown · 3.3 V logicPush button (6 mm tactile switch)D32GND12
Every connection
ESP32 DevKit V1Push button (6 mm tactile switch)WireNotes
D321yellowInternal pull-up holds the pin HIGH; pressing pulls it LOW.
GND2blackUse diagonally opposite legs of a 4-leg tactile switch so you never pick two legs that are always joined.

No supply — passive switch part, 3.3 V board. Wire the button between a GPIO and GND and use the internal pull-up. Never connect a button between a GPIO and 5 V on a 3.3 V board.

Board quirks

  • No resistor needed: INPUT_PULLUP turns on the ESP32’s internal pull-up (roughly 45 kΩ). Wire the button to GND, never to 5 V or VIN — a GPIO at 5 V is damaged.
  • D34, D35, VP and VN are input-only and have no internal pull-ups. A button there floats and reads random presses unless you add a 10 kΩ resistor to 3V3.
  • Keep buttons off D2, D12 and D15: a button held down during reset changes the boot mode or flash voltage. D32 is a plain GPIO with no boot role.
  • The board’s own BOOT button is GPIO0, which the 30-pin header doesn’t bring out. After the sketch starts you can still read it with pinMode(0, INPUT_PULLUP) as a free second button.
  • D32 is also an RTC pin, so the same button can wake the ESP32 from deep sleep with esp_sleep_enable_ext0_wakeup(GPIO_NUM_32, 0).

Code

push-button-esp32.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// Push button on an ESP32 DevKit V1 with the internal pull-up and software debounce.
// Leg 1 → D32 (GPIO32), leg 2 → GND. Pressed = LOW. Short and long presses are told apart.

constexpr uint8_t BUTTON_PIN = 32;
constexpr uint32_t DEBOUNCE_MS = 30;
constexpr uint32_t LONG_PRESS_MS = 800;

bool stableState = HIGH;     // debounced level (HIGH = released)
bool lastReading = HIGH;
uint32_t lastChange = 0;
uint32_t pressedAt = 0;
uint32_t presses = 0;

void setup() {
  Serial.begin(115200);
  pinMode(BUTTON_PIN, INPUT_PULLUP);  // GPIO32 has an internal pull-up; GPIO34–39 do not
  Serial.println("Button on GPIO32 — press it (hold for a long press)");
}

void loop() {
  bool reading = digitalRead(BUTTON_PIN);
  if (reading != lastReading) {
    lastChange = millis();
    lastReading = reading;
  }
  if (millis() - lastChange < DEBOUNCE_MS || reading == stableState) return;

  stableState = reading;
  if (stableState == LOW) {
    pressedAt = millis();
  } else {
    uint32_t held = millis() - pressedAt;
    presses++;
    Serial.printf("Press #%lu — %s (%lu ms)\n", (unsigned long)presses,
                  held >= LONG_PRESS_MS ? "long" : "short", (unsigned long)held);
  }
}

Expected serial output

Serial Monitor · 115200Output
Button on GPIO32 — press it (hold for a long press)
Press #1 — short (142 ms)
Press #2 — short (98 ms)
Press #3 — long (1260 ms)

Common errors

One press counts two or three times

Contact bounce. The sketch ignores changes shorter than 30 ms; raise DEBOUNCE_MS to 50 for worn or cheap switches.

Presses appear on their own

The pin is floating: either the button is on D34–D39 (no internal pull-up — add 10 kΩ to 3V3) or a long unshielded wire picks up noise. Add a 100 nF capacitor from the pin to GND on long runs.

Reads LOW all the time

You used two legs that are joined inside the switch. Rotate it 90° on the breadboard or use diagonal legs.

↑↓ to move · Enter to open