Before GPIO Zero launched in 2016, new users usually began exploring the GPIO pins with another Python module: RPi.GPIO.
RPi.GPIO is only slightly more work to understand, and that effort is worthwhile.
GPIO Zero isn’t intended as an alternative or replacement for RPi.GPIO. It’s a layer over it, designed to make using the RPI.GPIO as easy as possible for absolute beginners.
By dealing with RPi.GPIO directly, you better understand what’s happening under the hood, and develop a finer control that will be useful in future projects.
GPIO Zero’s API lets you tinker with things like pull up and pull down resistors, active-high, and active-low pins too. But if you use it more than occasionally, GPIO Zero’s advantage of simplicity is lost.
The other reason for using RPi.GPIO is that your fellow hackers and makers have shared many awesome projects using it. Once you grasp this module, that world opens to you!
You may also one day want to use a language like C or C++. They’re a bit more advanced, but they offer much more control and more efficient use of your hardware. Using RPi.GPIO doesn’t take you all the way to this goal; it’s just a step in that direction.
For the moment, don’t worry about squeezing the most out of each CPU cycle. Every Raspberry Pi has far more processing power than this project needs. Image: Raspberry Pi
The convention for importing the RPi.GPIO module is:
import RPi.GPIO as GPIO
The official documentation and most published projects follow this convention. If you use it too, it’s easier to borrow from their code.
There are two ways of numbering GPIO pins. You can refer to the pins by their physical position in the GPIO header; this is called “board numbering”.
You can also refer to them by the order they attach to the Broadcom chip at our Raspberry Pi’s heart; when you see GPIO pin numbers that have nothing to do with their position on the header, that’s what’s going on.
You can choose between either numbering system using RPi.GPIO’s setmode function:
GPIO.setmode(GPIO.BOARD)
GPIO.setmode(GPIO.BCM)
If you try to assign a pin before setting one of these modes, Python returns an error.
I personally prefer the Broadcom numbering. It’s clearer which pins are GPIO, ground, or power. I also build breadboard prototypes using a GPIO extension board which labels every pin with the GPIO number.
Others may feel board numbering is easier. If that works for you, great! It’s up to you.
For the rest of this article, we’ll use the Broadcom numbers.
If you’re ever at the interpreter and have forgotten which mode was set, try:
GPIO.getmode()
Once you’ve set a numbering mode, use the setup function to assign individual pins to input or output:
GPIO.setup(11, GPIO.OUT)
GPIO.setup(12, GPIO.IN)
With input pins, you’ll often want set a pull up or pull down resistor to prevent floating. You can set these resistors like this:
GPIO.setup(12, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(12, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
To read the current state of an input pin, use:
GPIO.input(12)
You can set output pins to HIGH or LOW with the output function, like this:
GPIO.output(11, True)
GPIO.output(11, False)
Your code will be much more readable if you assign the pin numbers to descriptively named variables, like this:
redLED = 11
button = 12
GPIO.setup(redLED, GPIO.OUT)
GPIO.setup(button, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.output(redLED, True)
GPIO.input(button)
This kind of code makes it much clearer what’s going on, doesn’t it?
You may feel this tutorial is simple enough to follow without these helpful labels, but it’s best to get used to making them. The habit pays off when your projects become elaborate, when you take breaks from working on them, or when someone else looks at your code.
If you leave these pins assigned, it’s much easier to accidentally short circuit them and fry the board.
GPIO Zero resets them automatically when the script ends or you exit the interpreter. In RPi.GPIO we use this function:
GPIO.cleanup()
This cleanup function only resets the pins you assigned with RPi.GPIO, so if another running process is using other pins, it won’t be disturbed.
You can reset specific pins too, bypassing them as an argument:
GPIO.cleanup(redLED)
GPIO.cleanup([redLED, button])
For this project, you’ll need:
A Raspberry Pi with power supply and an SD card with Raspbian installed | ![]() |
A breadboard | ![]() |
A GPIO extension board | ![]() |
A Green, a Red, and a Yellow LED | ![]() |
You’ll also need a device that lets you input commands, such as an SSH connection or a USB keyboard and mouse, a few jumper cables, and three resistors between 220 and 1,000 ohms.
Begin by attaching your GPIO extension board to your Raspberry Pi GPIO header and to the breadboard, if it’s not attached already. Then use a jumper cable to connect a ground pin to the negative power rail along the bottom of your breadboard.
Now to the LEDs. The D stands for diode, which means current only travels one way through it.
You can figure out which way around to wire the LED because one leg is slightly longer than the other. The longer leg is the anode, which connects to positive; the shorter is the cathode, which connects to negative.
In this circuit, we’re going to attach the longer legs – the anode – to the GPIO pins, and the short leg – the cathode – to the negative power rail.
Start by placing the red LED on your breadboard, not far from the extension board. Space the legs horizontally, with the anode closer to the extension board. Then connect a GPIO pin – I’m using pin 13 – to the anode.
Now use one of your resistors to connect the cathode to the negative power rail. It’s important to use a resistor, otherwise, the LED will try to draw too much current and could fry your Raspberry Pi.
Start by firing up the Python interpreter, by typing:
python3
Let’s load up RPi.GPIO, and set our pin numbering mode, remembering that Python is fussy about capitalization.
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
Remember the advice earlier to give pin numbers useful names? Let’s do that too.
redLED = 13
Now, assign this as an output pin, by typing:
GPIO.setup(redLED, GPIO.OUT)
If everything’s connected properly, you’ll be able to switch the LED on and off with the following commands:
GPIO.output(redLED, True)
GPIO.output(redLED, False)
If this didn’t work, check that the LED is the right way round, and that everything is connected properly. Perhaps the resistor wire just isn’t inserted well enough to close the circuit.
To the right of the red LED, place the yellow LED. Again, space the legs horizontally with the anode nearer to your extension board.
Then connect a jumper cable from a GPIO pin – I’m using pin 16 – to the anode of the yellow LED. Use a resistor to connect the cathode to the negative rail as we did before.
Now let’s name this pin, assign it as an output and test that we can switch the LED on and off:
yellowLED = 16
GPIO.setup(yellowLED, GPIO.OUT)
GPIO.output(yellowLED, True)
GPIO.output(yellowLED, False)
Is that working? If not, check that the LED is the right way around and that everything is attached correctly.
Now for the green LED.
Place it further up on the breadboard, again with the legs spaced horizontally and the anode closest to our extension board. Use a jumper to connect the anode to a GPIO pin – I’m using pin 21 – then use a resistor to connect the cathode to the negative rail and type some Python:
greenLED = 21
GPIO.setup(greenLED, GPIO.OUT)
GPIO.output(greenLED, True)
GPIO.output(greenLED, False)
That should do it!
We’re going to want the sleep command, otherwise, this will run too fast to see. Type:
from time import sleep
Now let’s put all our pin numbers into a tuple that we can iterate through.
LEDs = (redLED, yellowLED, greenLED)
Finally, write a for loop to iterate through this tuple, switching the LEDs on and off. Remember that Python is fussy about indentation!
for i in range(100):
GPIO.output(LEDs[i % 3], True)
sleep(2)
GPIO.output(LEDs[i % 3], False)
Press enter again to run the loop.
If everything’s working, you should see each LED light up for 2 seconds, one after another. It will take a few minutes to run through this, or you can press ctrl+C to end it.
If you’re unsure how this loop works, the following links may help:
• for loops
• range function
• modulo operator (%)
Don’t forget to tidy up the pins when you’re done! Type:
GPIO.cleanup()
You can exit the interpreter by pressing ctrl+D. Image: Finished Product
There’s so much you can do with these basic principles, especially once you add input pins to the mix too. Stay tuned for that!