Analogue Inputs with Raspberry Pi

We have been doing a lot more work with Raspberry Pi over the last few months on some interesting projects which we will soon be covering on the REUK.co.uk website.

Raspberry Pi has an infinite number of uses and offers a great mixture of power, flexibility, and price, but it is lacking in one regard – its GPIO (general purpose input output) does not offer analogue input (ADC – analog digital converter) pins. Therefore it cannot be connected directly to non-digital temperature sensors, light detectors, or measure voltages etc. (This is in comparison to the similarly priced Beaglebone Black which offers seven  12-bit ADC pins for analogue inputs, or Arduino.)

mcp3008 10 bit adc analogue to digital converter 8 channelThere are however simple and relatively cheap ways around this, one of which we will cover here: the MCP3008 10-bit 8 channel ADC pictured above. This is a microchip which can take up to 8 analogue inputs, and communicate their digital equivalent values (0-1023) to the Raspberry Pi via the SPI serial interface.

mcp3008 board to connect to raspberry pi with light detector and other analogue inputs

Pictured above is a small board we have made with the MCP3008 at its centre. Coming in on the left side are six connections to the Raspberry Pi GPIO – 3.3V and GND power connections, and the four connections for the SPI interface.

male to female jumper links for raspberry pi

To make the connections to the GPIO we used male to female jumper links. The female end pushes over a GPIO pin, and the male end goes into a screw in terminal on our MCP3008 board.

raspberry pi GPIO analogue inputs

In order to set up the Raspberry Pi to use the SPI interface there are some commands which are required and you also need to install the SpiDev module. This is all detailed together with connection diagrams in the links to some external resources at the end of this post.

Python code for raspberry pi analogue light detector input

The above shows the simple Python script we used to measure the light level of a light detector connected to our MCP3008 board (making a voltage divider with the light detector and a 10K resistor and feeding the output voltage into channel 0 of the MCP3008 ADC chip. The script simply measures the light level once per second and outputs it to the terminal.

Python light detector on raspberry pi outputThe measured light level is given a digital value from 0-1023. As we wired it, higher values correspond to darker light levels, so the above screen shot shows the results as the light detector was slowly shaded.

Having got the digital value for the analog light level in the Raspberry Pi, you can do anything with it – control lights, detect dawn and dusk, control motorised curtains, log it, view it online and so on. It is also possible to use the exact same technique and MCP3008 to measure a huge range of other analogue signals including temperature sensors, voltage measurement, potentiometers, etc.

Here are links to some useful resources online to find out more information about reading analogue signals with a Raspberry Pi:

Analogue Sensors on the Raspberry Pi Using an MCP3008 – this offers comprehensive details on setting up the Raspberry Pi for SPI as well as connecting it to the MCP3008 and related Python scripts.

Analog Inputs for Raspberry Pi using MCP3008 – a guide from Adafruit.

MCP3008 Datasheet – get a better understanding of the ADC.

Saving IO Pins with Simple Resistor Ladder and ADC

We are currently working on a project which has been updated to require the use of a 5 position rotary selector switch (knob). Each position of this switch corresponds to one mode of operation of the full device, and so we need our microcontroller to know which of the five possible positions the switch is in at any given time.

Unfortunately, due to the amount of inputs and outputs already connected to the microcontroller (PICAXE-18M2) used in this project, there is only one spare pin left – but it is an ADC pin (analog-to-digital converter) so all is not lost.

We decided to use something along the lines of a resistor ladder (Wikipedia link), but simplified to reduce the component count as the circuit board is already pretty full.

5 position rotary selector switch resistor ladder to one ADC pin

The image above shows the selector switch with +5V going into it up the blue wire, and then the wires corresponding to each position of the switch coming down the five green wires. When in position 3 for example, +5V is present on the third green wire, and the rest of the green wires are connected to nothing.

If we had lots of spare IO on the microcontroller we could just connect each of the five switch outputs directly to five individual microcontroller pins (not forgetting to add pull down resistors).  What we instead had to do is put together the following very simple circuit.

Resistor ladder for one ADC pin and rotary selector switchWhen the switch is in position one, +5V goes straight into the ADC pin on the microcontroller. When the switch is in position two, a voltage divider (Wikipedia) is formed with Vs = +5V, a 2k2 (2,200 Ohm) resistor as R1 and a 10k resistor as R2. Therefore the ADC pin will see Vo which is Vs * (R2/(R1+R2)) = 4.10 Volts. Switch position three sends 5V through a 3k3 10k voltage divider outputting 3.76V, position four through a 5k6 10k voltage divider outputting 3.21V, and position five through a 10k 10k voltage divider outputting 2.50V.

Using the 10-bit ADC pin on the 5.00V powered microcontroller, a numerical value from 0-1023 is assigned proportional to the voltage (0-5V) arriving on the pin. So, position one (analog 5V) is given the digital value 1023, position two (4.10V) is 839, position three (3.76V) is 769, position four (3.21V) is 657, and position five (2.5V) is 512.

These calculated ADC values will not be exact as the resistance of the resistors will change a little with temperature, the 5V regulator feeding the microcontroller may fluctuate a little etc – therefore, we actually use ranges instead of exact values to work out within software which switch position is selected – e.g. position three is 769, but as position two is 839 and position four is 657, we can say that the switch is in position three if the ADC value from the arriving voltage is in the range 714 to 803.

This is all relatively simple to set up in the software – we just added a short PIcaxe subroutine called whichMode which does the readadc10 command on the relevant pin and sets a variable modeValue to the mode value (1,2,3,4 or 5) to which the ADC value corresponds.