Interfacing Ultrasonic Rangefinder with AVR

In this tutorial, we are going to interface ultrasonic rangefinder with the all popular ATMEGA8. Ultrasonic rangefinder is used to find range of an obstacle or a wall from the sensor. However, when there are cheap methods available to find range like the IR sensor or even a combination of LED’s and LDR would do but the question is why we use a more costly sensor. The reason is:-

  • IR sensors are not accurate
  • Result varies from object to object
  • Calibration is required
  • Works good only for shot range

Normally the IR sensors have a range from 30-80 cm or even less depending upon the manufacturer and also the LED’s used. However for an ultrasonic rangefinder, the distance can be measured accurately up to 400cm with an accuracy of 1cm.

HC-SR04 sensor

Ultrasonic rangefinders find application to measure level of a liquid, object sensing. Also, the great thing with this sensor is they required no calibration; no conversion from analog to digital data and the code are is not limited to any particular manufacturer sensor. The code will work pretty much with almost all sensors available in the market.

Another advantage of using ultrasonic sensor is that ultrasonic waves are narrower than infrared or any other sound beam. This is useful to detect objects that are exactly in line with the sensor.

In this tutorial, we will find the distance of any object. You should know how to use AVR timers. However as mentioned above you can use any other sensor but before buying just make sure that these sensors are microcontroller compatible.

The sensors I am using is a 4 pin sensor, one for Vcc, one for ground and the other two pins are echo and trigger However there are sensors, that have three pins, mainly Vcc, ground, and the third pin to connect to microcontroller. The working principle is pretty much the same, but it will have one input lines instead of two and also since the number of input line has changed, the coding will also changed, but the main logic will remain the same. If you want to interface these types of sensors, you may comment below and I will give you the required changes or the algorithm.

The senor will usually have all the pins marked on the board itself. For the sake of the tutorial, I will be using a HC-SR04 sensor. The operation to be followed is:-

  • Send a short, but long enough 10us pulse on the trigger pin
  • Wait for the echo line to go high
  • Time the length of the line it stays high

According to the datasheet you should send trigger pulse after an interval of 50us or more. Also I am using the AVR at 12MHz external crystal. If you are using some other crystal, just make sure that you load the timers value correctly.

CODE:-

#define F_CPU 12000000
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>  /* for sei() */
#include <util/delay.h>     /* for _delay_ms() */
#define INSTR_PER_US 12                   // instructions per microsecond (depends on MCU clock, 12MHz current)
#define INSTR_PER_MS 12000                // instructions per millisecond (depends on MCU clock, 12MHz current)
#define MAX_RESP_TIME_MS 200      // timeout - max time to wait for low voltage drop (higher value increases measuring distance at the price of slower sampling)
#define DELAY_BETWEEN_TESTS_MS 50 // echo cancelling time between sampling
volatile long result = 0;
volatile unsigned char up = 0;
volatile unsigned char running = 0;
volatile uint32_t timerCounter = 0;
// timer overflow interrupt, each time when timer value passes 255 value
SIGNAL(TIMER0_OVF_vect)
{
        if (up) {       // voltage rise was detected previously
                timerCounter++; // count the number of overflows
                // dont wait too long for the sonar end response, stop if time for measuring the distance exceeded limits
                uint32_t ticks = timerCounter * 256 + TCNT0;
                uint32_t max_ticks = (uint32_t)MAX_RESP_TIME_MS * INSTR_PER_MS; // this could be replaced with a value instead of multiplying
                if (ticks > max_ticks) {
                        // timeout
                        up = 0;          // stop counting timer values
                        running = 0; // ultrasound scan done
                        result = -1; // show that measurement failed with a timeout (could return max distance here if needed)
                }
        }
}
// interrupt for INT1 pin, to detect high/low voltage changes
/** 
        We assume, that high voltage rise comes before low drop and not vice versa - 
        however this should be implemented more correctly using both interrupts INT0/INT1,
        (i.e. INT0 configured for high rise, and INT1 - for low rise, thus the code must be separated also)     
*/
SIGNAL(INT1_vect) 
{
        if (running) { //accept interrupts only when sonar was started
                if (up == 0) { // voltage rise, start time measurement
                        up = 1;
                        timerCounter = 0;
                        TCNT0 = 0; // reset timer counter
                } else {
                        // voltage drop, stop time measurement
                        up = 0;
                        // convert from time to distance(millimeters): d = [ time_s * 340m/s ] / 2 = time_us/58
                        result = (timerCounter * 256 + TCNT0) / 58; 
                        running = 0;
                }
        }
}
/**
        Sonar interfacing:
                1. Send high impulse to Trig input for minimum 10us
                2. Sonar automatically sends eight 40kHz inpulses
                3. Sonar rises high on Echo output and then after some time drops 
                   output to low (can take a while on long distances! - must include timeouts)
                4. Based on output time difference deltaT = lowT-highT calculate: 
                        distance = [ deltaT * sound_speed(340m/s) ] / 2
                5. Make a delay before starting the next cycle to compensate for late echoes
*/
// generate an impulse for the Trig input (starts the sonar)
void sonar() {
        PORTB = 0x00; // clear to zero for 1 us
        _delay_us(1);
        PORTB = 0x01; // set high for 10us
        running = 1;  // sonar launched
        _delay_us(10);
        PORTB = 0x00; // clear  
}
int __attribute__((noreturn)) main(void)
{
        // ------------------- ultrasonic init code --------------------
        DDRB = 1; // PB0 output - connected to Trig
        PORTB = 0; // clear
        // turn on interrupts for INT1, connect Echo to INT1
        MCUCR |= (0 << ISC11) | (1 << ISC10); // enable interrupt on any(rising/droping) edge
        GICR |= (1 << INT1);      // Turns on INT1
        // setup 8 bit timer & enable interrupts, timer increments to 255 and interrupts on overflow
        TCCR0 = (0<<CS02)|(0<<CS01)|(1<<CS00); // select internal clock with no prescaling
        TCNT0 = 0; // reset counter to zero
        TIMSK = 1<<TOIE0; // enable timer interrupt
        sei(); // enable all(global) interrupts
    for(;;){  /* main program loop */
                // other code here...
                if (running == 0) { // launch only when next iteration can happen
                        // create a delay between tests, to compensate for old echoes
_delay_ms(DELAY_BETWEEN_TESTS_MS); 
                        sonar(); // launch measurement!
                }
                // other code here...
    }
}

Circuit diagram:

Circuit_diagram

 

Download AVRStudio project files here: UltrasonicProjectFiles

Read

Bookmark the permalink.

19 Comments

  1. I want the same code with atmega 16 instead of atmega 8. I also want to add serial communication code in it to send the distance to the controller serially.

  2. You can use the same code fr Atmea 16., since they have identical sets of register. For serial.communication, if you want to do by register programming, have a look at the tutorial section at embedds.com . if you want to use library, search.google.for avruart library by peter fleurym It the simplest lbrary i have seen for uart of avr

  3. Hi..Can u please help with this circuit with Atmega32 ??..Or kindly gimme suggestions.

  4. SIGNAL(TIMER0_OVF_vect)
    {
    if (up) { // voltage rise was detected previously
    timerCounter++; // count the number of overflows
    // dont wait too long for the sonar end response, stop if time for measuring the distance exceeded limits
    uint32_t ticks = timerCounter * 256 + TCNT0;
    uint32_t max_ticks = (uint32_t)MAX_RESP_TIME_MS * INSTR_PER_MS; // this could be replaced with a value instead of multiplying
    if (ticks > max_ticks) {
    // timeout
    up = 0; // stop counting timer values
    running = 0; // ultrasound scan done
    result = -1; // show that measurement failed with a timeout (could return max distance here if needed)
    }
    }
    }

    in the above if condition u given only variable “up” in the condition.. Is it works fine?

  5. We want the program for atmega32 plz…for this project

  6. I am using 3 hc- sr04 in my project with atmega328 what would be the possible changes in the above code

  7. Hi,
    Thank you for the tutorial.
    I working on a project for helping blind people, and I am using three ultrasonic sensors, one for upward and one for downward and one for front.
    therefore I need the dc motor for vibration as an alarm.
    could you help me with the code and the circuit design?
    Regards.
    Mhd.

  8. Thanks for reading. I recommend you to checkout this website http://people.ece.cornell.edu/land/courses/ece4760/FinalProjects/

    of Cornell Univesity. They did a numerous projects on ultrasonic way finding, and the good thing is all the codes should be available. I can surely help you out, if you can tell me how much you have progressesd ?

  9. Hi,
    The output voltage of the echo pin is 5V, so do I need analog to digital converter(ADC) for connecting the sensor to the micro-controller.
    Regards.
    Mhd.

  10. You only need an ADC either when the input voltage is varying. In case of ultrasonic, the echo pin either gives you 5V or 0V. YOu can easily monitor this pin, if it’s getting high or low ! ADC would have been required only if the echo pin would have generated any random voltage between 5v and 0v.

  11. could you please modify on the code according to following:
    1) the microcontroller is atmega 16
    2) i am using three ultrasonic sensors
    -sensor 1: trig on portc.0
    echo on portc.1
    -sensor 2: trig on portc.2
    echo on portc.3
    -sensor 3: trig on portc.4
    echo on portc.5
    3) also i am using three dc motors for vibration:
    -motor1 is connected to portb.0 and when the detected distance with sensor1 is less than a certain value the motor works by square pulse.
    -motor 2 is connected to portb.1 and when the detected distance with sensor2 is less than a certain value the motor works by square pulse.
    -motor 3 is connected to portb.2 and when the detected distance with sensor3 is less than a certain value the motor works by square pulse.

    4) i connected a buzzer to the portd.0 and it works with the motors (when the sensors detect a low distance)
    but in this statue the buzzer works proportionally to the distance ( it become faster when the distance is lower)

    i created the circuit design on proteus, if you don’t mind please send me your email so I can send you the file.

    sorry for bothering you and thanks for the help
    regards

  12. Actually We did da project..ultrasonic sensors will detect obstacles in a native environment..now thinkin of selling it…Interested can mail me @ mageshwar399170@gmail.com. (Navigation Assistance system for Blind .Three sensors ,One with servo motor to cover vertical range opp to a person)

  13. Assalam-o-Alaikum!
    Please I request you to tell me the changes in coding while i am using the LCD with it to show the distance.

  14. sir…which ide is use for this code….i m using cvavr …

  15. I used avr studio.you can use any ide depending upon the need.

  16. I want to use ultrasonic sensor as a obstacle detector in a way that as it detects the obstacle the buzzer attached to output port of avr atmega8 starts beeping .. Plz provide me the coding for same.

  17. I want the coding for using ultrasonic sensor as obstacle detector with atmega8 & having buzzer.

  18. Hi sania,

    Thanks for reading the blog. It’s not really tough to interface a buzzer based on distance measurement. First try to understand what the code is doing and how it’s configured. If that’s done, then all you need is to put an if statement to sound the buzzer when the obstacle is at a particular distance.

Add Comment Register



Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>