Authorized Online Retailers:
Overview
In this project, we learn how to use SPI protocol to exchange complex data between Raspberry Pi and external device. SPI is a simple communication protocol to send data which can save a lot of GPIO pin resources. We will only how to program SPI in this lesson, you can google protocol detail if you are interested.
This external device is MCP3008 analog-digit-convert(ADC) chip. As we’ve learned from previous lessons, the Raspberry Pi could do many projects with various digital sensors. Unlike Arduino Board, Raspberry Pi doesn’t have integrated ADC(analog to digital converters) so it cannot read analog inputs.
In this lesson, we will use MCP3008 ADC chip to convert analog signal to digital signal and send it to Raspberry Pi through SPI.
1 * Raspberry Pi
1 * Breadboard
1 * MCP3008
Several jumper wires
Software Preparation
Note: In this lesson, we remotely control raspberry pi via PuTTy on PC. To learn how to config raspberry pi, please visit lesson 1: getting started with raspberry pi.
The MCP3008 is a 10-bit 8 channels Analog-to-Digital Converter (ADC) with SPI(Serial Peripheral Interface Bus) interface. learn more about SPI, please click here . You can also use MCP3004 instead which has 4 input channels , for the datasheet about MCP3004/MCP3008, please visit: https://osoyoo.com/driver/MCP3008_datasheet.pdf
In this project, we use Raspberry Pi 3.3V and GND as MCP3008 Input Channel 1 and Input Channel 2 respectly. the MCP3008 will convert the analog signal to digital quantity, this enables the Raspberry Pi to interpret analog voltages that are in turn typically emitted by analog-based sensors to reflect a measure of a physical characteristic such as acceleration, light intensity or temperature.
MCP3008 uses SPI interface, wiring up the MCP3008 to Pi as following connection graph, NC means Not Connected. B# means BCM system. i.e B10 means BCM GPIO 10 ( Physical 19, wPi#12).
*DIN/DOUT PINS
MCP3008 communicates with Raspberry Pi through SPI protocol . In raspberry Pi, SPI BUS pin pair are BCM 10(out) and BCM 9(in) which are connected to MCP3008 DIN pin and DOUT pin. We call it a BUS because BCM 10/BCM 9 can be shared with multiple devices.
Pi accept maximum two devices for SPI bus. We call them spiChannel 0 and spiChannel 1. Raspberry Pi use BCM 7 and BCM 8 pin to control these two channels. When an external Device enable pin is connected with Pi BCM 8 pin, it is a spiChannel 0. When device. enable pin is connected with Pi BCM 7 pin, it is a spiChannel 1 device. From above graph, our MCP3008 is a spiChannel 0 device because CS/SHDN(enable pin) is connected with B8.
**Analog Input Pin CH0,CH1…CH7
MCP3008 can read 8 different analog input signal from pin CH0,CH1..CH7. The Chip will compare input voltage with Maximum allowed voltage and output an integer between 0 to 1023. Input analog max value are defined by VREF pin. In this sample circuit, CH0 connected to 3.3V which is same as VREF voltage, so output integer for CH0 is 1023. Ch1 connected to GND, its output is 0. Output will be sent through SPI serial protocol.
we’ll provide two kinds of codes for C language users and Python language users.
For C Language users, please take following steps:
Note: please be sure installation wiringpi. Click here, you can learn more about how to check whether installing wiringpi and install wiringpi
Step 1)Enalble SPI, open file /boot/config.txt , find the code line as followed, change it as dtparam=spi=on
sudo nano /boot/config.txt
Press “ctrl” + “X” and then type “Y” to save the file which you revised.
Step 2) reboot the raspberry pi by typing following command:
sudo reboot
Step 3) Download the sample code from osoyoo by typing following commands:
cd ~
sudo wget http://osoyoo.com/driver/pi3_start_learning_kit_lesson_10/readmcp3008.c
Note:
If you want to customize the sample code file , you can use nano editor to edit source code by typing following command in terminal:
sudo nano readmcp3008.c
Step 4) Compile Code
C language is high level language. Before running the project, the code need to compile as an executable file. Please enter the following command:
gcc -Wall -o readmcp3008 readmcp3008.c -lwiringPi
Note: gcc: is GNU Compiler Collection. If you want to write your own C code and compile to run it, you need to master gcc. for more information about gcc, please visit here
-Wall: to get more error when compile the code
-o: to name the compiled file. You can name the file as your like. here we name as readmcp3008
buzzer.c: means the original file which is compiled
-lwiringPi: is to load the library wiringPi (l is short for library)
Step 5) Run the Program
a)Before running the program, using command: gpio readall to check if the MOSI、MISO、SCLK(B10、B9、B11) work mode is ALT0 (alternative functions), if not, please set them to ALT0 by typing terminal command as following:
gpio -g mode 9 alt0
gpio -g mode 10 alt0
gpio -g mode 11 alt0
b) Read all value from ADC MCP3008 by typing the following command:
./readmcp3008 all
Once run the program, the terminal will show print message as code firstly, then show all channels value.
c) Read Channel 1 value from ADC MCP3008 by typing the following command:
./readmcp3008 1
Once run the program, the terminal will show print message as code firstly, then show the channel 1 value . because we connected the CH1 to 3.3v, CH2 to 0V, so the output channel l value is 1023, the output channel 2 is 0
Read the comments in following code and understand the programming principle
//#define _GNU_SOURCE #include < unistd.h> #include < stdint.h> #include < string.h> #include < errno.h> #include < wiringPi.h> #include < stdio.h> #include < stdlib.h> #include < wiringPiSPI.h> #define TRUE (1==1) #define FALSE (!TRUE) #define CHAN_CONFIG_SINGLE 8 #define CHAN_CONFIG_DIFF 0 static int myFd ; char *usage = "Usage: mcp3008 all|analogChannel[1-8] [-l] [-ce1] [-d]"; // -l = load SPI driver, default: do not load // -ce1 = spi analogChannel 1, default: 0 // -d = differential analogChannel input, default: single ended void loadSpiDriver() { if (system("gpio load spi") == -1) { fprintf (stderr, "Can't load the SPI driver: %s\n", strerror (errno)) ; exit (EXIT_FAILURE) ; } } void spiSetup (int spiChannel) { if ((myFd = wiringPiSPISetup (spiChannel, 10000)) < 0) { fprintf (stderr, "Can't open the SPI bus: %s\n", strerror (errno)) ; exit (EXIT_FAILURE) ; } } int myAnalogRead(int spiChannel,int channelConfig,int analogChannel) { if(analogChannel< 0 || analogChannel>7) return -1; unsigned char buffer[3] = {1}; // start bit buffer[1] = (channelConfig+analogChannel) < < 4; wiringPiSPIDataRW(spiChannel, buffer, 3); return ( (buffer[1] & 3 ) < < 8 ) + buffer[2]; // get last 10 bits } void print_info() { printf("\n"); printf("|*****************************************|\n"); printf("| Read MCP3008(3004) ADC value |\n"); printf("| ------------------------------ |\n"); printf("| | ADC | | Pi | |\n"); printf("| |-----|-----------|-----| |\n"); printf("| | CS | connect to| CE0 | |\n"); printf("| | Din | connect to| MOSI| |\n"); printf("| | Dout| connect to| MISO| |\n"); printf("| | CLK | connect to| SCLK| |\n"); printf("| | CH0 | connect to| 3.3V| |\n"); printf("| | CH1 | connect to| GND | |\n"); printf("| OSOYOO|\n"); printf("|*****************************************|\n"); printf("\n"); } int main (int argc, char *argv []) { int loadSpi=FALSE; int analogChannel=0; //as MCP3008 enable pin connected to Pi B8, we need tell C program to use spiChannel 0 int spiChannel=0; int channelConfig=CHAN_CONFIG_SINGLE; if (argc < 2) { fprintf (stderr, "%s\n", usage) ; return 1 ; } if((strcasecmp (argv [1], "all") == 0) ) argv[1] = "0"; if ( (sscanf (argv[1], "%i", &analogChannel)!=1) || analogChannel < 0 || analogChannel > 8 ) { printf ("%s\n", usage) ; return 1 ; } int i; for(i=2; i< argc; i++) { if (strcasecmp (argv [i], "-l") == 0 || strcasecmp (argv [i], "-load") == 0) loadSpi=TRUE; else if (strcasecmp (argv [i], "-ce1") == 0) spiChannel=1; else if (strcasecmp (argv [i], "-d") == 0 || strcasecmp (argv [i], "-diff") == 0) channelConfig=CHAN_CONFIG_DIFF; } // if(loadSpi==TRUE) loadSpiDriver(); wiringPiSetup () ; spiSetup(spiChannel); print_info(); // if(analogChannel>0) { printf("MCP3008(CE%d,%s): analogChannel %d = %d\n",spiChannel,(channelConfig==CHAN_CONFIG_SINGLE) ?"single-ended":"differential",analogChannel,myAnalogRead(spiChannel,channelConfig,analogChannel-1)); } else { for(i=0; i< 8; i++) { printf("MCP3008(CE%d,%s): analogChannel %d = %d\n",spiChannel,(channelConfig==CHAN_CONFIG_SINGLE) ?"single-ended":"differential",i+1,myAnalogRead(spiChannel,channelConfig,i)); } } close (myFd) ; return 0; }
When programming with Python language , normally we use GPIO library called RPi.GPIO which comes with Rasbian Jessie OS. Click here, you can learn more about RPI.GPIO and Python.
1) download sample code by typing following command in terminal:
cd ~
sudo wget http://osoyoo.com/driver/pi3_start_learning_kit_lesson_10/readmcp3008.py
Note:
If you want to customize the sample code file , you can use nano editor to edit source code by typing following command in terminal:
sudo nano readmcp3008.py
2) Run the program
sudo python ./readmcp3008.py
3) Running result
a)Then type the output Channel that you want to read, for example: if we type 0 (zero) in terminal and press enter, then the terminal will print the Channel 0 value.
b) if the input value is not in scope, it will print the prompt message.
Read the comments in following code and understand the programming principle
import time import os import RPi.GPIO as GPIO # change these as desired - they're the pins connected from the # define SPI port on the ADC to the Cobbler # use BCM 11 as SPI clock signal SPICLK = 11 #MISO and MOSI are the data pins required by SPI, google it for detail #use BCM 9 as MISO to accept signal from external SPI output SPIMISO = 9 #use BCM 10 as MOSI to to send signal to external SPI input SPIMOSI = 10 #use BCM 8 as SPI CS to enable/disable extern SPI device SPICS = 8 #DEBUG = 1 #setup function for some setup---custom function def setup(): GPIO.setwarnings(False) #set the gpio modes to BCM numbering GPIO.setmode(GPIO.BCM) # 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) #print message at the begining ---custom function def print_message(): print ('|**********************************|') print ('| Read MCP3008(3004) ADC value |') print ('| ----------------------------- |') print ('| | ADC | | Pi | |') print ('| |-----|-----------|-----| |') print ('| | CS | connect to| CE0 | |') print ('| | Din | connect to| MOSI| |') print ('| | Dout| connect to| MISO| |') print ('| | CLK | connect to| SCLK| |') print ('| | CH0 | connect to| 3.3V| |') print ('| | CH1 | connect to| GND | |') print ('| ----------------------------- |') print ('| OSOYOO|') print ('|**********************************|\n') print ('Program is running...') print ('Please press Ctrl+C to end the program...') print ('please input 0 to 7...') # 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 to enable MCP3008 commandout = adcnum commandout |= 0x18 # start bit + single-ended bit commandout <<= 3 # we only need to send 5 bits here #Tell MCP3008 I am getting data from which ADC# 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) #Read SPI data from MCP3008 and save it to variable adcout 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 #main function def main(): #print info print_message() analogChannel = int(input()) if (analogChannel < 0) or (analogChannel > 7): print ('input error analogChannel number!') print ('please input 0 to 7...') else: adc = readadc(analogChannel, SPICLK, SPIMOSI, SPIMISO, SPICS) print ('analogChannel %d = %d'%(analogChannel,adc)) #define a destroy function for clean up everything after the script finished def destroy(): #release resource GPIO.cleanup() # # if run this script directly ,do: if __name__ == '__main__': setup() try: main() #when 'Ctrl+C' is pressed,child program destroy() will be executed. except KeyboardInterrupt: destroy()
DownLoad Url osoyoo.com