Jul 172013
 
RasPiTV-RPi.GPIO-IOPull

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.

Circuit for combining button input and LED output with external pull-down resistor

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.

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)…

Circuit for combining button input and LED output using internal pull-down resistor

…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)

…to…

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…

  1. How to check what RPi.GPIO version you have
  2. How to check what Pi board Revision you have
  3. How to Exit GPIO programs cleanly, avoid warnings and protect your Pi
  4. Setting up RPi.GPIO, numbering systems and inputs
  5. Setting up and using outputs with RPi.GPIO
  6. 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

RasPiO® Portsplus is really useful with RPi.GPIO

The RasPiO® Portsplus board labels the GPIO ports clearly for you so that you don't need to count pins. This helps you avoid wiring errors and damage. Click the photo for more information.

RasPiO Portsplus on Pi2

  13 Responses to “RPi.GPIO basics 6 – Using inputs and outputs together with RPi.GPIO – pull-ups and pull-downs”

  1. […] Alex continues his series on the GPIO by looking at using inputs and outputs together. His insight into granny stairlifts are particularly enlightening!  Read the article here […]

  2. Another great tutorial Alex! :-) Great to see someone going to the effort of explaining all the finer details (which usually get glossed over). Might even be worth suggesting to Ben Croston that he links to these in-depth tutorials from the RPi.GPIO wiki?

    I might suggest removing the “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.” until you’ve covered button debouncing though, otherwise people will be getting very confused when their program doesn’t behave properly.
    An alternative suggestion could be adding another LED to a different GPIO, and have one LED on while the other’s off and vice-versa.

  3. I’ve just been given a Raspberry Pi, and am making first tentative steps to getting to grips with it (I date from the age of Algol and punched cards), and I wanted to thank you for your excellent series of tutorials. Very clear and logical. You have obviously put a lot of thought and hard work into them. There must be a book in there!

  4. […] I completely forgot that the button on the HDMIPi driver board had its own pull-up resistor (explanation here) so I tried to use one of the i2c ports on the Pi. These have their own hardware pullups, so I […]

  5. very good tutorial thanks

  6. Just an FYI, this still doesn’t link to the last part – unless i completely missed it.. i used the sitemap though and found it

    Side note: got anything planned for UART / serial stuff soon? – sorry I know it doesn’t belong here.

  7. If I do
    GPIO.setup(24, GPIO.OUT, pull_up_down=GPIO.PUD_DOWN)
    GPIO.output(24, 1)
    will then a current flow internally from the pin to ground even if it is not connected?

    If I do
    GPIO.setup(24, GPIO.OUT, pull_up_down=GPIO.PUD_UP)
    GPIO.output(24, 0)
    will then a current flow internally from 3.3 V to the pin even if it is not connected?

    Would these currents be 0.33 mA? It could be 5.61 mA for 17 GPIOs and 8.58 mA for 26 GPIOs, but then the internal current could be even higher for GPIO2 and GPIO3 because the internal pull-up is lower there: 1k8 corresponding to 1.83 mA per GPIO, i.e. in total 8.62 mA in the last case for 17 GPIOs, and 11.59 mA for 26 GPIOs.

    • Using pullups/downs with output ports is not usually done (although I believe it still works). I have slightly clarified the article to try and remove the ambiguity. There really shouldn’t be any need to use them on outputs because output ports are driven.

Leave a Reply