Handheld Ultrasonic Rangefinder

Hardware/software design

Hardware design

The hardware for the rangefinder can be broken down into three functional units, the receiving circuit, the transmitting circuit, and the MCU circuit. The receiver and transmitter circuits can work independently of the MCU, which made testing with a signal generator quite useful. This allowed one of us to work on the hardware while the other worked on the software independently and not require one to be dependent on the other for testing.

At the heart of the receiver circuit is one of the ultrasonic transducers. The transducer converts an incoming sound wave and converts it into a voltage signal. This signal needs to be cleaned of noise, amplified, and turned into a TTL-type signal for the MCU. The signal from the transducer is fed through a capacitor to filter out noise and then through a voltage divider to center the signal at 2.5 volts. From here, the signal needs to be amplified to guarantee true TTL levels. Initially, this was attempted using an LM358 op-amp. However, the LM358 could not switch fast enough and was unable to create a clean square wave. At the suggestion of Prof. Land, we tried using a 74HC04 high speed CMOS inverter as a high gain linear amplifier. Initially, we used resistor values of 1 MΩ and 100 kΩ to achieve a gain of 10. This created voltage levels well beyond +5 volts and resulted in a clipped signal at the output. This, however, is actually desired because the output now represented a more of a square wave than a sine wave. The output of the inverter was then fed into a SN74HC14N Schmitt trigger to convert it into a true TTL square wave. The input of the Schmitt trigger was connected to ground using a 22 pF capacitor to clean the signal from noise. The output of the Schmitt trigger can now be fed into the MCU as the received pulse.

During testing, however, we noticed that this did not quite create a nice clean square wave and was influenced greatly by noise. To combat this, we changed the gain of the inverter amplifier by replacing the 100 kΩ resistor with a 10 kΩ resistor for a gain of 100. We then fed the signal through three cascaded Schmitt triggers to clean up the signal much more than previously. There is a single 22 pF capacitor on the input of the last Schmitt trigger to ground.

Unlike the receiver circuit which tries to generate a TTL square wave, the transmitter circuit starts with a TTL square wave. This square wave is generated by the MCU as a series of pulses. The goal of the transmitting circuit is to amplify the pulse train enough so that it can travel a significant distance and reflect back towards the receiver. Again, we had initially tried using a LM358 op-amp running into the same switching problems. We then tried using a 2N3904 BJT sourced by 9 volts at the collector as a simple switch. This ended up not working because the transducer did not create a DC path for current to flow through the BJT. In the end, a LM311 high speed comparator was used as the amplifier. In the spec sheet, an example of a zero-crossing detector was given. Changing that to a 2.5 volt-crossing detector was just a matter of changing the negative input terminal to 2.5 volts instead of GND and the VCC- pin to GND instead of -5 volts. By supplying the LM311s VCC+ pin with +18 volts, we were able to get high gain for the square wave generated by the MCU to transmit through the transducer.

Unfortunately, the high gain caused by the +18 volt supply also amplified noise in the circuit. The source of this noise is still unknown, but is likely due to the physical locations of the various circuits on the solder board. Many wires were crossing each other and are the likely culprit. As such, the amplified noise gave rise to incorrect readings by the receiver circuit. When we dropped the supply voltage back down to +9 volts, the range and accuracy of the device improved.

The Mega32 MCU is used as the brain of the rangefinder. Pins 4, 5, and 6 of PortB were used as the programming port. This allowed us to program the MCU using the STK500 development board without removing the MCU from the solder board. Pins 1, 2, and 3 of PortD were connected to SPST pushbuttons that are used to interface with the rangefinder. Depending on which mode the device is in, each button performs different functions. PortD.5 was used to supply the transmitter circuit with the TTL pulse train (ping), while PortD.7 was used as the input from the receiver circuit (pong). PortC was used for the LCD display. The LCD displays the calculated distance and speed to the user. PortA of the MCU was not used.

Power to the device was supplied by one 9 volt battery hooked up in series with a SPST pushbutton as the on/off switch. The +9 volts was fed into a LM340 voltage regulator to generate 5 volts for the MCU, ICs, and LCD. A 9 volt line was used to power the LM311 comparator to generate gain.

Acknowledgement must be paid towards Prof. Land and the TAs. Without their help, the hardware for the receiver and transmitter would have never been successful. Thanks.

Software design

The program for the rangefinder essentially does two things: 1) transmit a 40 kHz pulse, and 2) detect when the pulse is received. All that was needed to be done was to count the time that passed between the time of transmission of the ping and the reception of the pong. There were also 3 modes of operation: normal mode, change sample number mode, and calibration mode.

In order to generate the ping and count the time between ping and pong, we used two of the MCUs timers. Timer1 was running at 40 kHz in PWM mode to generate a square wave for transmission using PortD.5. Timer0 was running at 250 kHz. Timer0s purpose is to calculate time between the send pulse and the receive pulse.

In normal operation, the user pushes a button to send out the ping. The MCU then counts the number of ticks it takes before the receiver detects the pong. The number of ticks is then divided by a factor of two to represent the number of millimeters between the device and the object. As stated earlier, multiple distance samples are taken and then averaged to create more accurate readings. We noticed during testing that using one sample (or only a few) gave erroneous measurements due to picking up random noise spikes. By increasing the number of samples to a minimum of 50, we obtained pretty accurate measurements. The average of all the measurements is then displayed on the LCD. In addition, normal mode also displays the speed of the device relative to a stationary object. The speed is determined by using the distance values of the middle sample and the last sample using the dx/dt formula mentioned earlier. The LCD diplays the measured distance in millimeters and the speed in millimeters/second.

In the sample number changing mode you can change how many samples you want to take with a minimum number of samples being 50. This is to allow you to get a more precise measurement taking more measurements and eliminating randomness.

Calibration mode is used in cases when the speed of sound may differ from that at sea level. Factors such as altitude and humidity can affect the speed of sound. To maintain correct measurements, the user places the device exactly 5 centimeters from a flat wall or object. By pressing the pulse button, a pulse is sent out and received by the device. The MCU then uses the time between ping and pong to calculate the new number of ticks per meter. The MCU uses this value for all future measurements until the device is powered off.

The code was very straight forward in theory. The transducers that we used operate at 40 kHz. We first attempted to use a clock running at 80 kHz to toggle a port pin to generate a 40 kHz square wave. This did not work as well as expected. When we hooked up the port pin to the oscilloscope for testing, we noticed that the output was not an ideal 40 kHz square wave. To get around this we decided to use the PWM mode of Timer1. We configured the timer to toggle OC1A on compare match so we could pull a 40 kHz square wave off PortD.5. This seemed to solve the problem of producing a 40 kHz square wave from a port pin. To change the number of pulses in each pulse sequence for transmission we just turned on and off the toggle at certain times.

Another tricky part of the program was the timing and accuracy. As mentioned earlier, we programmed a timer tick to be 250 kHz. This translates roughly to 1.36 millimeters per second. To get the right distances required some floating point arithmetic. Finally knowing where to start and stop the counter clock was a bit tricky. We did not want to count any useless ticks that did not represent when the pulse was actually sent. These useless ticks are a result of the MCU performing other operations such as floating point calculation and conditionals. It was tricky to figure out where in the code to actually start the counter.