//By Don "AGlass0fMilk" Beckstein //Demo Code for SPI Communication with MCP3008 //A 10-bit, 8-channel ADC //Originally written for TI MSP430G2553 //Date: 11/3/2014 //Rev: 1 #include //As shown in the data sheet, start bit is 00000001 const byte startBit = 0b00000001; const unsigned int mask = 0b0000000000000011; void setup() { Serial.begin(9600); //@todo //Set the slave select pin as an output pinMode(SS, OUTPUT); //Initialize SPI SPI.begin(); SPI.setDataMode(SPI_MODE0); SPI.setBitOrder(MSBFIRST); //May not be neccessary? @todo SPI.setClockDivider(SPI_CLOCK_DIV128); //May not be neccessary? @todo } void loop() { //@test @todo for(int i=0; i<=7; i++) { Serial.print(i); Serial.println(readADC(i, true)); } } /* - Read a specific channel (0-7) of the ADC - Mode specifies if we should read the inputs as a single-ended input... - ...or a differential of two analog inputs. - If you don't know what this means, you probably want single-ended input. Read the datahseet - Mode 1 = Single-ended, Mode 0 = differential */ int readADC(int channel, boolean mode) { if(channel > 7 || channel < 0) //Cannot read channels that don't exist! return -1; /* On reading data from the MCP3008 ADC IC Please note, the SPI is in mode 0,0, which means SCLK idles in a 'low' state 1.) Pull CS/SS (Chip select/Slave select) pin LOW (0) 2.) Send start bit data, which is 00000001 or 0x01 (Read the datasheet) 3.) Send the input configuration/channel selection data Note: Input config data format: SGL/DIFF, D2, D1, D0, X, X, X, X SGL/DIFF selects what mode, D2, D1, and D0 (3 bits) select channel to read (0-7) and XXXX do not matter. 1 = single-ended, 0 = differential 4.) The first byte received will be as follows: ?/?/?/?/?/0/B9/B8, where ? is unknown, 0 is a null bit, and B9 and B8 are the first bits of the 10-bit sample The next byte received will be the rest of the 10-bit sample 5.) To get a meaningful reading, we have to combine the 2 bits from the first message with the second message We can acomplish this by trimming the first 6 bits of the first byte (using bitwise & with the mask 0b00000011) shifting the bits 8 to the left, and the bitwise OR-ing the first byte with the second byte 6.) End communication by setting CS/SS back high */ //Get everything ready to send: byte selectionData = 0; //if(!mode) //Differential mode, doesn't need to change from 0 if(mode) //Single-ended mode selectionData = 0b10000000; byte bitChannel = channel << 4; //We need the channel to be the X's in 0b0XXX0000, shift it left 4 bits selectionData |= bitChannel; //Combine the mode/channel data*/ //Step 1, Pull SS low digitalWrite(SS, LOW); //Step 2, Send start bit data SPI.transfer(startBit); //Please note: This next part may seem weird. ADC data is sent as soon as the first 4 bits are sent //Guess how long I spent wondering why all my data was garbage because of this litte gem of info? //Step 4/5, Get data and make it meaningful unsigned int receivedData = 0; //Step 3, Send configuration data (simultaneously receive the first few bits of the conversion) receivedData = SPI.transfer(selectionData); receivedData = receivedData & mask; //Get rid of stuff we don't need (all but last two bits) receivedData <<= 8; //Shift it to the left 8 bits*/ byte secondMessage = SPI.transfer(0x00); //Get the second message //Combine the first two bits with the last eight bits receivedData |= secondMessage; //Step 6, End communication digitalWrite(SS, HIGH); return receivedData; }