Pt100 e Smartec UTI

Aggiungo solo questo:

Poichè la pressione ambientale non normalizzata al momento dei test era di circa 996,8 hPa, posso desumere che la temperatura di ebollizione era di circa 99,56°C. Utilizzando i dati a disposizione trovo la formula:

T = 2,596415876 * Ohm - 264,95648

Facendo la formula inversa trovo che per 100°C la resistenza dovrebbe essere di 140,56 ohm. Levando l'offset di 2 ohm che ottengo dalla schermatura mi ritrovo 138,56°C, che dovrebbe essere il valore di costruzione per 100°C.

In ogni caso certo che voglio condividere, scrivo tutto proprio per questa ragione!! Appena ho novità metto tutto qui :smiley:

GianfrancoPa:
In ogni caso certo che voglio condividere, scrivo tutto proprio per questa ragione!! Appena ho novità metto tutto qui :smiley:

Giusto per curiosità, dove hai acquistato lo Smartec UTI ?
Sia Digikey che Mouser e RS non trattano questo produttore.

GRANDE! felice che sia riuscito a risolvere, ora che hai capito che il gosso problema era l'effetto antenna, vedi miglioramenti tra l'uso di resistenze di precisione e normali resistenze?

Allora, la differenza tra pt100 a 2 fili e 4 fili c'è, si vede, e non è poco. Su internet ho cercato molte informazioni sulle PT100 e su come realizzare la strumentazione adatta per limitare il più possibile l'errore nelle rilevazioni. Ad un certo punto mi son messo le mani nei capelli per quante cose possono incidere nella validità dei risultati! La soluzione a 4 fili risolve una moltitudine di problemi, come la resistenza del cavo, delle saldature, ecc ecc!

Alla fine all'errore di costruzione che per una PT100 classe A è di 0,15°C bisogna aggiungere quello della strumentazione che può valere tantissimo. Così tanto che forse è conveniente utilizzare un semplice ds18b20 che per costruzione ha un errore di mezzo grado C. Considerate che il solo smartec uti ha di suo un errore di costruzione di circa +- 0,1°C (80 mK).
Poi è un casino per quel che riguarda l'auto riscaldamento del sensore. Non nascondo che ancora non sono in grado di affrontare e gestire appieno questo inconveniente, infatti sarà questo l'oggetto dei miei prossimi studi...

Altra cosa che sto studiando per bene è la conversione del valore da ohm a gradi C. Il semplice dividere il valore della resistenza per 0,384 è davvero una pessima soluzione quando si vuole realizzare uno strumento di precisione!!!

Lo smartec uti l'ho preso da distrelect, quasi 9 euro di integrato più spese postali...

Ecco il link https://www.distrelec.it/sensor-interface-dil-16/smartec/uti-dil16/647495

Per la trasformazione da resistenza a temperatura potresti passare all'interpolazione polinomiale, ma non è così semplice.

vorrei fare qualche cosa del genere partendo dalla formula base RT = R0(1 + AT + BT² + C(T-100)T³), vediamo cosa riesco a combinare :smiley:

uhmm se vuoi una tale precisione io partirei da un termometro con già tale precisione, lo userei come riferimento per un range di misure molto più puntuali, e poi disegnerei il grafico della resistenza in funzione della temperatura. Poi dal grafico ricaverei (con non poca fatica) una funzione.

In generale, una volta che hai il grafico, testare formule come RT = R0(1 + AT + BT² + C(T-100)T³) è poco più difficile che inserire la formula in un foglio excel e vedere i valori ricavati al variare di R quanto sballano rispetto ai valori reali.

Avessi avuto lo strumento richiesto per fare il tuo esperimento lo avrei già usato, mi sarei segnato i valori grado per grado :smiley:

Ecco un pò di codice:

#include <stdio.h> 
#include "pins_arduino.h" 
#include <LiquidCrystal.h>

#define UTI_PIN 5 
#define UTI_RESISTANCE_REF 1000 

float TempStorage[20] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};  //Contiene le ultime 20 rilevazioni
float Media = 0.0; //Contiene il valore della temperatura media
int MediaCount = 0; //Contatore che permette il calcolo della media solo dopo aver riempito completamente l'array
int ArrayMax = 19; // Dimensione massima array
int CurPos = 0; //Contiene la posizione corrente nell'array

LiquidCrystal lcd(12, 11, 6, 4, 3, 2);
unsigned long samplingMillis, printMillis;
int samplingTime = 500; //In ms, frequenza di campionamento
int printTime = 1000; //in ms, frequenza di stampa dei dati

void setup() 
{ 
  Serial.begin(9600); 
  pinMode(UTI_PIN, INPUT);
  Serial.print("Avvio PT100");
  Serial.print("\n");
  lcd.begin(16, 2);
  lcd.print("PT100");
  CurPos=-1; //Inizializzo la posizione nell'array
  delay(3000);
} 

int ReadUTI(uint8_t pin, float * temp,int refRes) //Ottimizzato per PT100 4 fili - Modalità 5 (4 fasi)
{ 
    int state = HIGH; 
    int i,startindex=-1; 
    uint8_t bit = digitalPinToBitMask(pin); 
    uint8_t port = digitalPinToPort(pin); 
    uint8_t stateMask = (state ? bit : 0); 
    unsigned long width[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; 
    float nOff=0,nAB=0,nCD=0,nBC=0,nDF=0; 
        
    while ( (*portInputRegister(port) & bit) != stateMask) 
        ; 
    
    for(i=0;i<10;i++) { 
      while ( (*portInputRegister(port) & bit) == stateMask) 
          width[i]++; 
      while ( (*portInputRegister(port) & bit) != stateMask) 
          width[i]++; 
    } 
    for(i=1;i<10;i++) { 
      if(i<6) { 
        if(width[i]<width[i+2]&&width[i]<width[i+3]&&width[i]<width[i+4]&&width[i+1]<width[i+2]&&width[i+1]<width[i+3]&&width[i+1]<width[i+4]) { 
          startindex=i; 
          i=10; 
        } 
      } 
    } 
    if(startindex!=-1) { 
      nOff=width[startindex]+width[startindex+1]; 
      nAB=width[startindex+2]; 
      nCD=width[startindex+3]; 
      nBC=width[startindex+4]; 

      *temp=((nCD-nOff)/(nAB-nOff))*refRes; 
      
      return 1; 
    } 
    else { 
      return 0; 
    } 
} 

void readTemp()
{
  float temp;
  if(ReadUTI(UTI_PIN,&temp,UTI_RESISTANCE_REF)) {
      float TempNorm = 2.596415876*temp-264.95648; //Formula ricavata dalla calibrazione a 0 e 100 °C
      
      if (CurPos<ArrayMax){CurPos++;} else { CurPos=0; } //Gestisce la posizione del cursore all'interno dell'array
      TempStorage[CurPos]=TempNorm; //Registra la temperatura all'interno dell'array
      
      if (MediaCount<23) {MediaCount++;} //Calcola la media solo se l'array è stato riempito completamente
      else {
        Media =0.0;
        for (int i=0;i<=ArrayMax;i++) { Media = Media + TempStorage[i];}
        Media = Media / (ArrayMax+1);
      }
  } 
    else {
      printTempError(); //Se l'UTI non riceve alcuna temperatura, restituisce errore
    } 
}

void printTempError()
{
  Serial.print("Not Found");
  Serial.print("\n");
  lcd.setCursor(0, 1);
  lcd.print("NotFound");
}

void printTempMedia()
{
  if (MediaCount < 23) { //Stampa la media solo se l'array è completamente pieno
    Serial.print("Inizializzazione Sensore (");
    Serial.print(CurPos);
    Serial.print(")");
    Serial.print("\n");
    lcd.setCursor(0, 1);
    lcd.print("Init");
  } else {
    Serial.print(Media);
    Serial.print("\n");
    lcd.setCursor(0, 1);
    lcd.print(Media);
  }
}

void loop() 
{  
  if ((millis()- samplingMillis) > samplingTime) {
    samplingMillis = millis();
    readTemp();
  }
  if ((millis()- printMillis) > printTime) {
    printMillis = millis();
    printTempMedia();
  }
}

Al fine di poter trovare questa famosa formula magica, perfetta, di conversione, mi son messo un pochettino a giocare con Excel. Prego tutti voi di verificare che i miei ragionamenti sono esatti!!!

La formula base, per una PT100, che restituisce il valore della resistenza è la seguente:

1) Rt = R0*(1 + At + Bt^2 + C*(t-100)*t^3)

Supponendo di avere una PT100 ed un circuito che rispondano perfettamente a questa formula, andiamo avanti. Ho realizzato con excel una lista di valori derivati dalla suddetta formula, ed ho ricavato il seguente grafico:

Poi ho invertito x e y ed ho ottenuto il seguente grafico:

Al che ho fatto sviluppare a Excel la relativa formula:

2) t = 4E-13Rt^6 - 2E-10Rt^5 + 7E-08Rt^4 - 2E-05Rt^3 + 0,0038Rt^2 + 2,1705Rt - 241,09

Ho ridato quindi in pasto ad excel i dati ottenuti dalla formula 1) ed ho ottenuto un valore simile a quello iniziale. Ho quindi creato una lista degli scarti di cui ho fatto il grafico:

Ancora una volta il buon Excel ha fatto il lavoraccio:

3) y = -8E-05x2 - 0,0086x - 0,6422

Questa nuova formula corregge l'errore della 2)

In pratica, dopo tutto questo trambusto ottengo che la somma delle formule 2) e 3) danno un risultato compatibile con la formula generale 1) che è si lineare, con le dovute approssimazioni! Come vi sembra? Ho sprecato tempo??

Tutto questo mi è utile perchè, dando per scontata la correttezza di quanto fatto, ho notato che la mia configurazione pt100 + circuito, risponde alla legge generale delle PT100 (formula 1)) con un offset di 2,047 Ohm. Sapendo ciò posso facilmente adattare le formule 2) e 3) al mio caso... che ne pensate?

penso con terrore a cosa potrai essere capace di fare quando realizzerai il primo circuito con due sonde PT100 per rilevare il range di variazione :stuck_out_tongue_closed_eyes:

Non sapevo di incutere tanto timore :smiley:

ah, quindi hai preso la fomrula che usi - la formula vera = formula dell'errore, ma non vedo come ti possa aiutare la cosa, puoi usare direttamente la formula vera e bon. il problema quì è capire se la formula vera è abbastanza veritiera per la precisione che vuoi ottenere, no?

La formula vera (1) è quella che ho trovato in rete, tra le specifiche della resistenze al platino. Non posso usarla direttamente perchè restituisce la Resistenza in funzione della temperatura, mentre io ho bisogno di conoscere la temperatura in funzione della resistenza. Per tale ragione ho utilizzato Excel per trovarmi la formula inversa (2), soltanto che, vuoi per le approssimazioni, vuoi per la (forse) poca affidabilità di excel, produce un errore che in ogni caso ho calcolato e quindi eliminato aggiungendo un secondo passaggio (funzione 3).

In ogni caso ancora non posso utilizzare questa funzione perchè è ideale, ovvero non tiene conto delle imprecisioni che produce il mio hardware, che, se non ho fatto troppi errori, aggiunge 2ohm rispetto ai valori "ideali", per cui non ho 100 ohm a 0°C bensì 102 ohm; non ho 138,5 ohm a 100°C bensì 140,5ohm.

Perchè sto insistendo con la formula ideale? Mi è stato già consigliato di realizzare una semplice funzione partendo dai due punti di riferimento, cosa che ho fatto. Purtroppo questa funzione approssima il dato finale. Perchè? Leggendo in rete si trova che per ogni °C la resistenza subisce una variazione di 0,385 ohm. Purtroppo si tratta di un valore medio, perchè a 0°C la variazione è di 0,3909 ohm, mentre a 100°C è di 0,3793 ohm.

Qui trovi una tabella dei valori ricavati partendo dalla formula base: Tabella pt100 by Sevimpianti

L'ideale sarebbe, come consigliato da tutti quanti, avere uno strumento già tarato su cui tarare il mio. Purtroppo non dispongo uno strumento simile, per cui devo accontentarmi dei punti di fusione ed ebollizione!

In ogni caso, paranoie a parte, ecco lo schema:

Uploaded with ImageShack.us

PS: ho apportato una correzione allo schema

Rispetto allo schema presente nel topic http://arduino.cc/forum/index.php/topic,17349.0.html, ho modificato la RBias che ho portato a 2.2K e il pin 6 (SEL 3) che da GND ho portato a +5V in modo da poter usare la Modalità 5 dell'integrato, come specificato nel datasheet per l'utilizzo di una PT100 a 4 vie. Ovviamente il codice che ho riportato qualche post fa è stato modificato adeguatamente.

Ecco il board:

Allego pure i file di Eagle

Ricordo che questo è lo schema per utilizzare una PT100 a quattro fili, nella modalità 5 indicata nel datasheet.

Schematic.brd (56.9 KB)

Schematic.pro (1000 Bytes)

Schematic.sch (179 KB)

GianfrancoPa:
In ogni caso, paranoie a parte, ecco lo schema:

Uploaded with ImageShack.us

PS: ho apportato una correzione allo schema

Rispetto allo schema presente nel topic http://arduino.cc/forum/index.php/topic,17349.0.html, ho modificato la RBias che ho portato a 2.2K e il pin 6 (SEL 3) che da GND ho portato a +5V in modo da poter usare la Modalità 5 dell'integrato, come specificato nel datasheet per l'utilizzo di una PT100 a 4 vie. Ovviamente il codice che ho riportato qualche post fa è stato modificato adeguatamente.

rref non dovrebbe essere 100ohm per le pt100?

edit: ah no, come non detto :smiley: . Comunque sto provando il tuo codice e il tuo schema (ho uno uti smartec anche io), ma mi stampa valori di resistenza intorno a 8500..C'è qualcosa che non mi torna :slight_smile: cosa potrebbe essere?

ri-edit: come non detto. penso che sto usando il vecchio codice con il nuovo schema :smiley: potresti postare anche il nuovo codice?

Ottimo!! Qualcuno con cui confrontarmi è splendido!!

Allora, il tuo risultato è molto strano! La tua pt1000 è a 4 fili?? come li hai collegati i fili nel pinheader JP1? supponendo che i tuoi 4 fili siano in due coppie di colori, rosso e bianco come nel mio caso, devi mettere quelli bianchi nei pin 1-2, e quelli rossi nei pin 3-4. Ovviamente va bene anche il contrario :wink:

In ogni caso prova questo codice se puoi, ho portato il campionamento a 20 secondi ed immagazzino ogni volta il valore della resistenza e non della temperatura:

#include <stdio.h> 
#include "pins_arduino.h" 
#include <LiquidCrystal.h>

#define UTI_PIN 5 
#define UTI_RESISTANCE_REF 1000 

double TempStorage[40];  //Contiene le rilevazioni
int ArrayMax = 39; // Dimensione massima array: dimensione TempStorage - 1
double Media = 0.0; //Contiene il valore della temperatura media
int MediaCount = 0; //Contatore che permette il calcolo della media solo dopo aver riempito completamente l'array
int CurPos = 0; //Contiene la posizione corrente nell'array

LiquidCrystal lcd(12, 11, 6, 4, 3, 2);
unsigned long samplingMillis, printMillis;
int samplingTime = 500; //In ms, frequenza di campionamento
int printTime = 1000; //in ms, frequenza di stampa dei dati

void setup() 
{ 
  Serial.begin(9600); 
  pinMode(UTI_PIN, INPUT);
  Serial.print("Avvio PT100");
  Serial.print("\n");
  lcd.begin(16, 2);
  lcd.print("PT100");
  CurPos=-1; //Inizializzo la posizione nell'array
  for (int i=0;i<= ArrayMax;i++) { //Inizializzo array a zero
    TempStorage[i] = 0.0;
  }
  delay(3000);
} 

int ReadUTI(uint8_t pin, double * temp,int refRes) //Ottimizzato per PT100 4 fili - Modalità 5 (4 fasi)
{ 
    int state = HIGH; 
    int i,startindex=-1; 
    uint8_t bit = digitalPinToBitMask(pin); 
    uint8_t port = digitalPinToPort(pin); 
    uint8_t stateMask = (state ? bit : 0); 
    unsigned long width[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; 
    double nOff=0,nAB=0,nCD=0,nBC=0,nDF=0; 
        
    while ( (*portInputRegister(port) & bit) != stateMask) 
        ; 
    
    for(i=0;i<10;i++) { 
      while ( (*portInputRegister(port) & bit) == stateMask) 
          width[i]++; 
      while ( (*portInputRegister(port) & bit) != stateMask) 
          width[i]++; 
    } 
    for(i=1;i<10;i++) { 
      if(i<6) { 
        if(width[i]<width[i+2]&&width[i]<width[i+3]&&width[i]<width[i+4]&&width[i+1]<width[i+2]&&width[i+1]<width[i+3]&&width[i+1]<width[i+4]) { 
          startindex=i; 
          i=10; 
        } 
      } 
    } 
    if(startindex!=-1) { 
      nOff=width[startindex]+width[startindex+1]; 
      nAB=width[startindex+2]; 
      nCD=width[startindex+3]; 
      nBC=width[startindex+4]; 

      *temp=((nCD-nOff)/(nAB-nOff))*refRes; 
      
      return 1; 
    } 
    else { 
      return 0; 
    } 
} 

void readTemp()
{
  double temp;
  if(ReadUTI(UTI_PIN,&temp,UTI_RESISTANCE_REF)) {
      if (CurPos<ArrayMax){CurPos++;} else { CurPos=0; } //Gestisce la posizione del cursore all'interno dell'array
      TempStorage[CurPos]=temp; //Registra la temperatura all'interno dell'array
      
      if (MediaCount<(ArrayMax+4)) {MediaCount++;} //Calcola la media solo se l'array è stato riempito completamente
      else {
        Media =0.0;
        for (int i=0;i<=ArrayMax;i++) { Media = Media + TempStorage[i];}
        Media = Media / (ArrayMax+1);
      }
  } 
    else {
      printTempError(); //Se l'UTI non riceve alcuna temperatura, restituisce errore
    } 
}

void printTempError()
{
  Serial.print("Not Found");
  Serial.print("\n");
  lcd.setCursor(0, 1);
  lcd.print("NotFound");
}

void printTempMedia()
{
  if (MediaCount < (ArrayMax+4)) { //Stampa la media solo se l'array è completamente pieno
    Serial.print("Inizializzazione Sensore: ");
    Serial.print(CurPos);
    Serial.print("\n");
    lcd.setCursor(0, 1);
    lcd.print("Init");
  } else {
    //double TempNorm = 2.596415876*Media-264.95648; //Formula ricavata dalla calibrazione a 0 e 100 °C
    double TempNorm = 2.624704336*Media-266.3919005; 
    //double TempNorm = (0.0000000000004 * pow(Media,6)) - (0.0000000002 * pow(Media,5)) + (0.00000007 * pow(Media,4)) - (0.00002 * pow(Media,3)) + (0.0038 * pow(Media,2)) + (2.1705 * Media) - 241.09;
    //TempNorm = TempNorm - ((-0.00008 * pow(TempNorm,2)) + (-0.0086 * TempNorm) - 0.6422);
    Serial.print(TempNorm);
    Serial.print(" - ");
    Serial.print(Media);
    Serial.print("\n");
    lcd.begin(16, 2);
    lcd.print(Media);
    lcd.setCursor(0, 1);
    lcd.print(TempNorm);
  }
}

void loop() 
{  
  if ((millis()- samplingMillis) > samplingTime) {
    samplingMillis = millis();
    readTemp();
  }
  if ((millis()- printMillis) > printTime) {
    printMillis = millis();
    printTempMedia();
  }
}

esatto ho pt100 a 4 fili(colori diversi, bianco-blu-maroone-nero).

il bianco blu dovrebbe essere il rosso e marrone nero il bianco.

ho collegato come hai detto te e ricaricato il codice. adesso come resistenza mi rileva sempre 0 =(

Il circuito l'ho appena controllato e dovrebbe essere giusto

edit: temo che ho sbagliato i colori: il bianco dovrebbe andare col nero e il marrone con il blu. ora riprovo a vedere se cambia