www.mikrocontroller.net

Forum: Projekte & Code PT100 Berechnung der Temperatur @ Widerstand


Autor: THM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier eine kleine Möglichkeit, die Temperatur anhand des gemessenen 
Widerstandes zu berechnen (Platin-Temperaturkoeffizienten):
/* Diesen Block am Anfang global initialisieren.
double const A = 3.9083E-3;
double const B = -5.775E-7;
double const C = -4.183E-12;
double const R0 = 100;          // Widerstand bei 0°C
double T = 0;                   // Temperatur bei 0°C
*/

double PT100_Temp (double R)  // Temperaturberechnung -30 .. 500°C ausreichend genau
{
  T = ((-A*R0)+(sqrt(((A*R0)*(A*R0))-(4*B*R0*(R0-R)))))/(2*B*R0);
  return T;
}  

Zwischen -30°C und 400°C ist die Berechnung ausreichend genau, obwohl 
die DIN IEC 751 nur Temperaturen >0°C zulässt.

Ist ein bischen 'Krieg der Klammern' geworden, aber der Compiler 
optimiert die Rechenzeit auf 2.5µs @ 16MHz.

Für Verbesserungen bin ich jederzeit dankbar.

Autor: THM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Muss mich korrigieren, die Rechenzeit beträgt 1.38µs @ 16MHz.

Autor: Wolfram Quehl (quehl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
donnerwetter, kann ich nur sagen. In 22 takten mehrere Floating Point 
Multiplikationen und eine Wurzel Berechnung, das ist Rekord. Aber das 
steht ja nicht dabei, welcher Prozessor das ist. Vielleicht ein IBM 
Vektorrechner mit vielen parallel laufenden Prozessoren?

mfg

Autor: THM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry! Ist ein ATmega32 bei 16MHz.
Wie ich schon schrieb: der Compiler optimiert aufgrund der vielen 
Konstanten prima, also wird da nicht mehr viel gerechnet! ;-)

Autor: Wolfram Quehl (quehl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kannst Du den übersetzten Assembler Code hier mal reinstellen? Bei 22 
takten kann das ja nicht viel sein.

mfg

Autor: THM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Welchen denn? Das Teil ist in meinem Regler integriert, ohne weitere 
Includes krieg' ich das nicht auseinandergefieselt.

Lass' es doch einfach über den Debugger im AVR-Studio laufen, die 
Stoppuhr zeigt dir die Zeit korrekt an!

mfg

Autor: THM (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht hilft das weiter:
Quelltext:
#include <avr/io.h>
#include <math.h>


double const A = 3.9083E-3;
double const B = -5.775E-7;
double const C = -4.183E-12;
double const R0 = 100;          // Widerstand bei 0°C
double T = 0;                   // Temperatur bei 0°C
double Dummy = 0;


double PT100_Temp (double R)    // Temperaturberechnung -30 .. 500°C ausreichend genau
{
  T = ((-A*R0)+(sqrt(((A*R0)*(A*R0))-(4*B*R0*(R0-R)))))/(2*B*R0);
  return T;
}  

int main (void)
{

Dummy = PT100_Temp (109);

for (;;)
  {
  
  }
}
und das compilierte Hex-File als Anhang.

Autor: Branko Golubovic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
double T = 0;                   // Temperatur bei 0°C

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
THM wrote:
> Muss mich korrigieren, die Rechenzeit beträgt 1.38µs @ 16MHz.

Wohl eher 1.38 ms
Zumindest bewegt sich auf meinem Debugger die Zeit in diesem
Bereich. Was bei knapp 16000 verbrauchten Taktzyklen auch nicht
weiter verwunderlich ist.
Wurzel berechnen kostet nun mal seine Zeit.

Autor: Kai G. (runtimeterror)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Weiß gerade einer aus dem Stehgreif, wie der Compiler die Wurzel 
umsetzt? Das einzige Verfahren, das mir spontan einfällt ist das 
Heron-Verfahren und das braucht eine Division pro Approximationszyklus - 
und die muss auch erstmal dem Mega32 beigebracht werden...

Ich hätt's wahrscheinlich eher als Wertetabelle mit linearer 
Interpolation umgesetzt - oder kubisch, wenn's zu ungenau würde.

Können ja 'nen Contest draus machen, wer die schnellste Implementierung 
hinkriegt ;)=
(Macht natürlich nur Sinn, wenn die aktuelle Messlatte wirklich bei 
16000 liegt)

Autor: THM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, hab's nochmal extra getestet: komme auf 242.94µs.

So langsam glaube ich dem Debugger nix mehr! :(
Hat mich ehrlich gesagt auch gewundert, dass das Teil so schnell war ;)
#include <stdio.h>
#include <math.h>
#include <avr/io.h>


double const A = 3.9083E-3;
double const B = -5.775E-7;
double const C = -4.183E-12;
double const R0 = 100;          // Widerstand bei 0°C
double T = 0;                   // Temperatur bei 0°C
double Dummy = 0;


double PT100_Temp (double R)    // Temperaturberechnung -30 .. 500°C ausreichend genau
{
  T = ((-A*R0)+(sqrt(((A*R0)*(A*R0))-(4*B*R0*(R0-R)))))/(2*B*R0);
  return T;
}  

int main (void)
{

Dummy = PT100_Temp (109);
Dummy = 0;
for (;;)
  {
  }
return 0;
}

Autor: Wolfram Quehl (quehl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mehrere messungen in einer Schleife laufen lassen und die Ergebnisse 
über RS232 an PC senden und speichern. Und Uhrzeit jede sek. übertragen. 
Aus dem Abzählen der Übertragungen zwischen den Sekunden kann man die 
Rechenzeit berechnen. Das geht allerdings nur, wenn der RS232 keinen 
Engpaß darstellt.
Aber zwischen 2 µs und 230µs ist schon ein Riesenunterschied und man 
sollte auch die Glaubhaftigkeit anhand der Assemblerliste überprüfen. 
Deshalb hatte ich ja danach gefragt.

mfg

Autor: THM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast du Recht. Ich werde das in Zukunft auch in der Hardware testen.
;-)

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
<Zwischen -30°C und 400°C ist die Berechnung ausreichend genau, >

Bist Du Dir sicher, ob double dafür ausreicht? Oder was ist ausreichend?

Autor: THM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Double reicht dafür dicke.
Die Genauigkeit bezieht sich auf den berechneten Widerstand, bei 400°C 
sind das ca. 0.3°C Abweichung. Meines erachtens noch tolerierbar.

Autor: Kai G. (runtimeterror)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was die Zeitmessung angeht: Die Dauer der Wurzelberechnung ist 
vermutlich stark vom zu berechnenden Wert abhängig. Kann auch ein Grund 
sein, warum eure  Messungen so stark auseinanderlaufen.

Autor: THM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>stark vom zu berechnenden Wert abhängig.

Habe ich grade getestet:
schwankt zwischen 190 und 250µs (ca.)

Je nachdem ob Nachkommaanteil drin ist, die Größe der Zahl ist auch 
ausschlaggend.

Autor: Arc Net (arc)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Double reicht dafür dicke.

Dafür reichen normalerweise auch die (32-bit) floats mit denen der avr 
rechnet.

> Die Genauigkeit bezieht sich auf den berechneten Widerstand, bei 400°C
> sind das ca. 0.3°C Abweichung. Meines erachtens noch tolerierbar.

Da müsste auch mit floats ein Fehler << 0.1 K rauskommen.
Allerdings sollte man sich auch nicht auf jede Tabelle verlassen!
Mal sinds 247.038 Ohm, mal 247.07 Ohm oder 247.092 Ohm bei 400 °C.
(247.092 Ohm sollte man mit der Standardformel bei 400 °C rausbekommen)
    // simple Look-up-Tabelle
    // Fehler sind afair +-0.05 °C 
    ushort PT100Pos[150 + 1];
    ushort PT100Neg[40];

    // ohm = Widerstand * 100
    // Ergebnis = Temperatur in °C * 100
    int R2Temp(int ohm) {
        int r100 = ohm / 100;
        int r100rem = ohm - r100 * 100;
        int r1, r2;
        int r3;        
        if (ohm >= 10000) {
            r1 = PT100Pos[r100 - 100];
            r2 = PT100Pos[r100 - 100 + 1];
        } else {
            r1 = PT100Neg[100 - r100];
            r2 = PT100Neg[100 - r100 + 1];
        }
        r3 = (r2 - r1) * r100rem;
         
        return r1 + r3 / 100;
    }

    // Tabellenerzeugung
    for (int res = 100; res < 250 + 1; res += 1) {
        PT100Pos[res - 100] = (ushort)(RTDOhmToTemp(100.0, res) * 100.0);
    }
    for (int res = 100; res > 60; res -= 1) {
        PT100Neg[100 - res] = (ushort)(-RTDOhmToTemp(100.0, res) * 100.0);
    }

247.092 Ohm
http://grundpraktikum.physik.uni-saarland.de/scrip...
247.04 Ohm
http://www.temp-web.de/cms/front_content.php?idcat=214

Autor: Arc Net (arc)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kommt davon wenn man sowas aus dem Kopf postet...
Also noch mal das ganze
// int = 32-Bit 
// short = 16-Bit
// Tabellenerzeugung
void CreateTableUShort(void) {
    for (int res = 100; res < 250 + 1; res += 1) {
        PT100Pos[res - 100] = (ushort)(RTDOhmToTemp(100.0, res) * 100.0);
    }
    for (int res = 100; res > 60; res -= 1) {
        PT100Neg[100 - res] = (ushort)(-RTDOhmToTemp(100.0, res) * 100.0);
    }
}

int R2TempUS(ushort res) {
    ushort r100 = res / 100;
    ushort r100rem = res - r100 * 100;
    ushort r1, r2;
    int r3;
    if (res >= 10000) {
        r1 = PT100PosUS[r100 - 100];
        r2 = PT100PosUS[r100 - 100 + 1];
        r3 = (r2 - r1) * r100rem;
        return r1 + r3 / 100;
    } else {
        r1 = PT100NegUS[100 - r100];
        r2 = PT100NegUS[100 - r100 - 1];
        r3 = (r2 - r1) * r100rem;
        return -(r1 + r3 / 100);
    }
}


// Variante bis ~320 °C und signed short
void CreateTableShort(void) {
    for (int res = 100; res < 220 + 1; res += 1) {
        PT100PosS[res - 100] = (short)(RTDOhmToTemp(100.0, res) * 100.0);
    }
    for (int res = 100; res > 60; res -= 1) {
        PT100NegS[100 - res] = (short)(RTDOhmToTemp(100.0, res) * 100.0);
    }
}

short R2TempS(short res) {
    short r100 = res / 100;
    short r100rem = res - r100 * 100;
    short r1, r2;
    short r3;
    if (res >= 10000) {
        r1 = PT100PosS[r100 - 100];
        r2 = PT100PosS[r100 - 100 + 1];
    } else {
        r1 = PT100NegS[100 - r100];
        r2 = PT100NegS[100 - r100 - 1];
    }
    r3 = (r2 - r1) * r100rem;
           
    return r1 + r3 / 100;
}




Autor: THM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Arc Net:
float und double haben beim AVR beide 32 bit. ;)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.