If you are building a robotics project, a liquid level monitor, or a parking assistant, the HC-SR04 ultrasonic distance sensor is likely in your parts bin. It is cheap, ubiquitous, and surprisingly capable when you understand what it is actually outputting. The direct answer to how it works: the HC-SR04 does not output an analog voltage or a serial data packet. It outputs a raw digital 5V timing pulse on its Echo pin, where the width of the pulse in microseconds corresponds directly to the round-trip travel time of a 40 kHz sound wave.
To get reliable centimeter or inch readings, you must convert that raw pulse width using the speed of sound, protect your 3.3V microcontrollers from the 5V echo signal, and implement strict timeouts to prevent your code from hanging. This guide breaks down the exact physics, the hardware matrix, and the real-world interference fixes you need to make the HC-SR04 work on the bench.
How the HC-SR04 Actually Measures Distance
The HC-SR04 uses a pair of piezoelectric transducers (the silver metal cans) to emit and receive acoustic energy. When you pull the Trigger pin HIGH for at least 10 microseconds, the sensor's internal oscillator drives the transmitter transducer with an 8-cycle burst of 40 kHz ultrasonic sound. This acoustic wave travels through the air, hits a target, and reflects back to the receiver transducer. The internal logic board detects the returning echo and manipulates the Echo pin to map the exact flight time of the sound wave.
Because the sensor only measures time, the microcontroller must do the heavy lifting to convert that time into a physical distance. The Echo pin goes HIGH the moment the 40 kHz burst is transmitted and drops LOW the moment the echo is detected (or times out). The width of this HIGH pulse is your raw data. Since the sound wave travels to the object and back, the measured time is exactly double the actual one-way distance to the target.
The Raw-to-Unit Math
To convert the raw microsecond (µs) reading into centimeters or inches, we use the speed of sound in dry air at 20°C (68°F), which is approximately 343 meters per second, or 0.0343 cm/µs.
- Distance (cm) = (Pulse Width in µs × 0.0343 cm/µs) / 2
- Simplified Divisor (cm) = Pulse Width in µs / 58.3
- Simplified Divisor (inches) = Pulse Width in µs / 148
Hardware Specs, Pinout, and Wiring Matrix
Before wiring the sensor, you need to understand its electrical boundaries. The HC-SR04 is strictly a 5V device. While it will sometimes trigger on 3.3V logic, its internal comparator and oscillator require a 5V rail to function reliably, and its Echo pin will output a full 5V HIGH signal. Feeding a 5V Echo signal directly into an ESP32 or Raspberry Pi Pico GPIO pin will eventually degrade or destroy the silicon.
| Parameter | Value / Range | Notes & Edge Cases |
|---|---|---|
| Operating Voltage | 5V DC (4.5V - 6.0V) | Drops below 4.5V cause erratic pulse widths and phantom readings. |
| Quiescent Current | 2 mA (Standby) / 15 mA (Active) | The 15mA spike during the burst causes local voltage sag on long wires. |
| Acoustic Frequency | 40 kHz | Standard for hobby ultrasonic; easily absorbed by soft fabrics. |
| Blind Zone | 2 cm (Minimum) | Transducer mechanical ringing deafens the receiver for ~150µs post-burst. |
| Maximum Range | 400 cm (Practical: ~300 cm) | Beam divergence and acoustic attenuation degrade signal past 3 meters. |
| Beam Angle | ~15° (Half-angle cone) | Measures a cone, not a laser point; will detect adjacent walls. |
Microcontroller Wiring Matrix
Below is the exact wiring matrix for both 5V-tolerant (Arduino Uno/Mega) and 3.3V (ESP32/Raspberry Pi Pico) microcontrollers. For 3.3V boards, you must use a voltage divider on the Echo pin.
| HC-SR04 Pin | Arduino Uno (5V Logic) | ESP32 / Pico (3.3V Logic) | Function |
|---|---|---|---|
| VCC | 5V Pin | 5V Pin (VIN or USB) | Powers the internal oscillator and op-amps. |
| Trigger | Any Digital GPIO (e.g., D5) | Any Digital GPIO (e.g., GPIO 5) | Receives 10µs HIGH pulse to initiate measurement. |
| Echo | Any Digital GPIO (e.g., D6) | GPIO via Voltage Divider* | Outputs HIGH pulse proportional to distance. |
| GND | GND | GND | Common ground reference. |
*ESP32 Voltage Divider: Connect a 1kΩ resistor in series with the Echo pin, and a 2kΩ resistor from the GPIO side of the 1kΩ resistor to GND. This divides the 5V output down to a safe 3.33V. See the Espressif Hardware Design Guidelines for ESP32 GPIO absolute maximum ratings.
Real-World Interference and Calibration Fixes
The HC-SR04 is notorious for throwing random "400 cm" or "0 cm" spikes in data logs. These are rarely broken sensors; they are physics and electrical noise issues. Here are the primary interference sources and how to engineer them out of your build.
1. Acoustic Cross-Talk
If you are using multiple HC-SR04 sensors on the same robot or tank, firing them simultaneously will cause Sensor A's receiver to pick up Sensor B's transmitter echo. The Fix: Never poll them in parallel. Fire Sensor A, wait for the echo (or timeout), wait an additional 60 milliseconds for the acoustic energy to dissipate in the room, and then fire Sensor B.
2. Power Rail Sag and Phantom Echoes
When the HC-SR04 fires its 40 kHz burst, it draws a sudden 15 mA spike. If you are powering it through long, thin breadboard jumper wires, this spike causes a momentary voltage drop on the VCC line. The sensor's internal comparator misinterprets this sag, resulting in wild distance spikes. The Fix: Solder a 100nF (0.1µF) ceramic decoupling capacitor directly across the VCC and GND pins on the back of the sensor PCB.
3. Target Material and Beam Scatter
Ultrasonic waves behave like light bouncing off a mirror. If the target is angled more than 15 degrees away from the sensor's centerline, the sound wave reflects away from the receiver, resulting in a timeout (often read as 0 or max range). Similarly, soft materials like foam, heavy curtains, or clothing absorb 40 kHz frequencies. The Fix: For liquid level sensing or soft-target detection, tape a small piece of rigid plastic or acrylic to the target surface to provide a hard acoustic reflector.
Bulletproof ESP32 and Arduino Implementation
The most common mistake beginners make with the HC-SR04 is using the standard pulseIn() function without a timeout. If the sound wave hits a soft surface and never returns, pulseIn() will block the microcontroller forever, crashing your robot or freezing your web server. According to the official Arduino pulseIn() reference, you must always define a maximum wait time.
Since the maximum range is 400 cm, the round trip is 800 cm. At 343 m/s, 800 cm takes roughly 23.3 milliseconds. Therefore, a timeout of 30,000 µs (30 ms) is mathematically perfect to catch all valid echoes while immediately recovering from missed ones.
Step-by-Step Code Implementation
- Wire the hardware: Connect VCC to 5V, GND to GND, Trigger to GPIO 5, and Echo to GPIO 18 (via the 1k/2k voltage divider for ESP32).
- Initialize pins: Set Trigger as OUTPUT and Echo as INPUT.
- Trigger the burst: Pull Trigger LOW for 2µs (to ensure a clean edge), then HIGH for 10µs, then LOW.
- Read with timeout: Use
pulseIn(EchoPin, HIGH, 30000). - Calculate and filter: Apply the math and discard readings of exactly 0 (timeout/missed echo).
// HC-SR04 Bulletproof Code for ESP32 / Arduino
const int trigPin = 5;
const int echoPin = 18;
// Speed of sound in cm/uS (adjust for temperature if needed)
const float soundSpeed = 0.0343;
void setup() {
Serial.begin(115200);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
digitalWrite(trigPin, LOW); // Ensure clean start
}
void loop() {
long duration;
float distanceCm;
// 1. Clear the trigger pin and send the 10uS pulse
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// 2. Read the echo pin with a strict 30ms (30000uS) timeout
duration = pulseIn(echoPin, HIGH, 30000);
// 3. Calculate distance and handle timeouts
if (duration == 0) {
Serial.println("Error: Echo timeout (Target out of range or absorbed)");
} else {
distanceCm = (duration * soundSpeed) / 2.0;
// Filter out blind zone noise (readings under 2cm are physical transducer ringing)
if (distanceCm < 2.0) {
Serial.println("Warning: Inside 2cm blind zone");
} else {
Serial.print("Distance: ");
Serial.print(distanceCm);
Serial.println(" cm");
}
}
// 4. Mandatory 60ms delay to prevent acoustic cross-talk and ringing
delay(60);
}





