Raspberry Pi Banner

The GPIO pins on a Raspberry Pi are a great way to interface physical devices like buttons and LEDs with the little Linux processor. If you’re a Python developer, there’s a sweet library called RPi.GPIO that handles interfacing with the pins. In just three lines of code, you can get an LED blinking on one of the GPIO pins.

Installation

The newest version of Raspbian has the RPi.GPIO library pre-installed. You’ll probably need to update your library, so using the command line, run:
sudo python
import RPi.GPIO as GPIO
GPIO.VERSION

The current version of RPi.GPIO is 0.5.4 If you need to update to a newer version, run:
sudo apt-get update
sudo apt-get upgrade

If you don’t have the RPi.GPIO library because you’re using an older version of Raspbian, there are great instructions on the Raspberry Pi Spy website on installing the package from scratch.

Using the RPi.GPIO Library

Now that you’ve got the package installed and updated, let’s take a look at some of the functions that come with it. Open the Leafpad text editor and save your sketch as “myInputSketch.py”. From this point forward, we’ll execute this script using the command line:

sudo python myInputSketch.py

All of the following code can be added to this same file. Remember to save before you run the above command. To exit the sketch and make changes, press Ctrl+C.

To add the GPIO library to a Python sketch, you must first import it:

import RPi.GPIO as GPIO

Then we need to declare the type of numbering system we’re going to use for our pins:

#set up GPIO using BCM numbering
GPIO.setmode(GPIO.BCM)
#setup GPIO using Board numbering
GPIO.setmode(GPIO.BOARD)

The main difference between these modes is that the BOARD option uses the pins exactly as they are laid out on the Pi. No matter what revision you’re using, these will always be the same. The BCM option uses the Broadcom SoC numbering, which differs between version 1 and version 2 of the Pi.

GPIO BCM Descriptions
from Meltwater’s Raspberry Pi Hardware

In the image above, you’ll see that Pin 5 is GPIO01/03. This means that a v.1 Pi is GPIO 01, while a v.2 Pi is GPIO 03. The BCM numbering is what I’ll be using for the rest of this entry, because it’s universal across other programming languages.

Building a Circuit

Now we’re going to get into inputs and outputs. In the circuit shown below, two momentary switches are wired to GPIO pins 23 and 24 (pins 16 and 18 on the board). The switch on pin 23 is tied to 3.3V, while the switch on pin 24 is tied to ground. The reason for this is that the Raspberry Pi has internal pull-up and pull-down resistors that can be specified when the pin declarations are made.

Raspberry Pi Circuit
To set up these pins, write:

GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP)

This will enable a pull-down resistor on pin 23, and a pull-up resistor on pin 24. Now, let’s check to see if we can read them. The Pi is looking for a high voltage on Pin 23 and a low voltage on Pin 24. We’ll also need to put these inside of a loop, so that it is constantly checking the pin voltage. The code so far looks like this:

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
GPIO.setup(24, GPIO.IN, pull_up_down = GPIO.PUD_UP)
while True:
if(GPIO.input(23) ==1):
print(“Button 1 pressed”)
if(GPIO.input(24) == 0):
print(“Button 2 pressed”)
GPIO.cleanup()

The indents in Python are important when using loops, so be sure to include them. You also must run your script as “sudo” to access the GPIO pins. The GPIO.cleanup() command at the end is necessary to reset the status of any GPIO pins when you exit the program. If you don’t use this, then the GPIO pins will remain at whatever state they were last set to.

The Problem With Polling

This code works, but prints a line for each frame that the button is pressed. This is extremely inconvenient if you want to use that button to trigger an action or command only one time. Luckily, the GPIO library has built in a rising-edge and falling-edge function. A rising-edge is defined by the time the pin changes from low to high, but it only detects the change. Similarly, the falling-edge is the moment the pin changes from high to low. Using this definition, let’s change our code slightly:

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
GPIO.setup(24, GPIO.IN, pull_up_down = GPIO.PUD_UP)
while True:
GPIO.wait_for_edge(23, GPIO.RISING)
print(“Button 1 Pressed”)
GPIO.wait_for_edge(23, GPIO.FALLING)
print(“Button 1 Released”)
GPIO.wait_for_edge(24, GPIO.FALLING)
print(“Button 2 Pressed”)
GPIO.wait_for_edge(24, GPIO.RISING)
print(“Button 2 Released”)
GPIO.cleanup()

When you run this code, notice how the statement only runs after the edge detection occurs. This is because Python is waiting for this specific edge to occur before proceeding with the rest of the code. What happens if you try to press button 2 before you let go of button 1? What happens if you try to press button 1 twice without pressing button 2? Because the code is written sequentially, the edges must occur in exactly the order written.

Edge Detection is great if you need to wait for an input before continuing with the rest of the code. However, if you need to trigger a function using an input device, then events and callback functions are the best way to do that.

Events and Callback Functions

Let’s say you’ve got the Raspberry Pi camera module, and you’d like it to snap a photo when you press a button. However, you don’t want your code to poll that button constantly, and you certainly don’t want to wait for an edge because you may have other code running simultaneously.

The best way to execute this code is using a callback function. This is a function that is attached to a specific GPIO pin and run whenever that edge is detected. Let’s try one:

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
GPIO.setup(24, GPIO.IN, pull_up_down = GPIO.PUD_UP)
def printFunction(channel):
print(“Button 1 pressed!”)
print(“Note how the bouncetime affects the button press”)
GPIO.add_event_detect(23, GPIO.RISING, callback=printFunction, bouncetime=300)
while True:
GPIO.wait_for_edge(24, GPIO.FALLING)
print(“Button 2 Pressed”)
GPIO.wait_for_edge(24, GPIO.RISING)
print(“Button 2 Released”)
GPIO.cleanup()

You’ll notice here that button 1 will consistently trigger the printFunction, even while the main loop is waiting for an edge on button 2. This is because the callback function is in a separate thread. Threads are important in programming because they allow things to happen simultaneously without affecting other functions. Pressing button 1 will not affect what happens in our main loop.

Events are also great, because you can remove them from a pin just as easily as you can add them:

GPIO.remove_event_detect(23)
Now you’re free to add a different function to the same pin!

Adding Functionality

As convenient as callback functions are for the GPIO pins, it still doesn’t change the fact that the Raspberry Pi is just not ideal for analog inputs or PWM outputs. However, because the Pi has Tx and Rx pins (pins 8 and 10, GPIO 14 and 15), it can easily communicate with an Arduino. If I have a project that requires an analog sensor input, or smooth PWM output, simply writing commands to the serial port to the Arduino can make things seamless.

Mark Kleback

Mark Kleback

Mark is a freelance creative technologist residing in Brooklyn. He teaches electronics and programming to elementary school kids at Beam Center in Brooklyn. He also curates an independent video game gallery at the music venue Death By Audio.


  • Nawar Khabbaz

    Hey Mark, I just wanted to know how you drew the Pi with the Breadboard, what software did you use?

    • andy seredy

      *Looks like Fritzing.org

  • Daniel Román
  • http://www.altibreeze.com Damien

    Thanks for this tutorial Mark, I just started using my GPIO with that. So cool xD

  • Akhil Lawrence

    Thank you mark

  • InfiniteFeel

    I had been confused as to how to start using the GPIO with python. Nice article!

  • jake

    SyntaxError: Non-ASCII character ‘xe2′ in file test.py on line 11, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details

    • mike

      same here

      • Jeffrey Kho

        make sure you fix any scarequotes into regular quotes.

        for example: “ is not the same as “

  • Jaime Wissner

    How do you end the program out of the while loop? I’ve only found to ctr+c out and that doesn’t reach the cleanup command so I have to manually reset the pins

    • John Kroubalkian

      Jaime, have a look at KeyboardInterrupt in Python. It is raised when control-c is pressed.

      try:
      … Do some logic / processing here ….
      except KeyboardInterrupt:
      GPIO.cleanup()

      • Paulo

        A more robust way to do this would be:


        try:
        # Your code
        except KeyboardInterrupt:
        print('Program terminated.')
        finally:
        GPIO.cleanup() # Clean up regardless of how the try: block was terminated.

        That way you can
        1) cleanup after other exceptions in your code (the previous implementation won’t run GPIO.cleanup() if another exception occurs), and
        2) have the option to exit the try: block without hitting an exception and still run the cleanup code.

    • Paulo

      If you want to terminate your program, you can structure the while loop like this:


      running = True
      while running:
      # Do stuff
      running = False

      After you set the running variable to false, the next time round the while: loop the test condition will evaluate to false and so the loop won’t be executed.

    • Daniel Phelps

      One way is the break statement:

      while 1:
      (commands)

      if (statement) == (something):
      break

  • Emanuele Fanton

    Thank you
    pull_up_down = GPIO.PUD_DOWN
    resolved a long time problem I had along with the example with ground button.

  • danjperron

    Please correct you picture. GPIO9 is MISO and not MOSO.
    Master IN server OUT.

  • Tony

    Schönes anschauliches Tutorial!

    Für den neuen Banana Pi haben wir auch mal alle Pindefinitionen und Schnittstellen zusammengetragen: http://www.bananapi-kaufen.de/aufbau-und-pindefinitionen/

  • Ankita Chatterjee

    Hello , i executed this program and it worked , but the next day nothing works!!!! there is no compilation error but , there is no response from the button or bread board…i am worried that is there any problem with my button or board?? Please help!

    • Daniel Phelps

      In the terminal, type ” sudo idle “, and from there open your file.

  • Guest

    how can i use this circuit for a wasd keys

  • Quentin

    how can i use this circuit for wasd keys

  • Mark

    Hello everyone,

    I’m just the beginner in raspberry and programming in phyton. Could You tell me where I should write the “myInputSketch.py” file in order to open it successfully in python? Can I use another text editor like vi or nano? Thanks in advance, Mark.

    • Daniel Phelps

      You don’t have to open a specific file, but instead in the terminal, type ” sudo idle “, and from there go to , , and write your program.

  • Sindhu Patil

    Hello everyone,

    I am new to PI( currently i am using Raspberry Pi model B+), is it possible to pass the message/Communicate between two PI using GIPO serial communication? how ?

    Please can you help me here

    Thanks
    Sindhu

  • Whyoldman

    Great lesson!
    I followed it exactly, but I am getting “ghosts in the machine” as my Pi is registering button presses when none have occurred, and sometimes fails to see button releases. I have tried various pull up and pull down resistors, and the problem seems more pronounced when triggering the pull down pin. I have 3 Pi’s around the house and have tried the code with all of them and they all respond the same. By simply touching the wires on the breadboard between the switch and GPIO pins I get input triggers. Any suggestions would be greatly appreciated as I have re-entered the code and tried different components with only slightly different results, but none of them satisfactory. I am hoping to pole a set of contacts on my furnace so I can keep track of how long the furnace is firing, so I can calculate how much heating oil I have used (knowing that the unit consumes .75 gallons an hour, if I can keep track of the total run-time I would have a primitive flow meter of sorts)
    I will keep tweaking it, but any clues would be helpful.
    Thanks