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);
}