Chapter 3
IN THIS CHAPTER
Reading the status of the GPIO ports
Building an analog-to-digital converter
Using a potentiometer as input
In the previous chapter, I explain how you can use your Raspberry Pi’s GPIO ports in output mode, sending digital HIGH and LOW signals to the output ports by using the GPI.output function.
In this chapter, I turn the tables and use the GPIO ports as inputs. Here, I explain how to read a digital input from a GPIO port, which is easy because a digital input is simply HIGH or LOW. I also explain how to do something a bit more complicated: read an analog input through a digital port. This can be useful, for example, if you want to use a potentiometer as input to a Raspberry Pi. Unlike Arduino or BASIC Stamp, Raspberry Pi does not have a built-in ability to read analog input. As a result, you’ll have to construct some external circuitry to convert analog input — such as the voltage level flowing through a potentiometer — to a digital value that the Pi can use. I explain how to create and use an analog-to-digital converter in this chapter.
In Chapter 2 of this minibook, I explain how to connect an LED to a GPIO port and turn the LED on or off by using the GPIO.output function in a Python program. The GPIO.output function uses the GPIO ports as output pins by setting the status of a GPIO port to HIGH or LOW so that external circuitry (such as an LED) can react to the pin’s status. Before you can use GPIO.output, you must configure the port as an output by calling GPIO.setup, specifying GPIO.OUT as the port’s I/O mode.
But what if you want to use a GPIO port for input rather than for output? In other words, what if you want the Raspberry Pi to react to the status of an external circuit instead of the other way around? The easiest way to do that is to connect a push button to a GPIO port, and then use Python to program the port as an input port rather than as an output port. You can then use the GPIO.input function to read the status of the port.
With all the warnings out of the way, let’s look at two distinct ways of working with digital inputs connected to switches:
In other words, an active-high circuit is HIGH when the button is pressed. An active-low circuit is LOW when the button is pressed. Neither option is better than the other, but a program that works with an input port needs to know whether the input is active-high or active-low.
Figure 3-1 shows examples of both active-high and active-low push buttons. In the active-high circuit, the input port is connected to ground through resistors R1 and R2 when the push button is not pressed. Thus, the voltage at the input port is 0. When the push button is pressed, the input port is connected to through R1, causing the input port to see . As a result, the input port is HIGH when the button is pressed and LOW when the button is not pressed.
In the active-low circuit, the input port is connected to through resistors R1 and R2, causing the input port to be HIGH. When the button is pressed, the current from the source is shorted to ground through R2, causing the voltage at the input port to drop to zero. Thus, the input pin is LOW when the button is pressed and HIGH when the button is not pressed.
After you’ve connected a switch to a GPIO port, you need to know how to determine whether the switch is open or closed from a Python program. To do this, you must first designate the port as an input port by calling the GPIO.setup function. Then you can check the status of the input port by calling the GPIO.input function. The GPIO.input function returns GPIO.LOW or GPIO.HIGH depending on the current status of the input pin.
GPIO.setmode(GPIO.BOARD)
To designate a port as an input port, use the GPIO.setup function, like this:
GPIO.setup(3, GPIO.IN)
Then, to get the status of the port, you can call GPIO.input, like this:
GPIO.input(3);
You can test the status of an input port in an if statement like this:
if GPIO.input(3) == GPIO.HIGH:
print "Input is HIGH"
else:
print "Input is LOW"
Here’s an example that lights an LED on pin 5 (GPIO port 3) if the user presses the button on pin 3 (GPIO port 2) and turns the LED when the button is released:
if GPIO.input(3) == GPIO.HIGH:
GPIO.output(5, HIGH)
else:
GPIO.output(5, LOW)
Listing 3-1 shows an interesting program that works with a Raspberry Pi that has an active-high push-button switch connected to pin 33 and LEDs connected to pins 35 and 37. The program flashes the LED connected to pin 35 on and off at half-second intervals until the push-button switch is depressed. Then it flashes the LED on pin 37 as long as the button is held. When you release the button, the program returns to flashing the LED on pin 35.
LISTING 3-1 The Push-Button Program
import RPi.GPIO as GPIO
import time
BTN1 = 33
LED1 = 35
LED2 = 37
GPIO.setmode(GPIO.BOARD)
GPIO.setup(BTN1, GPIO.IN)
GPIO.setup(LED1, GPIO.OUT)
GPIO.setup(LED2, GPIO.OUT)
while True:
if GPIO.input(BTN1) == GPIO.HIGH:
GPIO.output(LED1, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(LED1, GPIO.LOW)
time.sleep(0.5)
else:
GPIO.output(LED2, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(LED2, GPIO.LOW)
time.sleep(0.5)
Project 57 shows how to build a simple circuit you can use to test the program in Listing 3-1, and Figure 3-2 shows the completed circuit.
In this project, you connect a breadboard with two LEDs and a push button to a Raspberry Pi board.
Insert the resistors.
: A13 to ground
: A17 to ground
: A5 to ground
: B5 to B8
LED |
Anode |
Cathode |
LED1 |
D11 |
D13 |
LED2 |
D15 |
D17 |
Insert the push button.
The pins should be inserted in C3, E3, C5, and E5 such that the switch opens and closes across rows 3 and 5.
Breadboard |
GPIO Raspberry Pi Pin |
A8 |
33 |
A11 |
35 |
A15 |
37 |
Ground bus |
39 |
Positive bus |
1 |
Use IDLE to enter and run the Flashing LED program (refer to Listing 3-1).
LED2 will flash on and off at half-second intervals. If you press the push button, LED1 will flash instead.
The Raspberry Pi is a purely digital machine. Unlike many microprocessors, including Arduino and BASIC Stamp, Raspberry Pi has no built-in capability for reading analog input. As a result, there’s no straightforward way to read something like a voltage level from a component such as a potentiometer, photocell, temperature sensor, or joystick.
To get around this limitation, you need to use a circuit that converts analog data to digital data. Such a circuit is called an analog-to-digital converter (ADC). There are many ways to build an ADC circuit, but the easiest way is to let someone else build the circuit for you. You can use an inexpensive IC called an MCP3008. This handy chip lets you convert as many as eight different analog inputs to a digital output, which can be read by your Raspberry Pi. You can purchase one from an online retailer for just a few dollars.
As shown in Figure 3-3, the MCP3008 is housed in a standard 16-pin package. Table 3-1 describes the 16 pins in greater detail.
TABLE 3-1 Pinouts for the MCP3008 Analog-to-Digital Converter
Pin |
Name |
What it does |
1 |
CH0 |
Analog input channel 0 |
2 |
CH1 |
Analog input channel 1 |
3 |
CH2 |
Analog input channel 2 |
4 |
CH3 |
Analog input channel 3 |
5 |
CH4 |
Analog input channel 4 |
6 |
CH5 |
Analog input channel 5 |
7 |
CH6 |
Analog input channel 6 |
8 |
CH7 |
Analog input channel 7 |
9 |
DGND |
Ground for the digital circuits |
10 |
CS |
Chip Select |
11 |
DIN |
Digital Serial Data In |
12 |
DOUT |
Digital Serial Data Out |
13 |
CLK |
Serial Clock |
14 |
AGND |
Ground for the analog inputs |
15 |
VREF |
Voltage Reference Input |
16 |
VDD |
Power supply ( to 5.5 V) |
The function of each of the 16 pins described in Table 3-1 will make more sense when you understand the following points about what the MCP3008 does and how you can use it:
Figure 3-4 shows a schematic of a typical circuit that uses an MCP3008 chip to connect a potentiometer to a Raspberry Pi. In this schematic, the potentiometer’s wiper is connected to analog input channel 0 (pin 1), and the four SPI pins of the MCP3008 are connected to the four default SPI ports on the Pi. You see a variation of this circuit used in an actual project later in this chapter.
Although the Raspberry Pi has built-in support for the SPI interface used by the MCP3008 analog-to-digital converter chip, the Raspbian operating system disables this support by default. So, before you can use the MCP3008, you must first enable SPI support in Raspbian. Here are the steps:
Click the LXTerminal icon in the menu bar at the top of the Raspbian desktop.
A terminal window opens.
Enter the command sudo raspi-config.
The Raspberry Pi Software Configuration Tool, shown in Figure 3-5, appears.
Scroll down to the Advanced Options and press Enter.
The Advanced Options page, shown in Figure 3-6, appears.
When asked if you would like the SPI interface to be enabled, select Yes and press Enter.
A confirmation screen indicates that SPI has been enabled.
When asked if you would like the SPI kernel module to be loaded by default, select Yes and press Enter.
A confirmation screen indicates that the SPI kernel module will be loaded by default.
Select Finish, and then press Enter.
You’re taken to the terminal window’s command prompt.
In the Raspbian Desktop, choose Menu⇒ Shutdown, select Reboot, and press Enter.
Your Pi restarts. When Raspbian starts back up, SPI will be enabled.
Python does not have built-in support for the MCP3008 analog-to-digital converter chip, but you can download and install a convenient package of functions named mcp3008 that will let you read an analog value from an MCP3008 chip with just a single line of Python code. Installing this package requires a few steps, but isn’t too difficult.
First, you need to make sure your Raspberry Pi can connect to the Internet. If you have a Pi 3 or a Pi 2 with a wireless USB adapter, just connect to a nearby wireless network. If you don’t have access to a wireless network, use the Ethernet connector and an Ethernet cable to plug your Pi into a wired network.
Next, you need to make sure that some key elements of your Python programming environment are up to date and properly installed. Open a terminal window (click the LXTerminal icon in the menu bar at the top of the Raspbian desktop), then enter the following commands:
sudo apt-get update
sudo apt-get dist-upgrade
sudo apt-get install build-essential
sudo apt-get install python-dev
sudo apt-get install python-smbus
sudo aptget install python-pip
Finally, enter the following command to download and install the mcp3008 package:
pip install https://pypi.python.org/packages/source/m/mcp3008/mcp3008-0.1a2.tar.gz
Note that the above command must be entered all on one line, with no line breaks. (The last part of the command, which follows the final forward slash, should be mcp3008-0.1a2.tar.gz.)
After the mcp3008 package downloads and installs, you’re ready to access the MCP3008 from your Python programs.
The mcp3008 package provides functions that let you determine the values of any or all of the input ports on an MCP3008 chip. To use these functions, you must include the following line near the top of your program:
import mcp3008
One more bit of housekeeping is required before you can read data from the MCP3008: You must create a variable that you’ll use to access the MCP3008 chip, like this:
adc = mcp3008.MCP3008
This statement creates a variable named adc that you can use to access the MCP3008.
The mcp3008 package defines eight constant values, which you use to refer to the eight analog input channels:
mcp3008.CH0
mcp3008.CH1
mcp3008.CH2
mcp3008.CH3
mcp3008.CH4
mcp3008.CH5
mcp3008.CH6
mcp3008.CH7
You use the read function to read the value of one or more analog input ports. This function uses a list of ports to be read as an argument, which means that you must enclose the input channel constants in square brackets when you call the function. For example, to read the value of input channel 0:
analog = adc.read([mcp3008.CH0])
Here, the variable analog will be set to an integer between 0 and 1023, corresponding to the voltage read by the analog input channel relative to the reference voltage.
You can read more than one input channel, like this:
analog = adc.read([mcp3008.CH0, mcp3008.CH1])
In this example, the values of channels 0 and 1 are read. The result is a list of two values, which are then stored in the analog variable. To retrieve these values separately, you’d have to slice them. For example:
analogCH0 = analog[0]
analogCH1 = analog[1]
After these statements execute, the variable analogCH0 will be set to the value of analog channel 0, and analogCH1 will be set to the value of analog channel 1.
If you want, you can read all eight of the analog channels at once by calling the read_all function, like this:
analog = adc.read_all()
This simply returns a list that contains the value for all eight of the analog channels.
Listing 3-2 shows a simple program that alternately flashes LEDs connected to pins 38 and 40. The rate at which the LEDs flash is set by a potentiometer connected to analog channel 0 of an MCP3008. As you can see, the program divides the value returned by the read function by 1023, and then uses the result as the sleep interval between flashes. Thus, as the user turns the potentiometer’s knob, the flash rate varies between 0 and one second.
LISTING 3-2 An LED Flashing Program That Uses a Pot
import RPi.GPIO as GPIO
import time
import mcp3008
LED1 = 38
LED2 = 40
GPIO.setmode(GPIO.BOARD)
GPIO.setup(LED1, GPIO.OUT)
GPIO.setup(LED2, GPIO.OUT)
adc = mcp3008.MCP3008
while True:
pot = adc.read([mcp3008.CH0])
pause = pot / 1023
GPIO.output(LED1, GPIO.HIGH)
GPIO.output(LED2, GPIO.LOW)
time.sleep(pause)
GPIO.output(LED1, GPIO.LOW)
GPIO.output(LED2, GPIO.HIGH)
time.sleep(pause)
Project 58 shows how to build a circuit that includes a potentiometer so that you can test the code in Listing 3-2. Figure 3-7 shows the completed circuit.
In this project, you connect a breadboard with two flashing LEDs and a potentiometer that controls the rate at which the LEDs flash. An MCP3008 analog-to-digital converter chip is used to interface the potentiometer to the Raspberry Pi.
Insert the MCP3008 IC.
Orient the chip so that pin 1 is in E18 and pin 16 is in F18.
Insert the resistors.
: J8 to Ground
: J4 to Ground
LED |
Anode |
Cathode |
LED1 |
G10 |
G8 |
LED2 |
G6 |
G4 |
Insert the potentiometer.
The pins should be inserted in A26, A28, and A30.
Insert the jumpers.
D18 to D28
E26 to F26
E30 to F30
J19 to the positive bus
J20 to the ground bus
J25 to the ground bus
J26 to the positive bus
J30 to the ground bus
J18 to the positive bus
Breadboard |
Raspberry Pi Pin |
J6 |
40 |
J10 |
38 |
J21 |
23 |
J22 |
21 |
J23 |
19 |
J24 |
24 |
Ground bus |
39 |
Positive bus |
1 |
Use IDLE to enter and run the Flashing LED program (see Listing 3-2).
The LEDs will alternate on and off at a rate determined by the potentiometer. When you turn the knob on the potentiometer, the rate of flashing will increase or decrease.