ESP32 UNO - Button - LED
Want a push button to switch a light with the ESP32 Uno? Put one button and one LED on the ESP32 Uno form board and you get a working button-controls-LED circuit in a few minutes. First the LED mirrors the button. Then each press flips the LED, like a real light switch, and you find out why a button toggle LED needs debounce to behave.
What you will do:
- Connect a push button and a 220 ohm LED circuit to the ESP32 Uno
- Light the LED only while the button is held down
- Toggle the LED on and off with single presses
- See contact bounce cause missed or double toggles
- Fix the bounce with the ezButton library

Components You Need
Or you can buy the following kits:
| 1 | × | DIYables Sensor Kit (18 sensors/displays) |
Additionally, some of these links are for products from our own brand, DIYables .
Buy Note: Use the LED Module for easier wiring. It includes an integrated resistor.
ESP32 Uno Pinout
The board prints Uno names like D3 and D7, but the sketch needs the chip's GPIO numbers. Look up both pins of this project in the picture first.

How to Connect It
When this part is done, the button sits on D7, the LED sits on D3, and both share GND.

This image is created using Fritzing. Click to enlarge image
| Component Pin | ESP32 Uno Pin |
|---|---|
| Button leg A | D7 (GPIO14) |
| Button leg B | GND |
| LED anode (long leg) via 220 ohm resistor | D3 (GPIO25) |
| LED cathode (short leg) | GND |
Good to know: skip the external resistor for the button. INPUT_PULLUP turns on a pull-up inside the chip, so GPIO14 rests at HIGH and drops to LOW on a push. Keep every signal at 3.3V; ESP32 Uno pins are not 5V tolerant.
Application 2 - Each Press Flips the LED
Now the LED keeps its new state after you let go. For that, the code must catch the single moment of the push.
ESP32 Uno Code - Toggle Without Debounce
The sketch stores the previous button reading. A HIGH followed by a LOW counts as one push and flips the LED.
Code Explanation
| Code Part | What It Does |
|---|---|
| prev_button_state | Holds the reading from the last loop pass |
| prev HIGH and now LOW | Detects the falling edge, which is one push |
| led_state = !led_state | Swaps LOW to HIGH or HIGH to LOW |
| digitalWrite(LED_PIN, led_state) | Sends the new level to GPIO25 |
The ! operator is a short form. It gives the same result as this longer block:
Upload and Test
- Paste this sketch into the Arduino IDE.
- Upload it to the ESP32 Uno.
- Push and release the button about ten times.
- Watch the LED after each push.
- Pro tip: count your pushes and the "The button is pressed" lines side by side. If the line count is higher, you have caught bounce in action.
Many pushes work fine. Some pushes, though, flip the LED two or three times in a row, or look like they did nothing (two flips, too fast to see). The metal parts in the button spring back and forth for a few milliseconds, and the fast ESP32 Uno loop reads every bounce as a new push.
⇒ The cure is to debounce the button.
ESP32 Uno Code - Toggle With Debounce
Hand-written debounce code is easy to get wrong. The ezButton library handles it in two lines. For the full story on bounce, see the ESP32 Uno - Button Debounce page.
This version waits until the button level stays stable for 50 ms, then reports exactly one push.
Upload and Test
- Install ezButton: open the Library Manager, search "ezButton" and click Install. Full steps are on the ezButton install guide.
- Paste the sketch into the Arduino IDE.
- Click Upload (Upload) to send it to the ESP32 Uno.
- Push and release the button four times.
- Check the LED: on, off, on, off, one change per push.
- Pro tip: a big panel-mount button can bounce longer than a small breadboard one. If it still double-toggles, try button.setDebounceTime(30) down to button.setDebounceTime(120) until one push equals one line.
Video Tutorial
See the ESP32 Uno build in action in the video below.
ESP32 Uno vs UNO R4 for This Project
Moving this button and LED build from the UNO R4 to the ESP32 Uno only touches the pin numbers and the voltage.
| Item | Arduino UNO R4 | ESP32 Uno |
|---|---|---|
| Logic voltage | 5V | 3.3V |
| Button pin in code | 7 (D7) | 14 (D7) |
| LED pin in code | 3 (D3) | 25 (D3) |
| Internal pull-up | Yes | Yes |
| ezButton library | Works | Works, no change |
| Arduino IDE board | Arduino UNO R4 WiFi or Minima | ESP32 Dev Module |
The wires stay in the same header holes, so you can move the breadboard over without changes. The LED looks a bit dimmer at 3.3V, which is normal.
Troubleshooting
| Problem | Possible Cause | Solution |
|---|---|---|
| No COM port shows up in Arduino IDE | CH340 driver not installed or the cable is charge-only | Install the CH340 driver and use a USB cable that carries data |
| Upload stops at "Failed to connect" or "Waiting for download" | The board did not go into download mode | Hold the BOOT button as the upload begins, then release it |
| LED stays dark in every sketch | LED turned around or resistor missing from the path | Long leg goes to the resistor and D3 (GPIO25), short leg to GND |
| LED is lit all the time and the button does nothing | Button leg B wired to 3.3V or 5V instead of GND | Move that leg to a GND pin |
| Monitor jumps between pressed and unpressed with no touch | Wire to D7 is loose, so GPIO14 floats | Reseat the jumper and check it lands in the button row |
| Sketch copied from another board does nothing | Pins 7 and 3 left in the code | Change them to 14 and 25 |
| ezButton.h no such file | Library not installed | Install ezButton from the Library Manager and compile again |
| Gibberish in the Serial Monitor | Baud mismatch | Choose 9600 baud in the Serial Monitor |
FAQ
How does a push button turn an LED on and off with the ESP32 Uno?
The button changes the level on an input pin, and the sketch reads it with digitalRead(). Based on that level, the sketch writes HIGH or LOW to the LED pin with digitalWrite(). The button never carries the LED current itself.
What is the difference between follow mode and toggle mode?
Follow mode copies the button: the LED is on only while you hold it. Toggle mode remembers the LED state and flips it once per push, so the LED stays on or off after you let go.
Why is the button signal LOW when I press it?
With INPUT_PULLUP, GPIO14 is pulled up to 3.3V inside the chip. Pressing the button connects the pin to GND, so it reads LOW. Released, it goes back to HIGH.
Which resistor value is right for the LED at 3.3V?
220 ohm works well. With a red LED it gives roughly 6 mA, which is safe for the ESP32 Uno pin and still clearly visible. 330 ohm is fine too, just a little dimmer.
Why do I type 14 and 25 in the code and not 7 and 3?
The ESP32 Uno code uses GPIO numbers. The D7 header hole is GPIO14 and the D3 hole is GPIO25. Writing 7 or 3 would point to other chip pins.
Could I use A2 for the button instead of D7?
Only with an extra part. A2 to A5 (GPIO35, 34, 36, 39) are input only on the ESP32 Uno and have no internal pull-up, so INPUT_PULLUP does nothing there. Add a 10k ohm resistor from the pin to 3.3V, or just keep D7.
Can the LED go on A3 or A4?
No. A2 to A5 cannot output a signal on the ESP32 Uno, so an LED there never lights. Keep the LED on a digital header pin like D3.
Do I need a driver to upload code to the ESP32 Uno?
This board uses a CH340 USB-to-serial chip. Windows and macOS often need the CH340 driver once. After that, the board shows up as a COM port in the Arduino IDE.
How can I control two LEDs with two buttons?
Copy the ezButton object and the led_state variable for the second pair, and give them new pins, for example D4 (GPIO17) for the button and D6 (GPIO27) for the LED. Call loop() on both button objects at the top of loop().
What if I run out of Uno header pins for more buttons and LEDs?
The ESP32 Uno has a few extra holes near the power header: GPIO32 and GPIO33 (I/O, PWM, analog on ADC1, so they also work while WiFi is on) and GPIO15 (I/O, PWM, analog on ADC2). Solder pin headers there and write the GPIO number in code. GPIO32 and GPIO33 are the best picks for extra buttons or LEDs in this project, since both support the internal pull-up. Two warnings: GPIO15 and GPIO0 (the IO0 pin at the unused Uno NC position) are boot strapping pins, and a wrong connection can stop the board from booting or uploading code, so use GPIO32/33 first. Never use the six holes under the digital header (SD0 to SD3, CMD, CLK = GPIO6 to GPIO11); they are wired to the flash chip and using them crashes the board.