A lightweight, bare-metal (AVR-C) driver for the HC-SR04 ultrasonic distance sensor, designed for AVR microcontrollers (e.g., ATmega328P on the Arduino Uno).
The key feature of this driver is its non-blocking, interrupt-driven design. It uses the Timer1 Input Capture unit (ICP1) to measure the echo pulse duration in hardware. This allows the main CPU loop to run freely without being frozen by _delay_ loops or while() polling, making it ideal for RTOS projects or concurrent task management.
This driver is not pin-agnostic. To achieve non-blocking operation, it relies on the Timer1 Input Capture hardware, which is physically tied to a specific pin.
- HC-SR04 VCC → Arduino 5V
- HC-SR04 GND → Arduino GND
- HC-SR04 Trig → Arduino Pin 9 (PB1)
- HC-SR04 Echo → Arduino Pin 8 (PB0 / ICP1)
Warning: The Echo pin connection to Pin 8 (ICP1) is mandatory for the hardware interrupt to function. The Trig pin can be changed by modifying the TRIGGER_PIN macro in ultrasonic.c.
To build and run the example, you need the AVR toolchain (compiler and uploader) and a serial monitor.
-
Install the Toolchain:
sudo pacman -S avr-gcc avr-libc avrdude make
-
Install Serial Monitor:
sudo pacman -S picocom
-
Grant Serial Port Permissions: You must add your user to the group that owns the USB device. This is typically
uucpon Arch/Manjaro ordialouton Debian/Ubuntu.# Use 'uucp' for Manjaro/Arch sudo usermod -aG uucp $USER # Or 'dialout' for Debian/Ubuntu # sudo usermod -aG dialout $USER
You must log out and log back in for this change to take effect.
-
Install the Toolchain:
- Download and install the Microchip AVR 8-bit Toolchain (which contains
avr-gcc,avr-libc, etc.) from the Microchip website. - Add the toolchain's
bindirectory to your system'sPATHenvironment variable.
- Download and install the Microchip AVR 8-bit Toolchain (which contains
-
Install Make & Avrdude: The easiest way is via a package manager like Chocolatey.
# Install make choco install make # Install avrdude choco install avrdude
-
Find your COM Port:
- Plug in your Arduino.
- Open Device Manager.
- Look under Ports (COM & LPT).
- Note your Arduino's port (e.g.,
COM3,COM4).
The included example (examples/SimpleTest) sends the measured distance (in cm) over the serial (UART) connection.
# 1. Clone this repository
git clone https://github.com/MatGonPer/avr-ultrasonic-sensor.git
cd avr-ultrasonic-driver
# 2. Navigate to the example directory
cd examples/SimpleTest(Windows Only): Before building, you must edit the Makefile in this directory:
- Open
examples/SimpleTest/Makefile. - Change the
PORTvariable from/dev/ttyACM0to your COM port.- From:
PORT = /dev/ttyACM0 - To:
PORT = COM3(or your port number)
- From:
Now, build the firmware:
makeThis will compile main.c and link it with the driver source from ../../src/ultrasonic.c.
With your Arduino still connected, run:
make uploadThis will flash the compiled main.hex file to the ATmega328P.
The Arduino is now running and sending data at 9600 baud.
-
On Linux:
picocom -b 9600 /dev/ttyACM0 # To exit: Ctrl+A, then Ctrl+X -
On Windows: Use any serial monitor program (like PuTTY, Tera Term, or the Arduino IDE's Serial Monitor).
- Connect to your
COM3(or other) port. - Set the baud rate to 9600.
- Connect to your
You should see the following output in your terminal, with the distance updating in real-time:
Non-blocking HC-SR04 driver - Test
Distance: 55 cm
Distance: 56 cm
...
To use this driver in your own project, copy the src/ directory and include ultrasonic.h.
#include "ultrasonic.h"Initializes the driver. Configures all necessary hardware (pins, Timer1, Input Capture, and interrupts). Must be called once at startup.
Triggers a new measurement. This function is non-blocking and returns immediately. The measurement is then performed by the hardware in the background.
Polls the driver to check if a new measurement is complete.
- Returns:
1(true) if a new echo has been received. - Returns:
0(false) if the driver is still waiting.
Fetches the last measured distance. This function also resets the is_ready flag, indicating the data has been "consumed".
- Returns: The measured distance in centimeters.