Chapter 3

Reading Digital and Analog Input

IN THIS CHAPTER

check Reading the status of the GPIO ports

check Building an analog-to-digital converter

check 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.

Using a GPIO Port for Digital Input

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.

warning Unlike all the other digital circuits presented in this book, including Arduino and BASIC Stamp circuits, the Raspberry Pi GPIO ports are designed to work at 3.3 V rather than 5 V. If you mistakenly connect a 5 V digital circuit to a GPIO input port, you’re likely to damage the port — and possibly fry the entire Raspberry Pi. So be careful when working with input ports to make sure that you connect only 3.3 V inputs.

warning Wow, two warnings in a row! I want to emphasize the importance of the 3.3 V versus 5 V warning by reminding you that the 40-pin GPIO header block on a Raspberry Pi has both images and images pins, and by reminding you that none of the pins on the header block are labeled on the board. The images power supplies are located on pins 2 and 4, so you must be careful to never use these pins in circuits that are connected to GPIO input ports. Instead, use pins 1 or 17, which provide images each.

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 images through R1, causing the input port to see images. As a result, the input port is HIGH when the button is pressed and LOW when the button is not pressed.

image

FIGURE 3-1: Active-high and active-low input circuits.

In the active-low circuit, the input port is connected to images through resistors R1 and R2, causing the input port to be HIGH. When the button is pressed, the current from the images 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.

technicalstuff In an active-high circuit, R1 is called a pull-down resistor because it pulls the current from the I/O pin down to zero when the push button isn’t depressed. In an active-low circuit, R1 is called a pull-up resistor because it pulls the voltage at the I/O pin up to Vdd (images) when the push button isn’t depressed.

warning Note that in both circuits, R2 is connected between the images and ground to prevent a short circuit when the button is pressed. Without this resistor, the Raspberry Pi would likely be damaged when the button is pressed.

technicalstuff You may be asking why resistors R1 and R2 are required at all in an active high. Why not just connect the input port through the push button directly to the images supply? That way, when the button is pressed, images flows into the input port, registering a HIGH condition, and when the button is not pressed, nothing is present at the input port, which would be interpreted as LOW. There are two reasons:

Checking the Status of a Switch in Python

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.

remember In Python, you can designate a GPIO port using either its internal port number or its pin number. For example, GPIO port 2 is actually connected to pin 3. Throughout this chapter, I assume that you’re using the pin numbers rather than the internal port numbers in your programs. To designate this option, you should place the following line in your program prior to any other statements that reference the ports:

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.

image

FIGURE 3-2: A circuit for testing an active-high push-button switch (Project 57).

Project 57: A Push-Button-Controlled Raspberry Pi LED Flasher

In this project, you connect a breadboard with two LEDs and a push button to a Raspberry Pi board.

image
image
image

Parts

  • One Raspberry Pi with software installed, connected to a monitor, keyboard, and mouse
  • One small solderless breadboard (RadioShack 2760003)
  • Two 5mm red LEDs (RadioShack 2760209)
  • One normally open DIP breadboard push button
  • Two images resistors (yellow-violet-brown)
  • One images resistor (brown-black-orange)
  • One images resistor (brown-black-red)
  • 6 jumper wires

Steps

  1. Insert the resistors.

    images: A13 to ground

    images: A17 to ground

    images: A5 to ground

    images: B5 to B8

  2. Insert the LEDs.

    LED

    Anode

    Cathode

    LED1

    D11

    D13

    LED2

    D15

    D17

  3. 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.

  4. Connect a jumper from A3 to the positive voltage bus on the breadboard.
  5. Connect jumpers from the breadboard to the GPIO pins on the Raspberry Pi.

    Breadboard

    GPIO Raspberry Pi Pin

    A8

    33

    A11

    35

    A15

    37

    Ground bus

    39

    Positive bus

    1

  6. 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.

Reading Analog Input

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.

image

FIGURE 3-3: Pinout for the MCP3008 analog-to-digital converter.

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 (images 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:

  • You can connect as many as eight input voltages to the MCP3008, each on pins 1 through 8. For example, suppose you want to use a potentiometer as the input for channel 0. To do that, connect one side of the potentiometer to any of the Pi’s images pins and the other side to any of the Pi’s ground pins. Then connect the center terminal of the potentiometer to pin 1 on the MCP3008. As you turn the potentiometer’s shaft, the voltage sent to the channel 0 of the MCP3008 will vary from zero to images.
  • Pin 15 provides a reference voltage, which determines the voltage range for the analog input channels. You’ll usually connect this to the images power provided by the Pi. That way, the maximum voltage of the analog input will be the same as the reference voltage: images.
  • All the analog input channels share a common ground at pin 14. This is generally connected to one of the ground pins in the Pi, as is the digital ground at pin 9 of the MCP3008.
  • The MCP3008 converts the voltage level on the analog input pin to a 10-bit binary number. A 10-bit binary number can have a maximum decimal value of 1023. Thus, the MCP3008 converts an analog input voltage to an integer between 0 and 1023.
  • The MCP3008 uses a special form of serial data communication called serial peripheral interface (SPI) to tell the Raspberry Pi what voltage levels are present on the analog inputs. SPI requires four digital ports to work, so the MCP3008 will tie up four GPIO ports on your Pi.
  • The ARM processors in the Raspberry Pi version 2 and 3 include built-in SPI capabilities, so you don’t have to worry about the details of making SPI work. Instead, you just connect the MCP3008 to the right GPIO pins and use special functions in Python to read data from the MCP3008.
  • By default, SPI communicates over the GPIO ports on pins 19, 21, 23, and 24. Although it is possible to move the SPI communications to different pins, there’s little reason to do so for most projects. So, if your project requires analog input, you’ll want to reserve ports 19, 21, 23, and 24 as communication ports for the MCP3008.
  • In case you’re interested, here are the four pins used for SPI to perform the following functions:
    • Pin 24 is the chip select pin, which is used to initiate a conversation between the MCP3008 and the Pi.
    • Pin 23 is the clock pin, which provides the timing used to send data between the MCP3008 and the Pi.
    • Pin 19 connects to the MCP3008’s data input pin and is used to transmit data one bit at a time from the Pi to the MCP3008.
    • Pin 21 connects to the MCP3008’s data output pin and is used to transmit data one bit at a time from the MCP3008 to the Pi.
  • The MCP3008 gives you an approximation of the actual voltage present on the analog input channel. The accuracy of the estimate depends on a number of complex factors. Although the approximation is close enough for most purposes, I probably wouldn’t use it to aim a laser that performs eye surgery!

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.

image

FIGURE 3-4: Using an MCP3008 to connect a potentiometer to a Raspberry Pi.

Enabling SPI on Your Raspberry Pi

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:

  1. Click the LXTerminal icon in the menu bar at the top of the Raspbian desktop.

    A terminal window opens.

  2. Enter the command sudo raspi-config.

    The Raspberry Pi Software Configuration Tool, shown in Figure 3-5, appears.

  3. Scroll down to the Advanced Options and press Enter.

    The Advanced Options page, shown in Figure 3-6, appears.

  4. Scroll down to SPI Enter.
  5. 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.

  6. Press Enter.
  7. 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.

  8. Select Finish, and then press Enter.

    You’re taken to the terminal window’s command prompt.

  9. Close the terminal window.
  10. In the Raspbian Desktop, choose Menu⇒  Shutdown, select Reboot, and press Enter.

    Your Pi restarts. When Raspbian starts back up, SPI will be enabled.

image

FIGURE 3-5: The Raspberry Pi Software Configuration Tool.

image

FIGURE 3-6: The Advanced Options page.

Using the MCP3008 in Python

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.

Using the mcp3008 Package

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 images potentiometer so that you can test the code in Listing 3-2. Figure 3-7 shows the completed circuit.

image

FIGURE 3-7: Using a potentiometer to control flashing LEDs (Project 58).

Project 58: A Variable-Rate LED Flasher

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.

image
image
image

Parts

  • One Raspberry Pi with software installed, connected to a monitor, keyboard, and mouse
  • One small solderless breadboard (RadioShack 2760003)
  • One MCP3008 analog-to-digital converter IC
  • Two 5mm red LEDs (RadioShack 2760209)
  • One images potentiometer
  • Two images resistors (yellow-violet-brown)
  • Jumper wires

Steps

  1. Insert the MCP3008 IC.

    Orient the chip so that pin 1 is in E18 and pin 16 is in F18.

  2. Insert the resistors.

    images: J8 to Ground

    images: J4 to Ground

  3. Insert the LEDs.

    LED

    Anode

    Cathode

    LED1

    G10

    G8

    LED2

    G6

    G4

  4. Insert the potentiometer.

    The pins should be inserted in A26, A28, and A30.

  5. 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

  6. Connect jumpers from the breadboard to the GPIO pins on the Raspberry Pi.

    Breadboard

    Raspberry Pi Pin

    J6

    40

    J10

    38

    J21

    23

    J22

    21

    J23

    19

    J24

    24

    Ground bus

    39

    Positive bus

    1

  7. 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.