ESP32 S3 UNO - Blink LED Without Delay

This ESP32 S3 Uno blink LED without delay tutorial shows you how to make an LED blink while the ESP32 S3 Uno form board keeps checking a button. With delay(), the board sleeps and misses button presses. With LED blink using millis(), it catches every press and the LED still blinks on time.

In this tutorial, you will:

  1. Blink an LED with delay() and see why it misses button presses
  2. Blink an LED without delay using the millis() function
  3. Read a button and blink an LED at the same time on the ESP32 S3 Uno
  4. Blink two LEDs at different speeds while reading a button
ESP32 S3 Uno blink LED without delay

※ NOTE THAT:

  • The idea here is bigger than an LED and a button. The same method lets the ESP32 S3 Uno run many tasks side by side, and none of them blocks the others.
  • This page explains how the method works in detail. If you only want a quick result, you can use the LED library (ezLED) instead.

Hardware Preparation

1×ESP32 S3 Uno-form Board
1×USB Cable Type-A to Type-C (for USB-A PC)
1×USB Cable Type-C to Type-C (for USB-C PC)
1×LED Kit
1×LED (red)
1×LED Module
1×Alternatively, Button and LED Kit
1×220Ω Resistor
1×Breadboard-mount Button with Cap
1×Breadboard-mount Button Kit
1×Panel-mount Push Button
1×Push Button Module
1×Breadboard
1×Jumper Wires

Or you can buy the following kits:

1×DIYables Sensor Kit (18 sensors/displays)
Disclosure: Some of the links provided in this section are Amazon affiliate links. We may receive a commission for any purchases made through these links at no additional cost to you.
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.

Overview of LED and Button

This project uses only two simple parts, an LED and a push button. If you have not used them before, it helps to learn the basics first, so the code below is easier to follow.

These tutorials cover the pinout, how each part works, and how to program it:

ESP32 S3 Uno Pinout

The image below shows the pinout of the ESP32 S3 Uno form board. Use it to find the Uno header pins (D3, D7…) and their GPIO numbers when you wire the circuit.

ESP32 S3 Uno pinout diagram

Wiring Diagram

Connect the LED through a 220 ohm resistor to pin D3, and connect the button between pin D7 and GND. The button needs no external resistor, because the code turns on the internal pull-up.

The wiring diagram between ESP32 S3 Uno LED and button

This image is created using Fritzing. Click to enlarge image

Component Pin ESP32 S3 Uno Pin
LED anode (+) through 220 ohm resistor D3 (GPIO17)
LED cathode (-) GND
Button pin 1 D7 (GPIO14)
Button pin 2 GND

ESP32 S3 Uno Code - With Delay

Start with the simple way, so you can see the problem for yourself. This sketch toggles the LED every second with delay(), and then it reads the button. While delay() runs, the ESP32 S3 Uno does nothing else, so it cannot see the button.

/* * This ESP32 S3 Uno code was developed by newbiely.com * * This ESP32 S3 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-s3-uno/esp32-s3-uno-blink-led-without-delay */ #define LED_PIN 17 // The ESP32 S3 Uno pin GPIO17 (D3) connected to the LED #define BUTTON_PIN 14 // The ESP32 S3 Uno pin GPIO14 (D7) connected to the button #define BLINK_INTERVAL 1000 // interval at which to blink LED (milliseconds) int led_state = LOW; // led_state used to set the LED int prev_button_state = LOW; // will store last time button was updated void setup() { Serial.begin(9600); // set the digital pin as output pinMode(LED_PIN, OUTPUT); // set the digital pin as an input pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { // if the LED is off turn it on and vice-versa led_state = (led_state == LOW) ? HIGH : LOW; // set the LED with the led_state of the variable digitalWrite(LED_PIN, led_state); delay(BLINK_INTERVAL); // If button is pressed during this time, ESP32 S3 Uno CANNOT detect int button_state = digitalRead(BUTTON_PIN); if (button_state != prev_button_state) { // print out the state of the button: Serial.println(button_state); // save the last state of button prev_button_state = button_state; } // DO OTHER WORKS HERE }

Detailed Instructions

  1. New to the ESP32 S3 Uno? Follow ESP32 S3 Uno - Getting Started first.
  2. Wire it up as shown in the diagram.
  3. Connect the board to your computer with a USB Type-C cable.
  4. Open Arduino IDE, choose the ESP32S3 Dev Module board and the correct COM port.
  5. Copy the code above and paste it into the Arduino IDE.
  6. Upload the code by clicking the Upload button.
  7. Open the Serial Monitor and set it to 9600 baud.
  8. Press the button four times, at a normal speed.
  9. Watch the LED. It turns ON and OFF every second.
  10. Check the Serial Monitor. You will see something like this:
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32S3 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32S3 Dev Module' on 'COM15')
New Line
9600 baud
1 0 1
Ln 11, Col 1
ESP32S3 Dev Module on COM15
2
  1. Tip: Some of your presses are missing from the output. The ESP32 S3 Uno was stuck inside delay() when you pressed, so it never read the button at that moment.

ESP32 S3 Uno Code - Without Delay

Now fix the problem. Instead of waiting, this sketch checks the time with millis() on every loop. When one second has passed, it toggles the LED. The rest of the time, the loop runs freely and reads the button again and again.

/* * This ESP32 S3 Uno code was developed by newbiely.com * * This ESP32 S3 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-s3-uno/esp32-s3-uno-blink-led-without-delay */ #define LED_PIN 17 // The ESP32 S3 Uno pin GPIO17 (D3) connected to the LED #define BUTTON_PIN 14 // The ESP32 S3 Uno pin GPIO14 (D7) connected to the button #define BLINK_INTERVAL 1000 // interval at which to blink LED (milliseconds) int led_state = LOW; // led_state used to set the LED int prev_button_state = LOW; // will store last time button was updated unsigned long prev_millis = 0; // will store last time LED 1 was updated void setup() { Serial.begin(9600); // set the digital pin as output: pinMode(LED_PIN, OUTPUT); // set the digital pin as an input: pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { unsigned long current_millis = millis(); // check to see if it's time to blink the LED 1 if (current_millis - prev_millis >= BLINK_INTERVAL) { // if the LED is off turn it on and vice-versa: led_state = (led_state == LOW) ? HIGH : LOW; // set the LED with the led_state of the variable: digitalWrite(LED_PIN, led_state); // save the last time you blinked the LED prev_millis = current_millis; } // check button state's change int button_state = digitalRead(BUTTON_PIN); if (button_state != prev_button_state) { // print out the state of the button: Serial.println(button_state); // save the last state of button prev_button_state = button_state; } // DO OTHER WORKS HERE }

Detailed Instructions

  1. Upload the code above to the ESP32 S3 Uno.
  2. Open the Serial Monitor at 9600 baud.
  3. Press the button four times.
  4. Watch the LED. It still switches between ON and OFF every second.
  5. Check the Serial Monitor. Every press and release now shows up:
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32S3 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32S3 Dev Module' on 'COM15')
New Line
9600 baud
1 0 1 0 1 0 1 0 1
Ln 11, Col 1
ESP32S3 Dev Module on COM15
2
  1. Tip: 1 means the button is released and 0 means it is pressed, because the internal pull-up keeps the pin HIGH until the button connects it to GND.

Code Explanation

The sketch saves the time of the last LED change in prev_millis. On each loop, it reads millis() and subtracts the saved time. If the difference reaches BLINK_INTERVAL (1000 ms), it flips the LED state and saves the new time.

This check takes almost no time, so the loop goes straight on to read the button. The code prints the button state only when it changes, so the Serial Monitor is not flooded. The comments inside the code explain each line.

Why use subtraction?

millis() counts up from zero when the board starts, and it rolls back to zero after about 49 days. The form current_millis - prev_millis >= BLINK_INTERVAL still works across that roll-over, because it uses unsigned long math.

Adding More Tasks

The real power of this method shows up when you add more jobs. This sketch blinks two LEDs at different speeds, one every 1000 ms and one every 500 ms, and still reads the button without missing a press.

For the second LED, add another LED with its own 220 ohm resistor on pin D4 (GPIO19), in the same way as the first one.

/* * This ESP32 S3 Uno code was developed by newbiely.com * * This ESP32 S3 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-s3-uno/esp32-s3-uno-blink-led-without-delay */ #define LED_PIN_1 17 // The ESP32 S3 Uno pin GPIO17 (D3) connected to the LED 1 #define LED_PIN_2 19 // The ESP32 S3 Uno pin GPIO19 (D4) connected to the LED 2 #define BUTTON_PIN 14 // The ESP32 S3 Uno pin GPIO14 (D7) connected to the button #define BLINK_INTERVAL_1 1000 // interval at which to blink LED 1 (milliseconds) #define BLINK_INTERVAL_2 500 // interval at which to blink LED 2 (milliseconds) int led_state_1 = LOW; // led_state used to set the LED 1 int led_state_2 = LOW; // led_state used to set the LED 2 int prev_button_state = LOW; // will store last time button was updated unsigned long prev_millis_1 = 0; // will store last time LED 1 was updated unsigned long prev_millis_2 = 0; // will store last time LED 2 was updated void setup() { Serial.begin(9600); // set the digital pin as output: pinMode(LED_PIN_1, OUTPUT); pinMode(LED_PIN_2, OUTPUT); // set the digital pin as an input: pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { unsigned long current_millis = millis(); // check to see if it's time to blink the LED 1 if (current_millis - prev_millis_1 >= BLINK_INTERVAL_1) { // if the LED is off turn it on and vice-versa: led_state_1 = (led_state_1 == LOW) ? HIGH : LOW; // set the LED with the led_state of the variable: digitalWrite(LED_PIN_1, led_state_1); // save the last time you blinked the LED prev_millis_1 = current_millis; } // check to see if it's time to blink the LED 2 if (current_millis - prev_millis_2 >= BLINK_INTERVAL_2) { // if the LED is off turn it on and vice-versa: led_state_2 = (led_state_2 == LOW) ? HIGH : LOW; // set the LED with the led_state of the variable: digitalWrite(LED_PIN_2, led_state_2); // save the last time you blinked the LED prev_millis_2 = current_millis; } // check button state's change int button_state = digitalRead(BUTTON_PIN); if (button_state != prev_button_state) { // print out the state of the button: Serial.println(button_state); // save the last state of button prev_button_state = button_state; } // DO OTHER WORKS HERE }

Each LED has its own interval, its own state and its own saved time. To add a third task, just copy the same pattern with new variables.

Video Tutorial

Watch the video below to see this ESP32 S3 Uno project step by step.

FAQ

Why should I avoid delay() on the ESP32 S3 Uno?

delay() stops your loop for the whole wait time. During that time, the ESP32 S3 Uno cannot read buttons, sensors or serial data. With millis(), the loop keeps running, so every task gets a turn.

Can I use the same code from the UNO R4 on the ESP32 S3 Uno?

Yes, the logic is the same. Only the pin numbers change. In code, you write the GPIO number, not the Uno label. So D3 becomes 17, D4 becomes 19 and D7 becomes 14.

Do I need a resistor for the LED on the ESP32 S3 Uno?

Yes. The ESP32 S3 Uno pins give 3.3V, and an LED without a resistor can draw too much current. A 220 ohm resistor is safe and still gives good brightness.

Why does the button not need a pull-up resistor?

The code uses INPUT_PULLUP, which turns on a resistor inside the ESP32 S3 Uno. The pin reads HIGH when the button is released and LOW when it is pressed. You only need to wire the button between the pin and GND.

What if my project needs more pins than the Uno headers give?

The ESP32 S3 Uno has two extra rows of holes with more GPIOs. They are GPIO15 and GPIO16 (I/O, PWM, analog), GPIO45 and GPIO35 to GPIO42 (I/O, PWM), and GPIO47/GPIO48 (output only, PWM). Solder pin headers to use them and write the GPIO number in code. For more LEDs, GPIO35 to GPIO42 are a good choice. For more buttons, use GPIO35 to GPIO42 or GPIO15/GPIO16, not GPIO47/GPIO48, because those are output only.

Be careful with two groups. GPIO47 and GPIO48 may run at 1.8V instead of 3.3V on some modules (especially ones with "V" in the name, like R8V or R16V), so 3.3V devices can be damaged or act strangely. GPIO0, GPIO3 (D6), GPIO45 and GPIO46 (D9) are boot strapping pins, and a wrong connection can stop the board from booting or uploading code. Use the other extra pins first.

Can I blink an LED without delay using a library?

Yes. The ezLED library has a non-blocking blink function. It uses the same millis() idea inside, so your loop stays free for other tasks.

Troubleshooting

Problem Possible Cause Solution
No COM port shows up in Arduino IDE USB driver missing or board not in upload mode Install the CP210x or CH340 driver, use a data USB cable, or hold BOOT while you press RESET
LED does not light up LED is reversed or wired to the wrong pin Put the long leg (anode) toward D3 (GPIO17) through the resistor and the short leg to GND
LED stays ON or OFF all the time Pin number in code does not match the wiring Check that LED_PIN is 17 in code, not 3
Button presses are not printed Button is wired to the wrong pin or not to GND Wire one leg to D7 (GPIO14) and the other leg to GND
Serial Monitor shows strange characters Baud rate does not match Set the Serial Monitor to 9600 baud
Button prints many 0 and 1 for one press Mechanical bounce of the button Add a short debounce with millis() or use the ezButton library
Second LED does not blink Second LED is not wired Add an LED and a 220 ohm resistor on D4 (GPIO19)

※ OUR MESSAGES

  • As freelancers, We are AVAILABLE for HIRE. See how to outsource your project to us
  • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!