- Blog entry posted in 'Electronics and Other Ramblings...', March 27, 2013.
Continuing on this topic; last time I included simple code for the PING sensor. Here I present equally simple code for the HC-SR04.
The hookup is pretty simple. Connect two I/Os from the PIC to the HC-SR04 I/Os. The code provides the following: (1) a 10us pulse output to the TRIG input of the sensor, (2) allows for "dead/wait" time, (3) measures the pulse width of the return pulse from the ECHO output of the sensor, and (4) converts this pulse width into distance.
I can confirm that the HC-SR4 (similar to the PING) does not operate at +3.3V; not a big issue, just something to keep in mind when working with these sensors.
Below is tested code used (using PIC12F683) for the PING sensor. The PC was used to read the returns. One observation about this sensor; the HC-SR04 appears (on first look) to provide a some first order filtering to the results (or otherwise be a little more directional) as compared to the PING. This is based on initial results which appear to show the results do not move around as much. Still, some simple software filter (e.g. mean filter) is recommended.
Hopes these examples help someone :)
Code :
'Author: languer (©2013)
'Pin Allocation:
'PIN# Main_Fn Secondary_Fn
'GP0 -> OUT_RS232 ICSP-DAT
'GP1 -> N/A ICSP-CLK
'GP2 -> N/A
'GP3 -> N/A MCLR
'GP4 -> OUT_SONAR
'GP5 -> IN_SONAR
'General Configuration
Define CONF_WORD = 0x33c4
Define CLOCK_FREQUENCY = 8
OSCCON = 0x71
'Variable Declarations
'>>I/O
Symbol io_rs232_tx = GP0 'rs-232 output
Symbol io_sonar_out = GP4 'hc-sr04/ping sensor
Symbol io_sonar_in = GP5 'hc-sr04/ping sensor
'>>Constants
Const _trisio = %11101110
'>>Variables
Dim flag_valid_dist As Bit
Dim _true As Bit
Dim _false As Bit
_true = True
_false = False
Dim cnt As Word
'Main Program
main:
Dim distance_in As Word 'distance in inches
WaitMs 2500
Call init()
Serout io_rs232_tx, 9600, CrLf, "Main..."
While _true
flag_valid_dist = False
distance_in = get_distance()
If flag_valid_dist = _true Then
Serout io_rs232_tx, 9600, CrLf, "Distance=", #distance_in, "_in"
Else
Serout io_rs232_tx, 9600, CrLf, "Invalid Measurement"
Endif
flag_valid_dist = False
WaitMs 1000
Wend
End
'init
Proc init()
AllDigital
TRISIO = _trisio
'set TMR1 prescaler to 1:2 -> with 8MHz clock
'this results in tmr1 resolution of 1uS, with maximum of 65.53ms
'or 0.007in resolution, with maximum of 442inches
T1CON.T1CKPS1 = 0
T1CON.T1CKPS0 = 1
'clear global variables
flag_valid_dist = False
Low io_rs232_tx
Low io_sonar_out
Serout io_rs232_tx, 9600, CrLf, "Power-up..."
End Proc
'get distance procedure
Function get_distance() As Word
Dim echo_time As Word
'transmit pulse
High io_sonar_out
WaitUs 10
Low io_sonar_out
'receive echo time
'zero-out timer1
TMR1L = 0
TMR1H = 0
PIR1.T1IF = 0
'allow for some holdoff time
WaitUs 200 '8-cycles of 40kHz is 200us
'wait for rising edge of echo pulse
While io_sonar_in = 0
Wend
'turn-on timer1
T1CON.TMR1ON = True
'wait for falling edge of echo pulse or timeout
While io_sonar_in = 1 And PIR1.T1IF = 0
Wend
T1CON.TMR1ON = False
If PIR1.T1IF Then
echo_time = 0
Else
echo_time.HB = TMR1H
echo_time.LB = TMR1L
flag_valid_dist = True 'flag a valid distance was measured
Endif
'zero-out timer1
TMR1L = 0
TMR1H = 0
PIR1.T1IF = 0
'return value
get_distance = echo_time / 148
End Function