Project 2 - Measuring distance of an object using ultrasonic sensor (HC-SR04)
C Code for HC-SR04 with ATmega328p using Input Capture Mode
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL
#define TRIG_PIN PB1
#define SOUND_SPEED 34300 // cm/s
volatile uint16_t start_time, end_time;
volatile uint8_t capture_flag = 0;
void Timer1_ICU_Init() {
TCCR1A = 0; // Normal mode
TCCR1B = (1 << ICES1) | (1 << CS11); // Rising edge, prescaler = 8
TIMSK1 = (1 << ICIE1); // Enable input capture interrupt
sei(); // Enable global interrupts
}
void Trigger_Ultrasonic() {
PORTB |= (1 << TRIG_PIN);
_delay_us(10);
PORTB &= ~(1 << TRIG_PIN);
}
ISR(TIMER1_CAPT_vect) {
if (capture_flag == 0) {
start_time = ICR1; // Capture start time
TCCR1B &= ~(1 << ICES1); // Switch to falling edge detection
capture_flag = 1;
} else {
end_time = ICR1; // Capture end time
TCCR1B |= (1 << ICES1); // Switch back to rising edge detection
capture_flag = 2;
}
}
uint16_t Measure_Distance() {
capture_flag = 0;
Trigger_Ultrasonic();
while (capture_flag < 2); // Wait for both rising and falling edges
uint16_t pulse_width = end_time - start_time; // Timer ticks
uint16_t distance = (pulse_width * SOUND_SPEED) / (2 * F_CPU / 8); // Distance in cm
return distance;
}
int main() {
DDRB |= (1 << TRIG_PIN); // Set TRIG_PIN as output
DDRB &= ~(1 << PB0); // Set Echo pin (PB0) as input
Timer1_ICU_Init();
while (1) {
uint16_t distance = Measure_Distance();
_delay_ms(500);
}
}
---
Explanation:
1. Timer1 Input Capture Mode:
Captures pulse width using ICR1 register.
Measures rising and falling edges to calculate time duration.
2. Ultrasonic Sensor Working:
Trigger pin (PB1) sends a 10μs pulse.
Echo pin (PB0) receives the reflected pulse.
Distance = (Pulse Width × Sound Speed) / 2.
3. Interrupt Service Routine (ISR(TIMER1_CAPT_vect)):
Captures start and end times of the pulse.
Switches detection edge dynamically.
4. Distance Measurement (Measure_Distance):
Converts timer ticks to distance in cm.
---
Expected Output:
The calculated distance can
be displayed via UART or LCD.