As interesting as the Raspberry Pi may be, it does not have a way to read analog inputs directly, which makes it difficult to use in some DIY projects. Luckily, working with an ADC on the RPi is really simple and easy thanks to this lesson from Adafruit.
In that tutorial, you’ll learn how to setup the MCP3008 ADC with the RPi by using SPI communication to use a potentiometer to adjust the volume of an MP3 that is currently playing. I followed the tutorial and it worked nicely but I had other ideas for this ADC.
For a long time now, I wanted to build a home-monitoring device with a bunch of analog sensors and the RPi, combined with this ADC, seems to be just the right computer for it. So, this required a small test and I decided to use two simple analog sensors to measure temperature (TMP36) and humidity (HIH4030). I followed the ADC connection diagram in the Adafruit tutorial and then connected the TMP36 and the HIH4030 to analog channels 0 and 1, respectively.
The following is the python code (adapted from the Adafruit tutorial code) that checks the analog sensors every second and calculates the right values for temperature and humidity:
#!/usr/bin/env python import time import os import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) DEBUG = 0 # read SPI data from MCP3008 chip, 8 possible adc's (0 thru 7) def readadc(adcnum, clockpin, mosipin, misopin, cspin): if ( (adcnum > 7) or (adcnum < 0) ): return -1 GPIO.output(cspin, True) GPIO.output(clockpin, False) # start clock low GPIO.output(cspin, False) # bring CS low commandout = adcnum commandout |= 0x18 # start bit + single-ended bit commandout <<= 3 # we only need to send 5 bits here for i in range(5): if (commandout & 0x80): GPIO.output(mosipin, True) else: GPIO.output(mosipin, False) commandout <<= 1 GPIO.output(clockpin, True) GPIO.output(clockpin, False) adcout = 0 # read in one empty bit, one null bit and 10 ADC bits for i in range(12): GPIO.output(clockpin, True) GPIO.output(clockpin, False) adcout <<= 1 if (GPIO.input(misopin)): adcout |= 0x1 GPIO.output(cspin, True) adcout >>= 1 # first bit is 'null' so drop it return adcout # change these as desired - they're the pins connected from the # SPI port on the ADC to the Cobbler SPICLK = 18 SPIMISO = 23 SPIMOSI = 24 SPICS = 25 # set up the SPI interface pins GPIO.setup(SPIMOSI, GPIO.OUT) GPIO.setup(SPIMISO, GPIO.IN) GPIO.setup(SPICLK, GPIO.OUT) GPIO.setup(SPICS, GPIO.OUT) # temperature sensor (TMP36) connected to adc #0 temperature_adc = 0; humidity_adc = 1; while True: # read the analog pin analog_temp_value = readadc(temperature_adc, SPICLK, SPIMOSI, SPIMISO, SPICS) analog_hum_value = readadc(humidity_adc, SPICLK, SPIMOSI, SPIMISO, SPICS) temp_voltage = (analog_temp_value * 3.3 / 1024.0) * 1000.0; temp = (temp_voltage - 500)/10; humidity = ((analog_hum_value * 12) / 75) - 26; if DEBUG: print "Temperature analog value: ", analog_temp_value print "Temperature voltage: ", temp_voltage print "Humidity analog value: ", analog_hum_value print "Temperature: ", temp print "Humidity: ", humidity print "" # hang out and do nothing for a second time.sleep(1)
Running this python script (it must be run as root, otherwise you won’t get access to the GPIO) should output something like:
Temperature: 21.865234375 Humidity: 72 Temperature: 22.1875 Humidity: 73
In case you’re wondering where those calculations for temperature and humidity came from: for temperature check this post, for humidity check this post.
UPDATE: CodingCat has left a very valuable set of comments regarding the process of obtaining exact values from the humidity sensor. Check the comments below.
I’d like to thank Filipe Valpereiro from Inmotion for providing the MCP3008 ADC for me to test. If you’re a “do-it-yourself-er” in Portugal, check their website for all kinds of components.
Line 23 contains an error. & should be replaced by &. & is the HTML representation of the ampersand.
You’re right. It’s corrected now!
I had some problems with this plugin for displaying code on wordpress and sometimes some elements appear as their html codes counterparts.
Does Orange Tux mean Line 22 instead of line 23?
Yes, in fact, it was 22.
Brilliant. This is exactly what I have been looking for.
Reading the tech specs for the humidity sensor it states that the value has to be adjusted for temperature. Have you taken that into account somewhere that I missed?
No, the processing of the values in this example is very basic. My concern wasn’t for the exact reading of the sensors, but only their connection to the Raspberry Pi.
So, further adjustments/processing may be required to get the exact values.
Thank you for posting high res pictures of your set up. I zoomed my browser way in and managed to pick up that you are indeed running everything off of the 3v line form the RPi. A little more research showed that the humidity sensor is tolerant of this (though it may lower its accuracy). Once I rewired the sensor it started showing values in the 400’s which converts to about 45% humidity which is what my AC is reporting.
I did a little digging and the tech sheet for the HIH4030 provides this equation for conversion to true humidity:
True RH = (Sensor RH)/(1.0546 – 0.00216T), T in ºC
Converted for you test code above it comes out as:
trueHumidity = humidity / (1.0546 – (0.00216 * temp))
Now for a little more digging to see if I can switch the power in the other direction and run the ADC from the 5v line of the RPi.
The answer is yes. The ADC will tolerate up to 7v. Everything is now tied to the 5v line of the RPi. And I am getting consistent results, including a spike when I exhale on the sensor.
Thanks again. 🙂
Awesome stuff. Thanks. Later, I’ll update the post to point to your findings.
Something isn’t quite right with my values. What type of numbers are you getting in from the sensor? Mine are in the 900 – 940 range. When I plug that into the equation I get a number around 120.
Perhaps I have it wired wrong. It is hard to tell from your photo’s, when you hooked up the ADC and the humidity sensors how did you power them? I have the ADC powered with the three volt line, the sensor powered with the five volt line, Vref tied to the five volt line and everything grounding to pin 6.
Does that mach your set up?
[…] the work with analog sensors on the Raspberry Pi, I decided to test the PulseSensor‘s behavior in building a pulse sensing application. […]