Project 2 - Measuring distance of an object using ultrasonic sensor (HC-SR04)
In this project, the implementation of code for “Measuring distance of an object using ultrasonic distance sensor (HC-SR04)
Goals:
- Measuring the distance of an object using Ultrasonic Distance Sensor (HC-SR04)
- Usage of Input Capture Mode
Key Highlights of the Project:
- Measuring the distance travelled by the wave to the object and gets bounced back from the object to sensor.
- Measuring Pulse width using Input Capture Mode
Deliverables of this project:
- The distance travelled by a wave to the object for which we want to measure the distance using Ultrasonic Distance Sensor (HC-SR04).
- Measuring Pulse width using Input Capture Mode of Timer 1
Expected Outcomes:
The students will get the Knowledge on Ultrasonic sensor (HC-SR04) to measure the distance travelled by wave to the object, the hardware connection of Atmega328p and HC-SR04 and how to use input capture mode of Timer1
Solution:
#include <avr/io.h> //Include AVR I/O library
#define F_CPU 16000000UL // Define the CPU frequency for delay functions
#include <util/delay.h> //Include delay library for _delay_ms
#include <avr/interrupt.h> //Include interrupt library for interrupt handling
#include <string.h> //Include string manipulation functions
#include <stdlib.h> //Include standard library functions
#define en_high PORTC |= (1 << 2) //Set the Enable (EN) pin of the LCD to high
#define en_low PORTC &= ~(1 << 2) //Set the Enable (EN) pin of the LCD to low
#define rw_high PORTC |= (1 << 3) //Set the Read/Write (RW) pin of the LCD to high
#define rw_low PORTC &= ~(1 << 3) //Set the Read/Write (RW) pin of the LCD to low
#define rs_high PORTC |= (1 << 4) //Set the Register Select (RS) pin of the LCD to high
#define rs_low PORTC &= ~(1 << 4) //Set the Register Select (RS) pin of the LCD to low
#define lcdport PORTD //Define the data port for the LCD as PORTD
#define trigger_pin 0 //Define the trigger pin for the ultrasonic sensor as pin 0
#define echo_pin 1 //Define the echo pin for the ultrasonic sensor as pin 1
int TimerOverFlow = 0; //Initialize a variable to keep track of timer overflows
void lcd_cmd(unsigned char cmd)
{
lcdport = cmd; //Function to send a command to the LCD
rs_low; //Set Register Select (RS) to command mode
rw_low; //Set Read/Write (RW) to write mode
en_high; //Enable the LCD
_delay_ms(1); //Delay for a short time
en_low; //Disable the LCD
}
void lcd_data(unsigned char data)
{
lcdport = data; //Function to send data to the LCD
rs_high; //Set RS to data mode
rw_low; //Set RW to write mode
en_high; //Enable the LCD
_delay_ms(1); //Delay for a short time
en_low; //Disable the LCD
}
void lcd_init()
{
// Function to initialize the LCD
lcd_cmd(0x38); //Initialize the LCD: 2 lines, 5x7 matrix.
_delay_ms(5);
lcd_cmd(0x02); //Return to the home position.
_delay_ms(5);
lcd_cmd(0x01); //Clear the screen.
_delay_ms(5);
lcd_cmd(0x0c); //Display on, cursor off.
_delay_ms(5);
lcd_cmd(0x06); //Increment cursor.
_delay_ms(5);
lcd_cmd(0x80); //Set the cursor to start from the 1st line.
_delay_ms(5);
}
void cursorpos(char x, char y)
{
if ((x < 1 || x > 2) || (y < 1 || y > 16)) {
x = 1;
y = 1;
}
if (x == 1) {
lcd_cmd(0x80 + y); //Set the cursor to start from the 1st row
} else {
lcd_cmd(0xc0 + y); //Set the cursor to start from the 2nd row
}
}
void lcd_out(char a, char b, char *str)
{
cursorpos(a, b); //Set the cursor position.
while (*str) {
lcd_data(*str); //Send characters one by one to the LCD.
str++;
}
}
void lcd_print(char row, char column, unsigned int value, int digits)
{
unsigned int temp;
unsigned int unit;
unsigned int tens;
unsigned int hundred;
unsigned int thousand;
unsigned int million;
unsigned char flag = 0;
if (row == 0 || column == 0)
{
cursorpos(1, 1);
}
else
{
cursorpos(row, column);
}
if (digits == 5 || flag == 1)
{
million = value / 10000 + 48;
lcd_data(million);
flag = 1;
}
if (digits == 4 || flag == 1)
{
temp = value / 1000;
thousand = temp % 10 + 48;
lcd_data(thousand);
flag = 1;
}
if (digits == 3 || flag == 1)
{
temp = value / 100;
hundred = temp % 10 + 48;
lcd_data(hundred);
flag = 1;
}
if (digits == 2 || flag == 1)
{
temp = value / 10;
tens = temp % 10 + 48;
lcd_data(tens);
flag = 1;
}
if (digits == 1 || flag == 1)
{
unit = value % 10 + 48;
lcd_data(unit);
}
if (digits > 5)
{
lcd_data('e');
}
}
ISR(TIMER1_OVF_vect)
{
TimerOverFlow++; //This interrupt service routine (ISR) increments the TimerOverFlow variable when a Timer1 overflow interrupt occurs
}
//Main function
int main(void)
{
//Declare variables
char string[10];
long count;
double distance;
DDRD = 0xff; //Set all pins on Port D as outputs.
DDRC |= (1 << 2); //Set Pin 2 on Port C as an output.
DDRC |= (1 << 3); //Set Pin 3 on Port C as an output.
DDRC |= (1 << 4); //Set Pin 4 on Port C as an output.
DDRA |= (1 << trigger_pin); //Set Pin 0 on Port A as an trigger pin
DDRA |= (1 << echo_pin); //Set Pin 1 on Port A as an echo pin
lcd_init(); //Initialize the LCD.
sei(); //Enable global interrupts.
TIMSK = (1 << TOIE1); //Enable Timer1 overflow interrupt.
TCCR1A = 0; //Configure Timer1 Control Register A.
while (1)
{
PORTA |= (1 << trigger_pin); //Set echo pin Pin to HIGH.
_delay_ms(10); //Delay for 10 milliseconds
PORTA &= ~(1 << trigger_pin); //set trigger pin to LOW
_delay_ms(10); //Delay for 10 milliseconds
PORTA |= (1 << echo_pin); //Set echo pin to HIGH
_delay_ms(10); //Delay for 10 milliseconds
PORTA &= ~(1 << echo_pin); //set echo pin to LOW
_delay_ms(10); //Delay for 10 milliseconds.
while ((TIFR & (1 << ICF1)) == 0); //Wait for Input Capture Flag to be set
TCNT1 = 0; //Reset the Timer1 counter
TCCR1B = 0x41; //Configure Timer1 Control Register B
TIFR = 1 << ICF1; //Clear the Input Capture Flag
TIFR = 1 << TOV1; //Clear the Timer1 overflow flag
TimerOverFlow = 0; //Reset the TimerOverFlow variable
while ((TIFR & (1 << ICF1)) == 0); //Wait for Input Capture Flag to be set again.
count = ICR1 + (65535UL * TimerOverFlow); //Calculate the count based on Input Capture and Timer overflow
distance = (double)count / 466.47; // Calculate the distance based on the count
lcd_out(1, 1, "ultrasonic"); // Display "ultrasonic" on the LCD
lcd_print(2, 6, distance ,4); // Display the distance on the LCD with 4 decimal places
lcd_out(2, 1, "dist= "); // Display "dist= " on the LCD
lcd_out(2, 12, "cm"); // Display "cm" on the LCD
_delay_ms(1000); // Delay for 1000 milliseconds
}
}