Challenge

Project 2 - Measuring distance of an object using ultrasonic sensor (HC-SR04)

Project #2

Aim

To write a C program to Measuring the distance of an object using Ultrasonic Distance Sensor (HC-SR04) by using of Input Capture Mode in the Microcontroller timer1.

Program :

#define F_CPU 16000000UL //use atmega328p so its freq is 16Mhz
#include <avr/io.h> // This header file includes the appropriate Input/output definitions for the device
#include <util/delay.h> // to use delay function we need to include this library
#include <stdlib.h> // we'll be using itoa() function to convert integer to character array

#define lcd_port PORTD // we have connected the LCD on port D
#define lcd_data_dir DDRD // we're defining the direction of the pins, weather it is input or output
#define rs PD0 // we need total six pin to show output on the LCD. Data pin 4, 5, 6, and 7 for sending the data to the lcd and Enable and RS pin for controlling the behavior of the LCD we have connected RS pin of LCD to port D pin 0
#define en PD1 // we have connected Enable pin of LCD to port D pin 1

#define US_PORT PORTC // we have connected the Ultrasonic sensor on port C. to use the ultrasonic we need two pins of the ultrasonic to be connected on port C
#define US_PIN PINC // we need to initialize the pin resistor when we want to take input.
#define US_DDR DDRC // we need data-direction-register (DDR) to set the direction of data flow. input or output. we will define it later, now we're just naming it.

#define US_TRIG_POS PC0 // the trigger pin of ultrasonic sound sensor is connected to port C pin 0
#define US_ECHO_POS PC1 // the echo pin of the ultrasonic sound sensor is connected to port C pin 1

#define US_ERROR -1 // we're defining two more variables two know if the ultrasonic sensor is working or not
#define US_NO_OBSTACLE -2

int distance, previous_distance;

void HCSR04Init();
void HCSR04Trigger();

void lcd_command( unsigned char );

void HCSR04Init()
{
US_DDR|=(1<<US_TRIG_POS); // we're setting the trigger pin as output as it will generate ultrasonic sound wave
}

void HCSR04Trigger()

// this function will generate ultrasonic sound wave for 15 microseconds Send a 10uS pulse on trigger line
{
US_PORT|=(1<<US_TRIG_POS); //high pulse

_delay_us(15); //wait 15uS

US_PORT&=~(1<<US_TRIG_POS); //low pulse
}

uint16_t GetPulseWidth()
{
// this function will be used to measure the pulse duration. When the ultra sound echo back after hitting an object
// the microcontroller will read the pulse using the echo pin of the ultrasonic sensor connected to it.

uint32_t i,result;

// Section - 1: the following lines of code before the section - 2 is checking if the ultrasonic is working or not
// it check the echo pin for a certain amount of time. If there is no signal it means the sensor is not working or not connect properly
for(i=0;i<600000;i++)
{
if(!(US_PIN & (1<<US_ECHO_POS)))
continue; //Line is still low, so wait
else
break; //High edge detected, so break.
}
if(i==600000)
return US_ERROR; //Indicates time out

// Section -2 : This section is all about preparing the timer for counting the time of the pulse. Timers in microcontrllers is used for timing operation
TCCR1A=0X00; // Setup Timer1
TCCR1B=(1<<CS11); // This line sets the resolution of the timer. Maximum of how much value it should count. input capture mode of timer1.
TCNT1=0x00; // This line start the counter to start counting time

// Section -3 : This section checks weather the there is any object or not
for(i=0;i<600000;i++)

// the 600000 value is used randomly to denote a very small amount of time, almost 40 miliseconds
{
if(US_PIN & (1<<US_ECHO_POS))
{
if(TCNT1 > 60000)

// if the TCNT1 value gets higher than 60000 it means there is not object in the range of the sensor
break;
else continue;
}
else
break;
}

if(i==600000)
return US_NO_OBSTACLE; //Indicates time out, Falling edge found
result=TCNT1;
// microcontroller stores the the value of the counted pulse time in the TCNT1 register. So, we're returning this value to the main function for utilizing it later
TCCR1B=0x00; //Stop Timer
if(result > 60000)
return US_NO_OBSTACLE; //No obstacle
else
return (result>>1);
}

void initialize (void)
{
lcd_data_dir = 0xFF; // this will set the LCD pins connected on the microcontroller as output
_delay_ms(15); // to show data on the LCD we need to send commands first then the data
lcd_command(0x02); // this command returns the cursor to the first row and first column position
lcd_command(0x28); // display 4 bit data in two line in 5x7 matrix
lcd_command(0x0c); //Making the cursor off and also display off
lcd_command(0x06); //auto Increment cursor
lcd_command(0x01); //Clearing the complete display including RAM DATA
_delay_ms(2);
}

void lcd_command( unsigned char cmnd )
{
// in order to send command to the lcd first we need to write the command on the data pins. then set the RS pin to zero and enable pin to high
// then wait for one microseconds and set the enable pin to low, this process repeats again. We're using 4 bit data communication but the data is 8-bit
// so we will send the data dividing it into two section. Higher 4 bit and lower 4 bit
// the following lines of codes are used to send higher 4 bits of data
lcd_port = (lcd_port & 0x0F) | (cmnd & 0xF0);

// this line writes the command on the data pins of the lcd connected to th microcontroller portD pin 4 to 7
lcd_port &= ~ (1<<rs); // LCD Command register select
lcd_port |= (1<<en);
_delay_us(1);
lcd_port &= ~ (1<<en);

_delay_us(200); // wait 200 microseconds

lcd_port = (lcd_port & 0x0F) | (cmnd << 4); // send the lower 4 bits of the data
lcd_port |= (1<<en);
_delay_us(1);
lcd_port &= ~ (1<<en);
_delay_ms(2);
}

void lcd_clear()
{
lcd_command (0x01); // this line clears the LCD screen
_delay_ms(2); // waits for two milliseconds
lcd_command (0x80); // this line sets the cursor to the row 1 column 1
}


void lcd_print (char *str)
{
// this function will be used to display the string on the LCD screen
int i;
for(i=0; str[i]!=0; i++)
{
// we can not send the whole string to the LCD we need to send character by character
// data sending is same as sending a command. there is one difference, in this case the RS pin will be set to HIGH while
// the RS pin was set to zero in case of the command sending
lcd_port = (lcd_port & 0x0F) | (str[i] & 0xF0);
lcd_port |= (1<<rs); //Data register select
lcd_port|= (1<<en);
_delay_us(1);
lcd_port &= ~ (1<<en);
_delay_us(200);
lcd_port = (lcd_port & 0x0F) | (str[i] << 4);
lcd_port |= (1<<en);
_delay_us(1);
lcd_port &= ~ (1<<en);
_delay_ms(2);
}
}

void lcd_setCursor(unsigned char x, unsigned char y)

// this function will be used to set cursor. the place where we want to display the data
{
unsigned char adr[] = {0x80, 0xC0};

// the 16x2 LCD has two rows first row has a value of 0x80. So let's say we want to go to the seconds column of first row
// we just need to send the command with adding 2 with the initial value. So, it will be (0x80 + 2) this is how the code works
lcd_command(adr[y-1] + x-1);
_delay_us(100);
}

int main()
{
initialize(); // we're initializing the LCD port and set the basic thinks
char numberString[4]; // we're defining an array of character. It will be utilized later to store integer to be displayed on the LCD screen
while(1)
{
uint16_t r;
_delay_ms(100); //Let the LCD Module start
HCSR04Init(); //Set io port direction of sensor
while(1)
{
//Send a trigger pulse
HCSR04Trigger(); // calling the ultrasonic sound wave generator function
//Measure the width of pulse
r=GetPulseWidth(); // getting the duration of the ultrasound took to echo back after hitting the object
//Handle Errors
if(r==US_ERROR) // if microcontroller doesn't get any pulse then it will set the US_ERROR variable to -1
// the following code will check if there is error then it will be displayed on the LCD screen
{
lcd_setCursor(1, 1); //lcd_setCursor(column, row)
lcd_print("Error!");
}
else
{
distance=(r*0.034/2.0); // This will give the distance in centimeters
if (distance != previous_distance) // the LCD screen only need to be cleared if the distance is changed otherwise it is not required
{
lcd_clear();
}
lcd_setCursor(1, 1); // set the row and column to display the data
lcd_print("Distance = "); // Show the String"Distance="
lcd_setCursor(12, 1); // lcd_setCursor(column, row)
itoa(distance, numberString, 10); // distance is an integer number, we can not display integer directly on the LCD. this line converts integer into array of character
lcd_print(numberString); // Show the Distance value
lcd_setCursor(14, 1); // set the row to 1 and and column to 14 to display the data
lcd_print(" cm"); // Show the String"cm"
previous_distance = distance;
_delay_ms(30);
}
}
}
}

Output: Display the Distance in ‘cm’

While change the Potentiometer for the reference input of SR04 the distance value shows on the 16x2 LCD display.

Output : Display the 'Error!' message

If the sensor is not working or the Trigger and Echo pins are not inserted correctly, it will shows the Error message on the LCD.

Your portfolio, next

Ship work like this
in your own course.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.