/*
HC‑SR04 Ultrasound Distance Measurement with Arduino – Parking Alert (LCD & Buzzer)
Displays distance on I2C LCD. Buzzer beeps faster as object gets closer.
Non‑blocking design using millis().
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// ---------- LCD Configuration ----------
// Common I2C addresses: 0x27 or 0x3F. Change if your LCD does not work.
LiquidCrystal_I2C lcd(0x27, 16, 2);
// ---------- HC-SR04 Pins ----------
const int trigPin = 9;
const int echoPin = 8;
// ---------- Buzzer Pin ----------
const int buzzerPin = 11;
// ---------- Constants ----------
const float SOUND_SPEED_CM_US = 0.034; // speed of sound in cm/µs
const long MAX_DISTANCE_CM = 400; // maximum reliable distance (cm)
const int MIN_BEEP_DELAY_MS = 50; // fastest beep (very close – 50ms apart)
const int MAX_BEEP_DELAY_MS = 1000; // slowest beep (far – 1 second apart)
// ---------- Variables ----------
long duration; // echo pulse duration in microseconds
float distanceCm; // calculated distance in centimeters
int beepDelayMs; // current delay between beeps (milliseconds)
// Timing for non‑blocking updates
unsigned long lastBeepTime = 0; // last time we turned the buzzer on
unsigned long lastDisplayUpdate = 0; // last time we refreshed the LCD
const unsigned long displayInterval = 200; // refresh LCD every 200 ms
void setup() {
Serial.begin(9600);
// --- LCD Initialization ---
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Parking Alert");
lcd.setCursor(0, 1);
lcd.print("Initializing...");
delay(2000);
lcd.clear();
// --- Sensor pin modes ---
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
// --- Buzzer pin ---
pinMode(buzzerPin, OUTPUT);
digitalWrite(buzzerPin, LOW);
Serial.println("HC‑SR04 Parking Alert Ready");
}
void loop() {
// --- Step 1: Measure Distance (runs every loop) ---
// Send a 10 µs HIGH pulse to trigger the sensor
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Measure the echo pulse duration (µs). Timeout after 30ms (≈5 meters).
duration = pulseIn(echoPin, HIGH, 30000);
if (duration == 0) {
// No echo received – object is out of range
distanceCm = MAX_DISTANCE_CM;
} else {
// Convert duration to centimeters: (time × speed) / 2
distanceCm = duration * SOUND_SPEED_CM_US / 2.0;
}
// Clamp distance to a sensible range
if (distanceCm > MAX_DISTANCE_CM) distanceCm = MAX_DISTANCE_CM;
if (distanceCm < 0) distanceCm = 0;
// --- Step 2: Map distance to buzzer beep delay ---
// Closer distance → smaller delay → faster beeps
beepDelayMs = map(distanceCm, 0, MAX_DISTANCE_CM, MIN_BEEP_DELAY_MS, MAX_BEEP_DELAY_MS);
beepDelayMs = constrain(beepDelayMs, MIN_BEEP_DELAY_MS, MAX_BEEP_DELAY_MS);
// --- Step 3: Update LCD (every 200 ms) ---
if (millis() - lastDisplayUpdate >= displayInterval) {
lastDisplayUpdate = millis();
// First line: distance
lcd.setCursor(0, 0);
lcd.print("Distance: "); // clear old text
lcd.setCursor(0, 0);
lcd.print("Distance:");
lcd.setCursor(9, 0);
lcd.print(distanceCm, 1);
lcd.print(" cm ");
// Second line: warning or safe message
lcd.setCursor(0, 1);
if (distanceCm < 20) {
lcd.print(">> TOO CLOSE! <<");
} else {
lcd.print(" "); // clear line
lcd.setCursor(0, 1);
lcd.print("Safe distance ");
}
}
// --- Step 4: Buzzer control (non‑blocking) ---
if (distanceCm < MAX_DISTANCE_CM) {
// Only beep if an object is detected within range
if (millis() - lastBeepTime >= beepDelayMs) {
lastBeepTime = millis();
digitalWrite(buzzerPin, HIGH);
delay(50); // short beep (50 ms)
digitalWrite(buzzerPin, LOW);
}
} else {
// No object – ensure buzzer is off
digitalWrite(buzzerPin, LOW);
}
// A tiny delay to prevent the loop from running too aggressively (optional)
delay(10);
}