Pt100 e Smartec UTI

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

Aiutati con un tester per individuare con certezza le coppie dei cavi, magari il problema e' questo!!

ed infatti era proprio quello il problema: avevo seguito il foglio che c'era dentro con le pt100 ma segnava sbagliati i colori. ho verificato col tester e sistemato correttamente i valori. ora funziona alla grande :slight_smile: (almeno, da valori sensati). ora provo un po' a vedere calibrazioni varie etc

edit: sto calibrando con acqua e ghiaccio, ma mi sa che non bisogno molto di calibrazione.la media dei risultati, dopo circa 5min dall'inserimento del ghiaccio in un pinta di acqua, varia tra 100.02 ohm e 100.06 ohm. direi come da manuale (Pt100 Classe A ±0,15 °C [0 °C] ±0,06 ? [0 °C]) :smiley:

beato te, io invece non ho dati da "manuale" e Onestamente non capisco il motivo...one dovrebbe dare questo problema usando i 4 fili!

ho provato con acqua tiepida a 37.5 misurati col termometro da febbre. mi da una resistenza di 114.64, che a detta della famosa formula "universale" (calcolabile qui http://www.thermibel.be/documents/pt100/conv-rtd.xml?lang=en) corrisponde a circa 37.67gradi. anche questa volta direi proprio come da manuale, senza nessuna calibrazione.

tutto ciò mi rende molto contento dal momento che avevo uno smartec uti da mesi che non ero mai riuscito a farlo andare decentemente (penso colpa delle pt100 a 2 fili che avevo e di un errore nel codice che mi portavo dietro). ti devo veramente ringraziare!!! se ti può interessare. le pt100 a 4 fili le ho comprate qui http://www.ebay.it/itm/190760784643?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1497.l2649

sono arrivate dopo 3gg :slight_smile:

c'era da adattare il codice alla modalità differente che richiede una pt100 a 4 fili!

Mi conforta che tu ottenga ottimi risultati, almeno adesso so che il problema non sta nel codice... hai modificato i collegamenti rispetto al mio?? come hai collegato i fili al circuito? li hai saldati??

grazie mille!!

E' strano, perchè se provo a leggere la temperatura del sensore con un tester e sottraggo quella del cavo ottengo un valore compatibile con la formula generale. Così com'è invece l'uti restituisce il valore del sensore non compensato!