Step‑by‑Step Guide to Building a Programmable Timing Circuit with the ESP32
You’ve probably stared at a blinking LED and thought, “I wish I could change the blink rate on the fly without soldering a new resistor each time.” In today’s maker world that wish is easy to grant – the ESP32 is cheap, powerful, and perfect for a little timing brain you can re‑program whenever the mood strikes. In this post I’ll walk you through a complete, hands‑on build that you can finish in an afternoon and then tweak forever.
What You Need
Before we dive into code, let’s gather the parts. I keep a small “starter box” on my workbench, so most of these items are already there.
- ESP32 development board (any variant with a USB‑C or micro‑USB port works)
- Breadboard and a handful of jumper wires
- One or two LEDs (I like a bright red and a soft amber for visual contrast)
- 220 Ω resistors (one per LED)
- A push‑button or two (for manual trigger)
- Optional: a small 5 V DC power supply if you want to run the circuit off a wall wart instead of USB
- A computer with the Arduino IDE installed (or PlatformIO, if you prefer)
If you’re missing anything, a quick trip to your local electronics store or a fast online order will sort it out. The total cost stays under $15, which is why I love this little project for teaching and prototyping.
Understanding the Basics
Timing vs. Delay
When people talk about “timing circuits” they often mean a fixed delay created by a resistor‑capacitor (RC) network. That works, but the delay is set in stone once you solder the parts. A programmable timing circuit replaces the passive RC with a microcontroller that can count clock cycles, adjust on the fly, and even respond to external events. The ESP32 runs at 240 MHz, so even a millisecond‑level delay is trivial for it.
Why the ESP32?
The ESP32 packs two cores, Wi‑Fi, Bluetooth, and a rich set of timers. For a simple blink you could use an Arduino Uno, but the ESP32 gives you room to grow. Want to sync the blink to a web API? Want to add a PWM dimmer later? The same board can handle it without a hardware change.
Wiring the Circuit
1. Power and Ground
Plug the ESP32 into your computer via USB. The board’s 3.3 V regulator will power the LEDs and button directly. Connect the breadboard’s power rail to the 3.3 V pin on the ESP32 and the ground rail to any GND pin.
2. LED Connections
Place each LED on the breadboard. The longer leg (anode) goes to a digital output pin, the shorter leg (cathode) goes through a 220 Ω resistor to ground. For this guide I’ll use GPIO 18 for the red LED and GPIO 19 for the amber LED.
ESP32 GPIO18 ----> LED anode
LED cathode ----> 220Ω ----> GND rail
Repeat for the second LED on GPIO 19.
3. Button Hook‑up
A simple momentary push‑button can be wired as a pull‑up input. Connect one side of the button to 3.3 V, the other side to GPIO 21, and also add a 10 kΩ resistor from GPIO 21 to ground. When you press the button, the pin reads HIGH; otherwise it stays LOW thanks to the pull‑up.
4. Double‑Check
Give the whole board a quick visual inspection. No stray wires, no shorted pins. When you’re satisfied, it’s time to write the code.
Programming the ESP32
Setting Up the IDE
Open the Arduino IDE, go to File → Preferences, and add the ESP32 board URL:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
Then open Tools → Board → ESP32 Arduino → ESP32 Dev Module. Select the correct COM port and you’re ready to upload.
The Sketch
Below is a minimal sketch that lets you change the blink interval with the button. Press once to speed up, press again to slow down, and hold for three seconds to reset to the default 500 ms.
// Signal Sync – programmable timing circuit
// Author: Riley Chen
const int ledRed = 18;
const int ledAmber = 19;
const int btnPin = 21;
unsigned long interval = 500; // start with 500 ms
unsigned long lastToggle = 0;
bool ledState = false;
void setup() {
pinMode(ledRed, OUTPUT);
pinMode(ledAmber, OUTPUT);
pinMode(btnPin, INPUT_PULLUP);
}
void loop() {
unsigned long now = millis();
// Toggle LEDs based on interval
if (now - lastToggle >= interval) {
ledState = !ledState;
digitalWrite(ledRed, ledState);
digitalWrite(ledAmber, !ledState);
lastToggle = now;
}
// Button handling
static unsigned long btnPressTime = 0;
static bool btnPrev = HIGH;
bool btnCurr = digitalRead(btnPin);
if (btnPrev == HIGH && btnCurr == LOW) { // button pressed
btnPressTime = now;
} else if (btnPrev == LOW && btnCurr == HIGH) { // button released
unsigned long pressDur = now - btnPressTime;
if (pressDur < 500) { // short press
interval = (interval > 100) ? interval - 100 : 100; // speed up
} else if (pressDur < 3000) { // medium press
interval += 100; // slow down
} else { // long press
interval = 500; // reset
}
}
btnPrev = btnCurr;
}
How It Works
- millis() returns the number of milliseconds since the board powered up. We use it to create a non‑blocking delay, which lets the button be read at any time.
- The button logic measures how long the button stays pressed. Short taps speed up the blink, longer presses slow it down, and a very long hold resets the timing.
- Two LEDs are driven opposite each other for a clear visual cue.
Upload the sketch, open the Serial Monitor if you like (optional), and watch the LEDs dance. Press the button and see the rhythm change instantly. That’s the power of a programmable timing circuit.
Testing and Tweaking
Verify Timing Accuracy
If you need precise timing (say, for a motor control loop), you can replace millis() with the ESP32’s hardware timer. The built‑in esp_timer library gives microsecond resolution. For most hobby projects, though, millis() is more than enough.
Add Wi‑Fi Control
Because the ESP32 talks Wi‑Fi out of the box, you can expose the interval as a simple HTTP endpoint. A quick GET request like http://<esp32_ip>/set?ms=250 could change the blink rate from a phone. I’ll cover that in a later Signal Sync post, but the skeleton is already here – just add the Wi‑Fi library and a tiny web server.
Power Considerations
Running the ESP32 from USB is fine for a desk demo, but if you plan to mount the circuit in a box, a small 5 V wall adapter feeding the board’s VIN pin works well. The board’s onboard regulator will drop the voltage to 3.3 V for the ESP32 core and your LEDs.
Expand the Design
- Multiple Channels: Add more LEDs on different pins and give each its own interval variable.
- PWM Dimming: Use the ESP32’s LEDC peripheral to fade LEDs instead of a hard on/off.
- Sensor Input: Hook up a light sensor or temperature probe and let the timing react to the environment.
The beauty of a programmable circuit is that you can keep building on the same hardware without re‑soldering anything.
Wrap‑Up Thoughts
Building a timing circuit with the ESP32 feels like giving a classic blink project a brain upgrade. You start with a few wires and a couple of LEDs, then end up with a platform that can talk to the cloud, respond to sensors, and evolve forever. That’s the kind of flexibility I love sharing on Signal Sync – simple hardware, powerful software, and a lot of room for imagination.
#timing #esp32 #makers