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
- Power off while wiring. Unplug USB before moving wires.
- Check every module’s voltage before connecting — each component page lists it.
- Red = power, black = GND, every time. Future you will thank you.
- Never connect 5V and 3V3 pins together, and never feed a board from USB and an external supply into the same rail.
- 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_TOPandR_BOTTOMin 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
// 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);
}// 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);
}