0

I have used the following ultrasonic sensor with Raspberry Pi 2, which works at 5V.

http://www.micropik.com/PDF/HCSR04.pdf

At the time I was not aware that Raspberry Pi 2 GPIO is not 5V tolerant so I did not have a voltage divider circuit, but it still worked pretty fine. Recently I have found out that GPIO should not be working with 5V, in fact I could have damaged the GPIO.

Of course I have used a voltage divider now, just in case. But my question is, how did I turned out okay and did not end up damaging the GPIO? In other words what property of HCSR04 could have saved my Raspberry, is it output current capacity? I just want to know to understand the entire picture and make sure I do not do something as such again.

4 Answers 4

2

As Joan explained this is usually OK if the current is limited.

The reason is that the GPIO have clamp diodes to 3.3V (and 0V). This prevents the actual circuitry from exceeding 3.3V + a diode forward drop. This is a standard technique for protecting digital circuits PROVIDED THE CURRENT IS LIMITED. So external resistance is required.

The substrate diodes on the SOC would have limited current carrying capacity and can be easily damaged, so you should not rely on this for protection. They are mainly there to protect against static.

You can use external high speed or Schottky diodes to provide more rugged and transient protection.

1

The GPIO are believed to be able to tolerate higher than 3V3 provided only a little current flows.

This suggests that you may be okay if the current is less than half a milliamp.

The easiest way to ensure a limited current is to use a large series resistor. I use something like a 20k resistor on the echo line when I can't be bothered to use a proper voltage divider.

I'd only use a single resistor if I didn't plan to leave the set-up running for very long.

The party line has always been and will remain: never expose the GPIO to more than 3V3.

1
  • Thanks, Im glad I did not learn this fact the hard way :)
    – ozgeneral
    Commented Apr 23, 2016 at 18:17
1

I just created this program to test the HC-SRO4 Ultrasonic Range Measurement device. I had a lot of problems getting it to work in a single process waiting for the edge of the measurement pulse, so I modified the program to created a separate (child) process to monitor and report the measurement from the sensor. In addition, just for fun, I also integrated a old Airtronics 94102 servo, moving it to reflect the distance measurement, between 2.5 and 11 inches. I used 1k & 2k resistors to reduce the 5 volt output from the ECHO lead of the sensor to 3.3 volts for input to the GPIO pin.

#!/usr/bin/env python
#
#   GPIO Range Measurement with Servo Control
#
#   This program is designed to demonstrate the Raspberry Pi
#   General Purpose I/O capabilities and also provide an
#   example program in Python using multiprocessing capabilities.
#
#   Author: Andy Whitt
#
#   Last Revised: 8 Jan 2016
#

import os
import multiprocessing
import RPi.GPIO as GPIO
import time

TRIG = 11       # RPi Pin (GPIO 17) initiate range measurement
ECHO = 12       # RPi Pin (GPIO 18) recieve measurement pulse
SERVO_CONTROL = 40  # RPi Pin (GPIO 21) control the servo

PWM_FREQ = 50       # Frequency (Hz) of signal to the servo

#
# Configure the Raspberry Pi GPIO interface and Pin Usage
#
def configGPIO():

    try:

        GPIO.setwarnings(False)
        GPIO.setmode(GPIO.BOARD) # Use RPi header pin numbering
        GPIO.setup(TRIG, GPIO.OUT, initial=GPIO.LOW)
        GPIO.setup(ECHO, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
        GPIO.setup(SERVO_CONTROL, GPIO.OUT)

    except Exception, reason:

        print 'GPIO configuration failed because', reason
        print ' '

        raise SystemExit

    print 'GPIO Version ', GPIO.VERSION

#
# Run in a separate process to measure ECHO lead pulse width, display
# distance value and command the servo to reflect the changes
#
def reportMeasurement():

    print 'pid :', os.getpid(),'-> Measurement Reporting Subprocess'

    PWM = GPIO.PWM(SERVO_CONTROL, PWM_FREQ) # Setup PWM signal

    dutyCycle = 3       # Initial width of pulses sent to the servo

    PWM.start(dutyCycle)    # Turn on pulse width modulation signal

    while True:         # Loop handling HC-SRO4 measurement events

        GPIO.wait_for_edge(ECHO, GPIO.RISING)
        pStart = time.time()

        GPIO.wait_for_edge(ECHO, GPIO.FALLING)
        pEnd = time.time()

        uSpulseWidth = (pEnd - pStart) + .00008 # RPi process delay adjustment

        pulseWidth = uSpulseWidth * 1000000 # Use x.x microsecond notation

        if ((pulseWidth < 150) | (pulseWidth > 25000)): # Effective sensor range

            print '*** Invalid Reading from Ranging Sensor'

        else:

            print ' '

            if (pulseWidth > 999.99): # Pulses above 1k microseconds, display ms

                print 'Pulse Duration   {0:9.2f}'.format(pulseWidth/1000), 'Milliseconds'

            else:

                print 'Pulse Duration   {0:9.2f}'.format(pulseWidth), 'Microseconds'

            distance = (uSpulseWidth / 58) * 1000000

            print '   Distance  {0:9.2f}'.format(distance), 'Centimeters'

            distance = (uSpulseWidth / 148) * 1000000

            print '     {0:9.2f}'.format(distance), 'Inches'

            dutyCycle = (uSpulseWidth / 148) * 1000000  # Use inches to set servo

            if ((dutyCycle > 2.5) & (dutyCycle < 11)):  # Effective range of servo

                PWM.ChangeDutyCycle(round(dutyCycle,1)) # Change position of servo

            else:

                print '*** Reached maximum range of servo movement'

#
# Loop until user terminates with control-C
#
def mainLoop():

    print ' '
    print 'pid :', os.getpid(),'-> Main Loop Process'

    time.sleep(1)

    print ' '

    for second in '54321':

        print 'Starting in', second
        time.sleep(1)

    print ' '

    while True: # Continuosly initiate range measurements

        GPIO.output(TRIG, GPIO.HIGH)
        time.sleep(.000001)     # Using 10 microsecond pulse
        GPIO.output(TRIG, GPIO.LOW)

        time.sleep(.1)          # Every 100 milliseconds

#
# Program Entry Point
#
if __name__ == "__main__": # Only run if module (source file) is the main program

    print ' '
    print 'Measuring Distance with the Cytron HC-SRO4 Ultrasonic Ranging Sensor'
    print ' '
    print '         Hit Control-C to exit'
    print ' '

    configGPIO()

    try: # Spawn child process for running measurement and reporting

        subProcess = multiprocessing.Process(target=reportMeasurement, args=())
        subProcess.start()

    except Exception, reason:

        print ' '
        print 'Failed to spawn child process because', reason
        print ' '

        GPIO.cleanup()

        raise SystemExit

    try: # Enter main program loop

        mainLoop()

    except KeyboardInterrupt:

        print ' '
        print 'Terminated by User'

    except Exception, reason:

        print ' '
        print 'Terminated abnormally because', reason

    subProcess.terminate()

    GPIO.cleanup()

    print ' '

1
  • I just ran across this and I'm greatly encouraged now to do something a bit similar. Is there any problem with main and reportMeasurement trying to access the GPIO at the same time? Or are these basically just locations in memory and everything takes care of itself?
    – uhoh
    Commented Dec 4, 2018 at 13:51
0

Your sensor requires 5V to function. You provided less than that, so it never turned on. Not enough supply voltage isn't normally a problem - just don't put more than 3.3V into a GPIO and you'll be fine.

1
  • Sensor worked with 5V there is no problem with that. However I connected the output directly to GPIO by mistake so I should have damaged it. I am just wondering how did my GPIO survived.
    – ozgeneral
    Commented Apr 23, 2016 at 17:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.