In an upcoming project I am using the MCP3008 to monitor several sensors. In this project I want to cover the details of using the Adafruit eTape Liquid Level Sensor on the MCP3008 8-Channel 10-Bit ADC with SPI interface with the Raspberry Pi 2, Windows 10 IoT Core and C#.
Using the MCP3008An ADC is an analog to digital converter. An analog signal is converted to a number and read into your application. The MCP3008 is a 10 bit ADC which means that it uses 10 bits to represent the value on the channel. The value will be represented as a number from 0 to 1023 (for a total 1024 possible values). This number is then converted into a meaningful value. For example, let's say I want to measure a voltage on one of the channels and the value read from the channel is 523. I know that the maximum voltage is 3.3V. The voltage on the channel is calculated using the formula
Value / Max Value * Vref
solving for my voltage I get
523 / 1023 * 3.3
which gives a value of 1.687V. I calculated this value by first normalizing the reading and then multiplying the normalized reading value by the known maximum value of 3.3V.
When getting an accurate voltage measurement is important, I highly recommend measuring the actual voltage of the Raspberry Pi and using this value in your calculations to get a more accurate conversion from the ADC. When I measured mine I found that the out put was 3.301V (the value found in the source code). Not far off the actual, however, other types of boards may vary more.
Of course, this makes sense when I want to calculate voltage, but every sensor has a different meaning. For each sensor connected to a channel on the MCP3008 I need to know the specific details and interpret the reading appropriately.
Wiring the MCP3008 is straightforward. The chip itself is marked with a notch at one end which represents pins 1 and 16 (see the data sheet here).
Pins 1 through 8 are the eight input pins and are referred to as channels 0 to 7. Channel 0 is pin 1. Pin 16 is Vdd and connects to the voltage source (either 3.3V or 5V on the Raspberry Pi). Pin 9 connects to the ground pin on the Raspberry Pi. Pins 15 and 14 are used to reference the analog circuit. Pin 15 is Vref and is used by the MCP3008 to determine what the maximum voltage on one of the channels would be. In my example I connected this pin to the 3.3V source on the Raspberry Pi. When a voltage is applied to one of the channels the MCP adjusts the reading so that 1023 represents 3.3V and 0 represents 0V. This allows the calculation I used above to work. Pin 14 is the analog ground pin. In my example I connected it to the ground pin on the Raspberry Pi. If there is a need to keep the analog circuit isolated from the digital circuit then this pin would be connected to ground on the analog circuit. The remaining four pins, 10 through 13, are the SPI Serial Interface pins used to communicate with the Raspberry Pi. The wiring diagram I have included with this projects shows how to connect these pins to the Raspberry Pi.
To see a demonstration in software of measuring voltage see the project "High Sensitivity Water Sensor on MCP3008".
Project OverviewThe Sensor
The eTape Liquid Level Sensor comes in a few varieties and sizes from Adafruit. In my project I am using the one with the Teflon jacket. The datasheet provides the basicdetails to connect the sensor and some suggestions on how to wire it.
I experimented with it in several configurations and severaltypes of circuits and found that dual voltage divider worked the best. Here aresome observations I made while experimenting:
- The output is NOT completely linear but is very close. Assuming linearity gives inaccurate readings at either the lower end or the higher end depending on how it is calibrated. Note the datasheet states the resistance is +- 20%
- Any flexing of the device or pressure applied to the device will change the response curve and will affect the reading
- The device will not remain straight in water on its own which affects the reading. The eTape device must be suspended inside of a tube to keep it straight without adding any pressure to the device. In this project I suspended the unit inside a clear polycarbonate tube with an inner diameter of 1 1/8" and an outer diameter of 1 1/4". I also tried a tube with an inner diameter of 1" but found this was just a hair to small and it affected the reading (it made it difficult to get consistent readings)
- The Teflon jacket wrapped around the Chemical version affects the curve and the reading (even without it is not linear). I ran tests with it on and then removed the jacket and reran the tests (note removing the Teflon jacket is permanent)
- Both Adafruit and the manufacturer do not recommend soldering wires directly to the device but instead using a connector. I found that the connector provided by Adafruit was difficult to attach to the pins on the eTape (the fit was not exact). I instead used four female to female jumper wires with some shrink tubing to make the connections
- As the datasheet states it is important that both sides of the sensor are exposed to the water and that the vent hole at top remains above water. I also found that for best performance, when place in a tube, the top of the tube needs to be exposed to allow the water to balance in the tube quickly; basically, leave the top of he tube open and exposed to the air in the container
- Between 0 and 1 inch the device is not very accurate and, in fact, the reading floats a little
There are four pins on the eTape Liquid level Sensor. With the pins facing up and looking at the printed side of the sensor the pins are numbered 1 o 4 from left to right. The outer pins (1 and 4) are the reference resistor (Rref
) and is used to compensate the reading for temperature variations. Since this sensor is placed directly in water that can vary greatly in temperature these two pins are very important. The inner pins, 2 and 3, are the sensor pins (Rsense
). The resistance on these pins will vary based n the depth of the water. When the device is completely removed from the water the resistance across these two pins will be somewhere between 2.2K and 2.4K Ω. When the device is submerged in water to the max line the resistance will drop to around 400 Ω.
The Circuit
The circuit I used is two simple voltage dividers; one for Rref
and the other for Rsense
. The application will use Rsense
to make adjustments to the reading from Rsense
. The output of the divider on Rsense
is connected to Channel 0 (pin 1) and the output of the Rref
voltage divider is connected to Channel 1 (pin 2).
The voltage divider circuit consists of two resistors in series between the power source and ground (or any higher and lower voltage potential). The voltage is measure from the point between the two resistors and the lower of the two voltage potential points (ground in this case). Usually, in a voltage divider circuit, both resistors are fixed. In this circuit one of the resistors will be the two pins from the eTape sensor and the other will be fixed. Since there are two sets of resistors on this sensor, Rsense
and Rref
, I am creating two separate voltage divider circuits each having a fixed resistor as the second resistor in the circuit.
Choosing the correct second resistor is important. The objective is to get the biggest voltage swing to increase accuracy as much as possible.
Increasing accuracy can be accomplished in multiple ways. Using an op-amp circuit, for example, could help to increase sensitivity on the sensor itself. Another option is to use a higher resolution ADC. I am using a 10-bit ADC that can convert the voltage to a number between 0 an 1023. A 12-bit ADC will convert the same voltage reading from 0 to 4095 and a 16-bit ADC will convert it to a value between 65,535. The more bits on the ADC (assuming greater sensitivity on the ADC) the more granularity there will be in the reading.
I chose the 10-bit ADC in this case which provides a good result and I chose a 1K Ω resistor as the secondary resistor for both voltage divider circuits. Using the standard equations for a voltage divider circuit (shown below) I used the known minimum and maximum values for Rsense
and I combined the two equations to create a third equation to calculate the voltage range for the device. I took approaches to solving fo the best R1 value. First, I plotted the values in Microsoft Excel and eyeballed the result. I have included the Excel spreadsheet as an attachment. Second, I gave the equation to a couple colleagues to get the equation by taking the differential of my primary equation (my calculus skills are a little rusty).
The graph below shows the curve when varying values of R1 in my voltage divider circuit. Based on the curve and the data, a resistor in the range of 900 Ω to 1000 Ω is the best fit. I made the decision to go with a 1K Ω resistor to make building the circuit easy since this is a standard size.
If you would like to understand how to calculate the ideal value for R1 using an equation click through the images below.
The application I created for this project is a Universal Windows Application and shows a meter in the main view. This meter shows the water level on the sensor. The software also allow for a calibration of the liquid level sensor. The link to the source code can be found near the bottom of the page.
Note the source contains several projects within a single solution. This project references the application called Water Level.
The MCP3008 LibraryThe software project also contains a separate project for interacting with the MCP3008. This code can be used in your application to easily integrate the MCP3008 chip into your projects.
To use it, first declare an class object as follows:
private Mcp3008 _mcp3008 = null;
In the OnNavigatedTo event add the following code:
_mcp3008 = new Mcp3008(0);
await_mcp3008.Initialize();
To read the voltage from channel 0 use the following line of code:
float voltage = _mcp3008.Read(Mcp3008.Channels.Single0).NormalizedValue;
Note the use of Channel.Single0
which indicates that the value is read from one channel. It is possible to specify that the device read the difference between two pins. This could be specified as Mcp3008.Channels.Differential0
which would indicate that the measurement should be taken as the different between channel 0 and channel 1 where channel 0 is positive and channel 1 is negative. The source code is document and will provide tooltips explaining each value.
When you are done using the object, typically in your OnNavigatedFrom event dispose of the object.
_mcp3008.Dispose();
_mcp3008 = null;
The solution contains a project called Windows.Devices.Sensors.Calibration
that is used to provide calibration for any sensor. It contains a linear calibration library as well as a non-linear library that uses a second order polynomial. The library works by supplying known points (calibration points) to one of the implementations and then using those points to translate the sensor reading. The linear calibration requires two points. The non-linear calibration requires 3 points. The points are collected using a calibration screen and stored in the application profile to be reloaded when the application is shutdown and restarted.
The solution contains a project called Windows.Devices.Sensors.SensorStability
that is used to determine when a sensor reading is stable. This is useful in the calibration views where the sensor changes frequently or when it takes some time to "settle down". The stability class will provide a measure of stability where the close the value is to zero the more stable the reading.
The circuit includes two voltage dividers. The first connected to the sensor output (Rsense
) an the other connected to the reference (Rref
). Both voltage dividers are connected to a channel on the ADC. The reference resistance is constants except for variations in temperature. The software uses the value read on the channel 1 (Rref
) to scale the value on read on channel 0 (Rsense
). This allows temperature variations to be canceled out because when the overall sensor resistance shifts the calibration is shifted with it keeping the sensor reading accurate.
Use this guide to assemble the circuit while using the diagram located near the bottom of the page as a guide (note the color of the wires are optional and have been selected to help make the circuit easy to follow when it is constructed).
- Place the T-shaped cobbler at the left end of the board (where the numbers start at 1). The two left most pins will be in E3 and F3 on the board. The two right most pins will be at E22 and F22
- Place the MCP3008 into E31 to E38 and F31 to F38 (the corner of the chip that has the indented circle will be placed at E31)
- Place the first 1K Ω resistor between F50 and D50
- Place the second 1K Ω resistor between F55 and D55
- Connect a red male to male jumper wire between A50 and 3.3V
- Connect a red male to male jumper wire between A55 and 3.3V
- Connect a blue male to male jumper wire between G50 and D31
- Connect an orange male to male jumper wire between G55 and D32
- Connect a red male to male jumper wire between H31 and 3.3V
- Connect a red male to male jumper wire between G32 and 3.3V
- Connect a black male to male jumper wire between G33 and Ground
- Connect a black male to male jumper wire between G38 and Ground
- Connect an orange male to male jumper wire between J37 and J14
- Connect a white male to male jumper wire between J36 and B12
- Connect a yellow male to male jumper wire between J35 and A13
- Connect a green male to male jumper wire between J34 and B14
- Cut two yellow wires about 6.5 feet in length each
- Connect the female end of a yellow female to female jumper wire on Pin 1 of the sensor
- Strip about 1 cm from the end of one of the yellow wires and push the exposed wire into the female end of the yellow jumper wire that is connected to Pin 1 on the sensor. Secure the wire
- Place the other end of this long yellow wire into the female end of a yellow male to female jumper. Secure the wire
- Connect the female end of the second yellow female to female jumper wire on Pin 4 of the sensor
- Strip about 1 cm from the end of the second yellow wire and push the exposed wire into the female end of the yellow jumper wire that is connected to Pin 4 on the sensor. Secure the wire
- Place the other end of this long yellow wire into the female end of a yellow male to female jumper. Secure the wire
- Cut two green wires about 6.5 feet in length each
- Connect the female end of a green female to female jumper wire on Pin 2 of the sensor
- Strip about 1 cm from the end of one of the green wires and push the exposed wire into the female end of the green jumper wire that is connected to Pin 2 on the sensor. Secure the wire
- Place the other end of this long green wire into the female end of a green male to female jumper. Secure the wire
- Connect the female end of the second green female to female jumper wire on Pin 3 of the sensor
- Strip about 1 cm from the end of the second green wire and push the exposed wire into the female end of the green jumper wire that is connected to Pin 3 on the sensor. Secure the wire
- Place the other end of this long green wire into the female end of a green male to female jumper. Secure the wire
- Slip the four wires connected to the sensor through one end of the clear polycarbonate tubing and carefully pull the eTape sensor through the tube until the bottom of the eTape sensor is even with the edge of the tube. Ensure that the eTape is not twisted or bent in the tube (make it a straight as possible)
- Connect the male end of the green jumper wire from Pin 2 of the sensor to J50
- Connect the male end of the green jumper wire from Pin 3 of the sensor to Ground
- Connect the male end of the yellow jumper wire from Pin 1 of the sensor to J55
- Connect the male end of the yellow jumper wire from Pin 4 of the sensor to Ground
- Place the tube containing the sensor into the graduated cylinder and fill it with water so that the sensor can be submerged in the water up to the max line
Securing the Long Wires
Use a small piece of electrical tape to keep the long wires in the jumper wire ends. Optionally shrink tubing can be used to keep the wires from disconnecting. After pushing the wire into the end of the jumper, press down on the small exposed tab inside of the plastic housing at the end of the jumper (using a very small flat head screw driver). This will clamp the wire and ensure it never comes out.
Below are photos of the circuit I built.
The following steps will turn the assembly of the 4x 6.5' wires, the 8x jumper wires, the clear polycarbonate tube and the eTape Liquid Level sensor into a single unit.
First, the tube I purchased from Amazon was 3' in length. I cut this down to a 2' length. I used a miter saw to do the cutting but any sharp aw will work. I found that putting some painters tape around the portion of the tube to be cut will protect it from being scratch. Just cut slow and evenly to get a clean perfect cut.
In addition to the steps to assemble the wires on the sensor I made a more permanent construction using a few more pieces of shrink tubing and a zip tie. First, I cut a small 2 cm piece of 3/8" tubing and shrunk it around the four wires on the sensor end. This helps keep them attached without physically altering the sensor. From this point I used a 4" piece of 3/16" tubing from the end of the sensor around the jumper wires to keep them together and give them more strength. This also leaves enough of the four wires uncovered so they can be looped inside he tube. The loop allows the sensor and wires to be placed into the tube in a manner that does not apply pressure to the sensor (works like a small spring) into. As indicated in the instructions I shrunk individual 1/16" pieces of tubing around each junction of the wire and female jumper ends (8 in total). I then shrunk 3/16" tubing along the entire length of the 6.5' wires. I had to purchase these in 3' lengths and use multiple pieces.
In one end of the tube I carefully drilled to 3/16" holes about 75 mm apart. I slipped a small zip tie into the holes and attached it around a portion of the wires that has been wrapped in the 3/16" tubing. This will prevent the sensor from inadvertently being pulled out of the tube as well as keep it from being moved around inside the tube when the wires are being connected and disconnected. As a final step I took a 2.5" of 1 1/2" tubing and shrunk it around the upper edge of the clear polycarbonate tube to cover the zip tie.
The photos below show the final result of constructing a single sensor unit.
In my construction I used orange and brown female to female jumpers on the connections to the eTape sensor (mainly because I did not have enough yellow and green). I recommend yellow and green in the directions to help eliminate the possibility of mis-wiring the unit. Note the color of the wires does not make a differenceStarting the Application
Right click the project named Water Level in the solution and click Set as Startup Project
.
Choose Debug
, ARM
configuration and Remote Machine
. Now right-click the project, and select Property and then click Debug tag. Next put the Raspberry Pi 2 IP address in the Remote machine field, and uncheck Use authentication.
Press F5. The application will deploy to the device which may take a few minutes the first time.
The video below is a demonstration the application:
View this video in You Tube using Theater mode for best quality.
Comments