The HC-SR04 is a 5 V part, and the Pico W is strictly 3.3 V — so this guide powers the sensor from VBUS and brings the Echo pulse down with a 1 kΩ / 2 kΩ divider before it reaches GP15.
MicroPython needs no library here: time_pulse_us() times the echo in microseconds, and the script prints the median of five pings in centimetres.
Wiring
| Raspberry Pi Pico W | HC-SR04 ultrasonic sensor | Wire | Notes |
|---|---|---|---|
| VBUS | VCC | red | VBUS (pin 40) is USB 5 V — the classic HC-SR04 does not work on 3.3 V. |
| GP14 | Trig | purple | GP14 is physical pin 19. A 3.3 V pulse is enough to trigger. |
| GP15 | Echo | green | Via 1 kΩ / 2 kΩ divider — Echo is 5 V. 1 kΩ from Echo to GP15, 2 kΩ from GP15 to GND → about 3.3 V. GP15 is physical pin 20. |
| GND | GND | black |
5 V (HC-SR04P / RCWL-1601: 3–5.5 V) part, 3.3 V board. The classic HC-SR04 needs 5 V and its ECHO pin outputs 5 V. On a 3.3 V board (ESP32, Pico) send ECHO through a 1 kΩ / 2 kΩ divider. A 3.3 V trigger signal is enough for TRIG.
Board quirks
- Never wire Echo straight to the Pico W: no RP2040 pin is 5 V tolerant, and a 5 V pulse slowly damages the input.
- VBUS only carries 5 V while the Pico runs from USB. On a battery into VSYS, use the 3.3 V HC-SR04P (or RCWL-1601) on 3V3 and drop the divider.
machine.time_pulse_us()returns −2 if the echo never started and −1 if it lasted past the timeout; the code treats both as “out of range”.- The median of five pings rejects the odd wild reading from a soft or angled surface.
Code
# HC-SR04 ultrasonic distance on a Raspberry Pi Pico W (MicroPython, no library).
# Wiring: VCC -> VBUS (pin 40, USB 5 V), GND -> GND, Trig -> GP14 (pin 19),
# Echo -> 1 kOhm -> GP15 (pin 20), and 2 kOhm from GP15 to GND. Echo is a 5 V pulse; the Pico
# is not 5 V tolerant, so the divider is not optional.
from machine import Pin, time_pulse_us
import time
trig = Pin(14, Pin.OUT, value=0)
echo = Pin(15, Pin.IN)
def distance_cm():
trig.value(1)
time.sleep_us(10)
trig.value(0)
t = time_pulse_us(echo, 1, 30000) # 30 ms timeout = about 5 m
if t < 0:
return None # -2: echo never started, -1: echo too long
return t * 0.0343 / 2 # speed of sound ~343 m/s at 20-25 C, there and back
def median_cm(n=5):
vals = []
for _ in range(n):
d = distance_cm()
if d is not None:
vals.append(d)
time.sleep_ms(60) # let the last echo die out
if not vals:
return None
vals.sort()
return vals[len(vals) // 2]
print("HC-SR04: Trig GP14, Echo GP15 (through divider)")
while True:
d = median_cm()
if d is None:
print("Out of range (no echo)")
else:
print("Distance: {:.1f} cm".format(d))
time.sleep_ms(200)# HC-SR04 ultrasonic distance on a Raspberry Pi Pico W (MicroPython, no library).
# Wiring: VCC -> VBUS (pin 40, USB 5 V), GND -> GND, Trig -> GP14 (pin 19),
# Echo -> 1 kOhm -> GP15 (pin 20), and 2 kOhm from GP15 to GND. Echo is a 5 V pulse; the Pico
# is not 5 V tolerant, so the divider is not optional.
from machine import Pin, time_pulse_us
import time
trig = Pin(14, Pin.OUT, value=0)
echo = Pin(15, Pin.IN)
def distance_cm():
trig.value(1)
time.sleep_us(10)
trig.value(0)
t = time_pulse_us(echo, 1, 30000) # 30 ms timeout = about 5 m
if t < 0:
return None # -2: echo never started, -1: echo too long
return t * 0.0343 / 2 # speed of sound ~343 m/s at 20-25 C, there and back
def median_cm(n=5):
vals = []
for _ in range(n):
d = distance_cm()
if d is not None:
vals.append(d)
time.sleep_ms(60) # let the last echo die out
if not vals:
return None
vals.sort()
return vals[len(vals) // 2]
print("HC-SR04: Trig GP14, Echo GP15 (through divider)")
while True:
d = median_cm()
if d is None:
print("Out of range (no echo)")
else:
print("Distance: {:.1f} cm".format(d))
time.sleep_ms(200)Expected serial output
HC-SR04: Trig GP14, Echo GP15 (through divider)
Distance: 42.7 cm
Distance: 42.5 cm
Out of range (no echo)
Distance: 118.3 cmHC-SR04: Trig GP14, Echo GP15 (through divider) Distance: 42.7 cm Distance: 42.5 cm Out of range (no echo) Distance: 118.3 cm
Common errors
Always "Out of range (no echo)"
VCC is on 3V3 instead of VBUS, Trig/Echo are swapped, or the divider is reversed (1 kΩ belongs next to the sensor, 2 kΩ to GND).
Works on USB, not on battery
VBUS is dead without USB. Use a 3.3 V-capable HC-SR04P on 3V3, or give the sensor its own 5 V with a shared GND.
Readings jump around
Soft or angled targets scatter the ping. Aim at something flat and hard; the median filter handles the rest.