Using PullUp and PullDown Resistors on the Raspberry Pi

When you start out creating circuits with the Raspberry Pi and its GPIO pins, there’s an unexpected but important concept to understand, called “floating”.

A Simple Circuit

Imagine you’re creating a circuit using a breadboard. Something very simple… a button, some wire and a power source (like the 3.3v pin on the Pi). You just want to be able to click a button to complete the circuit. Maybe it looks something like this.

Simple Button Circuit

The above circuit connects 3.3v, through a switch and 220Ω resistor, to pin #6.

That won’t be very useful though, without a script to read the state of the circuit and take some action, even if it’s just displaying a message. So here’s a small Python script that does just that. It detects when the circuit is opened or closed, and displays a message with a timestamp.

# coding=utf-8

import RPi.GPIO as GPIO  
import datetime

def my_callback(channel):  
    if GPIO.input(6) == GPIO.HIGH:
        print('\n▼  at ' + str(datetime.datetime.now()))
    else:
        print('\n ▲ at ' + str(datetime.datetime.now())) 

try:  
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(6, GPIO.IN)
    GPIO.add_event_detect(6, GPIO.BOTH, callback=my_callback)

    message = raw_input('\nPress any key to exit.\n')

finally:  
    GPIO.cleanup()

print("Goodbye!")  

A brief explanation of what the above script is doing, for those with little experience in Python / GPIO.

It specifies the board numbering system, and then sets up a pin to read input. Then we attach a function (here named “my_callback”) to the pin, such that some code runs whenever the circuit is closed or opened (the button is pressed or released). The code just displays a simple message with the current date/time.

Running the above script, I’d expect to see a pattern of output like this, showing the timestamp of each time I press and then release the button.

▼  at 2016-04-30 12:26:44.124712
 ▲ at 2016-04-30 12:26:44.399541
▼  at 2016-04-30 12:26:44.857414
 ▲ at 2016-04-30 12:26:45.032816
▼  at 2016-04-30 12:26:45.397896
 ▲ at 2016-04-30 12:26:45.666379
▼  at 2016-04-30 12:26:46.015800

Instead, I see this, with 10 more screens just like it, in about 5 seconds. The circuit keeps bouncing up and down, all over the place, only stopping when I press the button and close the circuit.

no bouncetime, no pulldown

The above behavior has a name. When the circuit isn’t closed, it’s not simply “off”. Instead, it’s said to be “floating”. When the circuit is open, the GPIO pin is still accepting input, and it picks up on all kinds of stuff in the environment, even static electricity. If you’re using wires in your circuit, they act like antennas, amplifying what the pin would pick up by itself.

Maybe it’ll help if I define a few concepts first.

Defining a Few Terms

Circuit

Your circuit is the collection of all the connections you’ve made, using wires, resistors, LEDs, buttons, GPIO and other pins, etc.

It can be closed (like when you press a button, and a signal is able to traverse from one end to the other), or it can be open (a button is not pressed, or there’s some other break in the circuit).

An open circuit is like a long train of dominos, where you’ve removed 4 or 5 from the middle. You can try sending a signal from one end, but it’s never going to bridge the gap.

domino-665547_1280

High / Low

Each GPIO pin has two states. You can call them on or off, high or low, 1 or 0, etc. A pin is set “high” when it’s outputting 3.3v or reading in 3.3v, and “low” when it’s off. The GPIO library calls these two states GPIO.HIGH and GPIO.LOW, and the library also helps you determine which state a pin is in.

Rising Edge

The moment a GPIO pin changes to a HIGH state.

Falling Edge

The moment a GPIO pin changes to a LOW state.

Bouncetime

You can specify a time during which repeat events will be ignored. For example, you can specify a bouncetime of 500 ms. That means that if you press a button multiple times in under half a second (or maybe the button’s a bit loose and registers a click multiple times), subsequent clicks after the first one will be ignored.

Output

Pins can be set to read input or send output, but not both at once. If a pin is set to output, the Pi can either send out 3.3 volts (HIGH), or not (LOW or 0 volts).

Input

If a pin is set to input, then the circuit must be closed for it read that input. In my case, that means pressing the button down in order to read HIGH or 1 (since I’m connected to 3.3v… if my pin were connected to ground, it’d read LOW or 0 when closed).

But what about when I’m not pressing the button in the above circuit? It should be LOW or 0, right? That’s where the problem lies. Since the circuit is open, the GPIO pin could be reading all kinds of things from the environment, and it’s fairly sensitive. We need a way to force the pin to LOW (also known as “pull down”) when the circuit is open (or to HIGH if the original circuit was connected to ground, also known as a “pull up”).

Floating

When you should be using a pull down or pull up resistor, but aren’t, the status is said to be “floating”. That is, the pin and any wires connected to it pick up on random radiation and electromagnetic signals from the environment. When the circuit is open, it’s not HIGH or LOW, but somewhere in between.

Pull Down

When you have a circuit that connects 3.3v to a GPIO pin, it’ll read HIGH when the circuit is closed. When it’s open, it could read anything. You need a “pull down” resistor connecting your circuit to ground, so that it reads LOW when the circuit is open. (I’ll show this in effect later.)

Pull Up

Similarly, if you have a circuit connecting your GPIO pin to ground when it’s closed, it’ll read LOW. You need a “pull up” resistor so that, when it’s open, it defaults to the HIGH state.

In both cases, the button has no resistance (or at least, less resistance), and so when the circuit is closed it short-circuits around the pull up or pull down resistor and reads the other value. Hopefully this will make more sense with a couple demonstrations.

Strong

Strong resistors versus weak resistors only has meaning relative to one another. A lower value resistor is going to be stronger, in that it allows more current to flow through.

Weak

The weaker resistor will be the higher value one, which allows less current to flow through it.

Internal Resistors

In my circuit, I added a 10kΩ resistor to the breadboard, so I could see the circuit. The Pi has its own 1.8KΩ internal resistors that you can use, though, and I’ll show you how to use both.

Fixing the Simple Circuit

Option 1: Adding a Pull-Down Resistor to the Breadboard

Here’s the circuit again, and it’s been modified. I shifted everything to the right a little bit, to make room for two things – a 10kΩ resistor and a wire, which effectively short-circuits pin #6 to ground. This forces (pulls down) the circuit into an “off” or 0 state when the button isn’t being pushed, preventing the ups and downs we saw earlier.

Simple Button Circuit with pulldown res

All of the examples I’ve seen use 10kΩ, but a 220Ω resistor as a pull-down seems to work just fine too.

A pull-up resistor is where it seems to be more of a consideration. A higher value resistor (such as 10kΩ) allows less current to flow through, using less electricity.

Option 2: Enabling an Internal Pull-Down Resistor in the Code

Another option is to leave our circuit the way it was originally, but enable one of the internal resistors that reside on the Pi itself.

That’s done by passing a value for pull_up_down to the GPIO.setup() function, as seen below. By specifying a value of GPIO.PUD_DOWN, we effectively add a pulldown resistor to our circuit.

# coding=utf-8

import RPi.GPIO as GPIO  
import datetime

def my_callback(channel):  
    if GPIO.input(6) == GPIO.HIGH:
        print('\n▼  at ' + str(datetime.datetime.now()))
    else:
        print('\n ▲ at ' + str(datetime.datetime.now()))

try:  
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(6, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    GPIO.add_event_detect(6, GPIO.BOTH, callback=my_callback)

    message = raw_input('\nPress any key to exit.\n')

finally:  
    GPIO.cleanup()

print("Goodbye!")  

Here’s a short video showing what I see with, and without, the pulldown resistor.

And here’s a much better video, where someone explains the same concept. They’re using a TI LaunchPad instead of a Raspberry Pi, but its the same problem.

Trying it Out Yourself

If you’re ready to start experimenting with the GPIO pins on your own, but all you’ve got right now is the Raspberry Pi, you’ll need a kit with a few basics.

Look for something with a breadboard and cables. You’ll want LEDs for visual feedback, and resistors to limit power (especially important when using LEDs).

I’d also recommend a kit with a cobbler board (the black “T” shaped board). It plugs into your breadboard, and connects to all of your GPIO pins at once, using a cable. It keeps your work area cleaner, and makes it less likely that you’ll plug a wire into the wrong pin.

The kit I purchased, and used for this post, is the CanaKit Raspberry Pi GPIO Breakout Board / Cobbler Bundle (aff link).

I wouldn’t recommend it if I didn’t like it. It’s extremely affordable (in keeping with the spirit of the whole Pi movement), has high reviews, and I haven’t had a problem with any of the parts that shipped in it.

Resources

A three-parter by Alex at RasPi.TV, titled “How to use interrupts with Python on the Raspberry Pi and RPi.GPIO”.

If you’re brand new to Python…

Subscribe to Weekly Updates!

Get an email with the latest posts, once per week...
* indicates required