Dunque, ho scoperto che esiste un ADC a 24 bit (l'LTC2400 della Analog Devices) interfacciabile in SPI con Arduino.
Il circuito è linkato sotto:
link
Ho costruito il circuito in questione, usando come riferimento di tensione il chip LT1021BCN8-5.
Per chi non volesse aprire il link sopra e volesse solo vedere il codice, lo riporto sotto:
/* 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;
}
}
I pin che uso sull'arduino UNO sono:
LTC_CS 10
LTC_MISO 12
LTC_SCK 13
Non funziona.
Sul monitor seriale leggo:
...
168; -5,000000
169; -5,000000
170; -5,000000
171; -5,000000
172; -5,000000
173; -5,000000
174; -5,000000
175; -5,000000
176; -5,000000
...
(i valori hanno una spaziatura temporale variabile, da 5 a 8 secondi.)
Non avendo collegato alcuna alimentazione in input, mi aspettavo di leggere 0,000000 (o qualcosa di prossimo allo 0).
Ovviamente, collegando qualcosa in input il risultato non cambia.
Ho provato a cablare il CS sul pin 2, ottenendo letture molto rapide ma come sopra (-5,000000).
Ho ricontrollato i collegamenti del circuito (ho stampato un PCB) ma mi sembra non ci siano problemi (anche perchè è molto semplice lo schema, fatto di soli 4 componenti...).
Da cosa può dipendere il problema??