Project 2 - Measuring distance of an object using ultrasonic sensor (HC-SR04)
/*
* Ultrasonic_32.c
*
* Created: 25-02-2024 15:58:49
* Author : Vishnu V Nair
*/
#include <avr/io.h>
#define F_CPU 8000000UL
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
#include <stdlib.h>
#define EN 6
#define RS 5
#define RW 4
int Timer_Overflow = 0;
//Function for LCD command
void lcd_cmd(unsigned char cmd)
{
PORTC = cmd;
PORTB &= ~(1<<RS) | (1<<RW);
PORTB &= ~(1<<EN);
_delay_ms(100);
PORTB |= (1<<EN);
}
//Function for LCD command
void lcd_data(unsigned char data)
{
PORTC = data;
PORTB |= (1<<RS);
PORTB &= ~(1<<EN);
_delay_ms(100);
PORTB |= (1<<EN);
}
//Function to display string in LCD
void lcd_display(char x,char y, unsigned char *s)
{
cursor_pos(x,y); //To set cursor position
for(int i = 0; s[i] != 0; i++)
{
lcd_data(s[i]); //Sending each char to display 1 by 1
}
}
//Function to set cursor position
void cursor_pos(char row, char coloumn)
{
//Checking the position are in valid LCD range(16*2)
if( (row < 1 || row > 2) || (coloumn < 1 || coloumn > 16) )
{
row = 1;
coloumn = 1;
}
//If cursor position in the first row
if(row == 1)
{
lcd_cmd(0x80 + coloumn); //In the beginning of first line with coloumn position
}
else //If not cursor position in the beginning of 2nd line
{
lcd_cmd(0xC0 + coloumn); //beginning of 2nd line with coloumn position
}
}
//To initialize LCD
void lcd_init()
{
lcd_cmd(0x38); //2 line & 5*7 matrix
lcd_cmd(0x02); //Return home
lcd_cmd(0x01); //Clear display screen
lcd_cmd(0x0c); //Display ON, cursor OFF
lcd_cmd(0x06); //Increment cursor to right
lcd_cmd(0x80); //Force cursor to the begenning of first line
}
//Function to print LCD data
void lcd_print(char row, char coloumn, unsigned int value, int digits)
{
unsigned int temp;
unsigned int ones;
unsigned int tens;
unsigned int hundred;
unsigned int thousand;
unsigned int million;
unsigned char flag=0;
//if the Row & coloumn is 0 set cursor position to(1,1)
if(row == 0 || coloumn == 0)
{
cursor_pos(1,1);
}
else //Else set to the desired position
{
cursor_pos(row,coloumn);
}
//If the value digit is in 5th position display million th place
if(digits == 5 || flag == 1)
{
million=value/10000+48; //Convert to ASII
lcd_data(million);
flag=1;
}
//If the value digit is in 4th position display thousand th place
if(digits == 4 || flag == 1)
{
temp = value/1000; //Extact 1000th value
thousand = temp%10 +48; //Convert to ASII
lcd_data(thousand);
flag=1;
}
//If the value digit is in 3rd position display hundred th place
if(digits == 3 || flag == 1)
{
temp = value/100; //Extact 100th value
hundred = temp%10 +48; //Convert to ASII
lcd_data(hundred);
flag=1;
}
//If the value digit is in 2nd position display ten th place
if(digits == 2 || flag == 1)
{
temp = value/10; //Extact 10th value
tens= temp%10 +48; //Convert to ASII
lcd_data(tens);
flag=1;
}
//If the value digit is in 1st position display one's place
if(digits == 1 || flag == 1)
{
ones = value%10 + 48; //Extact 1's value
lcd_data(ones);
}
//if value exceeds 5th value indicate over flow
if(digits>5)
{
lcd_data('e');
}
}
//Interrupt for timer over flow
ISR(TIMER1_OVF_vect)
{
Timer_Overflow++; //Incrementing overflow counter
}
int main(void)
{
char dis[10];
long count; //Variable to store timer count
double distance; //Variable to store distance
//Sensor part
DDRA |= (1<<PA0); //Trigger pin as o/p
DDRD |= 0x00; //Echo pin (turning on pull-up)
PORTD |= 0xff;
//LCD part
DDRC |= 0xff; //LCD data pin
DDRB |= (1<<RS) | (1<<EN); //RS & EN pin
DDRA = 0x01; /* Make trigger pin as output */
PORTD = 0xFF; /* Turn on Pull-up */
DDRB = 0xff; //Set the data direction register DDRB as output
DDRD |=(1<<0); //Set the Data direction Register port d pin 0as output
DDRD |=(1<<1); //Set the Data direction Register port d pin 1as output
lcd_init(); //Initialize LCD
lcd_display(1,0,"Distance:");
sei(); //Enable global interrupt
TIMSK = (1<< TOIE1); //Enable interrupt overflow
TCCR1A = 0; //Normal mode
while(1)
{
//Triggering sensor for 10us
PORTA |= (1<< PA0); //Triggering sensor
_delay_ms(10);
PORTA &= ~(1<< PA0); //Clearing trig pin
TCNT1 = 0; //Timer reset
TCCR1B = 0x41; //Input Capture and no prescaler(ICES1 & CS10)
TIFR = 1<<ICF1; //Clearing input capture flag
TIFR = 1<<TOV1; //Clearing timer overflow flag
//Calculating Echo
while ((TIFR & (1<<ICF1)) == 0); //Wait for the rising edge echo pulse
TCNT1 = 0; //Timer reset
TCCR1B = 0x01; //No prescaler
TIFR = 1<<ICF1; //Clearing input capture flag
TIFR = 1<<TOV1; //Clearing timer overflow flag
Timer_Overflow = 0; //Resetting overflow count
while ((TIFR & (1<< ICF1))== 0); //Waiting for falling edge of echo pulse
//Calculating distance
count = ICR1 +(65535 * Timer_Overflow);
distance = (double)count/466.47;
//Converting decimal to string
lcd_print(2,0,distance,4);
}
}