In this edition of the WebIOPi series, I’m finally taking on the challenge of reading analog input. I briefly discussed it at the beginning of the WebIOPi IOT Part 1 – Installation & LED Blinking and finally I have now arrived at my end goal! I’ve got two new parts to introduce as well. The component in the left side of the above picture is an analog light sensor and the other two components on the right are A/D converters. By the end of this second tutorial, we’ll be able to have the Raspberry Pi read the values from the light sensor.
CdS (cadmium sulfide) light sensor is a resistor that shows a drop in electrical resistance that corresponds to the intensity of the light shining on it. Because it has properties similar to that of the human eye (highly sensitive to green light), it is an ideal sensor for all brightness levels.
The light sensor featured here is the same one that has appeared many times in our Arduino Beginner’s Series.
A light sensor (also known as a CdS cell) has a large resistance value when placed in a dark location, and a low resistance value when placed in a bright location.
The light sensor is like a resistor; it is not polarity (plus-minus) sensitive. So, you can just connect it in.
With that said, I thought to myself “Let’s get to work!”, then realized that I couldn’t use the light sensor as it is. The reason is that this light sensor is analog. The Raspberry Pi’s GPIO is digital Inputs and Outputs (I/O) so it wouldn’t be able to read the analog input values directly.
For this reason, we will use an A/D Converter.
An A/D converter is an electrical circuit that is used to convert an analog signal into a digital signal.
For instance, analog signals are smooth and continuous (like sound waves). By changing this with an A/D converter to a signal containing 0s and 1s, it becomes possible to store, repeat, and modify this information with digital equipment.
“A/D” stands for “Analog/Digital.” In the current example, the analog signal from the light sensor is passed as a digital signal that the Raspberry Pi can understand.
Either of these A/D analog input converters can be placed directly on a breadboard. The number of pins are different on each converter but they basically work the same way. For this tutorial, I will be using the MCP3208-CI/P.
There were a lot of pins I wasn’t familiar with so this proved to be difficult to wire up.
MCP3208 Pin Diagram
The names of each pin are identified on the datasheet. Make sure you check that the orientation of the pins matches the schematic in the datasheet with the notched end of the converter facing the same direction as the schematic.
Here’s the Pin Function Table that explains what each pin does.
Pin Function Table
On the left side of the table, pins 1-8 (CH0 to CH7) are for analog inputs. This side should be connected to the light sensor.
On the right side, either of VDD or VREF pins can be connected to a power source. Pin 16 –VDD– is what I’m used to connecting to my power source. Pin 15 –VREF– says it’s for “reference voltage input” on the Pin Function Table. After doing some research, it appears that this reference value (largest value) is used to calculate the value of the analog input since the values read from the analog input are not absolute. This reference value can be determined in advance (e.g. if you want to read analog inputs ranging from 0V-5V, VREF should have an input of 5V). For our purposes, 3.3V should be fine.
Pin 14 –AGND– is the ground for the analog input and pin 9 –DGND– is the ground for the digital output. So, make sure to connect each pin to the appropriate GND.
The following four pins are used for SPI serial bus: CLK, DOUT, DIN, and CS/SHIN. You often see these pins written on data sheets as SPI.
Serial Peripheral Interface (SPI) is a bus used to connect embedded devices. Compared to a parallel bus, it has fewer connection terminals and it is used with devices that have comparatively slow data transfer rates.
The pin names from the SPI documentation on the Raspberry Pi site are as follows:
SCLK – Serial CLocK
CE – Chip Enable (often called Chip Select)
MOSI – Master Out Slave In
MISO – Master In Slave Out
MOMI – Master Out Master In
MIMO – Master In Master Out
Using the above information, I tried matching up the pins for the A/D converter and the Raspberry Pi. Here’s what I ended up with:
A/D Converter | Raspberry Pi | ||
CLK | Abbreviation for CLocK | SCLK – Serial CLocK | GPIO11 |
DOUT | Abbreviation for Digital OUT. “Output” from the perspective of the A/D converter | MISO – Master In Slave Out | GPIO9 |
DIN | Abbreviation for Digital IN. “Input” from the perspective of the A/D converter | MOSI – Master Out Slave In | GPIO10 |
CS/SHIN | Abbreviation for Chip Select/Shutdown. | CE – Chip Enable (often called Chip Select) | GPIO8 |
With that, let’s get to wiring!
I connected the light sensor to CH0. Make sure you adjust the amount of the resistance while reading the real values from the sensor.
Since there are so many jumper wires and pin names, be very careful when connecting everything up. If you wire things up incorrectly, the A/D converter can get really hot and fry the breadboard.
When using an A/D converter with the Raspberry Pi, “SPI” has to be activated. The article Raspberry Pi SPI documentation explains how to set it up in raspi-config. But, there’s another way to do it using the Raspberry Pi Configuration setup screen (based on the OS: Raspbian Jessie 9/24/2015 release).
Select Preferences then Raspberry Pi Configuration from the upper left corner of the drop down menu.
Click the Interfaces tab and then change the SPI radio button to Enable.
This message is then displayed. You have to reboot in order for SPI to be activated, so click “YES” and the system will reboot.
You can change many settings on this configuration screen, which is far more convenient than doing everything from the command line.
Preparing the WebIOPi
Now, let’s move on to WebIOPi. Please refer to the following pages on the WebIOPi site for this part:
MCP3000 series SPI Analog-to-Digital Converter
Python Example – ADC (Analog-to-Digital Converter) – WebIOPi
First, let’s take care of the settings for the MCP3208. Open the WebIOPi settings file.
sudo nano /etc/webiopi/config
Add the following under [DEVICES].
mcp0 = MCP3208
If you want to set the channel you’re using, add the channel number like this.
mcp0 = MCP3208 chip:0
If left unassigned, it defaults to 0.
If a device is activated that’s not in use, it will produce an error. So, make sure to comment out unnecessary codes. (If you’re using the program for the temperature sensor from the previous entry, comment out “temp2”).
Now, let’s get to coding!
Some source code that uses the MCP3208 can be found on the WebIOPi page. There are three standard functions available for reading analog values.
Returns the integer value of the given analog channel.
REST API : GET /devices/name/analog/channel/integer
name (str) : device name from configuration file
channel (int) : analog channel number
Returns the float value of the given analog channel, from 0.0 to 1.0.
REST API : GET /devices/name/analog/channel/float
name (str) : device name from configuration file
channel (int) : analog channel number
Returns the voltage value of the given analog channel.
REST API : GET /devices/name/analog/channel/volt
name (str) : device name from configuration file
channel (int) : analog channel number
Using these functions, I wrote a program that displays the values from the light sensor.
/home/pi/webiopi_sample/python/script.py
1 2 3 4 5 6 7 8 |
import webiopi def loop(): mcp = webiopi.deviceInstance("mcp0") cds1 = mcp.analogRead(0) cds2 = mcp.analogReadFloat(0) cds3 = mcp.analogReadVolt(0) print("read: %f float: %f volt: %f" % (cds1,cds2,cds3)) webiopi.sleep(5) |
Command to start debugging
sudo webiopi -d -c /etc/webiopi/config
If you see an error like the following displayed when you start debugging, it’s possible that SPI is not activated. Check your settings once more.
No such file or directory: ‘/dev/spidev0.0’
Here are the results from the program ran above. Using the three functions, analogRead, analogReadFloat, and analogReadVolt, the program is reading values at five second intervals and printing them to the screen.
The first six lines show the values read at ordinary room brightness. Lines 7-11 show what happened when I made the lights brighter; the values got larger very quickly. Lines 12-17 show what happened when I used my finger to cover the sensor and block the light; this time, the values got very small.
As a project, it is nice to be able to determine a reference value for the brightness in some location and then program some conditional branching based on that value.
/home/pi/webiopi_sample/python/script.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import webiopi import subprocess PLAY = False RADIO_URL = 'http://yp.shoutcast.com/sbin/tunein-station.pls?id=172098'; def setup(): webiopi.sleep(15) def loop(): global PLAY, RADIO_URL mcp = webiopi.deviceInstance("mcp0") cds1 = mcp.analogRead(0) cds2 = mcp.analogReadFloat(0) cds3 = mcp.analogReadVolt(0) print("read: %f float: %f volt: %f" % (cds1,cds2,cds3)) if((cds1>1000) and (PLAY==False)): cmd = "mplayer -playlist " + RADIO_URL + " > /dev/null &" subprocess.Popen(cmd, shell=True) PLAY = True print("radio start!!!!!") elif((cds1>=1000) and (PLAY==True)): subprocess.Popen("sudo killall mplayer", shell=True) PLAY = False print("radio stop!!!!!") webiopi.sleep(1) def destroy(): subprocess.Popen("sudo killall mplayer", shell=True) |
Like the project I built previously that used a temperature sensor and a light, a simple application can be made using conditional branching corresponding to the brightness level.
What I built this time is a program that automatically plays an internet radio station based on the brightness in the room. The radio starts playing automatically when it gets bright and then automatically stops when it gets dark. It can be written entirely in Python without HTML file.
First, check the average brightness level of the location where you want to use this device and then set a reference value for determining brightness.
In the above program, I assume that the sensor is on my desk in front of a screen so I set the reference at that brightness. The value returned by the analogRead function with the display on is 1300, and 600 when turned off so I set the reference value at 1000.
For the radio, I’m using the “mplayer” package. Mplayer is explained more fully in Raspberry Radio Part 1 – Internet Radio Receiver and Remote Access.
Command to install mplayer
sudo apt-get install mplayer
When using the Raspberry Pi’s HDMI port, HDMI is automatically selected as the audio output. To specify using the stereo jack, use the following command.
Setting the audio output to the stereo jack
sudo amixer cset numid=3 1
When building a project like this, it’s convenient to set it to run automatically. If a device isn’t recognized when the program autoruns, an error will occur. So, putting a roughly 15 second sleep command in the first “setup:” section makes things work better.
Command to set up autorun
sudo update-rc.d webiopi defaults
Command to remove autorun
sudo update-rc.d webiopi remove
In this tutorial, we learned how to read analog values using Raspberry Pi. This time, the wiring was harder than WebIOPi; the amount and the placement of the resistor, etc. The values will be off if something goes wrong. It’s challenging to stabilize analog read.
This concludes the WebIOPi tutorial series. That being said, this has been my favorite project so far, and I look forward to develop new projects implementing the concept we learned here today.
If you have any comments or questions, please leave them for us at Google +. Follow us there; we will be posting more soon.