Forum: Mikrocontroller und Digitale Elektronik STM32 Thermistor Temperaturberechnung ohne FPU


von Bert S. (kautschuck)


Lesenswert?

Hi,

Ich möchte so schnell wie möglich die Temperatur von einem Thermistor 
messen. Das ganze ist auf einem STM32L0 ohne FPU und von daher sehr 
ineffizient.

Folgende Zeilen Code verwende ich im Moment um die Temperatur zu 
bestimmen, was soweit auch klappt:
1
  int32_t tmp;
2
  float tmp_f;
3
4
  tmp = adc_data[ADC_OUTLET]; // 3V3|---|4k7 Balance|---|10k Thermistor|---|GND
5
  tmp = (tmp * ADC_REF_VOLTAGE_mV) / ADC_RESOLUTION; //Voltage over Thermistor
6
  tmp_f = (ADC_AMP_PULLUP_RESISTOR_OHM * tmp)/(ADC_REF_VOLTAGE_mV - tmp); //gives measured R_thermistor
7
  tmp_f = tmp_f / ((float) ADC_NTC_NOM_RESISTANCE_OHM); //Divide by nominal resistance
8
  tmp_f = (logf(tmp_f)/ADC_NTC_BETA ) + 1/AMBIENT_TEMPERATUR_IN_K;
9
  cm_master.temperatures.temp_outlet_dDeg = (int32_t)((10.0f/tmp_f) - ZERO_DEGREE_CELCIUS_IN_dK); //dDegC

Das Problem ist, dass ich einige FPU Operationen brauche und ebenfalls 
noch einen logf. Jemand eine Idee, wie ich das noch optimieren kann?

: Bearbeitet durch User
von STK500-Besitzer (Gast)


Lesenswert?

Bert S. schrieb:
> Jemand eine Idee, wie ich das noch optimieren kann?

Lookup-Table

von Bernadette (Gast)


Lesenswert?

Bert S. schrieb:
> tmp = adc_data[ADC_OUTLET]; // 3V3|---|4k7 Balance|---|10k
> Thermistor|---|GND
>   tmp = (tmp * ADC_REF_VOLTAGE_mV) / ADC_RESOLUTION;

Konstante Werte vorher zusammenfassen

von Walter T. (nicolas)


Lesenswert?

Bert S. schrieb:
> Ich möchte so schnell wie möglich die Temperatur von einem Thermistor
> messen.

Ist denn die float-Berechnung der begrenzende Teil bei der 
Geschwindigkeit?

von Bernadett (Gast)


Lesenswert?

Bert S. schrieb:
> tmp = adc_data[ADC_OUTLET]; // 3V3|---|4k7 Balance|---|10k
> Thermistor|---|GND
>   tmp = (tmp * ADC_REF_VOLTAGE_mV) / ADC_RESOLUTION;

Konstante Werte vorher zusammenfassen

von Bert S. (kautschuck)


Lesenswert?

Walter T. schrieb:
> Ist denn die float-Berechnung der begrenzende Teil bei der
> Geschwindigkeit?

Ja der kostet im Moment am meisten Ressourcen.

Bernadett schrieb:
> Konstante Werte vorher zusammenfassen

Yep das kann ich sicher schon einmal machen, danke.

STK500-Besitzer schrieb:
> Lookup-Table

Klingt nach einer guten Idee

von Gerhard O. (gerhard_)


Lesenswert?


: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Bert S. schrieb:
> Walter T. schrieb:
>> Ist denn die float-Berechnung der begrenzende Teil bei der
>> Geschwindigkeit?
>
> Ja der kostet im Moment am meisten Ressourcen.

Dann guck Dir mal das ASM-Listing an, ob überhaupt durchgehend 
float-Operationen stattfinden, oder ob irgendwo eine double promotion 
stattfindet.

von Klaus W. (mfgkw)


Lesenswert?

Warum rechnet man überhaupt in float, wenn es schnell gehen soll?

Ansonsten lookup-Tabelle mit linearer Interpolation zwischen den 
Stützstellen sollte das effizienteste sein, sowohl in float als auch in 
Festkomma.

(Abgesehen davon, daß ich nicht glaube, daß es wirklich schnell gehen 
muß. Temperaturmessungen bekommt man kaum im Millisekundentakt.)

von qq_q (Gast)


Lesenswert?


von Andreas M. (amesser)


Lesenswert?

Ich würde die Formel erstmal mathematisch optimieren. Z.b. logf(tmp_f / 
((float) ADC_NTC_NOM_RESISTANCE_OHM) ist das gleiche wie logf(tmp_f) - 
logf(ADC_NTC_NOM_RESISTANCE_OHM). Lezteres ist konstant und schon bist 
du eine Division los. Ich würde alles komplett in einander einsetzen und 
durch passendes Umformen erstmal versuchen die Division soweit es geht 
los zu werden. Als nächstes kann man sich dann logf genauer anschauen. 
Fix-Komma Zahlen ist ein Stichwort.

Da du aber sowieso nur ganzzahlige Temperaturwerte brauchst, reicht 
vermutlich einfach eine Lookuptabelle ADC->Temp. Die kann man komplett 
vorberechnen und die passt - wenn man sich schlau anstellt - bei 
typischen Temperaturbereichen in unter 100 Byte rein. Alleine die logf 
Funktion wird mehr Code brauchen.

von MaWin (Gast)


Lesenswert?

Temperaturen vom Thermistor ändern sich immer wesentlich langsamer als 
ein noch so langsamer uC zum umrechnen braucht.

Jede Floating Point Berechnung lässt sich auch auf Fixed Point 
Berechnung umstellen, zumal dir der Wertebereich des Ergebnisses ja 
bekannt ist.
Fixed Point ist nichts anderes als Umrechnung an der man den 
Dezimalpunkt (oder Binärpunkt) an eine beliebige Stelle hindefiniert 
hat.

Dein Problem ist der Logarithmus. Wenn du den umsetzen willst, solltest 
fu eine Tabelle nutzen. Die kann dann gleich die Umsetzung zwischen ADV 
Wert und Temperatur machen. Eventuell nicht 1024 Einträge, sondern 64 
und interpoliert.

von Walter T. (nicolas)


Lesenswert?

MaWin schrieb:
> Dein Problem ist der Logarithmus.

Sicher? Eigentlich sollte der Log2 eines normalisierten floats ein 
Kaffeekränzchen sein, und alle anderen Logarithmen sind Log2 
multipliziert mit einer Konstanten.

Nachtrag: Man kann übrigens alles, was im log() steht, (bis auf den 
ADC-Wert) ausklammern. Dann wird der Log2 eines Integers abgefragt. Der 
M0 hat zwar kein clz(), aber Raketenwissenschaft ist das auch nicht.

: Bearbeitet durch User
von Georg (Gast)


Lesenswert?

MaWin schrieb:
> Temperaturen vom Thermistor ändern sich immer wesentlich langsamer als
> ein noch so langsamer uC zum umrechnen braucht.

Deshalb habe ich solche Berechnungen (NTC -> Temperatur, in 0,1 Grad) 
schon vor 40 Jahren auf einem Z80 gemacht und der hatte keine Probleme 
damit, das so nebenher zu erledigen.

MaWin schrieb:
> Dein Problem ist der Logarithmus.

Muss er nicht, ein Näherungspolynom 3. Grades ist genau genug und 
braucht nur normale Multiplikationen (die Division habe ich nicht 
mitgelinkt).

Heute braucht man mindestens 32bit-Prozessoren mit GHz für etwas was in 
der Steinzeit ein 8bitter mit 4 MHz locker erledigt hat - was für ein 
Fortschritt.

Georg

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Bert S. schrieb:
> Ich möchte so schnell wie möglich die Temperatur von einem Thermistor
> messen.
So schnell wird das nicht sein müssen. Also könntest du die Berechnung 
auch in mehrere Schritte aufteilen und jeweils eine "Teilrechnung" pro 
Durchlauf der Mainloop berechnen.

STK500-Besitzer schrieb:
> Bert S. schrieb:
>> Jemand eine Idee, wie ich das noch optimieren kann?
> Lookup-Table
Mit linearer Interpolation zwischen den Stützpunkten. So würde ich das 
auch machen. Da wird man ganz schnell genauer als der Sensor an sich 
hergibt und kann aufhören, noch weiter zu rechnen.

von strolch (Gast)


Lesenswert?

Sinnvollerweise rechnet man einen Regelagorithmus in ADC Koordinaten und 
nicht in Temperatur.
Die Temperatur als float wird nur fuer den Benutzer benoetigt, und der 
ist hinreichend mit 2 updates pro sekunde ausgestattet. Mehr 
Screenupdates ergibt nur einen nervoesen Eindruck.

ADC Koordinaten bedeutet man rechnent des Sollwert von Temperatur nach 
ADC und rechnet den Fehler Soll-ADC- IST-ADC, und macht so weiter.

von uhuuuuuuu (Gast)


Lesenswert?


von DerEinzigeBernd (Gast)


Lesenswert?

Der µC hat einen 12-Bit-ADC. Wenn dessen Wertebereich komplett 
ausgenutzt wird (was schon eine sehr spezielle Beschaltung des Eingang 
benötigen dürfte), sind das 4096 Werte, die in der Lookup-Table 
aufgeführt werden müssen.

Man kann hier also schon mal rein überschlagsmäßig die Tabelle 
verkleinern, indem man betrachtet, was der realistisch vom ADC 
gelieferte Mindest- und Maximalwert ist (was wohl den vom Thermistor 
gemessenen Mindest- und Höchsttemperaturen entsprechen dürfte).

Dann sollte man das Thema Messauflösung betrachten. Welche Auflösung ist 
bei der Temperaturmessung tatsächlich sinnvoll? Welche Auflösung 
sollen denn die am Ende bestimmten Werte haben?

Wenn da Millikelvin rauskommen, hat man mit sehr hoher 
Wahrscheinlichkeit irgendwas grundlegendes übersehen.

von Patrick C. (pcrom)


Lesenswert?

Bert S. schrieb:
> Jemand eine Idee, wie ich das noch optimieren kann?

Ja, fang mal an die geschwindigkeit IMMER zu messen. Und definiere mal 
wie schnell du es haben wollst.

"So schnell wie moeglich" hat oft kein zweck

von Wolfgang (Gast)


Lesenswert?

Bert S. schrieb:
> Ich möchte so schnell wie möglich die Temperatur von einem Thermistor
> messen. Das ganze ist auf einem STM32L0 ohne FPU und von daher sehr
> ineffizient.

Was willst du beim Messen mit einer FPU?
Das einzige, was du brauchst, ist ein ADC. Alles andere muss nicht 
schneller sein, als sich die Temperatur auf Grund der Zeitkonstante des 
Sensors ändert.

Was ist dein eigentliches Problem?

von Anja (Gast)


Angehängte Dateien:

Lesenswert?

Bert S. schrieb:
> Jemand eine Idee, wie ich das noch optimieren kann?
Du schreibst nicht in welchem Temperaturbereich Du es brauchst.

Ansonsten: der Umweg über den Widerstand ist nicht notwendig.
Bei kleinen Temperaturbereichen (z.B. 10-40 Grad) reicht es den Pull-Up 
widerstand in die "Mitte" zu legen um bei linearer Interpolation 
(Spannung zu Temperatur) maximal 0.3 Grad Linearitätsfehler zu haben.
Bei größeren Temperaturbereichen -40 .. 125 Grad reicht eine 
Abschnittsweise lineare Interpolation.

Gruß Anja

von W.S. (Gast)


Lesenswert?

Bert S. schrieb:
> Ich möchte so schnell wie möglich die Temperatur von einem Thermistor
> messen. Das ganze ist auf einem STM32L0 ohne FPU und von daher sehr
> ineffizient.

Was ist für dich 'schnell' und was  'ineffizient'? Und wie schnell ist 
dein µC?
Ich hab mal kurz deinen Quellabschnitt überflogen und komme auf 2 
Multiplikationen, einen Logarithmus und fünf Divisionen. Soweit das 
dasteht.

Soweit ich mich erinnere, muß man für die gewöhnliche Steinhart-Hart 
Formel nicht x-mal irgend etwas immer wieder umrechnen, mal ganz grob 
geht das etwa so:
 tmp = ln(R);
 T = 1 / (A + B*tmp + C*tmp*tmp*tmp);
Und A, B und C sind Konstanten, die du beim Kalibrieren ermittelst. Ja, 
da mußt du deinen Thermistor bei 3 verschiedenen Temperaturen messen. 
Und das Nette an der Sache ist, daß der Maßstab, in dem R geliefert 
wird, herzlich egal ist, solange R auf die gleiche Weise bei der 
Kalibrierung gemessen wird, wie danach bei den Messungen. Der ganze 
Aufwand, um R in Ohm zu kriegen, ist dabei überflüssig.

Tja, um den ln kommst du nicht herum, aber wie viele Takte der bei 
deiner Implementierung braucht, wäre mal herauszukriegen. Notfalls 
kannst du den selber per Pseudodivision machen, das ist schneller als 
eine Reihenentwicklung.

W.S.

von Ralph S. (jjflash)


Lesenswert?

Lookup-Table-Generator:

https://www.sebulli.com/ntc/

Ich glaube, einfacher, effizienter und schneller wird das nichts werden. 
Bei 32-Stützstellen erzeugt die Tabelle im Schnitt einen Fehler von ca. 
0,15 °C bei Verwendung eines 12-Bit ADC's

von Bert S. (kautschuck)


Lesenswert?

Ralph S. schrieb:
> Lookup-Table-Generator:
>
> https://www.sebulli.com/ntc/
>
> Ich glaube, einfacher, effizienter und schneller wird das nichts werden.
> Bei 32-Stützstellen erzeugt die Tabelle im Schnitt einen Fehler von ca.
> 0,15 °C bei Verwendung eines 12-Bit ADC's

Das ist richtig gut! Die Zykluszeit des uC ist von 300us auf 15us 
runter, wenn ich in jedem Zyklus einen NTC auslese. Danke dir!

von Peter D. (peda)


Lesenswert?

Bert S. schrieb:
> Die Zykluszeit des uC ist von 300us auf 15us
> runter, wenn ich in jedem Zyklus einen NTC auslese.

Sowas nennt sich Mikrooptimierung, d.h. ohne jeden Effekt.
Kein Temperatursensor kann alle 300µs neue Werte liefern, dazu ist er 
viel zu träge. Dazu braucht man Sensoren, die auf Strahlungsmessung 
beruhen.

Alle 1s oder 10s eine Messung, ist für viele Aufgaben völlig 
ausreichend. Nebenbei kann man dadurch den Fehler durch Eigenerwärmung 
deutlich reduzieren, wenn man zwischen den Messungen den Sensor 
abschaltet.

von PittyJ (Gast)


Lesenswert?

Ich arbeite seit Jahren mit digitalen Temperatursensoren und auch mit 
NTCs am AD-Wandler.
Diese Sensoren sind meist sehr träge, weil sie ja auch erwärmt werden 
müssen, und da die Energie ins Gehäuse erst eindringen muss.
Bei normalen Umweltsensoren meiner Maschinensteuerung wird erst nach 
gewisser Zeit ein Temperaturanstieg gemessen. Von daher reicht bei mir 
eine Messung pro Sekunde mehr als aus. Die Kühlung dahinter ist immer 
noch super regelbar.

Falls du nicht im Millisekundenbereich mit einem Bunsenbrenner auf den 
Sensor gehst, ist eine 'schnelle' Abfrage und Umrechnung vollkommen 
überflüssig.

Schau erst einmal, wie schnell sich im Normalfall die Werte deines 
Sensors sich überhaupt ändern.

von PittyJ (Gast)


Lesenswert?

Achja, nochwas:
Dein ADC wird rauschen. Es wäre praktischer, erst einmal ein paar 
ADC-Werte zu sammeln, und dann einen Mittelwert daraus berechnen, um das 
Rauschen zu entfernen. Erst danach mit dem Mittelwert eine Temperatur 
berechnen.

von Georg (Gast)


Lesenswert?

Bert S. schrieb:
> Die Zykluszeit des uC ist von 300us auf 15us
> runter

Und wozu brauchst du 60000 Temperaturwerte pro Sekunde? 
Wasserstoffbombenexplosion analysieren?

Vermutlich hast du dich vollkommen verrannt.

Georg

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.