The MCP3208 is a 12bit, 8 channel, Serial Peripheral Interface (SPI) Analogue to Digital Converter. It comes as an 16 pin DIP (also soic) pinout below, get the datasheet here. Also available as the 3201/2/4 with 1, 2 and 4 channels.
NOTE: code is for single ended operation, read the datasheet for differential operation.
D10 indicates arduino digital pin 10 etc.
Pinout:
___ 1 | u | 16 2 | | 15 3 | | 14 4 | | 13 5 | | 12 6 | | 11 7 | | 10 8 |___| 9
Code:
#define SELPIN 10 //Selection Pin #define DATAOUT 11//MOSI #define DATAIN 12//MISO #define SPICLOCK 13//Clock int readvalue; void setup(){ //set pin modes pinMode(SELPIN, OUTPUT); pinMode(DATAOUT, OUTPUT); pinMode(DATAIN, INPUT); pinMode(SPICLOCK, OUTPUT); //disable device to start with digitalWrite(SELPIN,HIGH); digitalWrite(DATAOUT,LOW); digitalWrite(SPICLOCK,LOW); Serial.begin(9600); } int read_adc(int channel){ int adcvalue = 0; byte commandbits = B11000000; //command bits - start, mode, chn (3), dont care (3) //allow channel selection commandbits|=((channel-1)<<3); digitalWrite(SELPIN,LOW); //Select adc // setup bits to be written for (int i=7; i>=3; i--){ digitalWrite(DATAOUT,commandbits&1<<i); //cycle clock digitalWrite(SPICLOCK,HIGH); digitalWrite(SPICLOCK,LOW); } digitalWrite(SPICLOCK,HIGH); //ignores 2 null bits digitalWrite(SPICLOCK,LOW); digitalWrite(SPICLOCK,HIGH); digitalWrite(SPICLOCK,LOW); //read bits from adc for (int i=11; i>=0; i--){ adcvalue+=digitalRead(DATAIN)<<i; //cycle clock digitalWrite(SPICLOCK,HIGH); digitalWrite(SPICLOCK,LOW); } digitalWrite(SELPIN, HIGH); //turn off device return adcvalue; } void loop() { readvalue = read_adc(1); Serial.println(readvalue,DEC); readvalue = read_adc(2); Serial.println(readvalue,DEC); Serial.println(" "); delay(250); }
Here is a version that works with the MCP3304, which is an 8-channel, differential, 13-bit version of the above controller. The pinout is exactly the same.
This code uses the SPI library rather than bit-banging with digitalWrite() so is much more efficient. It can sustain about 32ksps with a 2MHz SPI clock on an Uno or Mega
Note that this code hard-codes the command bits:
// command bits for MCP3304 // 0000 = diff, ch0 = in+, ch1 = in- // 0010 = diff, ch2 = in+, ch3 = in- // 0100 = diff, ch4 = in+, ch5 = in-
(the read_adc function provides 3 differential input channels, I didn't bother to code up for the 4th differential channel)
Code:
// read the MCP3304 in quad differential mode, non-bit-banging version //#include <Serial.h> #include <SPI.h> #include <HardwareSerial.h> long ticks = 0; // for Uno //#define SELPIN 10 // chip-select //#define DATAOUT 11 // MOSI //#define DATAIN 12 // MISO //#define SPICLOCK 13 // Clock // for Mega2560 / Max32 #define SELPIN 53 // chip-select #define DATAOUT 51 // MOSI #define DATAIN 50 // MISO #define SPICLOCK 52 // Clock int readvalue; void setup(){ //set pin modes pinMode(SELPIN, OUTPUT); // disable device to start with digitalWrite(SELPIN, HIGH); SPI.setClockDivider( SPI_CLOCK_DIV8 ); // slow the SPI bus down SPI.setBitOrder(MSBFIRST); SPI.setDataMode(SPI_MODE0); // SPI 0,0 as per MCP330x data sheet SPI.begin(); Serial.begin(115200); } void loop() { long ticks = millis(); int A = 0, B = 0; A = read_adc(1); B = read_adc(2); // do whatever you want with these readings long tcnv = millis() - ticks; delay(100 - tcnv); } // non-bit-banging version // channel ranges from 1.. 3 (not zero!) // maximum clock frequency is 2.1 MHz @ 5V // // this is SPI_CLOCK_DIV8 // at DIV64, 512 in 60ms (8.5 ksps) // at DIV32, 512 in 35ms (14.6 ksps) // at DIV16, 512 in 22ms (23.3 ksps) // at DIV8, 512 in 16ms (32 ksps) int read_adc(int channel){ int adcvalue = 0; int b1 = 0, b2 = 0; int sign = 0; // command bits for MCP3304 // 0000 = diff, ch0 = in+, ch1 = in- // 0010 = diff, ch2 = in+, ch3 = in- // 0100 = diff, ch4 = in+, ch5 = in- digitalWrite (SELPIN, LOW); // Select adc // first byte // first byte will always be B000010xx where xx are the D2 and D1 channel bits byte commandbits = B00001000; commandbits |= (channel >> 1); // high bit of channel SPI.transfer(commandbits); // send out first byte of command bits // second byte; Bx0000000; leftmost bit is D0 channel bit commandbits = B00000000; commandbits |= (channel << 7); // if D0 is set it will be the leftmost bit now b1 = SPI.transfer(commandbits); // send out second byte of command bits // hi byte will have XX0SBBBB // set the top 3 don't care bits so it will format nicely b1 |= B11100000; //Serial.print(b1, BIN); Serial.print(" "); sign = b1 & B00010000; int hi = b1 & B00001111; // read low byte b2 = SPI.transfer(b2); // don't care what we send //Serial.print(b2, BIN); Serial.print("\r\n"); int lo = b2; digitalWrite(SELPIN, HIGH); // turn off device int reading = hi * 256 + lo; if (sign) { reading = (4096 - reading) * -1; } return (reading); }