|
| 1 | +# Analogue Inputs |
| 2 | + |
| 3 | +The Raspberry Pi's GPIO pins are digital pins, so you can only set outputs to high or low, or read inputs as high or low. However, using an ADC chip (Analogue-to-Digital converter), you can read the value of analogue input devices such as potentiometers. |
| 4 | + |
| 5 | +## SPI |
| 6 | + |
| 7 | +The analogue values are communicated to the Pi using the SPI protocol. While this will work in GPIO Zero out of the box, you may get better results if you enable full SPI support. |
| 8 | + |
| 9 | +1. Open a terminal window and install the `spidev` package: |
| 10 | + |
| 11 | + ```bash |
| 12 | + sudo apt-get install python3-spidev python-spidev |
| 13 | + ``` |
| 14 | + |
| 15 | +1. Open the **Raspberry Pi Configuration** dialogue from the main menu and enable **SPI** in the **Interfaces** tab: |
| 16 | + |
| 17 | +  |
| 18 | + |
| 19 | +1. Click **OK** and reboot the Pi. |
| 20 | + |
| 21 | +## Wiring the ADC (MCP3008) |
| 22 | + |
| 23 | +The MCP3008 is an ADC providing eight input channels. The eight connectors on one side are connected to the Pi's GPIO pins, and the other eight are available to connect analogue input devices to read their values. |
| 24 | +
|
| 25 | +Place the MCP3008 chip on a breadboard and carefully wire it up as shown in the following diagram: |
| 26 | +
|
| 27 | + |
| 28 | +
|
| 29 | +Alternatively, you could use the [Analog Zero](http://rasp.io/analogzero/) board, which provides the MCP3008 chip on a handy add-on board to save you from the complicated wiring. |
| 30 | +
|
| 31 | +## Add a potentiometer |
| 32 | +
|
| 33 | +Now that the ADC is connected to the Pi, you can wire devices up to the input channels. A potentiometer is a good example of an analogue input device: it's simply a variable resistor, and the Pi reads the voltage (from 0V to 3.3V). |
| 34 | + |
| 35 | + |
| 36 | + |
| 37 | +A potentiometer's pins are ground, data, and 3V3. This means you connect it to ground and a supply of 3V3, and read the actual voltage from the middle pin. |
| 38 | +
|
| 39 | +1. Place a potentiometer on the breadboard and wire one side to the ground rail, the other to the 3V3 rail, and the middle pin to the first input channel as shown: |
| 40 | +
|
| 41 | +  |
| 42 | +
|
| 43 | +## Code |
| 44 | +
|
| 45 | +Now your potentiometer is connected and its value can be read from Python! |
| 46 | +
|
| 47 | +1. Open **Python 3** from the main menu. |
| 48 | +
|
| 49 | +1. In the shell, start by importing the `MCP3008` class from the GPIO Zero library: |
| 50 | +
|
| 51 | + ```python |
| 52 | + from gpiozero import MCP3008 |
| 53 | + ``` |
| 54 | +
|
| 55 | +1. Create an object representing your analogue device: |
| 56 | +
|
| 57 | + ```python |
| 58 | + pot = MCP3008(0) |
| 59 | + ``` |
| 60 | +
|
| 61 | + Note the `0` represents the ADC's channel 0. There are 8 channels (0 to 7), and you're using the first one. |
| 62 | +
|
| 63 | +1. Try to read its value: |
| 64 | +
|
| 65 | + ```python |
| 66 | + print(pot.value) |
| 67 | + ``` |
| 68 | +
|
| 69 | + You should see a number between 0 and 1. This represents how far the dial is turned. |
| 70 | +
|
| 71 | +1. Now read the value in a loop: |
| 72 | +
|
| 73 | + ```python |
| 74 | + while True: |
| 75 | + print(pot.value) |
| 76 | + ``` |
| 77 | +
|
| 78 | + Try twisting the dial around to see the value change. |
| 79 | +
|
| 80 | +## PWMLED |
| 81 | +
|
| 82 | +Now you've tested you can read values from the potentiometer, you should connect it to another GPIO device. |
| 83 | + |
| 84 | +1. Add an LED to your breadboard and wire it to the Pi, connecting it to GPIO pin 21: |
| 85 | + |
| 86 | +  |
| 87 | + |
| 88 | +1. In your Python code, start by importing the `PWMLED` class: |
| 89 | + |
| 90 | + ```python |
| 91 | + from gpiozero import PWMLED |
| 92 | + ``` |
| 93 | + |
| 94 | + The `PWMLED` class lets you control the brightness of an LED using PWM, or pulse-width modulation. |
| 95 | + |
| 96 | +1. Create a `PWMLED` object on pin 21: |
| 97 | + |
| 98 | + ```python |
| 99 | + led = PWMLED(21) |
| 100 | + ``` |
| 101 | + |
| 102 | +1. Test you can control the LED manually: |
| 103 | + |
| 104 | + ```python |
| 105 | + led.on() # the led should be lit |
| 106 | + led.off() # the led should go off |
| 107 | + led.value = 0.5 # the led should be lit at half brightness |
| 108 | + ``` |
| 109 | + |
| 110 | +1. Now connect the LED to the potentiometer: |
| 111 | + |
| 112 | + ```python |
| 113 | + led.source = pot.values |
| 114 | + ``` |
| 115 | + |
| 116 | +1. Turn the dial to change the LED brightness! |
| 117 | + |
| 118 | +### Source and values |
| 119 | + |
| 120 | +GPIO Zero has a powerful feature: **source and values**. Every device has a `value` property (the current value) and a `values` property (a stream of the device's values at all times). Every output device has a `source` property which can be used to set what the device's value should be. |
| 121 | + |
| 122 | +- `pot.value` gives the potentiometer's current value (it's read only, as it's an input device) |
| 123 | +- `led.value` is the LED's current value (it's read/write: you can see what it is, and you can change it) |
| 124 | +- `pot.values` is a generator constantly yielding the potentiometer's current value |
| 125 | +- `led.source` is a way of setting where the LED gets its values from |
| 126 | + |
| 127 | +Rather than continuously setting the value of the LED to the value of the potentiometer in a loop, you can just pair the two devices. Therefore the line `led.source = pot.values` is equivalent to the following loop: |
| 128 | + |
| 129 | +```python |
| 130 | +while True: |
| 131 | + led.value = pot.value |
| 132 | +``` |
| 133 | +
|
| 134 | +## Multiple potentiometers |
| 135 | +
|
| 136 | +1. Add a second potentiometer to your breadboard and connect it to the ADC's channel 1: |
| 137 | +
|
| 138 | +  |
| 139 | +
|
| 140 | +1. Now create a second `MCP3008` object on channel 1: |
| 141 | +
|
| 142 | + ```python |
| 143 | + pot2 = MCP3008(1) |
| 144 | + ``` |
| 145 | +
|
| 146 | +1. Make the LED blink: |
| 147 | +
|
| 148 | + ```python |
| 149 | + led.blink() |
| 150 | + ``` |
| 151 | +
|
| 152 | + The LED will blink continuously, one second on and one second off. |
| 153 | +
|
| 154 | +1. Change the `on_time` and `off_time` parameters to make it blink faster or slower: |
| 155 | +
|
| 156 | + ```python |
| 157 | + led.blink(on_time=2, off_time=2) |
| 158 | + led.blink(on_time=0.5, off_time=0.1) |
| 159 | + ``` |
| 160 | +
|
| 161 | +1. Now use a loop to change the blink times according to the potentiometer values: |
| 162 | +
|
| 163 | + ```python |
| 164 | + while True: |
| 165 | + print(pot.value, pot2.value) |
| 166 | + led.blink(on_time=pot.value, off_time=pot2.value, n=1, background=False) |
| 167 | + ``` |
| 168 | +
|
| 169 | + Note you have to make it blink once in the foreground, so that each iteration gets time to finish before it updates the blink times. |
| 170 | +
|
| 171 | +1. Rotate the dials to make it blink at different speeds! |
| 172 | +
|
| 173 | +1. Also try changing `blink` to `pulse` and change `on_time` and `off_time` to `fade_in_time` and `fade_out_time` so that it fades in and out at different speeds, rather than just blinking on and off: |
| 174 | +
|
| 175 | + ```python |
| 176 | + while True: |
| 177 | + print(pot.value, pot2.value) |
| 178 | + led.pulse(fade_in_time=pot.value, fade_out_time=pot2.value, n=1, background=False) |
| 179 | + ``` |
| 180 | +
|
| 181 | +1. Rotate the dials to change the effect. |
| 182 | +
|
| 183 | +## What next? |
| 184 | +
|
| 185 | +- Use potentiometers to control other GPIO Zero output devices |
| 186 | +- Use potentiometers to control the speed of motors |
| 187 | +- Use potentiometers to control the visual settings of a Camera Module in real time |
| 188 | +- Find more analogue sensors that will work with the ADC |
| 189 | +- Use potentiometers to control a player in a [PyGame Zero](http://pygame-zero.readthedocs.io) game, or in [Minecraft](https://www.raspberrypi.org/learning/getting-started-with-minecraft-pi/) |
0 commit comments