EZdenki TOP
5V SD-Card-Reader
Avrdude Notes
H-Bridge Light Timer
AD9850 Sig-Gen
Ultrasonic Sensor
Dual Digital Dice
EZdenki SHOP
Contact Mike

The HC-SR04 Ultrasonic Sensor
Atmel ATtiny13
AVR Assembly Language

The HC-SR04 (pictured above) is an inexpensive ultrasonic sensor that can sense not only if an object presents itself, like a PIR sensor, but can also sense and relay the distance to that object.

There is quite a lot of information on the web regarding this sensor coupled with AVR microcontrollers, but basically they are all done in C with hefty AVRs, like those found on Arduinos. I really wanted to see if I could get this sensor to work on my favorite AVR, the Tiny13, and do it in AVR assembly language. Happily, I've discovered that this sensor can be used quite easily on a Tiny13 in assembly language. And obviously, if it works on a Tiny13, it'll work on other AVR chips just as well.

A good starting point is the sensor datasheet from iteadstudio.com. Download it, print it out, and get familiar with page 2 of the document. There you will find a diagram of the pulse timing. What follows is pretty much that same information in somewhat more detail.

Basic Operation and Timing of the HC-SRO4 Ultrasonic Sensor

  1. Make "Trig" (pin 2) on the sensor high for 10µs. This initiates a sensor cycle.
  2. 8x40kHz pulses will be sent from the "T" transmitting piezzo transducer of the sensor, after which time the "Echo" pin on the sensor will go from low to high.
  3. The 40kHz sound wave will bounce off the nearest object and return to the sensor.
  4. When the sensor detects the reflected sound wave, the the Echo pin will go low again.
  5. The distance between the sensor and the detected object can be calculated based on the length of time the Echo pin is high.
  6. If no object is detected, the Echo pin will stay high for 38ms and then go low.

What follows is the mathmatics behind the code of the project. If you are only interested in the nuts and bolts of getting your sensor working then please feel free to jump directly to the hardware and software sections.

Basic Distance Calculation for Ultrasonic Sensing

At first glance there may seem to be a lot of math involved. In fact it's just a few very simple calculations to convert between speed, time, and distance.

The speed of sound: 340.29 m/s (meters per second).

We will be measuring distance to an object by the time it takes a sound wave to make a round trip to the object and back again, so the the useful number is actually:

The speed of sound to an object and back: 170.15 m/s.

Since our sensor can only detect items relatively nearby, let's change to more useful units by converting from m/s to µs/cm:
           s        m     1x106µs   58.772µs
        ------- X ----- X ------- = --------
        170.15m   100cm      s         cm
Time for pulse to travel 1cm to an object and then return to the sensor: 58.772µs.

Time/Distance Quiz

Question 1: A ping takes 150µs to hit an object and return. How far away is the object?

        150µs X -------- = approx. 2.55cm

Question 2: How long for a ping to hit and return from an object 30cm away?

        30cm X -------- = approx. 1,763µs or 1.763ms

AVR Timings

The main piece of hardware used in this project (besides the sensor itself) is an Atmel ATtiny13(A) operating at the default fuse setting, which means it's running at 9.6MHz with a /8 prescaler, which comes out to a 1.2MHz clock on the chip. This is the speed at which instructions on the chip are run. Note that some instructions may require 2 or more clock cycles to complete. See the ATtiny13 Datasheet for details.

AVR Clock Cycles (clks) to Time Conversions
     ==============  1.2MHz clock timings  ==============
     1,200,000 clks  = 1s        1,000,000 clks = 833.3ms
       120,000 clks  = 100ms       100,000 clks =  83.3ms
        12,000 clks  = 10ms         10,000 clks =   8.3ms
         1,200 clks  = 1ms           1,000 clks = 833.3µs
           120 clks  = 100µs           100 clks =  83.3µs
            12 clks  = 10µs             10 clks =   8.3µs
           1.2 clks  = 1µs               1 clk  = 833.3ns
NOTE: The Tiny13 does not directly accept an external crystal ceramic resonator like other AVRs. Therefore the timings/measurements in this particular project are only accurate to ±10%. An external clock source could be used to drive an input pin, but it would hardly be worth the effort. If you really need more accuracy, I would suggest using an AVR that accepts an external crystal and, if you decide to go that route, the calculations that follow will change depending on the frequency of the crystal used.

Distance to AVR Clock Cycle Conversions

What we really need is a quick conversion between the AVR clock cycles and distance. We get that by combining the ultrasound timings with the AVR timings like this:

Distance to AVR Clock Cycles (clks)
    58.772µs   1.2 clks
    -------- X -------- =  70.526 clks/cm
       cm         µs
Or to shed more light on what this means, the inverse:
       cm         µs
    -------- X -------- =  0.014179 cm/clks
    58.772µs   1.2 clks
So the time for a pulse to shoot out, hit something a centimeter away, and return to the sensor would be about 71 clock cycles. Likewise, in a single clock cycle, a distance of 0.14mm can be reckoned. (This is a theoretical value and cannot be attained by this project because the resolution of the sensor itself is only 3mm.)

Clock-Cycle/Distance Quiz

Question 1: A ping takes 2,110 clock cycles (clks) to hit an object and return. How far away is the object?

        2,110 clks X ----------- = approx. 30cm
                     70.526 clks

Question 2: How many clock cycles will it take to sense an object 7cm away?

              70.526 clks
        7cm X ----------- = approx. 496 clks

You can see that the clock-cycle to distance conversions won't end up in exact numbers of clock cycles. This isn't a huge issue since the sensor itself is only rated for a resolution of 0.3cm, so the 1.2MHz clock speed is fast enough to achieve that resolution, albeit with a 10% error factor based on the accuracy of the AVR's internal clock. In practice, without a crystal, the best we can do is probably closer to about 5mm~1cm of resolution -- YMMV.

The Hardware

Here is all that is needed to run the HC-SR04 on a Tiny13.

And here is the schematic (click to enlarge).

The sensor itself needs 5V to operate, so a simple 5V regulated supply running off of a 9V battery is used. Other than that, you have the sensor itself, the Tiny13, and 2 LEDs and their current limiting resistors. The "Sense LED" (LED1 on the schematic) indicates if an object is detected, and the "Range LED" (LED2) tells us if the object is within the range specified in the program.

The Code

At this point, it's just a matter of counting clock cycles in the code. The code is heavily documented and includes most of the information on this page. It lists the number of clock cycles per instruction where it matters. There are 2 timing loops, a single-byte loop (BDELAY) and a word-length loop (WDELAY), to burn through clock cycles.

Here are links to the above code and the AVR hex file.

Here is the avrdude command I use for the USBasp programmer:
     sudo avrdude -p t13 -c usbasp -e -B 3 -U ultrasonic-trial-1.2.hex

And, just in case, the avrdude command to reset the Tiny13 fuses to their default values is:
     sudo avrdude -p t13 -c usbasp -e -B 3 -U lfuse:w:0x6a:m -U hfuse:w:0xff:m

Sample Application

I was able to throw together the following fairly high-level application in about 5 minutes using the above design as a base and the GNU Image Manipulation Program. :-)