The HC-SR04 ultrasonic sensor measures distances from 2 cm to 400 cm by timing 40 kHz sound wave echoes. When wiring an HC-SR04 sensor to an Arduino Uno R3, you connect VCC to 5V, GND to GND, Trig to Pin 9, and Echo to Pin 10. However, if you are using a 3.3V board like the ESP32 or Arduino Nano 33 IoT, the 5V Echo return will fry your GPIO unless you use a voltage divider or the 3.3V-compatible HC-SR04+ variant. This guide covers the exact hardware specs, a glitch-filtered code implementation, and how to debug the notorious serial monitor errors that plague this specific module.
HC-SR04 vs Alternatives: Spec Sheet & Selection Matrix
Before soldering, verify you have the right module for your environment. The standard HC-SR04 is a bench prototype part, not an industrial sensor. Below is a data-dense comparison of the most common 40 kHz ultrasonic modules available in 2026, highlighting why you might need to upgrade based on your operating environment.
| Model | Logic Level | Min / Max Range | Beam Angle | Blind Zone | Avg Price (2026) | Best Application |
|---|---|---|---|---|---|---|
| HC-SR04 | 5V Only | 2 cm / 400 cm | ~15° | < 2 cm | $1.50 | Indoor robotics, basic Arduino tutorials |
| HC-SR04+ | 3.3V & 5V | 2 cm / 400 cm | ~15° | < 2 cm | $2.20 | ESP32, Raspberry Pi Pico, 3.3V MCUs |
| JSN-SR04T | 5V Only | 20 cm / 600 cm | ~12° | < 20 cm | $4.50 | Outdoor, waterproof, car reverse parking |
| MaxBotix MB1010 | 2.5V - 5.5V | 0 cm / 500 cm | ~42° | 0 cm (No blind zone) | $29.99 | Industrial tank level, precision medical |
Hardware Build and Pin Mapping
This build targets the Arduino Uno R3 (ATmega328P), which operates at 5V logic. This allows direct wiring to the standard HC-SR04 without level shifters. If you are using an ESP32 or Arduino Uno R4 WiFi, you must use a 10kΩ/20kΩ voltage divider on the Echo pin, or purchase the HC-SR04+ variant listed above.
Parts List
- Microcontroller: Arduino Uno R3 (ATmega328P) - ~$27.00 (Official) / ~$14.00 (Clone)
- Sensor: Standard HC-SR04 (4-pin variant) - ~$1.50
- Wiring: 4x Male-to-Male jumper wires (Dupont 2.54mm pitch)
- Prototyping: Half-size 400-point solderless breadboard
- Optional (for 3.3V boards): 1x 10kΩ and 1x 20kΩ carbon film resistor (1/4W) for voltage division.
Pin Mapping Table
| HC-SR04 Pin | Arduino Uno R3 Pin | Wire Color (Standard) | Function |
|---|---|---|---|
| VCC | 5V | Red | Powers the internal oscillator and transducer boost converter |
| Trig | Digital Pin 9 | Yellow | Receives a 10µs HIGH pulse to initiate the measurement |
| Echo | Digital Pin 10 | Green | Outputs a HIGH pulse proportional to the distance measured |
| GND | GND | Black | Common ground reference |
Glitch-Filtered Arduino Code
The most common complaint with the HC-SR04 is random, massive distance spikes (e.g., jumping from 45 cm to 3400 cm for a single reading). This happens because the cheap internal microcontroller on the sensor occasionally misses an echo or suffers from acoustic crosstalk, pulling the Echo pin HIGH indefinitely until the watchdog resets it.
The code below avoids the standard pulseIn() blocking trap by implementing a strict timeout and a 5-sample median filter. This sorts the readings and discards the highest and lowest outliers, guaranteeing a stable serial output.
/*
* HC-SR04 Ultrasonic Sensor with Median Glitch Filter
* Target Board: Arduino Uno R3 (5V Logic)
* Author: ElectricalFlux Bench Team
*/
#define TRIG_PIN 9
#define ECHO_PIN 10
#define MAX_DISTANCE 400 // Max practical range in cm
#define TIMEOUT_US 25000 // 400cm takes ~23ms; 25ms timeout prevents infinite blocking
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
digitalWrite(TRIG_PIN, LOW); // Ensure clean start state
}
void loop() {
long stableDistance = readMedianDistance();
Serial.print("Distance: ");
Serial.print(stableDistance);
Serial.println(" cm");
delay(100); // Update rate ~10Hz (safe for 40kHz decay)
}
long readMedianDistance() {
long samples[5];
for (int i = 0; i < 5; i++) {
// 1. Clear the trigger pin
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
// 2. Send exactly 10µs HIGH pulse (HC-SR04 hardware requirement)
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// 3. Read the echo with strict timeout
long duration = pulseIn(ECHO_PIN, HIGH, TIMEOUT_US);
// 4. Convert to cm (Speed of sound = 343 m/s -> 0.0343 cm/µs)
// Divide by 2 for the round-trip
if (duration == 0 || duration > 23500) {
samples[i] = MAX_DISTANCE; // Assign max distance for timeouts/glitches
} else {
samples[i] = (duration * 0.0343) / 2;
}
delay(25); // Mandatory 25ms pause to let acoustic ringing dissipate
}
// Simple bubble sort for 5 elements to find the median
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4 - i; j++) {
if (samples[j] > samples[j+1]) {
long temp = samples[j];
samples[j] = samples[j+1];
samples[j+1] = temp;
}
}
}
return samples[2]; // Return the middle (median) value
}
0.0343 cm/µs assumes an ambient temperature of 20°C (68°F). If you are using this sensor in an unheated garage or outdoors in winter (e.g., 0°C), the speed of sound drops, and your sensor will read roughly 3% short. For high-precision tank level monitoring, wire a DS18B20 temperature sensor and apply the formula: v = 331.4 + (0.6 * Temp_C) to dynamically adjust your multiplier.
Debugging: First Three Things to Check When It Fails
When your serial monitor starts misbehaving, do not immediately rewrite your code. 90% of HC-SR04 failures are hardware or timing related. Here is the exact diagnostic sequence based on the error string you are seeing.
Symptom 1: Serial monitor stuck on Distance: 0 cm
Ranked Causes:
- Fried Echo Pin (3.3V Board): If you connected a 5V HC-SR04 Echo pin directly to an ESP32 or Raspberry Pi Pico GPIO, you have likely burned out the internal clamping diode on the MCU. Fix: Move the Echo wire to a new GPIO pin and implement a voltage divider (20kΩ from Echo to GPIO, 10kΩ from GPIO to GND).
- Charge-Only USB Cable: Your Arduino is running the sketch, but the data lines (D+ / D-) in your USB cable are missing. Fix: Swap to a verified data-sync USB cable.
- Dead Sensor Module: The internal STC microcontroller on the HC-SR04 has failed, or the 40kHz crystal oscillator is dead. Fix: Replace the sensor; they are largely unrepairable due to epoxy potting.
Symptom 2: Random massive spikes like Distance: 3452 cm
Ranked Causes:
- Missing Timeout in
pulseIn(): If you usepulseIn(ECHO_PIN, HIGH)without the third timeout parameter, and the sensor misses the echo, the Arduino will hang waiting for a falling edge that never comes, eventually overflowing the variable. Fix: Always usepulseIn(pin, HIGH, 25000)as shown in the code above. - Acoustic Crosstalk: You have multiple HC-SR04 sensors firing in the same room, or you are pinging faster than 20Hz. The sensor is hearing the echo from a previous ping or a neighboring sensor. Fix: Enforce a minimum 25ms
delay()between pings. - Soft Target Absorption: You are pointing the sensor at a couch, curtain, or angled wall. The 40kHz wave is being absorbed or reflected away from the receiver. Fix: Test against a flat, hard surface like a book or wall.
Symptom 3: Complete sketch hang (No serial output)
Ranked Causes:
- Trigger Pulse Width Incorrect: The HC-SR04 hardware requires a minimum of 10µs HIGH pulse on the Trig pin to initiate a measurement. If you use
delayMicroseconds(5), the internal chip will ignore the trigger, the Echo pin will never go HIGH, and a poorly written blocking loop will freeze. Fix: EnsuredelayMicroseconds(10)is exact.
Extending and Simplifying the Build
How to Simplify: The NewPing Library
If you do not want to manage raw timing and median filters yourself, the community-standard NewPing library handles timeouts, crosstalk delays, and median filtering natively. It strips out the 15ms blocking delay inherent in the standard pulseIn() function, freeing up your Arduino's main loop to handle motor control or WiFi tasks. Simply install "NewPing" via the Arduino Library Manager and use sonar.ping_median(5) to get the exact same filtered result in one line of code.
How to Extend: I2C Multiplexing and Fluid Sensing
The HC-SR04 is strictly a 4-pin parallel interface device; it does not have an I2C address. If your project requires multiple sensors (e.g., a 4-wheel obstacle avoidance robot), you will run out of GPIO pins and suffer from acoustic crosstalk.
The Extension Path: Use an I2C multiplexer like the TCA9548A paired with I2C-based ultrasonic sensors (like the DFRobot URM09), or build a simple transistor switching circuit to power-cycle individual HC-SR04 modules one at a time via N-channel MOSFETs (like the 2N7000) on their GND lines.
Fluid Level Sensing: To use the HC-SR04 for water tank depth, mount it inside a PVC pipe cap facing downward into the tank. The PVC pipe acts as an acoustic waveguide, narrowing the 15° beam angle and preventing false echoes off the tank walls. Just remember to invert your math: Fluid_Level = Tank_Height - Sensor_Distance.
Final Bench Note: According to SparkFun's ultrasonic sensor guides, the physical mesh covering the transducers is highly susceptible to dust and moisture buildup. If your sensor suddenly starts reading 2cm regardless of the actual distance, inspect the silver mesh. A quick blast of compressed air to clear debris from the receiver transducer often revives a seemingly dead module.






