Ultrasonic Module HC-SR04 interfacing with AVR ATmega16/ATmega32

The ultrasonic module HC-SR04 is generally used for finding the distance to an object and obstacle detection. It can operate in the range of 2-400cm.

83.2k views4 min readUpdated Aug 9, 2023
Ultrasonic Module HC-SR04 interfacing with AVR ATmega16/ATmega32

Overview of Ultrasonic Sensor

HCSR04
Ultrasonic HC-SR04 Module

 

  • Ultrasonic Module HC-SR04 works on the principle of SONAR and RADAR system.
  • HC-SR-04 module has an ultrasonic transmitter, receiver, and control circuit on a single board.
  • The module has only 4 pins, Vcc, Gnd, Trig, and Echo.
  • When a pulse of 10µsec or more is given to the Trig pin, 8 pulses of 40 kHz are generated. After this, the Echo pin is made high by the control circuit in the module.
  • The echo pin remains high till it gets an echo signal of the transmitted pulses back.
  • The time for which the echo pin remains high, i.e. the width of the Echo pin gives the time taken for generated ultrasonic sound to travel towards the object and return.
  • Using this time and the speed of sound in air, we can find the distance of the object using a simple formula for distance using speed and time.

For more information about ultrasonic module HC-SR04 and how to use it, refer to the topic Ultrasonic Module HC-SR04 in the sensors and modules section.

 

Connection Diagram of Ultrasonic Sensor HC-SR04 with ATmega16/32

Ultrasonic HCSR04 interface with ATmega
Interfacing HC-SR04 Ultrasonic Module With ATmega 16

 

 

 

Measure Distance and Print on LCD16x2 using Ultrasonic Sensor and Atmega16 Microcontroller

Let’s design an application in which we will find the distance to an object by interfacing ultrasonic module HC-SR04 with AVR ATmega16 and display the distance on 16x2 LCD.

Steps of Programming

  1. ATmega16 microcontroller needs to transmit at least 10 us trigger pulse to the HC-SR04 Trig Pin.
  2. After getting a trigger pulse, HC-SR04 automatically sends eight 40 kHz sound waves and the microcontroller waits for rising edge output at the Echo pin.
  3. When the rising edge capture occurs at the Echo pin which is connected to an input of ATmega16, start Timer of ATmega16 and again wait for a falling edge on the Echo pin.
  4. As soon as the falling edge is captured at the Echo pin, the microcontroller reads the count of the Timer. This time count is used to calculate the distance to an object.

Here we are using the input capture mode of ATmega16 on PD6(ICP1) pin as shown in the above interfacing diagram.

Calculation (distance in cm) (H1)

Sound velocity =   343.00 m/s = 34300 cm/s

 

The distance of Object (in cm) = \mathbf{\frac{Sound Velocity * TIMER}{2}}             

                                               = \mathbf{\frac{34300 * TIMER}{2}}

                                               = \textbf{17150 * TIMER} 

Now, here we have selected an internal 8 MHz oscillator frequency for ATmega16, with No-presale for timer frequency. Then time to execute 1 instruction is 0.125 us.

So, the timer gets incremented after 0.125 us time elapse.

                 = 17150 x (TIMER value) x 0.125 x 10^-6 cm

                 = 0.125 x (TIMER value)/58.30 cm

                 = (TIMER value) / 466.47 cm

 

Ultrasonic Sensor HC-SR04 Code for ATmega16/32

/*
 * Ultrasonic sensor HC-05 interfacing with AVR ATmega16
 * http://www.electronicwings.com
 */ 

#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <string.h>
#include <stdlib.h>
#include "LCD_16x2_H_file.h"	/* Include LCD header file */

#define  Trigger_pin	PA0	/* Trigger pin */

int TimerOverflow = 0;

ISR(TIMER1_OVF_vect)
{
	TimerOverflow++;	/* Increment Timer Overflow count */
}

int main(void)
{
	char string[10];
	long count;
	double distance;
	
	DDRA = 0x01;		/* Make trigger pin as output */
	PORTD = 0xFF;		/* Turn on Pull-up */
	
	LCD_Init();
	LCD_String_xy(1, 0, "Ultrasonic");
	
	sei();			/* Enable global interrupt */
	TIMSK = (1 << TOIE1);	/* Enable Timer1 overflow interrupts */
	TCCR1A = 0;		/* Set all bit to zero Normal operation */

	while(1)
	{
		/* Give 10us trigger pulse on trig. pin to HC-SR04 */
		PORTA |= (1 << Trigger_pin);
		_delay_us(10);
		PORTA &= (~(1 << Trigger_pin));
		
		TCNT1 = 0;	/* Clear Timer counter */
		TCCR1B = 0x41;	/* Capture on rising edge, No prescaler*/
		TIFR = 1<<ICF1;	/* Clear ICP flag (Input Capture flag) */
		TIFR = 1<<TOV1;	/* Clear Timer Overflow flag */

		/*Calculate width of Echo by Input Capture (ICP) */
		
		while ((TIFR & (1 << ICF1)) == 0);/* Wait for rising edge */
		TCNT1 = 0;	/* Clear Timer counter */
		TCCR1B = 0x01;	/* Capture on falling edge, No prescaler */
		TIFR = 1<<ICF1;	/* Clear ICP flag (Input Capture flag) */
		TIFR = 1<<TOV1;	/* Clear Timer Overflow flag */
		TimerOverflow = 0;/* Clear Timer overflow count */

		while ((TIFR & (1 << ICF1)) == 0);/* Wait for falling edge */
		count = ICR1 + (65535 * TimerOverflow);	/* Take count */
		/* 8MHz Timer freq, sound speed =343 m/s */
		distance = (double)count / 466.47;

		dtostrf(distance, 2, 2, string);/* distance to string */
		strcat(string, " cm   ");	/* Concat unit i.e.cm */
		LCD_String_xy(2, 0, "Dist = ");
		LCD_String_xy(2, 7, string);	/* Print distance */
		_delay_ms(200);
	}
}

 

Video of Distance Measurement using Ultrasonic Sensor and Atmega16 Microcontroller

Components Used

Powered byMouser Electronics

Downloads

Comments51

Join the discussion — share a question or tip.

  • SA
    SaberBorjoeifar

    I tested this program. It is accurate below 1 meter, but it does not show above 1 meter at all. (The number displayed on the LCD does not go beyond 100 centimeters). Why?

  • DK
    dk8156852

    Hello Sir, I downloaded the project file you provided, but it's not functioning correctly on my end. The display only shows "Ultrasonic Dist" with "Ultrasonic" in the first row and "Dist" in the second row. According to the project requirements, it should show the full word "Distance" followed by the measured distance from the ultrasonic sensor. I also have a question regarding the compatibility of the ultrasonic sensor with an ATmega32 using an external 16 MHz crystal clock frequency. I'm working in Microchip Studio 7 and Proteus 8 Professional. I’ve set up the hardware as well, but the results remain the same. Could you please assist with resolving this issue? Thank you.

  • MU

    where did you come up with number 466.47 in distance calculation, I calculate according to your formula but I didn't get the value you get

  • AA
    AayushiSharma

    There are some issue coming while running the code

  • AB
    AboooMohamadi

    Thanks for the project. How can I see the return and received frequency value?

  • AK
    AkashDutta

    I am using ATMEGA8 and connect Trig to PC0(23no pin) and Echo to PB0/IPC1(14 no pin) . Its not showing distance , but when I touch the Trig pin then show wrong distance with alphabet 'E'. please help me...

  • AL
    ALIUZAIRMEHDI· edited

    Data on the slave side is not appearing on LCD? any solution?

  • LI
    LijinChacko

    Severity Code Description Project File Line Error LCD_16x2_H_file.h: No such file or directory EP_Ultrasonic_Sensor c:\users\lijin\Documents\Atmel Studio\7.0\EP_Ultrasonic_Sensor\EP_Ultrasonic_Sensor\main.c 20 from where get header file

  • AH
    AhmedIsa

    Thank you.. is the Program code shown above all what I need to program the microcontroller ?

  • YA
    YASASMANUJAYA

    can we use these timer again for another device

  • YA
    YASASMANUJAYA

    can we use these timer again for another device

  • AS
    AseelMedia

    hello sir a question i do not have include "LCD_16x2_H_file.h" what should i do ?

    • NI
      NishantJ· edited

      Download and add.

  • SN
    SnNguynHng

    Thank you for your tutorial. It helps me so much. I wonder what if I use PD4 pin or other pins instead of PD6. Does the circuit work correctly?

    • NI
      NishantJ

      There is only one input capture pin.

  • MA
    MaulanaWahyudi

    Thank you very much, but please help me what is Timer Overflow = 0 for ? and why we must use (65535 * Timer Overflow) ?

    • NI
      NishantJ

      There is an limit to count from 0 to 65535 after that we use overflow to count by multiplying.

  • MI
    mitchmarciniak

    Hi nice project, tell me pls.. what is 466.47 and how did you calculate it?

  • JU
    juanjoze0424

    What if I want to use 2 HC-SR04? (A front sensor and a rear sensor). In my case I'm using the ATmega16 which only has one Input Capture Pin. I'm connecting both echoes to that pin and just triggering one sensor at a time, never both simultaneously, and somehow the echo pulse of both sensors can't be detected.

  • KW
    kwanddr

    Mantap lur

  • RA
    rauldachikara123

    HC-SR04 is same with HC-SR05?

  • RA
    rauldachikara123

    i got warning massage /************************************************ CodeVisionAVR C Compiler V3.0 (C) 1998-2012 Pavel Haiduc, HP InfoTech S.R.L. AVR Interrupt support and Atmel Studio 6 compatibility macros/functions. ************************************************/ #ifndef _INTERRUPT_INCLUDED_ #define _INTERRUPT_INCLUDED_ #include &lt;io.h&gt; #define sei() #asm("sei") #define cli() #asm("cli") #define __enable_interrupt() #asm("sei") #define __disable_interrupt() #asm("cli") #define cpu_irq_enable() #asm("sei") #define cpu_irq_disable() #asm("cli") #define ISR(vector) interrupt [vector] void __isr##vector (void) typedef unsigned char irqflags_t; static inline unsigned char cpu_irq_save(void) { irqflags_t flags = SREG; __disable_interrupt(); return flags; } #define cpu_irq_restore(flags) {SREG = flags;} #ifdef _ATXMEGA_DEVICE_ #define irq_initialize_vectors() {PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm;} #define cpu_irq_is_enabled_flags(flags) (flags &amp; CPU_I_bm); #else #define cpu_irq_is_enabled_flags(flags) (flags &amp; (1&lt;&lt;SREG_I)); #endif #define cpu_irq_is_enabled() cpu_irq_is_enabled_flags(SREG) #endif and the warning in __disable_interrupt(); can u solve that?

  • SA
    sanjaytr7090

    Error is coming for LCD library function

    • LO
      lokeshc

      what error you are getting? May be you have not included Libray.

  • JW
    jwool003

    Hi, I'm trying to incorporate an ultrasonic sensor into a project that is using ATmega 1284s. I made changes such as TIFR to TIFR0 which allowed this code to compile correctly, but I can't get the sensor to work. I'm not trying to measure variable distances. I just want to set a flag if an object is at or within 20cm of the sensor. For whatever reason though, the distance variable is not being updated. I'd appreciate any help you can give me

  • BI
    bilguunb091

    hii i am using the Atmega32. what should i change? it is very important for me. plz help me with short time thank you

    • LO
      lokeshc

      No need to do any change in program. But while creating project select atmega32.

    • BI
      bilguunb091

      Replying to @lokeshc

      thank u. in interface, im using the buzzer. if obstacle is in 60cm, buzzer should start ring. for this, what should i change, thank you for ur great help

  • SA
    Samkelisiwe

    Hello Sir Firstly, thank you very much for this project. how can I use two ultrasonic sensors to measure the distance between then at the same time and compare then. Thanks in advance

    • LO
      lokeshc

      In such case, you have to use Timer and external interrupt. So connect your echo pin of two ultrasonic module to two external interrupts and when pulse detected, start the timer/counter for counting the time. Use two different timers for this application.

  • KE
    kelwazoldick

    Hi sir, you are wonderful person i respect you and your work. I have two question the first the "TimerOverflow" should be volatile, second at this part of your program TCNT1 = 0; /* Clear Timer counter */ TCCR1B = 0x01; /* Capture on falling edge, No prescaler */ TIFR = 1&lt;&lt;ICF1; /* Clear ICP flag (Input Capture flag) */ TIFR = 1&lt;&lt;TOV1; /* Clear Timer Overflow flag */ TimerOverflow = 0;/* Clear Timer overflow count */ why you make TimerOverflow = 0, i don't get it if it was 2 and then you make it 0 when you use this equation "count = ICR1 + (65535 * TimerOverflow);" The TimerOverflow will be zero.

  • SU
    suwasbohora

    the correct distance is only 70 cm why? according to its datasheet up to 400 cm we can measure but unable to get the correct measure. I have used external crystal 16Mhz with atmega32, it counts the distance up to 70 cm correctly and if the distance &gt;70 again it show 2/3 cm . I mean it is working in the range of 70 cm for me. how to solve it

    • LO
      lokeshc

      Actually, 400 cm is theoretically but it will provide accurate data in the range of 4cm to 230 cm approx (in my case). Maybe you can try it by lowering the frequency to 8 MHz or below that.

    • SH
      sheorajsachin

      Hi, I also got the same problem. After spending nearly 4 hrs, I found that there is a bug in the code. It is not related to clock frequency. Problem is as soon as Timer overflows (in case of 16MHz freq. timer overflow occur at 70cm distance) TimerOverflow variable is not updating. Due to this error is there in distance measurement over 70cm. You can overcome or remove this bug by declaring TimerOverflow as "volatile" or "volatile int TimerOverflow = 0;" . This will solve this issue.

  • AJ
    ajpatil

    Hello, The distance is not displayed correctly, what should i do? The distance keeps changing even though I haven't moved sensor.

    • LO
      lokeshc

      Have you use above program? Please check for any loose connection. You can increase some delay to test it.

    • AJ
      ajpatil

      Replying to @lokeshc

      Yeah I have used above program. Which crystal should I use for microcontroller hardware?

    • LO
      lokeshc· edited

      Replying to @ajpatil

      Which crystal should I use for microcontroller hardware? I didnt get it. please elaborate.

    • AJ
      ajpatil

      Replying to @lokeshc

      8 Mhz or 12 Mhz?

    • AJ
      ajpatil

      Replying to @lokeshc

      When I connected 8 MHz crystal the range from 0 to 4 cm is shown incorrectly. 4 cm onward the range is shown properly.

    • LO
      lokeshc

      Replying to @ajpatil

      There is some sensitivity range for these sensors. This sensor has 2 cm to 400cm theoretically. But, practically some tolerance is there.

    • LO
      lokeshc

      Replying to @ajpatil

      In above program internal oscillator is used. You can connect external oscillator 12 MHz.

    • AJ
      ajpatil

      Replying to @lokeshc

      okay. thanks

  • AM
    amirf

    thx dear

  • AM
    amirf

    thx dear

  • AM
    amirf

    thx dear

  • AM
    amirf

    thx dear

  • EM
    emrekekil· edited

    Hello. Firstly, thank you very much for this project. And i have a question about a part of the code. " count = ICR1 + (65535 * TimerOverflow);" here, you used the '65535' value. I couldn't understand where it cames from. Could you explain this? Kind regards,

    • TH
      themuslim16

      it Count in 2 Register 16 Bit So 2^16 = 65535

    • LO
      lokeshc

      Replying to @themuslim16

      Yes correct. If timer overflows, we have to maintain the timer count to calculate distance. Otherwise timer will reset and start count again which is not accurate count to measure distance.