Jump to content
username

HC - SR04 Ultrasound Module Driver Code

Recommended Posts

Hey all,

 

Heres some code I wrote for an upcoming project which uses an ultrasound range detector. It uses a GPIO falling edge interrupt to determine time of echo pulse and uses a capture/compare pin w/ timer 1A for a ~100us pin trigger. The module is 5V so I power that off a test point on the launchpad and I use a open drain configuration bjt to get my 5V GPIO output for the trigger pin, then I use a resistor divider for the echo input.

 

Acouple drawbacks of using these modules:

-Distance measurement is relative to the module you buy

-Max sampling speed is relative to the module you buy

 

Code drawback:

-Apparently the MPS430G2553 GPIO falling edge interrupts can't detect short pulses so this doesn't work for super close proximity to the sensor.

/*
 * Author: Nathan Zimmerman
 * Date: 6/22/13
 *
 * Description: A simple program to turn on a LED with the HC-SR04
 * module if the module detects a object closer than 100 centimeters
 * 
 *
 */

#include "msp430g2553.h"
#include "stdint.h"

//GPIO Pins

#define trigger_pin            BIT1
#define echo_input_pin        BIT3
#define led                    BIT0

//Ultrasound parameters

#define timer_period        62500 // 4 * 62500 = 250ms
#define trigger_pulse        (timer_period - 10)
#define us_per_cm            14.5 // Depends on module
#define time_to_trigger_us    450
#define distance_check        100 //centimeters

//Statics

static uint16_t echo_pulse_counts = 0;

//Functions

void clk_setup_1mhz();
void setup_trigger_pulse();
void setup_gpio_echo_interrupt();
uint16_t get_distance_cm();

//Main

void main(void) {

    clk_setup_1mhz();
    setup_trigger_pulse();
    setup_gpio_echo_interrupt();

    P1DIR |= led;
    P1OUT &= ~led;

    while(1)
    {
        if (get_distance_cm() < distance_check)
        {
            P1OUT |= led;
        }
        else
        {
            P1OUT &= ~led;
        }
    }

} // End of main

void clk_setup_1mhz() {
    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL = CALDCO_1MHZ;
    WDTCTL = WDTPW + WDTHOLD;
}

void setup_trigger_pulse() {
    P2DIR |= trigger_pin;
    P2OUT &= ~trigger_pin;
    P2SEL |= trigger_pin;
    TA1CCR0 = timer_period;
    TA1CCTL1 = OUTMOD_7;
    TA1CCR1 = trigger_pulse;
    TA1CTL = TASSEL_2 + MC_1+ ID_2;
    __enable_interrupt();
}

void setup_gpio_echo_interrupt() {
    P1DIR &= ~echo_input_pin;
    P1OUT &= ~echo_input_pin;
    P1IE |= echo_input_pin;
    P1IES |= echo_input_pin;
    P1IFG &= ~echo_input_pin;
}

uint16_t get_distance_cm() {
    return (echo_pulse_counts - time_to_trigger_us)/ us_per_cm;
}

#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void) {
    echo_pulse_counts = TA1R;
    P1IFG &= ~echo_input_pin;
}

Share this post


Link to post
Share on other sites

 

Code drawback:

-Apparently the MPS430G2553 GPIO falling edge interrupts can't detect short pulses

 

It can detect pulses a few 10s of nanoseconds wide. Ultrasonic modules will typically disable the received pulse detection while transmitting and for a short time after. This prevents false triggering from the outbound chirp. So the close range limitation is probably due to an intentional feature of the ultrasonic module. Easy to check with a dual channel DSO.

Share this post


Link to post
Share on other sites

username - you don't need BJT for triggering at all. Input is 3.3V compatible, so you can trigger it directly from MCU. Actually the sensor is 3.3V Vcc compatible, but max distance is dramatically reduced (to about 0.5m).

 

AFAIK this sensor has minimum distance of about 20mm. OTOH I tried multiple sensors and all of them were performing with about 3mm accuracy up to 4 meters (I was using the Energia library for measurements). What I had to add was temperature coefficient (I'm measuring liquid levels outdoors).

Share this post


Link to post
Share on other sites

It can detect pulses a few 10s of nanoseconds wide. Ultrasonic modules will typically disable the received pulse detection while transmitting and for a short time after. This prevents false triggering from the outbound chirp. So the close range limitation is probably due to an intentional feature of the ultrasonic module. Easy to check with a dual channel DSO.

 

Going to have to look into that.... I checked it on the my rigol 1052 and the pulse was there which is why I concluded it was the MSP430s fault. Granted, its no perfect square pulse nor is it rail to rail. Going to have to use a level shifter as opposed to a resistor divider and see if that fixes it.

 

 

username - you don't need BJT for triggering at all. Input is 3.3V compatible, so you can trigger it directly from MCU. Actually the sensor is 3.3V Vcc compatible, but max distance is dramatically reduced (to about 0.5m).

 

AFAIK this sensor has minimum distance of about 20mm. OTOH I tried multiple sensors and all of them were performing with about 3mm accuracy up to 4 meters (I was using the Energia library for measurements). What I had to add was temperature coefficient (I'm measuring liquid levels outdoors).

 

I'll have to try that out as well. According to the datasheets that i've seen, some of these are 5V only modules. Perhaps i'm wrong

Share this post


Link to post
Share on other sites

Hi,

 

I tried your code, but i am a truly newbie for this. How to use the resistor divider for the echo pin? Do you mind posting the schematic diagram of your circuit?

 

Thank you so much~

Share this post


Link to post
Share on other sites

Hi,

 

I tried your code, but i am a truly newbie for this. How to use the resistor divider for the echo pin? Do you mind posting the schematic diagram of your circuit?

 

Thank you so much~

Hey Kent,

post-664-0-15880500-1373043484_thumb.png

Here is what I did with the trig pin and the echo pin. The Vin pin was set to 5V on the module.

Share this post


Link to post
Share on other sites

Hai,i started to interface hcsr04 with msp430 launchpad...your above code worked almost...But i am new to the msp430 coding. I myself figured out most of the operation, but i didn't understand how did you assigned the values for ultrasonic parameters.

 

#define timer_period        62500 // 4 * 62500 = 250ms    ---how did you assign 62500?
#define trigger_pulse        (timer_period - 10)    ---how is this 100us?
#define us_per_cm            14.5 // Depends on module   ---my hcsr04 datasheet says us/58=centemeters. so can i assign us_per_cm as 58 directly?
#define time_to_trigger_us    450 ---what does 450 means? how did you calculated?

 

and from above program i can see that led1 from launch pad is glowing...how to interface with an external led?

can you help me in this please?

Share this post


Link to post
Share on other sites

@@sagarika36

Hai,i started to interface hcsr04 with msp430 launchpad...your above code worked almost...But i am new to the msp430 coding. I myself figured out most of the operation, but i didn't understand how did you assigned the values for ultrasonic parameters.

 

#define timer_period        62500 // 4 * 62500 = 250ms    ---how did you assign 62500?
#define trigger_pulse        (timer_period - 10)    ---how is this 100us?
#define us_per_cm            14.5 // Depends on module   ---my hcsr04 datasheet says us/58=centemeters. so can i assign us_per_cm as 58 directly?
#define time_to_trigger_us    450 ---what does 450 means? how did you calculated?

 

and from above program i can see that led1 from launch pad is glowing...how to interface with an external led?

can you help me in this please?

SMCLK is set to 1MHz, TimerA is set to run at SMCLK/1, so also 1MHZ. 1MHZ means that each timer tick will be 1/1MHz = 1us.

62500 us = 62.5ms, 4 * 62.5ms = 250ms.

I'm not really sure why this multiple of 4 is mentioned, because I can't find it otherwise in the code.

 

trigger_pulse is set to the timer rollover value (timer_period) minus 10, in mode 7. Mode 7 which means there will be a negative pulse from timer_period - 10 until timer_period, using the mentioned open drain configuration would invert this to become a positive pulse. This means the pulse is 10us long, I don't know why he mentions it to be 100us, I also don't see any capture/compare.

 

Your description of us/58=centimeters seems odd, never have I seen an equation where one side only mentions the unit. I suppose your datasheet should mention us/centimeter=58

 

time_to_trigger_us may be experimentally confirmed, it seems to be some correction for the delay through the system. So the timer would count while the ultrasonic pulse has not been sent yet, this levels that off, I think.

Share this post


Link to post
Share on other sites

which mosfet should we use for triggering ? how to use it please explain how it works...?

The trig pin on the module wants to see a 0-5V digital input. The msp430 only has a 3.6V input max. That mosfet works as a 3.6V to 5V converter. Since its a 5V module I did this to be safe though i'm not sure its required. It might tolerate lower voltage inputs. Use any basic mosfet that can handle a 3.6V gate voltage. A 2n7007 is a basic FET that should work.

As for how a mosfet works, see wikipedia.

If your asking as to how the trig pin works on the module, see the module datasheet.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...