The HC-SR04 ultrasonic distance sensor Arduino setup measures distances from 2 cm to 400 cm by timing 40 kHz sound wave echoes. This guide targets the Arduino Uno R3 (ATmega328P) and provides exact wiring, robust C++ code with timeout error handling, and a debugging matrix for when your serial monitor spits out Distance: 0 cm or hangs entirely. We will cover the physics of the 58 µs/cm timing constant, the 5V logic requirement, and how to rescue a stalled pulseIn() function.

Project Spec Sheet & Parts List

Before wiring, verify you have the correct module variant. The market is flooded with clones, but the core timing parameters remain consistent across standard HC-SR04 boards.

Component Exact Variant / Model Est. Cost (2026) Technical Notes
Microcontroller Arduino Uno R3 (ATmega328P) $27.00 5V logic, 16 MHz clock. Code also runs on Nano/Mega.
Sensor Module HC-SR04 (4-pin variant) $2.50 Requires 5V VCC. 15mA working current. 40 kHz transducers.
Breadboard Standard 830-point solderless $6.00 Ensure power rails are continuous (no center splits).
Jumper Wires 22 AWG Male-to-Male $4.00 Use distinct colors for VCC (Red) and GND (Black).

Pin Mapping and Wiring Steps

The HC-SR04 uses a simple 4-pin interface. The critical detail here is voltage: the HC-SR04 requires a 5V supply to drive the ultrasonic transducers effectively. Feeding it 3.3V will result in weak acoustic output and severe range degradation.

HC-SR04 Pin Arduino Uno R3 Pin Wire Color Function
VCC 5V Red Power supply (4.8V to 5.5V acceptable)
Trig Digital 9 Yellow Trigger input (receives 10µs HIGH pulse)
Echo Digital 10 Green Echo output (returns HIGH for duration of flight)
GND GND Black Common ground reference
Callout Tip: If you are adapting this build for a 3.3V board like the ESP32 or Raspberry Pi Pico, you MUST use a voltage divider on the Echo pin (e.g., 1kΩ and 2kΩ resistors) to step the 5V Echo signal down to ~3.3V. Frying a 3.3V GPIO pin is the most common hardware mistake with this sensor.
  1. Insert the Arduino Uno and HC-SR04 into the breadboard, ensuring the sensor's transducers are facing outward, unobstructed by the breadboard plastic.
  2. Connect the red jumper from the Arduino 5V pin to the HC-SR04 VCC pin.
  3. Connect the black jumper from any Arduino GND pin to the HC-SR04 GND pin.
  4. Connect the yellow jumper from Arduino Digital Pin 9 to the HC-SR04 Trig pin.
  5. Connect the green jumper from Arduino Digital Pin 10 to the HC-SR04 Echo pin.
  6. Double-check that VCC and GND are not swapped. Reversing polarity on the HC-SR04 can instantly destroy the onboard MAX232 equivalent driver chip.

Complete C++ Code with Timeout Error Handling

Many basic tutorials use pulseIn() without a timeout, which causes the Arduino to hang indefinitely if the echo never returns. The code below targets the Arduino Uno R3, uses a strict 25,000 µs timeout (roughly 4.25 meters), and includes explicit error handling for timeouts and out-of-range readings.

#define TRIG_PIN 9
#define ECHO_PIN 10
// 25000 µs timeout = ~4.25 meters max range (speed of sound = 343 m/s)
#define TIMEOUT_US 25000 

void setup() {
  Serial.begin(115200);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  
  // Ensure trigger pin is low on startup to prevent phantom echoes
  digitalWrite(TRIG_PIN, LOW);
  delay(500); // Allow sensor to stabilize
  Serial.println("HC-SR04 Initialized. Awaiting readings...");
}

void loop() {
  // 1. Clear the trigger pin
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  
  // 2. Send a 10µs HIGH pulse to trigger the measurement
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  
  // 3. Read the echo pin with a strict timeout
  unsigned long duration = pulseIn(ECHO_PIN, HIGH, TIMEOUT_US);
  
  // 4. Error Handling & Calculation
  if (duration == 0) {
    // pulseIn returns 0 if the timeout is reached before a pulse is detected
    Serial.println("Error: Timeout - No Echo Received");
  } else {
    // Calculate distance: duration / 58.0 (based on 343 m/s at 20°C round-trip)
    float distance_cm = duration / 58.0;
    
    if (distance_cm > 400.0) {
      Serial.println("Error: Out of Range (>400cm)");
    } else {
      Serial.print("Distance: ");
      Serial.print(distance_cm, 1); // 1 decimal place precision
      Serial.println(" cm");
    }
  }
  
  // 5. Wait 60ms before next reading (HC-SR04 needs ~50ms to clear acoustic ringing)
  delay(60); 
}

Debugging: First Three Checks and Common Error Strings

When your serial monitor outputs Error: Timeout - No Echo Received or the distance is stuck at 0 cm, do not immediately rewrite your code. Hardware and physics are usually the culprits. Here are the first three things to check when it fails:

  1. Power Rail Continuity: Use a multimeter to verify exactly 5.0V (±0.2V) between the HC-SR04 VCC and GND pins while the circuit is powered. Breadboard power rails often have internal splits or loose contacts that drop voltage under the sensor's 15mA load.
  2. Trigger Pin Signal: If you have an oscilloscope or a logic analyzer, probe the Trig pin. You must see a clean 10 µs HIGH pulse every ~70 ms. If it's missing, your pin definition in code is wrong, or the jumper wire is broken.
  3. Echo Pin Voltage: Measure the Echo pin with a multimeter. When idle, it should read 0V. When an object is in range, it should pulse to ~5V. If it reads a floating voltage (e.g., 1.8V) constantly, the internal comparator on the sensor module is likely damaged or unpowered.

Ranked Causes for 'Error: Timeout - No Echo Received'

If the hardware checks out, evaluate these environmental and physical failure modes:

  • Cause 1: Acoustic Absorption. The target object is made of sound-absorbing material (thick foam, heavy curtains, angled soft fabric). The 40 kHz wave is absorbed rather than reflected.
  • Cause 2: Specular Reflection (Angle). The target surface is smooth but angled more than 15 degrees away from the sensor's normal axis. The sound wave bounces off into the room rather than back to the receiver.
  • Cause 3: The 2 cm Blind Zone. The object is too close. The HC-SR04 transducer physically rings for a few hundred microseconds after the trigger pulse ends. The receiver is effectively deaf during this time, making anything under 2 cm invisible.
Warning: Never use the HC-SR04 to measure the level of liquids in a sealed, narrow PVC pipe. The 15-degree beam angle will cause multiple internal reflections (multipath interference), resulting in wildly fluctuating distance readings.

Extending and Simplifying the Build

Depending on your end goal, you can either strip this project down to its bare essentials or scale it up into a robust industrial-style prototype.

How to Simplify the Build

If you want to avoid manual timing math and timeout handling, install the NewPing library via the Arduino Library Manager. NewPing handles the 10 µs trigger, the timeout, and the median filtering (taking 5 readings and discarding outliers) in a single non-blocking function call. It reduces the main loop to about three lines of code and prevents the microcontroller from stalling during pulseIn().

How to Extend the Build

To turn this into a practical parking sensor or tank-level monitor, add these modules:

  • Temperature Compensation (DS18B20): The speed of sound changes with air temperature. At 0°C, sound travels at 331 m/s; at 30°C, it travels at 349 m/s. Adding a DS18B20 temperature sensor allows you to dynamically adjust the 58.0 divisor in the code, reducing measurement error from ~3% down to <0.5%.
  • Visual Feedback (I2C OLED SSD1306): Wire an SSD1306 128x64 OLED display to the I2C pins (A4/A5 on the Uno) to render a real-time bar graph of the distance, eliminating the need for a tethered serial monitor.
  • Proximity Alerts (Active Buzzer): Map the distance reading to a PWM frequency to drive a piezo buzzer, increasing the beep rate as the distance drops below 50 cm.

Frequently Asked Questions

Why is my ultrasonic distance sensor Arduino reading stuck at 0 cm?

A reading of exactly 0 cm (or 0.0) usually means the pulseIn() function timed out and returned 0, but your code divided 0 by 58 without an error check. Physically, this happens when the sensor is pointed at an open doorway, a heavily angled wall, or a sound-absorbing material like a couch cushion. The trigger pulse fires, but the echo never bounces back to the receiver within the timeout window.

Can I use the HC-SR04 ultrasonic sensor with a 3.3V ESP32 or Raspberry Pi Pico?

Yes, but with a critical hardware modification. The HC-SR04 requires 5V to power its transducers, and its Echo pin outputs a 5V HIGH signal. Connecting a 5V Echo pin directly to a 3.3V ESP32 GPIO will eventually degrade or destroy the ESP32's internal silicon. You must power the sensor's VCC with 5V, but place a voltage divider (e.g., a 1kΩ resistor in series with the Echo pin, and a 2kΩ resistor to GND) to step the 5V Echo signal down to a safe ~3.3V before it reaches the microcontroller.

How do I make the HC-SR04 ultrasonic distance sensor Arduino code non-blocking?

The standard pulseIn() function is blocking; the Arduino does nothing else while waiting for the echo. To make it non-blocking, you must abandon pulseIn() and use hardware interrupts or timer capture. Alternatively, use the NewPing library, which utilizes timer interrupts to measure the pulse width in the background, allowing your loop() to continue executing other tasks like updating displays or reading buttons.

Does temperature affect the accuracy of the HC-SR04 sensor?

Yes, significantly. The hardcoded 58.0 divisor in standard Arduino code assumes the speed of sound is exactly 343 meters per second, which is only true at 20°C (68°F). If you use this sensor in a freezing garage (0°C), the speed of sound drops to 331 m/s, and your distance readings will be off by roughly 3.5%. For precision applications under 1 cm tolerance, you must integrate a temperature sensor and calculate the real-time speed of sound.