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


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.


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.


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.

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

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():


        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)

    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'


    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'


            print ' '

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

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


                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


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

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

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


    print ' '

    for second in '54321':

        print 'Starting in', second

    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 ' '


    try: # Spawn child process for running measurement and reporting

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

    except Exception, reason:

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


        raise SystemExit

    try: # Enter main program loop


    except KeyboardInterrupt:

        print ' '
        print 'Terminated by User'

    except Exception, reason:

        print ' '
        print 'Terminated abnormally because', reason



    print ' '

  • 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 Dec 4 '18 at 13:51

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.

  • 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 Apr 23 '16 at 17:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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