Unit G - ESP32 Foundations

36. 3.3 V Logic, Power Rails and Level Shifting

Protect ESP32 GPIO and build a safe front-panel acknowledge button with a status LED - never feed 5 V into pins.

Estimated time 2-3 hours

Learning outcomes

  • State why 5 V must never be applied to ESP32 GPIO
  • Identify USB, VIN and 3V3 rails on a typical DevKit
  • Design a two-resistor divider for a 5 V digital echo into 3.3 V logic
  • Build a panel acknowledge button with debounce and status LED
  • Describe when a MOSFET bidirectional shifter beats a divider

Parts and preparation

ESP32 DevKit, USB data cable, push-button, LED + 220-330 ohm resistor, jumper wires. Optional: two resistors (e.g. 2.2 k ohm and 3.3 k ohm) for a 5 V echo divider demo; optional HC-SR04.

Before power: inspect wiring, confirm supply voltage and ensure all connected circuits share GND.

3.3 V Logic, Power Rails and Level Shifting instructional connection diagram

Project: Safe panel acknowledge

Build a 3.3 V-safe front-panel control: press to acknowledge / arm a status LED. That is the same habit you need on any ESP32 machine panel - buttons to GND with INPUT_PULLUP, no 5 V on GPIO, modest LED current.

Sketch 1 proves the button and prints the 3.3 V rule. Sketch 2 is the useful panel: edge-detect press, debounce with millis, toggle a status LED on GPIO 2.

5 V Uno logic versus 3.3 V ESP32 logic
ESP32 GPIO expects 3.3 V - never connect 5 V directly.

Never put 5 V into ESP32 GPIO

ESP32 pins are 3.3 V logic. A 5 V signal from an Uno or many sensor modules can damage the pin. If a module outputs 5 V on a data line, add level shifting or use a 3.3 V-safe variant.

USB, VIN and 3V3 rails

USB powers most DevKits. VIN/5V may accept external 5 V within board limits. 3V3 feeds the ESP32 and 3.3 V peripherals. Do not inject 5 V into 3V3. Do not draw strip/motor current from the tiny regulator. Share GND.

Rail / pathTypical use
USB 5 VPower the DevKit from the PC
VIN / 5V headerExternal 5 V input if the board allows it
3V3ESP32 core and 3.3 V logic devices
GNDCommon return - always share with sensors

Voltage divider for a 5 V sensor echo

HC-SR04 Echo is about 5 V - use a divider before ESP32 GPIO. Course example: R1 = 2.2 k ohm from Echo, R2 = 3.3 k ohm to GND, mid-point to GPIO. Vout = Vin * R2 / (R1 + R2) -> about 3.0 V from 5 V. Trig can often stay 3.3 V from ESP32.

Two-resistor divider from 5 V echo to about 3 V
Echo -> R1 -> mid-point to GPIO; R2 to GND.
// Vout = Vin * R2 / (R1 + R2)
// Example: 5 V * 3.3k / (2.2k + 3.3k) = 3.0 V

MOSFET bidirectional shifters

Dividers are fine for one-way 5 V -> 3.3 V inputs. For I2C or bidirectional lines use a proper MOSFET shifter module.

GPIO 0 caution; this lesson uses GPIO 4

GPIO 0 is a strapping pin. A button to GND there can confuse boot. Use GPIO 4 with INPUT_PULLUP for the panel button.

Wiring and safe build sequence

  1. ESP32 GPIO 4 -> one side of push-button; other side -> GND
  2. Sketch 2: GPIO 2 -> 220-330 ohm -> LED anode; cathode -> GND (or on-board LED)
  3. USB power; Serial Monitor 115200
  4. Optional HC-SR04 divider on Echo as described in theory
Power rule: switch off before moving wires. Arduino I/O pins are control signals; high-current loads require a driver and suitable external supply.

Worked sketch 1: Safe button read

Download .ino sketch

What this sketch is for: Discovery: INPUT_PULLUP button on GPIO 4 prints pressed/open and reminds you ESP32 is 3.3 V logic.

const int btnPin = 4;

void setup() {
  pinMode(btnPin, INPUT_PULLUP);
  Serial.begin(115200);
  delay(300);
  Serial.println("ESP32 is 3.3 V logic - never feed 5 V into GPIO");
}

void loop() {
  int pressed = (digitalRead(btnPin) == LOW);
  Serial.println(pressed ? "button pressed" : "button open");
  delay(200);
}

How the code works

  1. INPUT_PULLUP: idle HIGH; press to GND reads LOW.
  2. GPIO 4 avoids the GPIO 0 boot-strap hazard.

Worked sketch 2: Panel acknowledge with status LED

Download .ino sketch

What this sketch is for: Useful panel control: each clean button edge toggles a status LED (armed/acknowledged). millis debounce stops bounce from flipping twice. Match the breadboard layout below before upload.

Breadboard layout for ESP32 panel acknowledge: button on GPIO 4 to GND, LED and resistor on GPIO 2
Breadboard for sketch 2: button between GPIO 4 and GND (INPUT_PULLUP); LED with series resistor on GPIO 2 to GND. Share GND with the ESP32. Click to enlarge.
const int btnPin = 4;
const int ledPin = 2;
const unsigned long debounceMs = 40;

bool ledOn = false;
bool lastStable = HIGH;
bool lastRead = HIGH;
unsigned long lastEdge = 0;

void setup() {
  pinMode(btnPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  Serial.begin(115200);
  Serial.println("Panel ACK - press to toggle status LED");
}

void loop() {
  bool reading = digitalRead(btnPin);
  if (reading != lastRead) {
    lastEdge = millis();
    lastRead = reading;
  }

  if ((millis() - lastEdge) > debounceMs && reading != lastStable) {
    lastStable = reading;
    if (lastStable == LOW) {
      ledOn = !ledOn;
      digitalWrite(ledPin, ledOn ? HIGH : LOW);
      Serial.println(ledOn ? "ACK / armed" : "cleared");
    }
  }
}

How the code works

  1. Toggle only on the press edge (HIGH to LOW), not while held.
  2. debounceMs filters mechanical bounce.
  3. Same 3.3 V button habit scales to larger control panels.
  4. Build from the breadboard photo: GPIO 4 button, GPIO 2 LED + resistor.

Test and record evidence

Expected result: Sketch 1: Serial shows pressed/open as you use the button. Sketch 2: each clean press toggles the status LED and prints ACK / cleared.

Practical evidence checklist

Common faults and checks
  • Always open: button legs and common GND.
  • Double toggles: increase debounceMs slightly.
  • GPIO 0 mistakes: keep the button on GPIO 4 for this lab.
  • HC-SR04: verify divider mid-point before connecting Echo to ESP32.
Extension challenge: Measure a 5 V Echo divider mid-point with a multimeter and confirm it stays at or below about 3.3 V.

Check your understanding

Q1. What project is sketch 2?

Show answer

A safe front-panel acknowledge button with status LED.

Q2. What voltage class are ESP32 GPIO pins?

Show answer

3.3 V - do not apply 5 V.

Q3. What must you share with every sensor?

Show answer

GND.

Q4. Divider formula?

Show answer

Vout = Vin * R2 / (R1 + R2).

Q5. Why avoid GPIO 0 for the button?

Show answer

Strapping/boot pin - can disturb boot or download.

Q6. When is a MOSFET shifter better?

Show answer

Bidirectional or open-drain buses such as I2C.

Q7. Why debounce the panel button?

Show answer

Mechanical bounce can create false extra edges.