Today, it’s time for us to combine inputs and outputs into the same script. It’s nothing scary and it’s not new either. It’s simply a case of doing what we’ve already done in the last two days’ of GPIO basics, but combining them.
To make it super-easy, we’ll even stick to the same port numbers we used for the last two days. We’re going to make a new program which takes parts from both the “read a button press” and the “flash an led every half second” programs.
We’re going to make a simple new program which switches the LED on when the button is pressed and switches it off again when the button is released. But before we do that…
Here’s a quick recap of inputs and outputs with RPi.GPIO
import RPi.GPIO as GPIO # import RPi.GPIO module GPIO.setmode(GPIO.BCM) # choose BCM or BOARD GPIO.setup(port_or_pin, GPIO.IN) # set a port/pin as an input GPIO.setup(port_or_pin, GPIO.OUT) # set a port/pin as an output GPIO.output(port_or_pin, 1) # set an output port/pin value to 1/HIGH/True GPIO.output(port_or_pin, 0) # set an output port/pin value to 0/LOW/False i = GPIO.input(port_or_pin) # read status of pin/port and assign to variable i
So now we need a combined circuit
This is simply a combination of the circuits from the last two exercises.
Here’s a simple Python program
This takes bits from each of the previous two programs.
import RPi.GPIO as GPIO from time import sleep # this lets us have a time delay (see line 12) GPIO.setmode(GPIO.BCM) # set up BCM GPIO numbering GPIO.setup(25, GPIO.IN) # set GPIO25 as input (button) GPIO.setup(24, GPIO.OUT) # set GPIO24 as an output (LED) try: while True: # this will carry on until you hit CTRL+C if GPIO.input(25): # if port 25 == 1 print "Port 25 is 1/HIGH/True - LED ON" GPIO.output(24, 1) # set port/pin value to 1/HIGH/True else: print "Port 25 is 0/LOW/False - LED OFF" GPIO.output(24, 0) # set port/pin value to 0/LOW/False sleep(0.1) # wait 0.1 seconds finally: # this block will run no matter how the try block exits GPIO.cleanup() # clean up after yourself
Every 0.1s, this program checks the button status…
- if pressed (input port 25 == 1), button status is displayed and the LED is switched on (output port 24 is set to 1)
- otherwise, if not pressed (input port 25 == 0), button status is displayed and the LED is switched off (output port 24 is set to 0)
- It keeps going until CTRL+C is pressed, then the ports are cleaned up before exit
Now YOU make it better
That’s the input/output (I/O) part sorted, now it’s over to you to improve the script. I can think of several improvements you could try to make.
- Fewer messages: Only display a message when the button status changes, rather than on every iteration of the loop.
- Light switch mode: Make it switch on the LED when the button is pressed and released once and leave it on until the button is pressed and released again. (You might need to investigate a little bit about “button debounce” if you run into difficulties)
- Flashing: Reinstate the flashing, while keeping the “on – off” light switch mode
Internal pull-ups and pull-downs
In the button circuit, we’re using resistors to “pull-down” the port. This gives it a “default” state of 0V (0, LOW, False). I mentioned in day 5 that we’d cover this in more detail, so that’s what we’re doing now.
Why are they necessary/useful?
If you have no pull-up or pull-down resistors attached to an input port, its status is not clearly defined. It is “floating”. It is susceptible to random electromagnetic radiation or static from you, from any devices near or far and from the environment. Any wires attached to the GPIO ports act as antennae for this radiation (it’s mostly radio waves).
So imagine the situation where you have a motor with a propellor on it, or one which controls Granny’s stairlift, which is controlled by a GPIO input port. If that port is susceptible to random changes of state, the propellor might spin when it shouldn’t and hurt someone. Or Granny might be sent back upstairs when she wants to be downstairs. It’s an out-of-control situation. You can easily get it under control by using pull-up or pull-down resistors, so that’s what we do.
What’s all this about internal ones then?
In our button circuit, we used resistors to pull down the voltage. This was to demonstrate the idea.
But, in fact, the Raspberry Pi has built-in pull-up and pull-down resistors which can be enabled in software. This means we can eliminate our pull-down resistors for the button – as long as we enable the internal ones.
How do you do that? RPi.GPIO to the rescue.
You enable these internal pull-ups/pull-downs at the time of setting up the port for input or output, by adding an extra, optional, argument to the GPIO.setup() function call.
We’re using pull-down, so it’s pull_up_down=GPIO.PUD_DOWN. If you want/need pull-up you can change the PUD_DOWN for PUD_UP. (It depends on how you’ve wired your circuit.)
GPIO.setup(port_or_pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
How does that apply to our program?
We’ll need to change the circuit first, to this (you could also just remove the 10k resistor to GND from the previous circuit)…
…and then, once you’ve done that, line 4 needs changing to enable the pull-down on the button port (25).
Change line 4 from…
GPIO.setup(25, GPIO.IN) # set GPIO25 as input (button)
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) # set GPIO25 as input (button)
The whole program should then look like this…
import RPi.GPIO as GPIO from time import sleep # this lets us have a time delay (see line 12) GPIO.setmode(GPIO.BCM) # set up BCM GPIO numbering GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) # set GPIO25 as input (button) GPIO.setup(24, GPIO.OUT) # set GPIO24 as an output (LED) try: while True: # this will carry on until you hit CTRL+C if GPIO.input(25): # if port 25 == 1 print "Port 25 is 1/HIGH/True - LED ON" GPIO.output(24, 1) # set port/pin value to 1/HIGH/True else: print "Port 25 is 0/LOW/False - LED OFF" GPIO.output(24, 0) # set port/pin value to 0/LOW/False sleep(0.1) # wait 0.1 seconds finally: # this block will run no matter how the try block exits GPIO.cleanup() # clean up after yourself
As you’ll see if you try it out, it works just the same as the previous version.
That was simultaneous inputs and outputs in RPi.GPIO, along with internal pull-ups/pull-downs
So now you know how to use inputs and outputs at the same time with RPi.GPIO in Python on the Raspberry Pi.
You also, hopefully understand a bit about pull-up and pull-down resistors and why they are used.
One final part to come
There’s just one more part to come on RPi.GPIO basics. It’ll be out in a day or two.
In the series so far, we’ve covered…
- How to check what RPi.GPIO version you have
- How to check what Pi board Revision you have
- How to Exit GPIO programs cleanly, avoid warnings and protect your Pi
- Setting up RPi.GPIO, numbering systems and inputs
- Setting up and using outputs with RPi.GPIO
- Using inputs and outputs at the same time with RPi.GPIO, and pull-ups/pull-downs
Part 7 can be found here…
RPi.GPIO cheat sheet