A few months back, I bought myself a cheap SR04 ultrasonic rangefinder (Datasheet: http://goo.gl/LBZeDG), as per off the magical eBay (Example – Link will expire: http://goo.gl/h9j79O). As you can imagine, these things are ridiculously cheap at a mere 99p inc. p+p. How that is even profitable, I’ll never know!
They’re actually pretty nice devices and allow for relatively large distances to be measured using the speed of sound over distance to create a pulse with length dependent on the distance. The whole protocol of using this device is also really simple too and I shall explain below:
A distance measurement is started by sending a trigger pulse through the trigger line of at least 10us to the SR04 sensor. This initializes the pulse emitting sequence which consists of emitting 8 40kHz ultrasonic pulses (200us in total). Once the 8 pulses have been emitted, the echo pin will change from a low to a high. This pin will remain high until the SR04 receives the pulses back or the module times out. In a non-timeout situation, the module will set the echo pin low once the pulses have been received. This gives a pretty simple distance measurement flow. Send a 10us pulse, wait for the rising edge of the echo pin then start a timer, wait for the falling edge of the echo pin and stop the timer. The value present when the timer is stopped will be proportional to the distance of the object from the module.
Its all good having an arbitrary value of distance but when you’re trying to measure how far away something is in human values, it isn’t the best! As mentioned in the title, I’ve written a simple program for my STM32F0 discovery which is non-blocking and uses rising and falling edge EXTI interrupts to start and stop the timer, allowing for relatively good timing resolution. Once the timer has a value of distance, this is converted into meters using floating point operations (disgusting, I know!), mainly as its easy and the math is relatively nice. I’m reading this value using the standard CooCox debugging functionality and I’ve explained how to use this function in previous tutorials!
My version of the code includes a timeout in case the SR04 module is disconnected or the pulse length is too long for the timer to measure. I’m using timer 2 in my example which in the STM32F0 discovery board is a 32bit timer, with the ability to run at a full system clock speed of 48MHz. This allows pretty accurate time measurements of length up to 48e6/(2^32-1) = ~11.18ms. With a speed of sound of 343m/s, this equates to a maximum distance of 343*11.18/2 = 1.92m. By introducing a timer prescaler, this maximum distance can be increased at the downfall of precision though considering the module is accurate to 3mm, this isn’t a massive deal.
Calculating the distance in metres is really easy once the arbitrary timer value has been acquired. The steps to do this will be done below and are commented in my code.
TimerPerTick = (Prescaler)/SystemClock
With a prescaler of 1.
TimePerTick = 1/SystemClock = 1/48e6 = 20.833…ns
Therefore, if the timer value returned for the pulse width is 123456, the time that the pulse was high is:
PulseHighTime = TimerValue*TimePerTick
In the above example where pulse width returned 123456 and TimePerTick is 20.83…ns
PulseHighTime = 123456*20.83…e-9 = 2.572ms
As the high time is the time taken for the pulse to be emitted, the pulse to bounce off the object and the pulse to return to the sensor, this needs to be halved to find the one way route. Therefore, the time taken for the pulse to travel from the ultrasonic transducer to the object is PulseHighTime/2. In the above example, this will be:
TimeOfFlight = 2.572/2 = 1.286ms.
Now that the time of flight is known, the distance can be calculated. Taking the speed of sound as a constant of 343m/s (it varies with temperature and pressure!), the distance can be easily calculated as TimeOfFlight*343. In the above example, this will be:
Distance = 1.286e-3*343 = 0.441m = 44.1cm.
Voila! A simple way to calculate distance using the SR04 sensor. As you can see, this is easily done using floating point calculations and if you’re only taking a measurement every few milliseconds or so, the floating point speed will be negligible, even with a software FP library!
With regards to wiring up the sensor, according to the datasheet, a minimum supply voltage of 5v is required. Fortunately, the STM32F0 can supply this, however only a selection of the pins are 5v tolerant and I don’t fancy destroying perfectly good pins for the sake of an ultrasonic sensor! To remedy this, I’ve used a potential divider network of two 220ohm resistors. One of these resistors is placed from the echo output to the STM32F0 GPIO pin. The other resistor is placed from the GPIO pin to ground.
I’ll probably integrate this with one of my graphics libraries for a really simple STM32F0 based ultrasonic rangefinder!
The code for this project can be found on my github at: https://github.com/pyrohaz/STM32F0-SR04_Ultrasonic_Rangefinder
The second revision in the github is the non-blocking version whereas the first uses a blocking while loop to wait for the returning pulse!
Hopefully this can help some of you out there!