Go Down

Topic: lettura mV ad alta precisione (Read 1 time) previous topic - next topic

zoomx

Anche quella potrebbe essere una soluzione. Forse l'ho già vista ma in ogni caso mi sembra semplice anche se non elegantissima.

Se cerchi "opencv recognize lcd numbers" o parole chiave simili trovi parecchi risultati. Io ricordavo l'uso del RaspberryPi ma dimenticavo l'uso di un normale PC con una camera USB.


mikiti

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:

Code: [Select]
/* 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:

Code: [Select]

...
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??


 

Maurotec

Quote
Ho provato a cablare il CS sul pin 2, ottenendo letture molto rapide ma come sopra (-5,000000).
Cioè? Aspe pin 2 o bit 2 di PORTB?
Quote
LTC_CS 10
LTC_MISO  12
LTC_SCK  13
I pin fisici di Arduino uno sono quelli, però il codice non lo devi modificare, devi lasciare:
Code: [Select]

#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

perché il codice non si riferisce ai pin fisici di arduino ma alle porte della MCU.

Ciao.


zoomx

Inoltre
Code: [Select]
float v_ref=3.0;          // Reference Voltage, 5.0 Volt for LT1021 or 3.0 for LP2950-3
Visto che usi un riferimento a 5V devi cambiare quella riga.

mikiti

Cioè? Aspe pin 2 o bit 2 di PORTB?
I pin fisici di Arduino uno sono quelli, però il codice non lo devi modificare, devi lasciare:
Code: [Select]

#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

perché il codice non si riferisce ai pin fisici di arduino ma alle porte della MCU.

l'errore era proprio quello! Grazie!
Infatti ripristinando i valori indicati nel codice originario il sistema funziona.

Come faccio a specificare altri pin di collegamento?
Io ho predisposto il pcb con i pin (uno a fianco all'altro sull'arduino):
GND --> GND
CS --> 13
MISO --> 12
SCK --> 11

Come faccio a fare la media di 10 valori?
Io di solito uso (es.):
Code: [Select]
int media = 0;
 for (int i=0; i < 9; i++) {
 media = media + analogRead(A0);
 }
 media = media/9;

ma nel codice riportato nel primo post non so proprio come fare....

In realtà ho trovato un altro sketch, in cui posso specificare "facilmente" i pin di collegamento, ma quando provo a fare la media come ho indicato su, il valore non è corretto... non capisco perchè...



Inoltre
Code: [Select]
float v_ref=3.0;          // Reference Voltage, 5.0 Volt for LT1021 or 3.0 for LP2950-3
Visto che usi un riferimento a 5V devi cambiare quella riga.
ovviamente. A quello c'ero arrivato. Grazie comunque per la nota.

Maurotec

#20
Apr 15, 2019, 11:22 pm Last Edit: Apr 15, 2019, 11:24 pm by Maurotec
Quote
Come faccio a specificare altri pin di collegamento?
Io ho predisposto il pcb con i pin (uno a fianco all'altro sull'arduino):
GND --> GND
CS --> 13
MISO --> 12
SCK --> 11
Non puoi scegliere i pin a piacere, il codice usa la SPI (Serial Peripheral Interface) hardware di cui è dotata la MCU e pin fisici non sono modificabili, quelli sono e quelli sei obbligato ad usare.

Quote
ma nel codice riportato nel primo post non so proprio come fare....
Ok il codice per ricavare la media, ma nell'esempio tu leggi da A0, mentre nel codice per LTC2400 viene ricavato da SPI, tu su questo valore vuoi effettuare la media?

La variabile ltw contiene il valore grezzo ricavato da SPI, accumulare più letture e poi calcolare la media, esempio:
Code: [Select]

   
   if (sig) ltw |= 0xf0000000;    // if input negative insert sign bit
   ltw=ltw/16;                    // scale result down , last 4 bits have no information
   
   mediaCounter++;
   mediaValue += ltw;

   if ( mediaCounter == nSamples ) {
       mediaValue /= nSamples;
       volt = mediaValue * v_ref / 16777216; // max scale

       Serial.print(cnt++);
       Serial.print(";  ");
       printFloat(volt,6);           // print voltage as floating number
       Serial.println("  ");

       mediaCounter = 0;
       mediaValue = 0;
   }

Fuori da ogni funzione devi dichiara le seguenti 3 variabili:

Code: [Select]

long int mediaValue = 0;
byte mediaCounter = 0;
const byte nSamples = 5;   // The LTC2400 gives you a resolution of up to 24 bit at a datarate of 5 samples per seconds


Quindi in totale accumuli 5 campioni in mediaValue in 1 secondi, quando mediaCounter
== 5 calcoli media e stampi.

Ciao.

mikiti

intanto, grazie mille per gli aiuti.

Leggendo lo stesso segnale di riferimento (5V) prodotto dall' LT1021 riesco ad avere una precisione minima di 5 uV.

Ho adesso alcune perplessità sul lato elettronico.

Intanto, il circuito riportato al link (e che ho realizzato, pur costruendo un PCB "migliore")
http://interface.khm.de/wp-content/uploads/2009/01/ltc2400_5v_sch.png
ha in ingresso un condensatore elettrolitico da 10 uF (di livellamento, immagino). Ma, mi chiedo, tale capacità non perturba il segnale di ingresso?
Altra questione riguarda la possibilità di inserire un filtro passa basso. Il termometro (che comunque è uno strumento di precisione, per quanto sia vecchio, ed è quindi dotato di opportuna elettronica, immagino) è alimentato a 230Vac, potrebbe esserci una certa componente alternata a bassa frequenza (50 Hz o meno) trasmessa sull'uscita, o è improbabile?
Al contrario di quanto si vede nella pagina in cui è riportato quello schema, sarebbe necessario fare un piano di massa esteso, magari sul layer opposto a quello del circuito?
Dato che il segnale oscilla moltissimo, cosa posso fare per ridurre tale oscillazione?
Ho montato il circuito in un box di metallo per prototipi, collegando il GND allo stesso, ma l'oscillazione è sempre presente. Mi chiedo se è smorzabile in qualche modo, del resto la lettura sul display è abbastanza stabile.

In allegato sono riportate le immagini dell'acquisizione del segnale di riferimento e di un test di lettura (i punti con indicatore a croce indicano le letture fatte usando il display dello stesso termometro). In realtà, ho traslato il segnale acquisito eseguendo una correzione basata sulle stesse letture fatte da display ma, non riuscendo a definire una costante di correzione, solo una parte dei punti cadono nella zona delle letture.

Maurotec

Quote
ha in ingresso un condensatore elettrolitico da 10 uF (di livellamento, immagino). Ma, mi chiedo, tale capacità non perturba il segnale di ingresso?
Ma me lo chiedo anche io, cosa dice il datasheet in merito al valore e qualità di questa capacità?

Di sicuro se chi genera il segnale da campionare ha una impedenza di uscita costante e bassa il convertitore lavora meglio, sempre se la conversione è ti tipo sample/hold

RTFM e facci sapere.

Patrick_M

RTFM e facci sapere.
tanto per chiarire... "Read The Fucking Manual" :D
per inserire (lo sketch) il programma, dall'IDE clicca modifica, clicca copia per il forum poi vieni qui e incolla nel tuo post (ctrl+v) ;)

mikiti

tanto per chiarire... "Read The Fucking Manual" :D
non so se si è capito, ma io non sono un esperto di elettronica digitale... altrimenti mi sarei risolto il problema da solo...

Ma me lo chiedo anche io, cosa dice il datasheet in merito al valore e qualità di questa capacità?
Cercando qua e là in rete ho trovato un altro schema
http://www.steveluce.com/24bits/LTC2400%20wireless%20-%20full%20wireless%20wiring%20diagram%20-%20larger%20ARD%20version.jpg
dove viene usato un condensatore da 1 uF.
Il datasheet del LTC2400 non mi sembra dica (esplicitamente) qualcosa a riguardo ma a pagina 38 riporta lo schema della demo board DC228 del produttore dell'ADC in cui si vede che sull'ingresso mette un condensatore da 10 uF.

Di sicuro se chi genera il segnale da campionare ha una impedenza di uscita costante e bassa il convertitore lavora meglio, sempre se la conversione è ti tipo sample/hold
non conosco l'impedenza di uscita del termometro nè come avvenga la conversione.
Mi sa che proverò a cambiare il valore di quel condensatore e vedrò che succede...

Maurotec

Quote
non so se si è capito, ma io non sono un esperto di elettronica digitale... altrimenti mi sarei risolto il problema da solo...
Guarda che anche se un ingegnere legge il datasheet non è detto che il problema se lo può risolvere da solo, ma comunque è sempre un ingegnere, tu stai facendo il compito che spetta ad un ingegnere elettronico pur non essendolo. Procedi pure per tentativi, prova e riprova magari esce fuori ciò che ti soddisfa, ma è uno streess. Dico, chiedo, mi pongo una domanda;  sei in un laboratorio, ci sarà pure uno straccio di ingegnere a cui chiedere lumi. Mi chiedo anche; che laboratorio è se non è possibile recapitare uno straccio di oscilloscopio, lo hai  o no?

Quote
Cercando qua e là in rete ho trovato un altro schema
http://www.steveluce.com/24bits/LTC2400%20wireless%20-%20full%20wireless%20wiring%20diagram%20-%20larger%20ARD%20version.jpg
dove viene usato un condensatore da 1 uF.
Il datasheet del LTC2400 non mi sembra dica (esplicitamente) qualcosa a riguardo ma a pagina 38 riporta lo schema della demo board DC228 del produttore dell'ADC in cui si vede che sull'ingresso mette un condensatore da 10 uF.
mmmmm, grrrrr. Strada che non porta a nulla provare con questo e con quello copiato li e la.

Quote
Altra questione riguarda la possibilità di inserire un filtro passa basso. Il termometro (che comunque è uno strumento di precisione, per quanto sia vecchio, ed è quindi dotato di opportuna elettronica, immagino) è alimentato a 230Vac, potrebbe esserci una certa componente alternata a bassa frequenza (50 Hz o meno) trasmessa sull'uscita, o è improbabile?
Al contrario di quanto si vede nella pagina in cui è riportato quello schema, sarebbe necessario fare un piano di massa esteso, magari sul layer opposto a quello del circuito?
Dato che il segnale oscilla moltissimo, cosa posso fare per ridurre tale oscillazione?
Il datasheet dice:
Quote
Conversion ClockA  major  advantage  delta-sigma  converters  offer  overconventional  type  converters  is  an  on-chip  digital  filter(commonly  known  as  Sinc  or  Comb  filter).  For  highresolution, low frequency applications, this filter is typi-cally designed to reject line frequencies of 50 or 60Hz plustheir  harmonics.  In  order  to  reject  these  frequencies  inexcess  of  110dB,  a  highly  accurate  conversion  clock  isrequired.  The  LTC2400  incorporates  an  on-chip  highlyaccurate oscillator. This eliminates the need for externalfrequency setting components such as crystals or oscilla-tors.  Clocked  by  the  on-chip  oscillator,  the  LTC2400rejects line frequencies (50 or 60Hz ±2%) a minimum of110dB.
Brevemente, se si configura il chip per usare l'oscillatore interno, il 2400  filtra i residui 50 oo 60Hz al valore di 110dB (che ottimo, ma non sufficiente).  Per vanificare il filtraggio il tuo termometro dovrebbe essere afflitto da un disturbo di linea in cui è presente un segnale a queste frequenze di intensità 110dB.

Oscilloscopio alla mano, si analizza il segnale analogico fornito dal termometro è si verifica l'entità di questo segnale indesiderato.

Ancora il fottuto manuale dice:
Quote
Frequency Rejection Selection (FO Pin Connection)The LTC2400 internal oscillator provides better than 110dBnormal  mode  rejection  at  the  line  frequency  and  all  itsharmonics for 50Hz ±2% or 60Hz ±2%. For 60Hz rejec-tion, FO (Pin 8) should be connected to GND (Pin 4) whilefor 50Hz rejection the FO pin should be connected to VCC(Pin 1).
Per filtrare 60Hz FO (pin-8) collegalo  a GND.
Per filtrare 50Hz FO (pin-8) collegalo a VCC (pin-1)

Il resto del manuale me lo leggo (forse più tardi).

Ciao.


Standardoil

Dio Bono è un termometro, giusto?
Non importa molto il tempo di risposta
Ammennocche la frequenza di campionamento non sia vicina a un (sotto)multiplo della frequenza di rete in pochi secondi di media si toglie tutto il ripple
Che poi sarebbe a 100 o 120 Hz, doppia semionda
Prima legge di Nelson (che sono io): A parità di risultato maggiore è il pensiero, minore il lavoro. Quindi prima di fare pensa!
Non si da retta a studenti: andate a copiare da un'altra parte...
Lo hai visto su Youtube? -> lo chiedi su Youtube

Datman

#27
May 04, 2019, 01:18 pm Last Edit: May 04, 2019, 01:27 pm by Datman
"Questi convertitori hanno un filtro digitale nel chip (detto Comb filter). Per applicazioni a bassa frequenza e alta risoluzione, questo filtro offre una reiezione della frequenza di rete a 50 o 60Hz e relative armoniche. Per ottenere una reiezione di oltre 110dB (300.000 volte!), è richiesta una frequenza del clock di conversione molto precisa. L'LTC2400 incorpora un oscillatore molto preciso. (...) Con oscillatore interno, l'LTC2400 offre una reiezione (a 50 o 60Hz+- 2%)  di almeno 110dB."
Hi,I'm Gianluca from Roma.I play&work with electronics since I was16(1984).
After 25yrs of maintenance on cameras&video mixers,since 2013myJob is HDTVstudios design.
Since Jan2015 IPlayWith Arduino:bit.ly/2F3LPWP
Thanks 4 a Karma if U like my answer

Standardoil

Quindi o abbiamo una buona alimentazione, o abbiamo un buon clock oppure andiamo di filtri....
Prima legge di Nelson (che sono io): A parità di risultato maggiore è il pensiero, minore il lavoro. Quindi prima di fare pensa!
Non si da retta a studenti: andate a copiare da un'altra parte...
Lo hai visto su Youtube? -> lo chiedi su Youtube

Standardoil

Che poi servirebbe conoscere anche la rejezione della fonte di tensione, il valore del ripple e eventuali filtrati lato analogico, quel condensatore a qualcosa servirà...
Comunque se ricordo bene 110 decibel sono 11 Bel, ovvero lascia una parte su 100 miliardi, mi sembra anche eccessivo, non si parlava di precisioni dell'ordine di una parte su centomila?
1 centesimo su alcune decine, diciamo una parte su centomila, e stiamo sicuri
Prima legge di Nelson (che sono io): A parità di risultato maggiore è il pensiero, minore il lavoro. Quindi prima di fare pensa!
Non si da retta a studenti: andate a copiare da un'altra parte...
Lo hai visto su Youtube? -> lo chiedi su Youtube

Go Up