Chapter 8. Analog Input and Output

In Chapter 6, you learned about digital inputs and outputs with buttons, switches, LEDs, and relays. Each of these components was always either on or off, never anything in between. However, you might want to sense things in the world that are not necessarily one or the other—for instance, temperature, distance, light levels, or the status of a dial. These all come in a range of values.

Or you may want to put something in a state that’s not just on or off. For example, if you wanted to dim an LED or control the speed of a motor rather than just turning it on or off. To make an analogy for analog and digital, you can think of a typical light switch versus a dimmer switch, as pictured in Figure 8-1.

gsrp 1001
Figure 8-1. Digital is like the switch on the left: it can be either on or off. Analog, on the other hand, can be set at a range of values between fully on and completely off.

Output: Converting Digital to Analog

Just as in Chapter 7, you’ll use the GPIO Python module already installed in the most recent versions of Raspbian Linux. The module has experimental functions for controlling the GPIO pins, sort of like a dimmer switch.

We say that it’s “sort of” like a dimmer switch because the module uses a method called pulse-width modulation, or PWM, to make it seem like there’s a range of voltages coming out of its outputs. What it’s actually doing is pulsing its pins on and off really quickly. So if you want the pin to behave as though it’s at half voltage, the pin will be pulsed so that it is on 50% of the time and off 50% of the time. If you want the pin to behave as though it’s at 20% power, the Raspberry Pi will turn the pin on 20% of the time and off 80% of the time. The percentage of time that it’s on versus total time of the cycle is called the duty cycle (Figure 8-2). When you connect an LED to these pins and instruct the Raspberry Pi to change the duty cycle, it has the effect of dimming the LED.

gsrp 1002
Figure 8-2. The duty cycle represents how much time the pin is turned on over the course of an on-off cycle

Test-Driving PWM

For the next few steps, we’ll assume you’re using the desktop environment, but feel free to use the command line to write and execute these Python scripts if you prefer:

  1. Connect an LED to pin 25 as you did in “Beginner’s Guide to Breadboarding”.

  2. Open the File Manager by clicking its icon in the taskbar.

  3. Be sure you’re in the home directory, the default being /home/pi. If not, click on the home icon under the Places listing.

  4. Create a file in your home directory called blink.py. Do this by right-clicking in the home directory window, going to “Create New” and then clicking “Blank File.” Name the file fade.py.

  5. Double-click on fade.py to open it in Leafpad, the default text editor.

  6. Enter the following code and save the file:

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(25, GPIO.OUT)

p = GPIO.PWM(25, 50) 1
p.start(0) 2

while True:
   for dc in range(0, 100, 5): 3
      p.ChangeDutyCycle(dc) 4
      time.sleep(0.05)
   for dc in range(100, 0, -5): 5
      p.ChangeDutyCycle(dc)
      time.sleep(0.05)
1

Create a PWM object called p and set it to GPIO pin 25 with a frequency of 50 Hz.

2

Start PWM on p.

3

Run the indented code below this line, each time incrementing the value of dc by 5 from starting at 0 and going to 100.

4

Set the duty cycle of p to the value of dc.

5

Run the indented code that follows, each time decrementing the value of dc by 5 from starting at 100 and going to 0.

  1. Open LXTerminal, then use these commands to make sure the working directory is your home directory, and execute the script:

    pi@raspberrypi ~/Development $ cd ~
    pi@raspberrypi ~ $ python fade.py
    
    
  2. Your LED should now be fading up and down!

  3. Press Ctrl-C to stop the script and return to the command line.

Note
If you’re accustomed to using PWM on a microcontroller like the Arduino, you’ll find that—unlike Arduino—there is unsteadiness in the PWM pulses from the Raspberry Pi. This is because in this example, you’re using the CPU to turn the LED on and off. Because that CPU is used for multiple things at one time, it may not always keep perfect time. You can always reach for other hardware like Adafruit’s PWM/Servo Driver if you need to have more precise control.

Taking PWM Further

With the ability to use pulse-width modulation to fade LEDs up and down, you could also connect an RGB LED and control the color by changing the brightness of its red, green, and blue elements.

Pulse-width modulation can also be used to control the speed of a direct current motor that’s connected to your Raspberry Pi through transistors. The position of the shaft on a hobby servo motor (the kind that steer RC cars) can also be controlled with specific pulses of electricity. Though, keep in mind that you may need additional hardware and power in order to control these motors with a Raspberry Pi.

Input: Converting Analog to Digital

Just like you controlled the output of a GPIO pin on a scale of 0 to 100, it’s also possible to read sensors that can offer the Raspberry Pi a range of values. If you want to know the temperature of a room, the light level, or the amount of pressure on a pad, you can use various sensors. On a microcontroller like the Arduino, there’s special hardware to convert the analog voltage level to digital data. Unfortunately, your Raspberry Pi doesn’t have have this hardware built in.

To convert from analog to digital, this section will show you how to use an ADC, or analog-to-digital converter. There are a few different models of ADCs out there, but this chapter will use the ADS1x15 from Texas Instruments. The package of the ADS1x15 chip is too small for your standard breadboard, so Adafruit Industries has created a breakout board for it, shown in Figure 8-3. Once you’ve soldered header pins to the breakout board, you can prototype with this chip in your breadboard. The chip uses a protocol named Inter-Integrated Circuit (commonly called I2C) for transmitting the analog readings. Luckily, we don’t need to understand the protocol in order to use it. Adafruit provides an excellent open source Python library to read the values from the ADS1115 or its little brother, the ADS1015, via I2C.

To connect the ADS1115 or ADS1015 breakout to your Raspberry Pi:

  1. Connect the 3.3 volt pin from the Raspberry Pi to the positive rail of the breadboard. Refer to Figure 6-2 for pin locations on the Raspberry Pi’s GPIO header.

  2. Connect the ground pin from the Raspberry Pi to the negative rail of the breadboard.

  3. Insert the ADS1x15 into the breadboard and use jumper wires to connect its VDD pin to the positive rail and its GND pin to the negative rail.

  4. Connect the SCL pin on the ADS1x15 to the SCL pin on the Raspberry Pi. The SCL pin on the Pi is the one paired with the ground pin on the GPIO header.

  5. Connect the SDA pin on the ADS1x15 to the SDA pin on the Raspberry Pi. The SDA pin is in between the the SCL pin and the 3.3 volt pin.

gsrp 1003
Figure 8-3. The ADS1015 analog-to-digital converter breakout from Adafruit

Now you’ll need to connect an analog sensor to the ADS1x15. There are many to choose from, but for this walk-through, you’ll use a 2K potentiometer so that we can have a dial input for your Raspberry Pi. A potentiometer, or pot, is essentially a variable voltage divider, and can come in the form of a dial or slider.

Note
The value of the potentiometer you use doesn’t have to be 2K. If you only have a 10K or 1M potentiometer, it will work just fine.

To connect a potentiometer to the ADS1x15:

  1. Insert the potentiometer into the breadboard.

  2. The pot has three pins. Connect the middle pin to pin A0 in on the ADS1x15.

  3. One of the outside pins should connect to the positive rail of the breadboard. For now, it doesn’t matter which.

  4. Connect the other outside pin to the negative rail of the breadboard.

The connections should look as shown in Figure 8-4.

gsrp 1004
Figure 8-4. Using the ADS1x15 to connect a potentiometer to the Raspberry Pi

Before you can read the potentiometer, you’ll need to enable I2C and install a a few things (see Figure 8-5):

gsrp 1008
Figure 8-5. Enabling the I2C interface
  1. Open up the Raspberry Pi Configuration tool by clicking on Menu→Preferences→Raspberry Pi Configuration.

  2. Click the Interfaces tab.

  3. Next to I2C, click Enable.

  4. Click OK and reboot your Raspberry Pi.

  5. Open up a Terminal window and update your list of packages:

    $ sudo apt-get update
    
  6. Install i2c-tools tools:

    $ sudo apt-get install i2c-tools
    
  7. Restart your Raspberry Pi.

  8. After you’ve restarted your Raspberry Pi, test that the Raspberry Pi can detect the ADS1x15 with the command:

    $ sudo i2cdetect -y 1
    
  9. If the board is recognized, you’ll see the number in the grid that is displayed:

         0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
    00:          -- -- -- -- -- -- -- -- -- -- -- -- --
    10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
    50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    70: -- -- -- -- -- -- -- --
    
  10. Now that we know that the device is connected and is recognized by our Pi, it’s time to start reading the potentiometer. To do so, download the Raspberry Pi Python library from Adafruit’s code repository into your home folder. Type the following command at the shell prompt, all on one line with no spaces in the URL:

    wget https://github.com/adafruit/Adafruit_Python_ADS1x15/
      archive/master.zip
  11. Unzip it:

    $ unzip master.zip
    
  12. Change to the library’s ADS1x15 directory:

    $ cd Adafruit_Python_ADS1x15-master/
    
  13. Install the library:

    $ sudo python setup.py install/
    
  14. Run one of the example files:

    $ python examples/simpletest.py
    
  15. Turn the potentiometer all the way in one direction and back in the other. Notice how the value in the pin 0 column changes:

    Reading ADS1x15 values, press Ctrl-C to quit...
    |      0 |      1 |      2 |      3 |
    -------------------------------------
    |      0 |   4320 |   4496 |   4528 |
    |      0 |   4224 |   5104 |   4432 |
    |      0 |   4352 |   4688 |   5104 |
    |   6128 |   4640 |   4384 |   5552 |
    |  10928 |   4592 |   4592 |   5056 |
    |  18736 |   4384 |   4992 |   4384 |
    |  23312 |   4496 |   4912 |   4784 |
    |  26512 |   4912 |   4800 |   5968 |
    |  25968 |   4816 |   4800 |   5008 |
    |  16528 |   4416 |   4928 |   4928 |
    |   9280 |   4656 |   4416 |   5312 |
    |   2688 |   4240 |   5008 |   4464 |
    |      0 |   4384 |   4352 |   5360 |
    |      0 |   4336 |   4624 |   4272 |
    |      0 |   4256 |   4432 |   4592 |
    
  16. Press Ctrl-C to terminate the script.

As you can see, turning the dial on the potentiometer changes the voltage coming into channel 0 of the ADS1x15. The code in the example does a little bit of math to determine the voltage value from the data coming from the ADC. Of course, your math will vary depending on what kind of sensor you use.

You can look inside that example script to see how it works, or try out the even simpler example that follows to learn how to take readings from the ADC. Create a new file with the code from Example 8-1 and execute it.

Example 8-1. Writing the code to read the ADC
from Adafruit_ADS1x15 1
from time import sleep

adc = Adafruit_ADS1x15.ADS1115() 2

while True:
   result = adc.read_adc(0) 3
   print result
   sleep(.5)
1

Import Adafruit’s ADS1x15 library.

2

Create a new ADS1x15 object called adc.

3

Get a reading from channel A0 on the ADS1x15 and store it in result.

When you run this code, it will output out raw numbers for each reading twice a second. Turning the potentiometer will make the values go up or down.

Once you get it all set up, the Adafruit ADS1x15 library does all the hard work for you and makes it easy to use analog sensors in your projects. For instance, if you want to make your own Pong-like game, you could read two potentiometers and then use Pygame to draw on the game on screen. For more information about using Pygame, see Chapter 4.

Variable Resistors

Not all analog sensors work like the potentiometer, which provides a variable voltage based on some factor (such as the amount the dial on the pot is turned).

Some sensors are simply variable resistors that resist the flow of electricity based on some factor. For instance, a photocell like the one in Figure 8-6 will act like a resistor that changes values based on the amount of light hitting the cell. Add more light, and the resistance goes down. Take away light, and the resistance goes up. A force-sensitive resistor decreases its resistance as you put pressure on the pad.

gsrp 1005
Figure 8-6. The photocell and force-sensitive resistors act as variable resistors and can be used as analog inputs

In order to read sensors like these with analog input pins, you’ll need to incorporate a voltage divider circuit.

Voltage Divider Circuit

When you’re working with sensors that offer variable resistance, the purpose of a voltage divider is to convert the variable resistance into a variable voltage, which is what the analog input pins are measuring. First, take a look at a simple voltage divider.

In Figure 8-7, you’ll see two resistors of the same value in series between the positive and ground and one wire connected to analog input 0 between the two resistors. Because both resistors are 10K ohms, there’s about 1.65 volts going to analog input 0, half of 3.3 volts.

gsrp 1006
Figure 8-7. With two of the same value resistors between voltage and ground, the voltage between the two would be half of the total voltage

Without getting bogged down in the math involved, if you removed the 10K resistor connected to 3.3 volts and replaced it with a resistor of a higher value, the voltage going into the analog pin would decrease. If you removed that 10K resistor and replaced it with one of a lower value, the voltage going into the analog pin would increase. We can use this principle with sensors that are variable resistors in order to read them with the analog input pins. You’ll simply replace one of the resistors with your sensor.

To try the circuit out, you’ll have to wire up a type of variable resistor called a force-sensitive resistor, or FSR.

Force-Sensitive Resistor

A force-sensitive resistor is a variable resistor that changes based on the amount of pressure placed on its pad. When there’s no pressure on the pad, the circuit is open. When you start placing pressure on it, the resistance drops.

The exact figures will depend on your particular FSR, but typically you’ll see 100K ohms of resistance with light pressure and 1 ohm of resistance with maximum pressure. If you have a multimeter, you can measure the changes in resistance to see for yourself, or you can look at the component’s datasheet, which will tell you what to expect from the sensor.

If you’re going to replace the resistor connected to 3.3 volts in Figure 8-7 with a variable resistor like an FSR, you’ll want the value of the other resistor to be somewhere in between the minimum and maximum resistance so that you can get the most range out of the sensor. For a typical FSR, try a 10K ohm resistor. To give the force-sensitive resistor a test drive:

  1. Wire up an FSR to the ADC as shown in Figure 8-8.

  2. Execute the code in Example 8-1 again.

  3. Watch the readings on the screen as you squeeze the FSR.

If everything is working correctly, you should see the values rise as you increasingly squeeze harder on the FSR. As you press harder, you’re reducing the resistance between the two leads on the FSR. This has the effect of sending higher voltage to the analog input.

You’ll encounter many analog sensors that use this very same principle, and a simple voltage divider circuit, along with an analog-to-digital converter, will allow your Raspberry Pi to capture that sensor data.

gsrp 1007
Figure 8-8. Wiring up a force-sensitive resistor to the ADC requires a voltage divider circuit

Going Further

Controlling a DC Motor with PWM

Adafruit has an excellent guide that teaches you how to use PWM to control the speed of a DC motor.

Reading Resistive Sensors with RC Timing

Adafruit also shows you how to use a simple circuit to read resistive analog sensors without an analog-to-digital converter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset