Hey! This is a really old article. You should really be using gpiozero these days.
I hadn’t realised it, but the The Quite Rubbish Clock did something that a lot of people seem to have trouble with on the Raspberry Pi: communicating using hardware SPI. Perhaps it’s because everything is moving so fast with Raspberry Pi development, tutorials go out of date really quickly. Thankfully, hardware SPI is much easier to understand than the older way of emulation through bit-banging.
SPI is a synchronous serial protocol, so it needs a clock line as well as a data in and data out line. In addition, it has a Chip Enable (CE, or Chip Select, CS) line that is used to choose which SPI device to talk to. The Raspberry Pi has two CE lines (pins 24 and 26) so can talk to two SPI devices at once. It supports a maximum clock rate of 32 MHz, though in practice you’ll be limited to the rate your device supports.
The device I’m testing here is an MCP3008 10-bit Analogue-to-Digital Converter (ADC). These are simple to use, cheap and quite fast converters with 8 input channels. If you hook them up to a 3.3 V supply they will convert a DC voltage varying from 0-3.3 V to a digital reading of 0-1023 (= 210 – 1). Not quite up there in quality for hi-fi audio or precision sensing, but good enough to read from most simple analogue sensors.
The sensor I’m reading is the astonishingly dull LM35DZ temperature sensor. All the cool kids seem to be using TMP36s (as they can read temperatures below freezing without a negative supply voltage). One day I’ll show them all and use a LM135 direct Kelvin sensor, but not yet.
To run this code, install the SPI libraries as before. Now wire up the MCP3008 to the Raspberry Pi like so:
MCP 3008 Pin Pi GPIO Pin # Pi Pin Name ============== =============== ============= 16 VDD 1 3.3 V 15 VREF 1 3.3 V 14 AGND 6 GND 13 CLK 23 GPIO11 SPI0_SCLK 12 DOUT 21 GPIO09 SPI0_MISO 11 DIN 19 GPIO10 SPI0_MOSI 10 CS 24 GPIO08 CE0 9 DGND 6 GND
The wiring for the LM35 is very simple:
LM35 Pin MCP3008 Pin ========== ============= Vs 16 VDD Vout 1 CH0 GND 9 DGND
The code I’m using is a straight lift of Jeremy Blythe’s Raspberry Pi hardware SPI analog inputs using the MCP3008. The clever bit in Jeremy’s code is the
readadc() function which reads the relevant length of bits (by writing the same number of bits; SPI’s weird that way) from the SPI bus and converting it to a single 10-bit value.
#!/usr/bin/python # -*- coding: utf-8 -*- # mcp3008_lm35.py - read an LM35 on CH0 of an MCP3008 on a Raspberry Pi # mostly nicked from # http://jeremyblythe.blogspot.ca/2012/09/raspberry-pi-hardware-spi-analog-inputs.html import spidev import time spi = spidev.SpiDev() spi.open(0, 0) def readadc(adcnum): # read SPI data from MCP3008 chip, 8 possible adc's (0 thru 7) if adcnum > 7 or adcnum < 0: return -1 r = spi.xfer2([1, 8 + adcnum << 4, 0]) adcout = ((r & 3) << 8) + r return adcout while True: value = readadc(0) volts = (value * 3.3) / 1024 temperature = volts / (10.0 / 1000) print ("%4d/1023 => %5.3f V => %4.1f °C" % (value, volts, temperature)) time.sleep(0.5)
The slightly awkward code
temperature = volts / (10.0 / 1000) is just a simpler way of acknowledging that the LM35DZ puts out 10 mV (= 10/1000, or 0.01) per °C. Well-behaved sensors generally have a linear relationship between what they indicate and what they measure.
If you run the code:
you should get something like:
91/1023 => 0.293 V => 29.3 °C 93/1023 => 0.300 V => 30.0 °C 94/1023 => 0.303 V => 30.3 °C 95/1023 => 0.306 V => 30.6 °C 96/1023 => 0.309 V => 30.9 °C 97/1023 => 0.313 V => 31.3 °C 97/1023 => 0.313 V => 31.3 °C 98/1023 => 0.316 V => 31.6 °C 99/1023 => 0.319 V => 31.9 °C 99/1023 => 0.319 V => 31.9 °C 100/1023 => 0.322 V => 32.2 °C 100/1023 => 0.322 V => 32.2 °C 100/1023 => 0.322 V => 32.2 °C 101/1023 => 0.325 V => 32.5 °C 101/1023 => 0.325 V => 32.5 °C 102/1023 => 0.329 V => 32.9 °C 102/1023 => 0.329 V => 32.9 °C 103/1023 => 0.332 V => 33.2 °C
Note that the sensor had been sitting over the Raspberry Pi’s CPU for a while; I don’t keep my house at 29 °C. I made the temperature go up by holding the LM35.
So, you’ve just (fairly cheaply) given your Raspberry Pi 8 analogue input channels, so it can behave much more like a real microcontroller now. I remember from my datalogging days that analogue inputs can be pretty finicky and almost always return a value even if it’s an incorrect one. Check the chip’s datasheet to see if you’re doing it right, and if in doubt, meter it!