Introduction to Digital Outputs on ESP32
A digital output pin actively drives a voltage: either 3.3 V (HIGH, logic 1) or 0 V (LOW, logic 0). Through digital outputs you turn LEDs on and off, trigger relay coils, control motor drivers, signal other microcontrollers, and create timing signals. The ESP32 provides up to 30 usable output-capable GPIOs with a maximum of 40 mA per pin — powerful enough for most direct-drive applications.
Output Current Capabilities
Staying within safe current limits is critical to protect your ESP32 from damage:
| Limit | Value | Meaning |
|---|---|---|
| Max per GPIO pin | 40 mA | Absolute maximum — do not exceed |
| Recommended per pin | 12 mA | Safe for continuous operation |
| Total across all GPIOs | 1200 mA | Chip-wide limit |
| 3.3 V rail (VDD) | 600 mA | Combined board regulator output |
Standard 5 mm LEDs draw ~20 mA, which is fine. Relay coils (60–100 mA), buzzers, and DC motors far exceed GPIO limits — use a transistor or dedicated driver IC for those.
Safe Output Pins on ESP32
| Pin Group | Use As Output? | Notes |
|---|---|---|
| GPIO4, GPIO13, GPIO14 | Safe ✓ | General purpose, no boot concerns |
| GPIO16, GPIO17, GPIO18, GPIO19 | Safe ✓ | Excellent general-purpose outputs |
| GPIO21, GPIO22, GPIO23 | Safe ✓ | Also used for I2C/SPI — share carefully |
| GPIO25, GPIO26, GPIO27 | Safe ✓ | Also DAC-capable (GPIO25, GPIO26) |
| GPIO32, GPIO33 | Safe ✓ | Also good ADC channels |
| GPIO0, GPIO2, GPIO5, GPIO12 | Careful ⚠ | Affect boot mode or flash voltage |
| GPIO6–GPIO11 | Avoid ✗ | Internal flash — do not use |
| GPIO34–GPIO39 | Never ✗ | Input only — no output capability |
Basic Digital Output: The Blink Sketch
#define LED_PIN 2 // Built-in LED on ESP32 DevKit
void setup() {
pinMode(LED_PIN, OUTPUT);
Serial.begin(115200);
Serial.println("Blink demo running...");
}
void loop() {
digitalWrite(LED_PIN, HIGH); // LED on (3.3 V on pin)
Serial.println("LED ON");
delay(1000);
digitalWrite(LED_PIN, LOW); // LED off (0 V on pin)
Serial.println("LED OFF");
delay(1000);
}
Controlling Multiple Outputs
const int LEDS[] = {16, 17, 18, 19};
const int NUM_LED = 4;
void setup() {
for (int i = 0; i < NUM_LED; i++)
pinMode(LEDS[i], OUTPUT);
}
void loop() {
// Knight Rider scan
for (int i = 0; i < NUM_LED; i++) {
digitalWrite(LEDS[i], HIGH);
delay(100);
digitalWrite(LEDS[i], LOW);
}
for (int i = NUM_LED - 2; i > 0; i--) {
digitalWrite(LEDS[i], HIGH);
delay(100);
digitalWrite(LEDS[i], LOW);
}
}
Non-Blocking Output Timing with millis()
Using delay() blocks the entire processor. For projects that must do other things while toggling outputs, use millis():
#define LED_PIN 2
#define INTERVAL 500 // ms between toggles
unsigned long lastToggle = 0;
bool ledState = false;
void setup() {
pinMode(LED_PIN, OUTPUT);
Serial.begin(115200);
}
void loop() {
unsigned long now = millis();
if (now - lastToggle >= INTERVAL) {
lastToggle = now;
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
Serial.printf("LED is now %sn", ledState ? "ON" : "OFF");
}
// Other code here runs continuously without blocking
}
Driving an LED with Current Limiting
Never connect an LED directly between GPIO and GND — it will draw unlimited current and burn out the LED or damage the GPIO. Always use a current-limiting resistor:
R = (Vsupply - Vf) / If Standard red LED: Vf = 2.0V, If = 20mA R = (3.3 - 2.0) / 0.020 = 65Ω → use 68Ω or 100Ω Blue/white LED: Vf = 3.2V, If = 20mA R = (3.3 - 3.2) / 0.020 = 5Ω → too low! Limit to 5–10mA instead R = (3.3 - 3.2) / 0.010 = 10Ω
| Component | Connection |
|---|---|
| LED anode (+) | Via 100 Ω resistor to ESP32 GPIO |
| LED cathode (–) | ESP32 GND |
Driving High-Current Loads via Transistor
When you need to switch loads above 40 mA (buzzers, motors, relay coils), a small NPN transistor like the 2N2222 or BC547 lets the GPIO control the load safely:
3.3V or 5V ──────────── Relay coil (+)
|
Relay coil (–)
|
Collector (NPN)
Emitter ──── GND
ESP32 GPIO ── 1kΩ ── Base (NPN)
Add flyback diode across relay coil: anode to GND, cathode to VCC.
GPIO State at Boot
Several ESP32 GPIOs are sampled at boot to determine the boot mode. Placing an output device on a strapping pin can cause boot failures:
- GPIO0: LOW at boot → enters flash download mode (avoid for general output)
- GPIO2: Must be LOW or floating at boot for normal operation
- GPIO5: Outputs 1 kHz PWM signal during boot
- GPIO12: HIGH at boot selects 1.8 V flash voltage (very dangerous)
For reliable output control, stick to GPIO16, GPIO17, GPIO18, GPIO19, GPIO21, GPIO22, GPIO23, GPIO25, GPIO26, GPIO27, GPIO32, GPIO33.
Summary
Digital outputs on ESP32 are simple but require awareness of three constraints: current limits (40 mA max per pin, 12 mA recommended), boot-strapping conflicts (avoid GPIO0, GPIO2, GPIO5, GPIO12), and input-only pins (GPIO34–GPIO39 cannot be outputs). Use millis() instead of delay() for non-blocking timing, a transistor for loads above 40 mA, and always include current-limiting resistors for LEDs.