STANNUM
Open the simulator

Tutorials / Input

Ultrasonic distance sensor (HC-SR04)

Trigger a ping, time the echo: 58 microseconds per centimeter, measured by the firmware itself.

Parts in the example:
  • Ultrasonic
  • Active buzzer
  • LED
The Ultrasonic block as it appears on the canvas.

What it is

The HC-SR04 sends a burst of ultrasound when TRIG is pulsed for 10 µs and raises ECHO for as long as the sound takes to come back: about 58 µs per centimeter of distance. The firmware measures that pulse with pulseIn() — the timing is the data, which is why this sensor is the classic exercise in microsecond timing.

In the simulator

The block has one slider, the distance to the obstacle, from 2 to 400 cm (the useful range of the real sensor); the Control scale setting shows it in meters instead. Everything else happens in the simulation: when the firmware pulses TRIG, the ECHO pulse comes back with the width that distance calls for.

Pins

PinWhat it is
TRIGtrigger — to a GPIO the code pulses
ECHOecho — to a GPIO the code times
5Vpower — to a 3V3 symbol here; on a bench the module wants 5 V, and its ECHO then returns 5 V — use a divider
GNDground — to a GND symbol

Wiring

The circuit below is the example Parking sensor — ultrasonic + buzzer from the lab — open it with Project → Open example… and it comes ready to run.

The wired circuit, as the lab draws it.
Ultrasonic pinGoes to
TRIGD5 on the board (GPIO 5)
ECHOD18 on the board (GPIO 18)
5Va 3V3 symbol
GNDa GND symbol

Settings

Double-click the block's title bar to open its card, then the Settings tab. Changes apply to the running simulation right away.

The Settings tab of the Ultrasonic.
SettingAcceptsDefaultNotes
Control scaleCentimeters (2 to 400) · Meters (0.02 to 4)Centimeters (2 to 400)The useful range of the HC-SR04 is 2 cm to 4 m; below 2 cm it cannot tell the echo apart.

Code

sketch.cpp
#include <Arduino.h>

const int TRIG = 5, ECHO = 18, BUZZER = 26, LED = 2;

// A single HC-SR04 reading is noisy — on the real sensor too, because the echo
// bounces back crooked off soft surfaces, off angles, off the air temperature.
// The standard recipe is to measure several times and keep the MEDIAN, which
// throws out the wild values without needing a moving average.
long medirUmaVez() {
  digitalWrite(TRIG, LOW);  delayMicroseconds(4);
  digitalWrite(TRIG, HIGH); delayMicroseconds(10);
  digitalWrite(TRIG, LOW);
  return pulseIn(ECHO, HIGH, 40000UL);      // µs; 0 = no echo
}

float medirDistancia() {
  const int N = 5;
  long v[N];
  int n = 0;
  for (int i = 0; i < N; i++) {
    long us = medirUmaVez();
    if (us > 0) v[n++] = us;                // drop the timeouts
    delay(20);
  }
  if (n == 0) return -1;

  for (int i = 1; i < n; i++) {             // sort (n is tiny)
    long x = v[i]; int j = i - 1;
    while (j >= 0 && v[j] > x) { v[j + 1] = v[j]; j--; }
    v[j + 1] = x;
  }
  return v[n / 2] / 58.0;                   // median, in cm
}

void setup() {
  Serial.begin(115200);
  delay(300);
  pinMode(TRIG, OUTPUT); pinMode(ECHO, INPUT);
  pinMode(BUZZER, OUTPUT); pinMode(LED, OUTPUT);
  digitalWrite(TRIG, LOW);
  Serial.println("parking sensor ready — move the distance on the sensor");
}

void loop() {
  float cm = medirDistancia();
  if (cm < 0) { Serial.println("no reading"); delay(300); return; }

  // gap between beeps: right on top = continuous, far away = quiet
  int intervalo;
  if (cm < 30)       intervalo = 80;
  else if (cm < 80)  intervalo = 250;
  else if (cm < 150) intervalo = 600;
  else               intervalo = 0;         // out of useful range: silence

  Serial.printf("%.0f cm%s\n", cm, intervalo ? "" : "  (clear)");

  if (intervalo) {
    digitalWrite(BUZZER, HIGH); digitalWrite(LED, HIGH);
    delay(40);
    digitalWrite(BUZZER, LOW);  digitalWrite(LED, LOW);
    delay(intervalo);
  } else {
    digitalWrite(BUZZER, LOW);  digitalWrite(LED, LOW);
    delay(300);
  }
}

The three-line trigger, then pulseIn(ECHO, HIGH, 40000) with a timeout, then µs / 58. The example measures five times and keeps the median — the standard recipe, because a single reading of the real sensor is noisy — and beeps faster the closer the obstacle is.

Run it

Press Build and run. The first build of a project takes a while; after that, only what changed is rebuilt.

The simulation running: the canvas reacts and the serial monitor shows what the code prints.

Drag the distance slider: the serial monitor prints the centimeters and the buzzer's rhythm changes — continuous under 30 cm, slow around a meter, silent past 1.5 m.

How the simulation models it

Try this

  1. Print the distance in inches as well (÷ 148 instead of ÷ 58).
  2. Light an LED bar as a proximity gauge: more segments the closer the obstacle.

See also