Interrupt Driven HC-SR04 MicroPython Pi Pico

by stevensarns in Circuits > Raspberry Pi

10 Views, 0 Favorites, 0 Comments

Interrupt Driven HC-SR04 MicroPython Pi Pico

pico robot 1.png

All of the SR04 drivers I found were written with "wait" loops, meaning that the driver would hang (block) until the wait condition was satisfied. In the case of the SR04 Ultrasonic distance sensor this would be up to 2.5 milliseconds. This driver is interrupt driven, consequently does not interfere with normal operation of the microcontroller.

Supplies

Pi Pico

SR04 Ultrasonic distance sensor

Programming

Programming is straightforward. I used Thonny. There are many versions of the SR04 but I think this will work with any of them. The only issue might be the timeout of an ECHO pulse that does not detect a reflection. In my case it was 150 milliseconds. The decision to run the sensor at 5 Hz (trig_rate = Timer(mode=Timer.PERIODIC, period=200, callback=sr04trigger)) is to ensure that a trigger pulse is not applied until the echo signal has reset. I tested several sensors and found that the longest ECHO pulse ranged from 70 mS to 180 mS. On the other hand, perhaps it would not affect the sensor to apply the TRIG pulse during a sampling period. If that is the case, the trigger rate could be increased without concern and the code would return the last valid result. I tested this at a trigger rate of 100 triggers/second and the results appeared ok although I did detect a few bogus returns.

from machine import Pin, PWM, Timer
from time import sleep, ticks_us

TRIG_PIN = 7 # Pi Pico W powered by 3.7V LiPo thru 1N5819
ECHO_PIN = 6 # SR04 powered by same source

trig_pin = Pin(TRIG_PIN, Pin.OUT) # SR04
echo_pin = Pin(ECHO_PIN, Pin.IN) # SR04
led_pin = machine.Pin("LED", machine.Pin.OUT) # LED pin, obscure location not 25

data_rdy_flag = False # distance data ready
echo_start = 0 # time of echo signal rising
echo_dist = 0 # result of echo pulse in cm

def echo_isr(pin): # isr handles both rising and falling edge of pulse
global data_rdy_flag # flag set if data ready
global echo_start # save time start for next call
global echo_dist # result in cm
if(echo_pin.value()): # echo pin high, has risen
echo_start = ticks_us() # echo rises ~500uS after trigger
else: # echo has fallen
echo_dist = int((ticks_us()-echo_start)*0.0171)
data_rdy_flag = True # data ready

def sr04trigger(timer):
trig_pin.value(0) # echo rises ~500 uS after trig falls
trig_pin.value(1) # trig high for ~12 uS
trig_pin.value(1) # echo will fall after ~150mS if no target
trig_pin.value(0) # reset trig pin

echo_pin.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=echo_isr) # int on change
trig_rate = Timer(mode=Timer.PERIODIC, period=200, callback=sr04trigger) # software timer

while True:
while data_rdy_flag == False: # wait for next valid data
sleep(.1)
print(echo_dist, "cm")
data_rdy_flag = False # last data used, reset flag
led_pin.value(not led_pin.value()) # Toggle the LED state (ON/OFF)

Downloads