These chips are analogue to digital converters with 8 inputs, they can read values from POT's, NTC sensors and other resistive passive sensors. The MCP3008 is 10 bit resolution and the MCP3208 is 12 bit resolution. There is also MCP3004 and MCP3204 these are the same but with 4 inputs. To connect to the Raspberry PI you need to enable the SPI (Serial Peripheral Interface) chip interface. The chip reads eight parallel inputs and converts them to a serial data stream. It is possible to chain more than one chip using this interface to increase the amount of inputs or use the another chip for outputs (74HC595) or digital inputs (74HC165).
Install and enable the SPI interface
- First make sure the system is up to date
sudo apt-get update
sudo apt-get upgrade
sudo reboot - To install the development software that includes spi_dev type the following command. Note:Raspberry PI needs internet connection for this to work.
sudo apt-get install python-dev python3-dev
The command will indicate the package size before installing. Then install the spidev for Pyhon with the below commands.
cd ~
git clone https://github.com/doceme/py-spidev.git
cd py-spidev
make
sudo make install - Enable the SPI interface
- sudo raspi-config select Advanced the enable SPI and set to load by default.
- Reboot the Raspberry PI
- sudo reboot
- To check that the interface is enabled type lsmod and check that spi_bcm2835 is listed.
Chip connections
MCP3004/ MCP3204
|
MCP3008/ MCP3208
|
Signal
|
Description
|
1
|
1
|
CH0
|
Analogue Input 1
|
2
|
2
|
CH2
|
Analogue Input 2
|
3
|
3
|
CH2
|
Analogue Input 3
|
4
|
4
|
CH3
|
Analogue Input 4
|
-
|
5
|
CH4
|
Analogue Input 5
|
-
|
6
|
CH5
|
Analogue Input 6
|
-
|
7
|
CH6
|
Analogue Input 7
|
-
|
8
|
CH7
|
Analogue Input 8
|
5
|
-
|
NC
|
No Connection
|
6
|
-
|
NC
|
No Connection
|
7
|
9
|
DGND
|
Digital Ground
|
8
|
10
|
CS/SHDN
|
Chip Select/Shut Down
|
9
|
11
|
DIN
|
Digital Serial Input
|
10
|
12
|
DOUT
|
Digital Serial Output
|
11
|
13
|
CLK
|
Clock
|
12
|
14
|
AGND
|
Analogue Input Ground
|
13
|
15
|
VREF
|
Reference Voltage
|
14
|
16
|
VDD
|
Positive Supply Voltage
|
Chip Communication
The input values are read and stored in chip addresses continuously. CLK is the clock for communication timing. The CS pin starts high then pulled low to enable to chip data to be read. The address of the input to be read is sent to DIN (MSB IN) and the requested data is sent to DOUT (MSB OUT) after a null data bit. The output of the MCP3008/4 will be 0 to 3FF hex and the MCP3208/4 output will be form 0 to FFF hex. For more details download the detailed data sheets MCP3004, MCP3008, MCP3204, MCP3208.
Wiring Connections
The wiring drawing shows the MCP3008 connections. Connections to all the chips are listed in table below:-
MCP3004/ MCP3204
|
MCP3008/ MCP3208
|
Signal
|
Description
|
GPIO
|
RPI Pin
|
1
|
1
|
CH0
|
10K NTC Sensor
|
-
|
-
|
2
|
2
|
CH1
|
10K POT
|
-
|
-
|
7
|
9
|
DGND
|
Digital Ground
|
GND
|
6
|
8
|
10
|
CS/SHDN
|
Chip Select/Shut Down
|
CS0
|
24
|
9
|
11
|
DIN
|
Digital Serial Input
|
MISI
|
19
|
10
|
12
|
DOUT
|
Digital Serial Output
|
MISO
|
21
|
11
|
13
|
CLK
|
Clock
|
SCLK
|
23
|
12
|
14
|
AGND
|
Analogue Input Ground
|
GND
|
6
|
13
|
15
|
VREF
|
Reference Voltage
|
3.3 Volts
|
1
|
14
|
16
|
VDD
|
Positive Supply Voltage
|
3.3 Volts
|
1
|
The drawing shows just two inputs connected. A 10KΩ POT is connected to GND and 3.3 volts and the wiper is connected to the analogue input 2. Wiring a sensor requires a resistor of the same value as the sensors reference value in this case 10KΩ. The sensor is connected to analogue input 1 and GND and the resistor is also connected to input 2 and 3.3 volts.
Python Code
import spidev
import time
import math
spi = spidev.SpiDev()
import math
spi.open(0,0)
#Read SPI Sensor input 0 to 7 for MCP3008
def ReadInput(Sensor):
adc = spi.xfer2([1,(8+Sensor)<<4,0])
data = ((adc[1]&3) << 8) + adc[2]
return data
#Read SPI Sensor input 0 to 7 for MCP3008
def ReadInput(Sensor):
adc = spi.xfer2([1,(8+Sensor)<<4,0])
data = ((adc[1]&3) << 8) + adc[2]
return data
#Convert Voltage to Resistance
def VoltToOhm(V):
Rd = 10000
Rd_effective =(Rd * 16800.0) / (Rd + 16800.0)
Ohm = (3.3 - V) / V * Rd_effective
return Ohm
#Convert resistance to temperature
def OhmToCelsius(ohms):
#NTC Sensor Characteristics
A = 0.00335401643468053
B = 0.0002744032
C = 0.000003666944
D = 0.0000001375492
r = math.log(ohms/10000.0)
temp = 1.0 / (A + B*r + C*r**2 + D*r**3)
temp = temp - 273.15
return temp
def VoltToOhm(V):
Rd = 10000
Rd_effective =(Rd * 16800.0) / (Rd + 16800.0)
Ohm = (3.3 - V) / V * Rd_effective
return Ohm
#Convert resistance to temperature
def OhmToCelsius(ohms):
#NTC Sensor Characteristics
A = 0.00335401643468053
B = 0.0002744032
C = 0.000003666944
D = 0.0000001375492
r = math.log(ohms/10000.0)
temp = 1.0 / (A + B*r + C*r**2 + D*r**3)
temp = temp - 273.15
return temp
while True:
for i in range(0,2):
RawValue = ReadInput(i) #Read the raw input from the chip
percent = (RawValue/10.24) #Convert to a percentage
Voltage = (percent /100.0)*3.3 #Convert % to a 0 to 3.3 Volts
if (Voltage > 0): #Skip If 0 to avoid divide by zero error
Ohms = VoltToOhm(Voltage) #Convert Voltage to resistance
DGC = OhmToCelsius(Ohms) #Convert to temp in Celsius
else:
Ohm = 0.0
DGC =-50.0
#Format values to 2 decimal places
PCTStr = ",PCT={0:.2f}".format(percent)+"%"
VoltsStr = ",Volts={0:.2f}".format(Voltage)+"V"
OhmsStr = ",Ohms={0:.2f}".format(Ohms)+"ohms"
DGCStr = ",Temperature={0:.2f}".format(DGC)+"DGC"
print "Sensor No "+str(i),"Raw="+str(RawValue), PCTStr, VoltsStr, OhmsStr, DGCStr
time.sleep(2) #Delay to slow down display for use humans
The SPIDEV function is imported to communicate with the MCP3008. I have also imported time for delays and math for the conversion to temperature. The SPI interface is defined and opened on channel 0 at start-up. The ReadInput function reads an input from the chip and returns the raw value. The VoltagetoOhm function converts the calculated voltage to a resistance value. OhmToCelsius converts the resistance to a temperature. In the main program the for loop reads the first two sensors (could be changed depending on the inputs used and chip used). Percentage, Voltage etc.. are calculated and displayed for the two inputs.
The SPIDEV function is imported to communicate with the MCP3008. I have also imported time for delays and math for the conversion to temperature. The SPI interface is defined and opened on channel 0 at start-up. The ReadInput function reads an input from the chip and returns the raw value. The VoltagetoOhm function converts the calculated voltage to a resistance value. OhmToCelsius converts the resistance to a temperature. In the main program the for loop reads the first two sensors (could be changed depending on the inputs used and chip used). Percentage, Voltage etc.. are calculated and displayed for the two inputs.
The program output
NTC Sensor Characteristics
The sensor characteristics can sometimes be obtained from the supplier but not always. Here is a table of the sensors I have found and there characteristics. There is no guarantee but this helped me to get sensors reading reliably. When testing I would recommend testing values around the target temperatures against a know sensor. The value may need an offset or +/- 10 on the final value. The below are for 10K NTC sensors if you don't know the NTC sensor number just try each one until you get the best fit.
NTC Sensor
|
A
|
B
|
C
|
D
|
3490
|
0.003354016
|
0.000292425
|
3.45753E-06
|
2.33526E-07
|
3590
|
0.003354016
|
0.000255056
|
1.62764E-06
|
2.21525E-07
|
3740
|
0.003354016
|
0.000274403
|
3.66694E-06
|
1.37549E-07
|
3977
|
0.003354016
|
0.000256985
|
2.62013E-06
|
6.38309E-08
|
3435
|
0.003354016
|
0.000307404
|
1.01915E-05
|
9.09371E-07
|
3960
|
0.003354016
|
0.000255056
|
1.62764E-06
|
2.21525E-07
|
3610
|
0.003354016
|
0.000282875
|
2.98965E-06
|
4.84086E-08
|
3570
|
0.003354016
|
0.000286452
|
3.25226E-06
|
4.5945E-08
|
3940
|
0.003354016
|
0.000257077
|
1.89389E-06
|
1.89729E-07
|
3430
|
0.003354016
|
0.000303944
|
6.31344E-06
|
-6.85454E-08
|
3984
|
0.003354016
|
0.000256524
|
2.60597E-06
|
6.32926E-08
|
4090
|
0.003354016
|
0.000249339
|
2.2881E-06
|
7.98311E-08
|
3435
|
0.003354016
|
0.000300131
|
5.08516E-06
|
2.18765E-07
|
Is your pin 15 supposed to go to ground? I thought that was supposed to go to positive voltage.
ReplyDeleteIs there a difference between spidev (3.2) and the library 'python-periphery', or the 'py-libbcm2835' library? They all seem to do spi, however not sure if they have different applications or if they are just deprecated libraries?
ReplyDeleteInterestingly, the spidev documentation says you can set the number of bits per word(transfer) , 8..16, however according to the pi documentation, the spi peripheral connected to the header only supports 8/9! So perhaps spidev is a generic driver whose functionality may or may not be fully supported by the rpi?
BTW, doesn't a python list ([0x90,0,0,0,0]) consist of ints and not bytes? Does the driver take this into account and convert it to 8-bit bytes before sending?
You worked with 3008, Can yopu help me with 3208?
ReplyDeletePlease respond asap
Did you already find a solution??
ReplyDeleteMcp3204-bi/p
ReplyDeleteWhat would I need to change to read a 12bit MCP3208? Something in the `def ReadInput` `spi.xfer2`? Right now I'm topping out at 1025, but I should be able to get a value of 4095 with those other two bits, correct?
ReplyDelete