Forum: Mikrocontroller und Digitale Elektronik Berechnung Temperatur aus PT1000 Spannungsmessung


von Mr Bean (Gast)


Angehängte Dateien:

Lesenswert?

Hallo

Ich habe hier schon einige Beiträge zum Thema PT1000 gelesen. Bin 
allerdings immernoch nicht richtig weiter gekommen.
Vorneweg, ich habe diese Temperaturmessung so auf meinem Board. Ein 
Digitaler Sensor ist auch vorhanden, dieser soll aber mit dem Analogen 
verglichen werden. Also brauche ich diese Analoge Messung.
Die Umrechnung soll auf einem 8051 in C erfolgen.
Der Strom durch den PT1000 kommt aus einer Konstantstromquelle.
Wenn ich mir den "Rohwert" der Messung ausgeben lasse, komme ich bei 
Zimmertemperatur (22°C) auf 3700. Ich habe jetzt mal so angefangen dass 
ich diesen Wert durch die Verstärkung und den Strom geteilt hab. Dann 
sollte ich ja den Widerstand herausbekommen. Dann wollte ich über die 
Geradengleichung die Temperatur errechnen. Allerdings funktioniert das 
so nicht.
Habt ihr mir hier ein paar Tipps wie ich das am besten hin bekomme?

Vielen Dank schonmal!

Grüße

Bean

von Thilo M. (Gast)


Lesenswert?

Du musst erst in Widerstand (Ohm) umrechnen, dann siehe hier:
Beitrag "PT100 Berechnung der Temperatur @ Widerstand"

von Mr Bean (Gast)


Lesenswert?

Ja, vielen Dank.

Diesen Beitrag habe ich mir auch schon durchgelesen. Allerdings möchte 
ich mir die Wurzelberechnung sparen, da ich nicht die math.h includieren 
will. (8051, wenig resourcen). Ich wollte das über eine Geradengleichung 
annähern. dann wäre ich auf:
Temp = (R - b) / m gekommen.
Wobei m die Steigung (4,0) und b der Achsenabschnitt mit 984 wären.
Das wäre denke ich einfacher zu rechnen auf dem Controller. Natürlich 
muss ich dann die Genauigkeit noch überprüfen...

Wie rechne ich denn bei obiger Schaltung sinnvoll den Widerstand aus!?

Grüße

Bean

von Thilo M. (Gast)


Lesenswert?

Ich berechne den Widerstand so:

Messwert: aktueller ADC-Wert
Rconst: autokalibrierter Wert mittels zwei Widerständen (0°C / 100°C)
        kann aber auch einmalig ausgemessen werden
R_null_cal: autokalibrierter Wert für 0°C
R_ende_cal: autokalibrierter Wert für 100°C
ADC_Null: autokalibrierter ADC-Wert für 0°C
ADC_Ende: autokalibrierter ADC-Wert für 100°C
1
double Rconst = (R_ende_cal-R_null_cal)/(ADC_Ende-ADC_Null);
2
3
double R = ((1000+((Messwert-ADC_Null)*Rconst))+(1000-R_null_cal));

und die Temperatur:
1
double r = R/R0-1;
2
3
double T = (r*(255.8723+r*(9.6+r*0.878)));  // Temperatur berechnen

Ich hoffe, dukanns damit 'was anfangen. ;-)

von ein_bisher_nicht_beteiligter (Gast)


Lesenswert?

Du brauchst um den Widerstand auszurechnen keine Wurzel. Ein 
Spannungsteiler von:

- ----1k------#-----1k----- +
              |
              |
              A

ergibt an A genau die Hälfte an Spannung. So kannst du den Wiederstand 
berechnen. U=R*I

von ein_bisher_nicht_beteiligter (Gast)


Lesenswert?

Allerdings.... mul und div auf einem 8051er sind mehr als nur ungenau...

Für ein 22,x° Zimmerthermometer wirds wohl noch reichen, aber mehr auch 
nicht.

von Bernd N (Gast)


Lesenswert?

>> Zimmertemperatur (22°C) auf 3700.

Dann verwende doch eine 2te Stützstelle z.B. 0 C = ? dann hast du ein 
Wertepaar DeltaU / Delta ADC und fertig.

Ausgang dann auf deine Temperaturmessung skalieren und das Ganze dann 
mittels "fixed point" berechnen.

von Mr Bean (Gast)


Lesenswert?

Hallo

Danke für die Antworten.
Dass ich den Widerstand über R = U/I berechnen kann ist mir schon klar. 
Allerdings weiß ich nicht wie ich den OP (Verstärkung = 23) in meine 
Berechnung mit einfließen lassen soll.
Muss ich den vom AD-Wandler ausgegebnen Wert durch 23 teilen? Im Moment 
siehr mein Code zur Berechnug folgendermaßen aus:
1
uint8_t GetAnalogTemp(int16_t *temp)
2
{
3
  int16_t analogTemp = 0;
4
  uint16_t current = 9950;
5
  uint8_t gain = 23;
6
7
  calcAverage(TEMPSENSOR, 8, &analogTemp);
8
  analogTemp = analogTemp / gain;
9
  analogTemp = analogTemp / current;
10
  analogTemp = analogTemp >> 10;
11
  analogTemp = analogTemp - 984;
12
  analogTemp = analogTemp / 4;
13
14
  *temp = analogTemp;
15
   
16
   return SUCCESS;
17
}

Wobei calcAverage in diesem Fall 8 mal den AD wandler bemüht, und einen 
Mittelwert aus diesen 8 zurückliefert.
Den Strom habe ich mal 1000 genommen und dann wieder geschoben. Kann 
aber auch sein dass ich hier noch einen Fehler drin hab.
Die Zeilen:
1
analogTemp = analogTemp - 984;
2
analogTemp = analogTemp / 4;
Kommen aus der Geradengleichung des PT1000.
Wo liegt mein Denkfehler?

Grüße

Bean

von Karl H. (kbuchegg)


Lesenswert?

Mr Bean schrieb:

> Muss ich den vom AD-Wandler ausgegebnen Wert durch 23 teilen? Im Moment
> siehr mein Code zur Berechnug folgendermaßen aus:
>
> [c]
> uint8_t GetAnalogTemp(int16_t *temp)
> {
>   int16_t analogTemp = 0;
>   uint16_t current = 9950;
>   uint8_t gain = 23;
>
>   calcAverage(TEMPSENSOR, 8, &analogTemp);
>   analogTemp = analogTemp / gain;
>   analogTemp = analogTemp / current;
>   analogTemp = analogTemp >> 10;
>   analogTemp = analogTemp - 984;
>   analogTemp = analogTemp / 4;


Für meine Begriffe gehst du hier etwas zu naiv an die Dinge ran.
Du musst dir eines merken: Rechnen auf dem Papier wie ein Mathematiker 
und Rechnen in einem Computer sind 2 Paar Schuhe.

Bits die dir in einer Berechnung verloren gehen, sind verloren!

Das bedeutet:

Wenn man eine Formel implementiert, dann geht man erst her und macht 
seine Hausaufgaben auf dem Papier. Und das bedeutet: Die Formel 
aufschreiben und umformen.

Das Ziel: Man will die Berechnungen so umformen, dass Divisionen 
möglichst zum Schluss auftauchen. Denn bei einer Division (insbesondere 
einer Integer Division) gehen dir Bits verloren. Sie sind einfach nicht 
mehr da.
In einer Integer Division ergibt dir 10 / 3 nun mal eine glatte 3. Die 
Berechnungen  10/3*4   und 10*4/3 liefern unterschiedliche Ergebnisse! 
10/3 gibt 3 und das mal 4 macht 12.  10*4 macht 40 und das durch 3 
ergibt aber 13!

Und den Rechtsshift mit 10: Mach erst mal den Rest richtig und dann 
kümmerst du dich um Geschwindigkeit. Ein schnell errechnetes Ergebnis 
bringt dir nichts, wenn es falsch ist.


ALso: Hausaufgaben machen und die Formeln auf dem Papier rechnertauglich 
zusammenfassen und umformen.
Das dann implementieren. Und zwar ohne Haken und Ösen.
Dann Testen
Und erst dann nachsehen, wie man die Operationen noch schneller machen 
kann.

Und nein: Wenn man während der Programmierung darüber nachdenken muss, 
in welcher Reihenfolge Dinge berechnet werden müssen, dann hat man seine 
Hausaufgaben definitiv nicht gemacht. Im Idealfall hat man vorher schon 
auf dem Papier mit ein paar fiktiven Messwerten die Berechnung 
durchgeführt und sich davon überzeugt, dass die Formeln stimmen.

von Karl H. (kbuchegg)


Lesenswert?

> Der Strom durch den PT1000 kommt aus einer Konstantstromquelle.
> Wenn ich mir den "Rohwert" der Messung ausgeben lasse, komme ich
> bei Zimmertemperatur (22°C) auf 3700. Ich habe jetzt mal so
> angefangen dass ich diesen Wert durch die Verstärkung und den
> Strom geteilt hab. Dann sollte ich ja den Widerstand herausbekommen.
> Dann wollte ich über die Geradengleichung die Temperatur errechnen.

Das heißt du hast doch im Grunde 2 lineare Transformationen 
hintereinander geschaltet.

In der einen berechnest du aus dem ADC Wert den Widerstand und in der 
anderen berechnest du aus dem Widerstand die Temperatur.

Das kann man auch zu einer einzigen zusammenfassen. Denn: Im Grunde 
interessiert der tatsächliche Widerstandswert keinen Menschen.

Deine ganze Umrechnung von ADC auf Temperatur lässt sich also zu

   Temperatur = k * ADC + d

eindampfen. Die einzige Frage ist: wie gross ist k, wie gross ist d.

Und da musst du jetzt deine Hausaufgaben machen und Vorarbeit auf dem 
Papier leisten. (oder aber ganz einfach die Werte empirisch bestimmen)

von Bernd N (Gast)


Lesenswert?

Meine Vorredner haben dir ja schon alles bestens erklärt. Eine weitere 
Möglichkeit ist deine Ganzen Ideen zu verwerfen und dir einen 2ten 
Referenzpunkt zu definieren, einen hast du ja schon.

>> Zimmertemperatur (22°C) auf 3700

Der 2te Wert wäre der ADC Wert bei z.B. 0 Celsius. Die Linearisierung 
erfolgt dann über die 2 Stützpunkte.

Beispiel:
1
#define AdcRawHigh      3700                                      // ADC Wert bei OutHigh
2
#define AdcRawLow       ?                                         // ADC Wert bei OutLow
3
#define DeltaRaw        (AdcRawHigh - AdcRawLow)                  // Differenz der Rawwerte
4
5
/*
6
    Ausgabewerte für die Stützpunkte mit Skalierungsfaktor. Mittels Skalierung werden die Werte
7
    von Steigung und Offset um die Kommastellen erweitert "Fixed-point Arithmetik".
8
*/
9
#define OutHigh         0.0                                       // Ausgabewert für AdcRawHigh (00 Grad Celsius)
10
#define OutLow          370.0                                     // Ausgabewert für AdcRawLow  (37 Grad Celsius)
11
#define Scale           65536                                     // zur Basis 2^16
12
#define DeltaOut        (OutHigh - OutLow)                        // Differenz der Ausgangswerte
13
14
/*
15
    Berechnung der ADC Korrekturwerte mittels Referenzpunkte.
16
    Theorie: Steigung = DeltaOut Ausgabewert / DeltaOut ADC-Wert.
17
    Daraus ergibt sich: Ausgangswert min = ADC-Wert min * Steigung + Offset.
18
    Nach Offset aufgelöst: Offset = Ausgangswert min - (ADC-Wert min * Steigung)
19
*/
20
#define Slope       (DeltaOut / DeltaRaw)                         // DeltaOut / DeltaRaw  = Steigung
21
#define Nullpunkt   (OutLow - AdcRawLow * Slope)
22
#define Offset      (int32_t) (Nullpunkt * Scale)                 // Offset zur Basis 2^16
23
#define Factor      (int32_t) (Slope * Scale)                     // Faktor zur Basis 2^16

Nun ist jedweder Fehler herausgerechnet und das Ausgabeformat paßt auch, 
ledigilich das Komma an die richtige Stelle setzen und fertig.
1
return (((ADC * Factor) + Offset) >> 16);

In den Beispiel hatte ich lediglich eine 1N4148 als Temp. Sensor und es 
funktioniert.

von Mr Bean (Gast)


Lesenswert?

Hallo

Vielen Dank nochmal für die Antworten. Habe mir fast alle irgendwie 
geholfen. :-)

Meine Funktion sieht mittlerweile folgendermaßen aus:
1
uint8_t GetAnalogTemp(int16_t *temp)
2
{
3
  int16_t analogTemp = 0;
4
  int16_t b = 3544;
5
  int16_t m = 408;
6
7
  calcAverage(TEMPSENSOR, 8, &analogTemp);
8
9
  analogTemp = analogTemp - b;
10
  analogTemp = analogTemp << 6;
11
  analogTemp = analogTemp / m;
12
13
  *temp = analogTemp;
14
   
15
   return SUCCESS;
16
}

Funktioniert soweit auch.
Ich hab mir einfach euren Rat zu Herzen genommen, zwei Werte gemessen 
und dann über die Zweipunkteformel m und b berechnet.
Brauche es nur aufs Grad genau. Verglichen zum ebenfalls verbauten lm75 
haut das ganze sehr gut hin.

Vielen Dank!

Grüße

Bean

von Bernd N (Gast)


Lesenswert?

:-) Wenn man die Lösung erkennt dann wirds sehr einfach, gut gemacht.

von Karl H. (kbuchegg)


Lesenswert?

Mr Bean schrieb:

> Ich hab mir einfach euren Rat zu Herzen genommen, zwei Werte gemessen
> und dann über die Zweipunkteformel m und b berechnet.
> Brauche es nur aufs Grad genau. Verglichen zum ebenfalls verbauten lm75
> haut das ganze sehr gut hin.

Jetzt hast du deine Hausaufgaben richtig gemacht :-)

Es ist nicht ungewöhnlich, dass sich mit ein bischen Vorarbeit einfache 
unkomplizierte Berechnungen ergeben, die auf Anhieb funktionieren.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.