Online Shipping | GrabExpress & Lalamove instant delivery for Penang Islandsupport@icontech.com.my | 017-481 1886
← Back to Articles
HC-SR04 + LCD 1602 Distance Meter with ESP32

HC-SR04 + LCD 1602 Distance Meter with ESP32

8 April 2026


The HC-SR04 is one of the most popular ultrasonic distance sensors in the maker world — cheap, accurate to within a few millimetres, and dead simple to wire. Pair it with a 16x2 LCD display and an ESP32, and you have a compact, self-contained distance meter that shows live readings without needing a computer or serial monitor. This is a great beginner project that teaches you PWM timing, I2C displays, and clean real-time output all in one build.

Components for This Project

ComponentShop
ESP32 DEVKIT (WROOM 32)View Product
HC-SR04 Ultrasonic SensorView Product
LCD 1602 I2C DisplayView Product
I2C Serial Interface Board (for parallel LCD)View Product

How the HC-SR04 Works

Before writing any code, it helps to understand what is happening at the hardware level.

The HC-SR04 uses sound to measure distance — the same principle as a bat or a car parking sensor. Here is the sequence:

  1. Your microcontroller sends a short 10 µs HIGH pulse to the TRIG pin
  2. The sensor fires a burst of 8 ultrasonic pulses at 40 kHz
  3. The sound bounces off the nearest object and returns to the sensor
  4. The sensor holds the ECHO pin HIGH for exactly as long as the round-trip took
  5. You measure that pulse duration and convert it to distance

The conversion formula uses the speed of sound (~343 m/s at 20°C):

textcode
1distance (cm) = pulse duration (µs) / 58.0

Or equivalently:

textcode
1distance (cm) = (pulse duration (µs) * 0.0343) / 2

Effective range: 2 cm to 400 cm. Objects closer than 2 cm may not return a reliable echo. Objects further than 4 m or with soft/angled surfaces (like fabric or carpet at 45°) can give inconsistent readings.


What You Will Need

ComponentNotes
ESP32 Development BoardDEVKIT V1 DOIT or any 30/36-pin variant
HC-SR04 Ultrasonic Sensor4-pin module (VCC, TRIG, ECHO, GND)
LCD 1602 with I2C BackpackThe I2C version saves 6 wires vs parallel wiring
BreadboardFull-size or half-size
Jumper WiresMale-to-male and male-to-female
USB CableData cable for programming

Why the I2C LCD? The standard LCD 1602 without I2C requires 6 data pins plus power — nearly half your ESP32's GPIO pins just for a display. The I2C backpack solves this with just 2 data wires (SDA + SCL). If you only have a parallel LCD, you can add an PCF8574 I2C expander module for under RM 2.


Wiring Guide

HC-SR04 to ESP32

The ECHO pin outputs 5V on many HC-SR04 modules. The ESP32 GPIO pins are 3.3V tolerant only. Use a voltage divider (2x resistors) or a logic level shifter to protect the ESP32.

Simple voltage divider for ECHO (1kΩ + 2kΩ):

textcode
1HC-SR04 ECHO ──── 1kΩ ──── ESP32 GPIO (safe 3.3V)
2                      |
3                     2kΩ
4                      |
5                     GND
HC-SR04 PinConnect To
VCC5V (VIN on ESP32 dev board)
GNDGND
TRIGGPIO 5
ECHOGPIO 18 (via voltage divider)

LCD 1602 I2C to ESP32

LCD I2C PinESP32 Pin
VCC5V (VIN)
GNDGND
SDAGPIO 21
SCLGPIO 22

I2C Address: Most PCF8574-based I2C LCD modules use address

textcode
10x27
. Some use
textcode
10x3F
. If the display stays blank after uploading, try
textcode
10x3F
in the code.


Installing Required Libraries

You need two libraries. Install both via Arduino IDE > Tools > Manage Libraries:

LibrarySearch ForAuthor
LiquidCrystal I2C
textcode
1LiquidCrystal I2C
Frank de Brabander
No extra library needed for HC-SR04Uses built-in
textcode
1pulseIn()

The Code

cppcode
1#include <Wire.h>
2#include <LiquidCrystal_I2C.h>
3
4// ── Pin Definitions ───────────────────────────────────────────────────────────
5#define TRIG_PIN  5    // HC-SR04 trigger
6#define ECHO_PIN  18   // HC-SR04 echo (use voltage divider from 5V to 3.3V)
7
8// ── LCD Setup ─────────────────────────────────────────────────────────────────
9// Parameters: I2C address, columns, rows
10// Try 0x3F if 0x27 does not work
11LiquidCrystal_I2C lcd(0x27, 16, 2);
12
13// ── Measure distance in centimetres ───────────────────────────────────────────
14float measureDistance() {
15  // Send 10 µs trigger pulse
16  digitalWrite(TRIG_PIN, LOW);
17  delayMicroseconds(2);
18  digitalWrite(TRIG_PIN, HIGH);
19  delayMicroseconds(10);
20  digitalWrite(TRIG_PIN, LOW);
21
22  // Read echo pulse duration (timeout = 30 ms → ~5 m max)
23  long duration = pulseIn(ECHO_PIN, HIGH, 30000);
24
25  if (duration == 0) return -1;   // no echo received (out of range)
26
27  return duration / 58.0;         // convert to cm
28}
29
30void setup() {
31  Serial.begin(115200);
32
33  pinMode(TRIG_PIN, OUTPUT);
34  pinMode(ECHO_PIN, INPUT);
35
36  // Initialise LCD
37  lcd.init();
38  lcd.backlight();
39
40  // Splash screen
41  lcd.setCursor(0, 0);
42  lcd.print("  Distance Meter");
43  lcd.setCursor(0, 1);
44  lcd.print(" HC-SR04 + ESP32");
45  delay(2000);
46  lcd.clear();
47}
48
49void loop() {
50  float distance = measureDistance();
51
52  // ── Print to Serial Monitor ────────────────────────────────────────────────
53  if (distance < 0) {
54    Serial.println("Out of range");
55  } else {
56    Serial.printf("Distance: %.1f cm\n", distance);
57  }
58
59  // ── Update LCD ─────────────────────────────────────────────────────────────
60  lcd.setCursor(0, 0);
61  lcd.print("Distance:       ");   // trailing spaces clear old characters
62
63  lcd.setCursor(0, 1);
64  if (distance < 0 || distance > 400) {
65    lcd.print("Out of range    ");
66  } else {
67    // Format: "123.4 cm        "
68    String display = String(distance, 1) + " cm";
69    // Pad to 16 chars to overwrite previous longer values
70    while (display.length() < 16) display += " ";
71    lcd.print(display);
72  }
73
74  delay(200);   // update 5 times per second
75}

Understanding the Code

The
textcode
1measureDistance()
Function

This is the heart of the project. It drives TRIG LOW briefly to clean up any noise, then pulls it HIGH for 10 µs to fire the ultrasonic burst.

textcode
1pulseIn(ECHO_PIN, HIGH, 30000)
blocks execution and measures how long ECHO stays HIGH — up to the 30 ms timeout. Dividing by 58 converts microseconds to centimetres (accounting for the round-trip and speed of sound).

Clearing Old Characters on the LCD

LCD displays do not auto-clear when you write shorter text over longer text. For example, writing

textcode
1"9.5 cm"
over
textcode
1"123.4 cm"
would leave
textcode
1"9.5 cmcm"
on screen. The fix is to pad each string to the full 16-character line width with trailing spaces, which overwrites any leftover characters from the previous update.

The Update Rate

textcode
1delay(200)
gives 5 readings per second — fast enough to feel real-time, slow enough that the LCD is readable without flickering. For very fast-moving targets you can reduce this to
textcode
1delay(50)
or
textcode
1delay(100)
.


Serial Monitor Output

Open Tools > Serial Monitor at 115200 baud and press the RESET button. You should see:

textcode
1Distance: 14.3 cm
2Distance: 14.4 cm
3Distance: 14.2 cm
4Distance: 14.3 cm
5Out of range
6Distance: 28.7 cm

This is useful for debugging — if the LCD shows garbage but the Serial Monitor looks correct, the issue is with the LCD address or wiring.


Calibration and Accuracy Tips

The HC-SR04 is reasonably accurate for most DIY purposes, but there are a few things that affect readings:

FactorEffectFix
TemperatureSpeed of sound changes ~0.6 m/s per °CAdd a temperature sensor (DS18B20) and use
textcode
1distance = duration * (331.3 + 0.606 * tempC) / 20000.0
Surface angleAngled or soft surfaces absorb/deflect ultrasoundWorks best on flat, hard, perpendicular surfaces
Fast movementObject moves during echo travelAverage 3–5 readings for stability
Electrical noiseLong TRIG/ECHO wires act as antennasKeep wires short; add 100 nF ceramic capacitor across VCC/GND on the sensor
Multiple sensorsSensors interfere with each otherTrigger them one at a time with at least 60 ms between triggers

Averaging for Stability

For smoother readings, take multiple samples and average them:

cppcode
1float stableDistance() {
2  const int SAMPLES = 5;
3  float total = 0;
4  int valid = 0;
5  for (int i = 0; i < SAMPLES; i++) {
6    float d = measureDistance();
7    if (d > 0 && d <= 400) {
8      total += d;
9      valid++;
10    }
11    delay(15);
12  }
13  return valid > 0 ? total / valid : -1;
14}

Replace

textcode
1measureDistance()
with
textcode
1stableDistance()
in the loop for noticeably smoother LCD readings.


Troubleshooting

SymptomLikely CauseFix
LCD shows nothingWrong I2C address or no backlight powerTry
textcode
10x3F
; check VCC is 5V not 3.3V
LCD shows squares/blocksDisplay initialised but no characters sentCheck SDA/SCL wiring; confirm I2C address with I2C scanner sketch
Distance always 0 or -1ECHO pin not receiving signalCheck TRIG and ECHO pins are not swapped; check voltage divider
Readings wildly inconsistentECHO is at 5V directly on ESP32 GPIOAdd voltage divider — ESP32 GPIO are not 5V tolerant
Readings too shortObject further than 4 m, or surface absorbing soundMove object closer; test with a flat hard wall
ESP32 resets randomlyInsufficient powerUse a powered USB hub or add a 10 µF capacitor on VIN/GND

Taking It Further

Once your distance meter is working, there are many directions to expand it:

  • Proximity alert — add a buzzer that beeps faster as objects get closer, like a car parking sensor
  • Water level monitor — mount the sensor facing down into a tank; calculate water level from
    textcode
    1tank_height - distance
  • People counter — place the sensor in a doorway and count when the reading drops below a threshold
  • Robot obstacle avoidance — mount on a motor car chassis and steer away when distance drops below 20 cm
  • Wi-Fi dashboard — use the ESP32's Wi-Fi to POST readings to a local Node-RED or web dashboard every second
  • Temperature-compensated distance — add a DS18B20 for accurate speed-of-sound correction

Wrapping Up

You have built a complete real-time distance meter using an HC-SR04 ultrasonic sensor, a 1602 LCD display, and an ESP32. Along the way you learned how ultrasonic ranging works, how to protect ESP32 GPIO pins from 5V signals, how to drive an I2C LCD, and how to keep display output clean and readable.

Browse our HC-SR04 sensors, LCD displays, and ESP32 boards in the store — all the components for this project ship together.

Happy building!