Connect a LTC2400 High Precision 24 Bit Analog to Digital Converter
If the resolution of the Arduino is not enough for your application you have to try it with a better ADC. The LTC2400 gives you a resolution of up to 24 bit at a datarate of 5 samples per seconds and is quite simple to connect. With this device you can connect sensors which have only a low output level like thermo couples or force strain gauges. The high sensitivity can make the use of of an preamp needless.
In the Lab we achieved an effective resolution of about 18 to 19 bits which are roughly 500.000 counts so you improve Arduinos analog capabilities by 500.
Two versions where tried , one with a LP2930 regulator used as voltage reference and one with a LT1021-5 reference chip. The latter one has the better performance but needs a 9 Volt source, so you have to have an extra power supply for the board. The LP2950 version can be fed by the 5Volt of the board.
With an Open Office Spreadsheed › ltc2400_analyser you can try to analyze the accuracy of the setup. Copy and paste 200 lines of the Monitor output into the first 2 rows of the Spreadsheed and observe the “resolution” cell on the bottom of the sheet.
Since the LTC2400 comes in an SO8 package the circuit was breadboarded on a SMD prototype board which is available at your electronic shop.
The to communicate with the LTC2400 the Software makes use of the ATMEGA168 hardware SPI. To print a float type number the “printFloat” procedure found in the Arduino Playground was used.
Schematics
LTC2400 with LP2950 3 Volt regulator as reference.
LTC2400 with LT1021-5 precision reference.
Software
/* LTC2400 24 Bit ADC Test * Connect an LTC2400 24 Bit ADC to the Arduino Board in SPI Mode * * * * KHM 2009 / Martin Nawrath * Kunsthochschule fuer Medien Koeln * Academy of Media Arts Cologne */ #include <Stdio.h> #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif #define LTC_CS 2 // LTC2400 Chip Select Pin on Portb 2 #define LTC_MISO 4 // LTC2400 SDO Select Pin on Portb 4 #define LTC_SCK 5 // LTC2400 SCK Select Pin on Portb 5 void setup() { cbi(PORTB,LTC_SCK); // LTC2400 SCK low sbi (DDRB,LTC_CS); // LTC2400 CS HIGH cbi (DDRB,LTC_MISO); sbi (DDRB,LTC_SCK); Serial.begin(57600); // init SPI Hardware sbi(SPCR,MSTR) ; // SPI master mode sbi(SPCR,SPR0) ; // SPI speed sbi(SPCR,SPR1); // SPI speed sbi(SPCR,SPE); //SPI enable Serial.println("LTC2400 ADC Test"); } float volt; float v_ref=3.0; // Reference Voltage, 5.0 Volt for LT1021 or 3.0 for LP2950-3 long int ltw = 0; // ADC Data ling int int cnt; // counter byte b0; // byte sig; // sign bit flag char st1[20]; // float voltage text /********************************************************************/ void loop() { cbi(PORTB,LTC_CS); // LTC2400 CS Low delayMicroseconds(1); if (!(PINB & (1 << PB4))) { // ADC Converter ready ? // cli(); ltw=0; sig=0; b0 = SPI_read(); // read 4 bytes adc raw data with SPI if ((b0 & 0x20) ==0) sig=1; // is input negative ? b0 &=0x1F; // discard bit 25..31 ltw |= b0; ltw <<= 8; b0 = SPI_read(); ltw |= b0; ltw <<= 8; b0 = SPI_read(); ltw |= b0; ltw <<= 8; b0 = SPI_read(); ltw |= b0; delayMicroseconds(1); sbi(PORTB,LTC_CS); // LTC2400 CS Low delay(200); if (sig) ltw |= 0xf0000000; // if input negative insert sign bit ltw=ltw/16; // scale result down , last 4 bits have no information volt = ltw * v_ref / 16777216; // max scale Serial.print(cnt++); Serial.print("; "); printFloat(volt,6); // print voltage as floating number Serial.println(" "); } sbi(PORTB,LTC_CS); // LTC2400 CS hi delay(20); } /********************************************************************/ byte SPI_read() { SPDR = 0; while (!(SPSR & (1 << SPIF))) ; /* Wait for SPI shift out done */ return SPDR; } /********************************************************************/ // printFloat from tim / Arduino: Playground // printFloat prints out the float 'value' rounded to 'places' places //after the decimal point void printFloat(float value, int places) { // this is used to cast digits int digit; float tens = 0.1; int tenscount = 0; int i; float tempfloat = value; // if value is negative, set tempfloat to the abs value // make sure we round properly. this could use pow from //<math.h>, but doesn't seem worth the import // if this rounding step isn't here, the value 54.321 prints as // calculate rounding term d: 0.5/pow(10,places) float d = 0.5; if (value < 0) d *= -1.0; // divide by ten for each decimal place for (i = 0; i < places; i++) d/= 10.0; // this small addition, combined with truncation will round our tempfloat += d; if (value < 0) tempfloat *= -1.0; while ((tens * 10.0) <= tempfloat) { tens *= 10.0; tenscount += 1; } // write out the negative if needed if (value < 0) Serial.print('-'); if (tenscount == 0) Serial.print(0, DEC); for (i=0; i< tenscount; i++) { digit = (int) (tempfloat/tens); Serial.print(digit, DEC); tempfloat = tempfloat - ((float)digit * tens); tens /= 10.0; } // if no places after decimal, stop now and return if (places <= 0) return; // otherwise, write the point and continue on Serial.print(','); for (i = 0; i < places; i++) { tempfloat *= 10.0; digit = (int) tempfloat; Serial.print(digit,DEC); // once written, subtract off that digit tempfloat = tempfloat - (float) digit; } }
Source Code
Contact
Martin Nawrath, nawrath@khm.de