After I had been playing around with the PICs for awhile I happened to notice that the web was full of small interface boards that could do a variety of interesting tasks. Even better, they were cheaper than trying to build your own little boards. Alas, they were almost all labeled as being for the Arduino or the Raspberry Pi or some such thing. But on taking a closer look I could see that that was only a clever disguise because they were also perfect for hooking up to a PIC. So, of course, I acted like a kid in a candy shop and bought a few different ones. One of the ones I bought was an ultrasonic module and that’s what we will look at in this post.
The picture shown here is typical of the ultrasonic modules available and is the exact version I used. Connection is pretty simple and will be detailed in the next step. The way it works is that a short pulse is put on the Trigger input and that causes the module to briefly turn on the ultrasonic output. The module then waits for the echo return. The Echo pin on the module will go high when a Trigger is received and will stay high until the module receives an echo or times out. As we will see, that behavior meshes nicely with our PIC capabilities.
In the previous two posts we used an itty bitty 8-pin PIC just because we could. In this episode we are stepping all the way up to a 14-pin PIC. The one we are using here is the 16F688. I like it for a lot of reasons, not the least of which is that I don’t have to change the jumpers on my programmer when switching between this and the 8-bit PIC we have been using. Laziness can be a powerful motivator.
As you can see in the diagram, the Ultrasonic Module is connected to three of the PIC pins. The software supports the LCD interface I detailed in the 3-wire, 8-bit LCD Interface post and the pin connections I used are listed at the bottom of the diagram. Since we have several available I/O pins on this version of the PIC, you have several you can choose from for the LCD interface and for the Trigger to the Ultrasonic Module. What is critical in the wiring is that the Echo pin of the Ultrasonic Module must be connected to pins 3 and 11 of this PIC, or to the equivalent pins on whatever PIC you use. Pin 3 is the Timer1 Gate (T1G) input and pin 11 is the External Interrupt (EXT or INT). T1G helps us to measure the pulse width of the echo which we can then convert to distance. INT (or EXT on some PICs) prompts us to go read Timer1 at the end of the Echo pulse. In practice, T1G enables Timer1 to begin counting when Echo goes high and stops Timer1 from counting when Echo goes low. At the same time, the low going edge of Echo triggers an external interrupt on the INT pin. Given that we are using the default 4-MHz internal clock of the PIC, Timer1 will increment at a very convenient 1us rate while measuring the Echo pulse.
The software link is listed below. While it is targeted for the 16F688, it is easily ported to other versions of the PIC. Just make sure that you choose one that has the Timer1 Gate (T1G) input and an external interrupt input (INT or EXT). You will also need to change the line that identifies the PIC version (LIST=) and the INCLUDE file but those are intuitive changes. The __CONFIG line may also need tweaking just because one or two of the labels used are spelled differently in some of the INCLUDE files.
The interrupt handler here is a little fancier than the one used in Episode 2, not because it needs to be, but because it shows how you can handle multiple interrupt sources. Basically you just check to see which individual interrupt flag has been set and then GOTO that handler. If more than one interrupt flag has been set you can either check again from inside the interrupt handler or simply return from the interrupt. If another interrupt flag is still set, the interrupt handler will be triggered again automatically.
As indicated in the software header, the Ultrasonic Module requires a 10us or longer Trigger pulse. It then takes up to 38ms for the Echo pulse to complete, with 38ms considered a “no echo” value. The Ping routine sends out a Trigger pulse of about 14us and then waits 50ms for the Echo pulse. It is expected that the interrupt will occur during that time delay. The interrupt handler just saves the Timer 1 count values (all 16-bits) and then clears the timer and the external interrupt flag. The general interrupt enable (GIE) is re-enabled automatically when exiting the interrupt handler. The 200ms delay in the LCD_Loop is an arbitrary value that limits the distance measurement updates to about 4 per second.
The effective range of the Ultrasonic Module results is a maximum pulse of about 25ms or 168 inches. The software has, for convenience sake, been limited to a maximum of about 98 inches (3800 hex). The conversion factors for both centimeters and inches are noted in the software header so feel free to modify the Convert routine to extend the reportable range or change the measurement units.
The LCD will display “xx INCHES” unless the Convert routine determines that the distance is greater than the arbitrary limit of 98 inches. In that case, it will display “OUT OF RANGE”. That’s it for this post. Check out my other electronics projects.