Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

Day 11 of 30 · about 26 minutes

3.3 V vs 5 V: level shifting and safe wiring

Today you build: A voltage divider you measure with the Uno

  • Read 6 min
  • Wire the divider 6 min
  • Upload & compare 4 min
  • Try it 10 min

Community draft — report a mistake

Next week you move to the ESP32, which runs at 3.3 V. Many modules you already own — the HC-SR04, relay boards, some LCD backpacks — speak 5 V. Today is about connecting the two without killing a pin.

The rule

  • A 5 V board reading a 3.3 V signal is usually fine. The Uno sees anything above about 3 V as HIGH.
  • A 3.3 V board receiving a 5 V signal is not. ESP32 and Pico pins are not 5 V tolerant. It may work for a day and then the pin — or the chip — dies.

Fix 1: a voltage divider (one direction)

Two resistors in series share the voltage in proportion to their values:

V_out = V_in × R_bottom ÷ (R_top + R_bottom)

With 1 kΩ on top and 2 kΩ at the bottom: 5 × 2 ÷ 3 = 3.33 V. That’s the exact divider every FlashReady ESP32 page uses for an HC-SR04 ECHO pin. The voltage divider calculator does the maths for other values.

A divider only works for signals going into the 3.3 V board, and only for slow-ish signals.

Fix 2: a level shifter (both directions)

I2C uses the same wire in both directions, so a divider won’t do. Use a BSS138 4-channel level shifter (about ₹40): 5V on HV, 3.3V on LV, GND to both sides, signals pass through. Our water tank alarm uses one for its LCD.

Today’s build

Prove the divider on the Uno, where 5 V is safe:

  • 5V → 1 kΩ → middle row → 2 kΩ → GND
  • Middle row → A0
  • A jumper from the Uno’s 3.3V pin → A1

The sketch prints the expected and measured voltages. You should see about 3.3 V on both. If your 5V pin really measures 4.8 V on USB (common), put that in VCC and watch the numbers line up.

Safe-wiring habits for the rest of the course

  1. Power off while wiring. Unplug USB before moving wires.
  2. Check every module’s voltage before connecting — each component page lists it.
  3. Red = power, black = GND, every time. Future you will thank you.
  4. Never connect 5V and 3V3 pins together, and never feed a board from USB and an external supply into the same rail.
  5. Count your current. A pin gives about 20 mA; a whole Uno around 200 mA through its pins. Motors and relays need drivers. The current budget tool helps.

Try it

  • Predict, then measure. Swap the two resistors (2 kΩ on top, 1 kΩ at the bottom). Work out the new middle voltage with the formula first — then read it. The sketch’s “expected” stays at 3.33 V until you also swap R_TOP and R_BOTTOM in the code.
  • Find three modules in your kit and write down whether each one is 5 V, 3.3 V, or happy with both. Check against their component pages.

You’re done when…

  • Once a second the Serial Monitor (9600 baud) prints Divider: expected 3.33 V, measured … with the measured value within about 0.1 V of expected, and (safe for 3.3 V logic).
  • The 3.3V pin reads about 3.3 V on A1.
  • With the resistors swapped you predicted about 1.67 V before you measured it.
  • You can say which way a divider works (5 V → 3.3 V input only) and when you need a level shifter instead.

Today's code

Verified — core avr 1.8.8, 3 Nov 2026Compile-only
lesson-divider.inoArduino C++Open in PlaygroundOpen in Playground
// Day 11 — 3.3 V vs 5 V: a voltage divider you can measure (Arduino Uno / Nano)
// Divider: 5V → 1 k → (middle) → 2 k → GND. Middle point → A0.
// Plain jumper from the Uno's 3.3V pin → A1.
// The middle point is exactly what an HC-SR04 echo needs before it goes into an ESP32.

const float VCC = 5.0;       // measure your 5V pin with a meter and put the real value here
const float R_TOP = 1000.0;  // 1 k between 5 V and the middle point
const float R_BOTTOM = 2000.0;

float readVolts(int pin) {
  long sum = 0;
  for (int i = 0; i < 16; i++) sum += analogRead(pin);  // average 16 readings to calm the noise
  return (sum / 16.0) * VCC / 1023.0;
}

void setup() {
  Serial.begin(9600);
  Serial.println(F("Divider check: expected vs measured"));
}

void loop() {
  float expected = VCC * R_BOTTOM / (R_TOP + R_BOTTOM);   // 5 x 2k / 3k = 3.33 V
  float middle = readVolts(A0);
  float rail33 = readVolts(A1);

  Serial.print(F("Divider: expected "));
  Serial.print(expected, 2);
  Serial.print(F(" V, measured "));
  Serial.print(middle, 2);
  Serial.print(F(" V   |   3.3V pin: "));
  Serial.print(rail33, 2);
  if (middle > 3.6) Serial.println(F(" V   <- too high for a 3.3 V pin!"));
  else Serial.println(F(" V   (safe for 3.3 V logic)"));
  delay(1000);
}

↑↓ to move · Enter to open