Pfad:
Home =>
AVR-DE =>
Anwendungen => Temperaturmessung mit ATtiny24
This page in english:
 |
AVR-Anwendungen
Temperaturmessung mit einem ATtiny24 |
ATtiny24-Thermometer
Manche der neueren AVR-Typen haben eingebaute Thermometer. Diese messen die Temperatur
auf dem Controller-Chip, wenn eine ADC-Wandlung in einem besonderen Multiplex-Kanal
angestoßen wird. Das Ergebnis der Messung wird im 10-Bit-Modus vom ADC auf dem
eingestellten Kanal bereitgestellt. Diese Seite hier zeigt, wie man die Messergebnisse
auslösen, diese auswerten und in Temperaturwerte - entweder in Kelvin, in Grad
Celsius oder in Grad Fahrenheit - umrechnen und auf einer kleinen LCD ausgeben kann.
Wer lieber einen professionellen PT100-Sensor dafür benutzen will:
hier gibt es das.
Diese Seite zeigt,
- wie die Messung vor sich geht, und
- wie die Messergebnisse mit einer quadratischen Funktion interpoliert werden
können, da keine einfache lineare Funktion vorliegt, und
- wie eine ausgefuchste Hardwarelösung dafür aussieht, und
- wie das alles Mittels eines Assembler-Quellcodes erledigt werden kann.
Diese Seite zeigt ferner, wie
- zwei 16-Bit-Zahlen per Software miteinander multipliziert werden können,
da der ATtiny24 keinen Hardware-Multiplizierer an Bord hat,
- man Festkomma-Dezimalzahlen verwendet, um sich damit die Fließkomma-Bibliothek
vom Hals zu halten und die Temperaturauflösung damit auf 0,1°C zu bringen,
- wie man eine quadratische Funktion y = a*x2 + b*x + c verwenden kann, um
damit nicht-lineare Daten zu interpolieren,
- wie man die Genauigkeit von Berechnungen erhöhen kann, wenn man Faktoren von
256n auf die zu berechnenden Zahlen aufschlägt,
- wie man Binärzahlen von 0,45 aufwärts aufrunden kann, und wie
- eine Drei-Faktor-Gleichung mit Potenziometern justierbar gemacht werden kann.
Wie immer gibt es alle Zeichnungen auf dieser Seite als LibreOffice-Draw-Datei unter
hier, alle Berechnungen als LibreOffice-Calc-Datei
hier.
Wenn man das interne Portregister ADMUX auf den folgenden Kanal einstellt:
ldi R16,0b100010|(1<<REFS1) ; Temperaturmessung, Ref-Spannung = 1.1 V
out ADMUX,R16
und wenn man den ADC mit diesem Kanal startet, z. B. so:
.equ cAdcClkDiv = (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
ldi R16,(1<<ADEN)|(1<<ADSC)|cAdcClkDiv ; Startet ADC und erste Messung
out ADCSRA,R16
Wenn Du dann wartest, bis der ADC seine Arbeit verrichtet hat und sein ADSC-Bit
wieder auf Null zieht, kannst Du das Wandler-Ergebnis mit dem folgenden
Instruktionsdschungel
WaitAdc:
sbic ADCSRA,ADSC ; Pruefe ADSC-Bit
rjmp WaitAdc ; Wandlung noch nicht fertig, warte weiter
in R0,ADCL ; Lese LSB des Ergebnisses
in R1,ADCH ; dto., MSB
in das Registerpaar R1:R0 einlesen.
1.1 Die Temperaturkennlinie des ATtiny24
Das ist das, was ATMEL/Microchip im Handbuch des ATtiny24 schreibt. Bitte beachten,
dass hier steht "Typical Case", nicht garantierter Wert. Es steht noch da,
dass Steigerungen der Temperatur um ein Grad den ADC um eine Einheit erhöhe
(was offenkundig unzutreffend ist und nur stimmt, wenn man es nicht ganz so genau
nimmt und "roughly" davorschreibt). Wir lernen daraus, dass jedes Exemplar
so seine eigenen Vorstellungen von Temperatur hat und dass eine Kalibrierung
nötig wird, wenn wir es etwas genauer haben wollen.
1.1.1 Linearfunktion
Wenn man sich die angegebenen Datenwerte etwas genauer anschaut, sieht man, dass
die Steigung der ADC-Werte unterhalb von 25°C, die sich zu (25 - (-40)) /
(300 - 230) = 0,92857 ergibt, etwas höher ist als oberhalb: (85 - 25) /
(370 - 300) = 0,85714. Daher muss bei einer Erhöhung der Genauigkeit dies
berücksichtigt werden. ATMEL/Microchip geht mit keinem Wort darauf ein und
empfiehlt stattdessen eine lineare Näherung.
Wenn man das so tut, kann man entweder eine Gerade durch alle drei Punkte legen
und den ADC-Wert von 300 als fest setzen oder man bestimmt die Gerade aus den
drei Punkten. Auch das ergibt zwei unterschiedliche Geraden.
Auf jeden Fall sollten wir bei unseren mathematischen Bemühungen im Folgenden
die absolute Temperatur in Kelvin anwenden, damit wir die negativen Werte der
Celsius- und Fahrenheit-Skalen loswerden. Von Kelvin kommt man auf Celsius, indem
man 273,15 davon abzieht, von Fahrenheit kommt man zu Kelvin, indem man 32°F
abzieht und das Ergebnis mit 5 / 9 malnimmt und 273,15 hinzu addiert.
Das ist schon alles an Berechnungen, womit wir eine Steigung von
ADC = (25 + 273,15) / 300 = 0,9938 pro K
kriegen, also auch nicht so ganz Eins.
Wenn wir die zwei anderen Punkte zusätzlich berücksichtigen und eine
Gerade unter Bestanpassung (Best-Fit) errechnen, kriegen wir mit dem Temperatur
T in Kelvin die Formel:
ADC = 0,1395 * T (K) + 286,2619
Wenn wir hingegen zwei unterschiedliche lineare Funktionen ansetzen, kriegen wir
unterhalb von 25°C: ADC = 0,14509 * T (K) + 195,786
oberhalb von 25°C: ADC = 0,13393 * T (K) + 410,071
1.1.2 Eine quadratische Funktion
Aus den drei doch sehr unterschiedlichen Funktionen erkennt man, dass eine
lineare Funktion nicht das Gelbe vom Ei ist: sie produziert erhebliche
Abweichungen, Ungenauigkeiten und Fehler. Lasse uns daher lieber eine
quadratische Funktion ausprobieren. Die quadratische Funktion geht
folgendermaßen:
ADC = a * T2 + b * T + c
Weil wir mehr an der Berechnung der Temperatur aus ADC-Werten interessiert
sind, lautet sie auch folgendermaßen:
T = a * ADC2 + b * ADC + c
wobei a, b und c sich natürlich in beiden Formeln unterscheiden.
Das hier ist die quadratische Funktion, die wir im Folgenden verwenden.
Tatsächlich beginnt sie bei Temperaturen etwas unter Null, was
natürlich physikalischer Unsinn ist. Sie endet oberhalb von 1.023,
wonach sie wieder abwärts geht, was ebenfalls Unsinn ist. Weil der
ADC aber nur Werte zwischen 230 und 370 zurückliefert, bleiben wir
von den beiden Chaosbereichen weit genug weg: wir verwenden nur den rot
gefärbten Teil der Kurve.
Weil das Handbuch drei ADC/t-Datenpunkte hergibt, und weil die Quadratfunktion
genau drei Konstanten braucht, können wir diese drei aus den Datenpunkten
bestimmen. Das Bild rechts zeigt, wie man das mit 3-mal-3-Determinanten macht.
Die Berechnung findet man in der Rechentabelle "quadratisch".
Die Werte der drei Konstanten in T = a * ADC2 + b * ADC + c sind:
a = -0,000510
b = 1,198980
c = -15,625510
Wenn eine einzelne ADC-Messung in Kelvin umgewandelt werden soll, kann man
diese drei Konstanten verwenden.
Weil beim praktischen Messen immer 64 Einzelmessungen aufsummiert werden, kann
man die Summe 64*ADC auch direkt verwenden. Die Parameter dafür lauten
dann:
a = -1,2456E-06
b = 0,18734
c = -156,2551
Bitte beachten, dass a und c negativ sind, nur der lineare Term mit b ist
positiv.
Die Tabellenzellen von A68 bis H97 demonstrieren die Temperaturberechnung aus
den ADC-Werten im Detail. Die Zeile mit ADC=300 (der 25°C-Wert) kommt zu
den folgenden Einzelbeiträgen:
- Quadratischer Teil: -45,9184,
- Linearer Teil: 359,6939,
- Konstanter Teil: -15,6255.
Das bedeutet, dass alle drei Teile der Funktion signifikant zum Endergebnis
beitragen. Der lineare Teil leistet zwar den höchsten Anteil, aber die
beiden Subtraktoren sind auch nicht zu verachten und korrigieren den linearen
Teil ganz gehörig abwärts.
So wirkt sich die Funktion aus: während der lineare Teil mit b * ADC
linear anwächst, subtrahiert der quadratische Funktionsanteil
a * ADC2 zunehmend mehr. Der Beitrag ist von relevantem Umfang.
1.1.3 Logarithmische Funktion
Die meisten natürlichen Phänomene haben logarithmische Funktionen.
Das sollten wir also ebenfalls ausprobieren.
Das Ergebnis ist die Formel, wie sie in rot im Diagramm steht. Sie zeigt etwas
höhere Temperaturwerte im mittleren Temperaturbereich um 25°C und
geringfügig zu niedrige an den beiden Enden.
Aber: wenn wir die Formel auf unsere drei Punkte anwenden, enden wir mit
-1,45° bei -40°C und mit -1,83° bei +85°C, während die
berechnete Temperatur bei +25°C um ganze 1,83° zu hoch ist.
Folglich ist die logarithmische Funktion offenkundig kein guter Ansatz zur
Temperaturberechnung, wenn man die Genauigkeit in Richtung auf das
0,1 K/°C-Ziel steigern will. Außerdem ist der Logaritmus bei
Assembler-Programmierern sowieso sehr unbeliebt, da er in Riesentabellen
endet, die mich sehr an meine frühe Schulzeit erinnern (ich habe in
den Sechziger Jahren des letzten Jahrhunderts noch mit Logarithmentabellen
in Büchern rechnen dürfen).
1.1.4 Vergleich der quadratischen Funktion mit linearen Funktionen
Das hier vergleicht die quadratische mit der linearen Best-Fit-Kurve. Gerechnet
ist die Temperatur in Kelvin und in °C aus gegebenen ADC-Werten.
Wie man sieht, unterschätzt die lineare Funktion die Temperatur um 25°C
herum und überschätzt sie an den Extrempunkten. Wir werden später
noch sehen, wieviel Grad genau das ausmacht.
Eine kurzes Resumee: wir verlassen uns lieber auf die quadratische Funktion als auf
die von ATMEL/Microchip vorgeschlagene lineare Funktion.
Wir müssen drei Messungen der drei Potenziometer vornehmen, um deren
Stellung zu ermitteln. Danach müssen wir den Temperaturkanal messen,
und das alles dann in Temperaturen umwandeln und anzeigen.
2.1 Mittelwertbildung
Zu allererst: es ist keine gute Idee, die Spannungen und die Temperatur einmalig zu
messen, in eine Temperatur umzurechnen und anzeigen. Warum nicht? Weil das alles
viel zu schnell geht und wir die LCD mit einer Vielzahl von Einzelmessungen fluten
würden. Und das würde die letzte Ziffer unlesbar machen. Um das zu
demonstrieren, hier die Berechnung der Messfrequenz. Einmal mit einem
ADC-Taktvorteiler von 2, einmal mit dem Maximum von 128.
Parameter | Schnell | Langsam |
Taktfrequenz | 1 MHz |
ADC-Taktvorteiler | 2 | 128 |
ADC-Zyklen pro Wandlung | 13 |
ISR-Zyklen bis zum ADC-Neustart | 17 |
ADC-Kanäle zu messen | 4 |
Gesamt-Takt-Teiler | 172 | 15.360 |
Messfrequenz | 5,81 kHz | 65,1 Hz |
Messdauer | 0,172 ms | 15,36 ms |
Rechen-/Anzeigedauer | 1,7 ms |
Messen plus Rechnen | 1,872 ms | 17,06 ms |
Mess-/Anzeigefrequenz | 534 Hz | 58,6 Hz |
Die Konklusio ist, dass selbst im langsamsten Fall mit 59 Hz die letzte Ziffer
der Temperatur nur noch flackert und jedenfalls nichts mehr Vernünftiges ablesbar
sein würde. Nun, ganz so schnell geht es nicht, weil wir ja für die
Temperaturberechnung und die LCD-Ausgabe noch etwa eine Millisekunde brauchen, was
aber den Ablauf auch nicht arg genug abbremst.
Um das Flackern der letzten Ziffer zu vermeiden, könnten wir natürlich
von allen Messungen nur jede 30ste anzeigen lassen. Wir könnten aber auch
64 dieser Messungen aufsummieren und diese Summe dann durch 64 teilen (sechs
mal rechts-schieben). Wenn wir das machen, kriegen wir die obere Rechnung noch
mal durch 64 geteilt, und das kann man nun bequem und sekündlich ablesen.
Den Durchschnitt aus 64 ADC-Messungen zu nehmen, hat auch noch den Vorteil, dass
das Klappern des letzten Bits beim Messen wegfällt. Das ist fast so gut
wie ein elftes ADC-Wandler-Bit, daher können wir es unternehmen, das letzte
Digit hinter dem Komma auch noch etwas ernst zu nehmen (25,0 anstelle 25°C).
Natürlich bleibt uns das elende Teilen durch 64 mit zwölf Mal
Rechts-Schieben dann auch noch erspart, wenn wir es direkt in unsere Formeln
hineinpacken. Der Packen heißt im Folgenden 64*ADC oder kürzer 64ADC.
Und: wir programmieren eine interrupt-getriebene Routine anstelle des ewigen
Wartens, bis ADSC wieder Null wird. Hier ist der Assembler-Code dafür:
; ADCC interrupt service routine
AdccIsr:
in rSreg,SREG ; Save SREG
in rimp,ADCL ; Read LSB from ADC
add rAdcL,rimp ; Add to sum, LSB
in rimp,ADCH ; dto., read MSB
adc rAdcH,rimp ; dto., add MSB to sum
dec rAdcCnt ; Decrease ADC counter
brne AdccIsrRestart
sbr rFlags,1<<bAdc ; Set ADC flag
reti ; Return from interrupt
AdccIsrRestart:
ldi rimp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|cAdcClkPrsc ; Restart ADC
out ADCSRA,rimp
reti
Nach 64 Wandlungen, wenn die bAdc-Flagge gesetzt wird, sind alle Messungen
aufsummiert und das Resultat steht im Registerpaar rAdcH:rAdcL. Die nachfolgenden
Berechnungen erfolgen dann außerhalb, als Reaktion auf diese gesetzte Flagge.
Nach Abschluss der Berechnungen gibt es dort noch folgendes zu tun:
- Nullsetzen von rAdcH:rAdcL, und
- den Zähler in rAdcCnt auf 64 setzen, und
- den nächsten MUX-Kanal in ADMUX schreiben, und
- die erste Wandlung durch Schreiben in das ADCSRA starten.
Alles weitere läuft dann wieder in der ISR des ADCC-Interrupts ab und der
Controller kann schlafen gelegt werden.
2.2 Die Temperatur als Festkommazahl
Die Forderung, bei der Temperatur auch noch eine Dezimalziffer hinter dem Komma
auszugeben, macht den denkfaulen C-Programmierer jetzt ganz wuschig: wo hatte ich
bloß die Fließkommabibliothek? Und flugs wechselt er schnell den
AVR-Typ, denn seine Float-Lib passt so gar nicht in das super-mickrige Flash vom
ATtiny24 hinein. Hatte ich es doch gewusst: dazu brauche ich jetzt natürlich
meinen Arduino und einen ATmega328, drunter geht es schon mal gar nicht.
Wie, der macht die Kommazahlen jetzt ganz ohne Floats? Wie soll das denn gehen?
Nun, einfach, indem man T in Kelvin 10 * T ausrechnet, die Binärzahl in
Dezimal umwandelt und vor die letzte Ziffer ein Komma einschmuggelt. Schon ist alles
Integer und die Fließkomma-Bibliothek mehr als flüssig. Und schon passt
alles in das Micker-Flash - Intelligenz ersetzt unnötigen Binärschrott.
So sieht dann unsere Formel aus, mit der wir die 64ADC-Werte in Kelvin umrechnen:
10 * T (K) = a * 64ADC² + b * 64ADC + c
Um aus den 10 * T dann die 10 * °C zu machen, müssen wir einfach statt
273,15 nur einfach 2.731,5 abziehen. Die Umwandlung von Kelvin in °F ist ein
wenig komplizierter, siehe unten für die Details.
2.3 Bestimmung von a, b und c in der quadratischen Funktion
Das Bestimmen von a, b und c für die obige 10*T-Formel geht wieder einfach
mit Determinanten, nur setzen wir jetzt statt ADC 64ADC ein und statt T 10*T.
Das ändert nur die Konstanten, sonst nix. Die lauten jetzt mit den Werten
aus dem Handbuch:
a = -1.24561543367347E-06
b = 0.18734056122449
c = -156.255102040816
Nun, der zweite entscheidende Trick, um solche krummen Kommazahlen loszuwerden
ist es, die mit Vielfätigen von 256n malzunehmen und dann
einfach n Bytes vom Ergebnis hinten wegzustreichen (oder zum Runden zu
benutzen). Die Tabelle zeigt, wie es geht.
Mult | Wert | 256n | Multiplikator | Multiplizierter Wert | Gerundet |
a | -1,24561543367347E-06 | 2564 | 4.294.967.296 | -5349,87755102041 | -5.350 |
b | 0,18734056122449 | 2562 | 65.536 | 12277,5510204082 | 12.278 |
c | -156,255102040816 | 2561 | 256 | -40001,306122449 | -40.001 |
Wie durch ein Wunder passen jetzt alle Zahlen auch noch in einen 16-Bit-Integer,
mit dem sich herrlich weiter rechnen lässt. Und die Rundungsfehler sind
auch ziemlich klein geworden (z. B. 0,45 gegenüber 12.277 beim
Faktor b), da lassen sich gemächlich 0,1° ausreichend genau berechnen.
Wer nun allerdings aus lauter Angst vor der 16-mal-16-Bit-Multiplikation der
Ansicht ist, dass es eigentlich auch ganz ohne Multiplikation gehen sollte,
weil der AVRxy gar keinen Hardware-Multiplikator hat, der befüllt sein
Flash mit einer riesigen Tabelle und liest für jeden 64ADC-Wert die
zugehörige Temperatur heraus. Binärschrott statt Intelligenz halt.
2.4 Vergleich der quadratischen Funktion mit den linearen Funktionen
Unter diesen Umständen (64ADC, 10T, 256n) noch mal zurück
zum Vergleich der quadratischen mit der linearen Funktion.
Was noch aussteht, ist die genaue Abweichung der Linearfunktion von der
quadratischen, und zwar in Grad. Hier ist sie.
Die Parameter a, b und c sind wie oben dargstellt ausgewählt. Die blaue
Kurve sieht ziemlich linear aus, ist sie aber rein gar nicht. Das zeigt die
rote Kurve an, die mit der rechten Skala die Differenz zwischen der linearen
und der quadratischen Funktion darstellt. Die Abweichungen reichen von +10
bis -17, da 10*T abgebildet ist sind das plus 1,0° bzw. -1,7°. Die
Differenz ist nur in einem sehr engen Wertebereich unter 0,1°. Mit so was
linearem kommt eine Auflösung von 1° gerade recht, und schon mal
rein gar nicht bei Raumtemperatur, da sind es eher 2° Fehler.
Und das kriegt man mit einer Geraden auch nicht besser hin.
Schlaumeier nehmen nun lieber zwei Geraden: eine oberhalb und eine unterhalb
von 25°C. Nun halten sich die Abweichungen der Linear- von der quadratischen
Funktion in etwas engeren Grenzen, sie liegen bei einem 10T von 6, entsprechend
0,6°. Aber auch nichts, mit dem man sich eine Auflösung von 0,1°
zutrauen würde, hier ist eher bei 0,5° Ende Gelände. Alles
darunter wäre eine dreiste Lüge.
Oder man nimmt halt die quadratische Funktion, die kriegt das allemal besser
hin.
2.5 Justieren der quadratischen Kurve mit Potentiometern
Aus dem Handbuch wird deutlich: ohne Justierung gibt es keine verlässlichen
Temperaturmessungen. Wir müssen daher a, b und c in der quadratischen
Gleichung anpassbar machen. Eine Möglichkeit wäre, sie um +/- 5%
um ihren Wert herum zu ändern.
Für z. B. den Parameter a heißt das, dass der Multiplikator von
5.350 um 5% niedriger anzusetzen wäre, also stattdessen 5.083, und 5%
höher, also 5.618. Daraus ergibt sich eine Variation von 5.618 - 5.083 =
535. Diese Bandbreite wäre durch die Poti-Stellung zum Mindestwert von
5.083 hinzu zu addieren. Wir müssen daher 64ADC nur mit 535 multiplizieren,
das Ergebnis durch 65.536 teilen und zu 5.083 hinzu addieren, um den justierten
Multiplikatorwert zu kriegen.
Selbiges geht nun genauso mit b und c, allerdings mit anderen Zahlenwerten
für die Untergrenze und die Variationsbreite.
In Assembler würde das dann so aussehen:
.equ cPercent = 5 ; Prozent Variation +/- 5%
; Default Mittelwerte fuer a, b und c aus der Tabellenkalkulation
.equ cMidA = 5350 ; a Mittelwert aus Berechnung
.equ cMidB = 12278 ; b Mittelwert
.equ cMidC = 40001 ; c Mitelwert
; Berechnung der Variationsbreite (Range)
.equ cLowA = (cMidA * (100 - cPercent) + 50) / 100 ; Niedriger Wert a
.equ cHighA = (cMidA * (100 + cPercent) + 50) / 100 ; Hoher Wert a
.equ cRangeA = cHighA-cLowA ; Range ueber die a variiert
.equ cLowB = (cMidB * (100 - cPercent) + 50) / 100 ; Niedriger Wert b
.equ cHighB = (cMidB * (100 + cPercent) + 50) / 100 ; Hoher Wert b
.equ cRangeB = cHighB-cLowB ; Range ueber die b variiert
.equ cLowC = (cMidC * (100 - cPercent) + 50) / 100 ; Niedriger Wert c
.equ cHighC = (cMidC * (100 + cPercent) + 50) / 100 ; Hoher Wert c
.equ cRangeC = cHighC-cLowC ; Range ueber die c variiert
Diese Werte packen wir in eine Struktur im SRAM:
.dseg
.org SRAM_START
sParamStruct:
; Werte fuer a
.byte 2 ; cRangeA
.byte 2 ; cLowA
sCa:
.byte 2 ; cA
.byte 2 ; Dummy
; Werte fuer b
.byte 2 ; cRangeB
.byte 2 ; cLowB
sCb:
.byte 2 ; cB
.byte 2 ; Dummy
; Werte fuer c
.byte 2 ; cRangeC
.byte 2 ; cLowC
sCc:
.byte 2 ; cC
.byte 2 ; Dummy
; Verschiebung gegenueber dem Tabellenanfang
.equ ndal = sCa - sParamStruct
.equ ndah = sCa - sParamStruct + 1
.equ ndbl = sCb - sParamStruct
.equ ndbh = sCb - sParamStruct + 1
.equ ndcl = sCc - sParamStruct
.equ ndch = sCc - sParamStruct + 1
Diese Struktur wird als Tabelle in das Flash geschrieben:
ParamTable:
.dw cRangeA, cLowA, cMidA, 0
.dw cRangeB, cLowB, cMidB, 0
.dw cRangeC, cLowC, cMidC, 0
Zu Beginn wird ParamTable mit LPM eingelesen und in das SRAM kopiert.
Das Registerpaar XH:XL dient dabei als Zeiger in das SRAM, das Paar
ZH:ZL als Zeiger auf die Flash-Adresse (mal zwei natürlich).
Das Registerpaar YH:YL zeigt danach dauerhaft auf den Beginn der
Struktur, sodass die Parameter a, b und c bei der Temperaturberechnung
über ihre Verschiebung leicht zugänglich sind: so holt
LDD R16,Y+ndal das LSB von a, LDD R16,Y+ndah das MSB.
Immer dann, wenn ein Kanal mit 64 Einzelmessungen abgeschlossen ist,
geht dann Folgendes vor sich:
- das ADC-Summenresultat wird von rAdcH:rAdcL zum Multiplikator
M2 kopiert, und
- die nächsten zwei Bytes, auf die XH:XL zeigt, die Range,
wird in den Multiplikator M1 kopiert (LSB und MSB), und
- M1 und M2 werden als 16-mal-16-Bit-Zahlen multipliziert, und
- das Multiplikationsergebnis wird auf 16 Bits gerundet (Addieren
von 0,55 zu Byte 0 und 1, carry zu Byte 2 und 3), und
- die nächsten zwei Bytes, der niedrige Wert, werden aus
dem SRAM gelesen und zu den Bytes 2 und 3 des
Multiplikationsergebnisses hinzu addiert, und
- die Bytes 2 und 3 des gerundeten Multiplikationsergebnisses
werden als neuer Multiplikationsfaktor in das SRAM geschrieben
(von wo aus diese später für die Temperaturberechnung
verwendet werden).
Die Variationsbreite, die mittels Variation von a, b und c erreicht
werden kann, in Bezug auf die angezeigte Temperatur ist entsprechend
des sehr unterschiedlichen Einflusses von a, b und c ebenfalls
unterschiedlich. Hier die Tabelle mit den Variationsbreiten
gegenüber dem Mittelwert.
Variation von | Niedrig | Hoch | Bereich |
a | 2,3 | -2,3 | 4,6 |
b | -18,0 | 18,0 | 35,9 |
c | 0,8 | -0,8 | 1,6 |
a+b+c | -14,9 | 14,9 | 29,8 |
Bitte beachten, dass a und c gegenläufig wirken und bei höherem
Potentiometerwert niedrigere angezeigte Temperaturen bewirken.
Natürlich ergibt sich die höchste Variation mit dem b-Poti.
Hier bedeuten 5° von 270° Drehwinkel 0,67 K. Ist aber trotzdem
noch gut einstellbar, kein Grund einen 10-Gang-Poti zu bemühen.
3.1 Schaltbild des Thermometers
Das ist das Schaltbild der Angelegenheit:
- Der ATtiny24 misst die Temperatur durch Vergleich mit seiner internen
1,1-Volt-Spannungsreferenz, die mit einem externen Kondensator am AREF-Pin
geglättet wird.
- Für die spätere Berechnung der Temperatur werden zuerst die
drei Pontenziometer an den Analog-Eingängen ADC1, ADC2 und ADC3
vermessen und in die Faktoren a, b und c verwandelt (mit 5%-Bereich).
Die drei Potis kriegen ihre 1,1V-Betriebsspannung über einen
11k-Widerstandsteiler.
- Nach der Messung der drei Potis ist die Messung der Temperatur am
dransten. Das 64-er ADC-Resultat wird mit dem aktuellen Wert von b
malgenommen und auf 24 Bit gerundet. Ferner wird das ADC-Resultat
mit sich selbst malgenommen, auf 16 Bits gerundet und dann mit a
multipliziert. Dieses Ergebnis wird auf 24 Bits gerundet und vom
Ergebnis der b-Multiplikation abgezogen. Danach wird auch noch c
abgezogen und das Ergebnis auf 16 Bits gerundet. Die Zahl ist nun
das Zehnfache der Temperatur in Kelvin. Daraus wird dann je nach
Einstellung °C oder °F errechnet.
- Die Temperaturzahl wird in dezimal umgewandelt, formatiert und
auf einer einzeiligen LCD-Anzeige mit 8 Zeichen dargestellt. Die LCD
wird mit dem oberen Nibble von Port A als bidirektionaler Datenbus
und mittels den Kontrollsignalen RS, RW und E des Port B bedient.
- Das ISP6-Interface ermöglicht das Programmieren des Controllers
im fertigen System.
3.2 Montage des Thermometers
Das ist das Thermometer auf einem Breadboard.
Die Montage des 100nF-Kondensators am AREF-Pin hat das Rauschsignal von
+/-0,3°C auf weniger als +/-0.1°C reduziert.
Hier kann man den kompletten Aufbau sehen. Der ISP6-Verbinder programmiert
den Controller und dient auch als Betriebsspannungsanschluss.
Hier sind die drei Einstellpotis zu sehen. Bitte beachten, dass die Potis
für a und c umgekehrt wirken wie bei b.
3.3 Ein Layout für eine gedruckte Schaltung
Hier angezeigt ist die verkleinerte Version der gedruckten Schaltung. Ein
Rechtsklick auf das Bild und "Speichern unter" lädt ein
höher aufgelöstes GIF herunter.
Bitte bei der gedruckten Schaltung beachten, dass die LCD auf der Unterseite
der Platine zu liegen kommt, die beiden 7-poligen Pinleisten also von unten
her zu löten sind und nach unten zeigen. Das erlaubt es, den ATtiny24
thermisch leichter zugänglich zu behalten und vermeidet einen
Wärmestau unter der LCD (den es eh gar nicht gibt bei den paar mW, die
der ATtiny24 verbrät).
Bitte auch beachten, dass von den ISP6-Pins nur GND und Vop
mit Leiternbahnen verbunden sind. Wenn Du also das Programmier-Interface
benutzen willst, musst Du noch die RESET-, die USCK-, die MISO- und die
MOSI-Pins zwischen ISP6 und den entsprechenden ATtiny24-Pins verbinden.
So sitzen die Bauteile auf der gedruckten Schaltung. Das ISP6-Interface
ist als gerade eingezeichnet, es kann aber auch gewinkelt sein.
Und nicht vergessen, die 7-Pin-Buchsen nach unten hin einzulöten.
Wenn Du die Höhe der gedruckten Schaltung auf standardisierte
40 mm steigern möchtest, hast Du auch noch Platz für
drei oder vier M2.5-mal-20 mm-Schrauben, um die gedruckte Schaltung
mit einer Plastikabdeckung zu versehen.
3.4 Bauteileliste
Das hier ist die komplette Bauteileliste. Wenn Du das ganze mit drei
1,5V-Batterien betreiben möchtest, kannst Du den 11k-Widerstand
auf 10k verringern, um die volle Einstellmöglichkeit zu erhalten.
Der Betrieb mit Akkus ist zwar etwas teurer, aber schon nach wenigen
Batteriewechseln hast Du die Mehrkosten wieder raus.
30 Euronen für ein Thermometer sind zwar nicht gerade ein
Schnäppchen, aber damit hat man was Eigenes und nicht nur
schnöden Standard-China-Import.
Im Folgenden sind einige grundlegenden Algorithmen der Software etwas
eingehender beschrieben. Das könnte bei eigenen Änderungen
der Software hilfreich sein.
4.1 16-mal-16-Bit Multiplikation
Die wird hier ausgiebig benutzt. Weil der ATtiny24 keinen Hardware-Multiplikator
hat, formulieren wir dieses Stück Software als Unterroutine.
Der Quellcode dafür braucht
- zwei Register für den Multiplikator M1,
- zwei Register für den Multiplikator M2 plus zwei zusätzliche
Register, um M2 fortgesetzt mit zwei zu multiplizieren (maximal 16 mal),
- vier Register für das Ergebnis der Multiplikation.
Der Quellcode sieht dann so aus:
; Registers
.def rM1L = R0 ; M1, LSB
.def rM1H = R1 ; M1, MSB
.def rM2L = R2 ; M2, LSB
.def rM2H = R3 ; M2, MSB
.def rM22L = R4 ; M2 2-Multiplikator, LSB
.def rM22H = R5 ; M2 2-multiplikator, MSB
.def rMR0 = R6 ; Multiplikationsergebnis, Byte 0
.def rMR1 = R7 ; dto., Byte 1
.def rMR2 = R8 ; dto., Byte 2
.def rMR3 = R9 ; dto., Byte 3
; Multiplikation 16-mal-16-Bit
MultM1M2:
clr rM22L ; Nullsetzen der oberen 16 Bits von M2
clr rM22H
clr rMR0 ; Nullsetzen des Ergebnisses, Byte 0
clr rMR1 ; dto., Byte 1
clr rMR2 ; dto., Byte 2
clr rMR3 ; dto., Byte 3
MultM1M2a:
lsr rM1H ; Schiebe niedrigstes Bit in carry, MSB
ror rM1L ; dto., LSB
brcc MultM1M2b ; Ist Null, nicht addieren
add rMR0,rM2L ; Addieren zum Ergebnis
adc rMR1,rM2H
adc rMR2,rM22L
adc rMR3,rM22H
MultM1M2b:
tst rM1L ; Ist M1 schon Null, LSB?
brne MultM1M2c ; nein, weitermachen
tst rM1H ; dto., MSB?
breq MultM1M2d ; M1 ist Null, fertig
MultM1M2c:
lsl rM2L ; Multipliziere M2 mit 2
rol rM2H
rol rM22L
rol rM22H
rjmp MultM1M2a ; Weiter multiplizieren
MultM1M2d:
ret
Das Ergebnis muss gerundet werden. Entweder wird das komplette 4-Byte-Ergebnis
zu einer 16-Bit-Zahl gerundet (und damit durch 65.536 geteilt) oder es wird
zu einer 24-Bit-Zahl gerundet (und damit durch 256 geteilt). Das Aufrunden
erfolgt hier schon dann, wenn das niedrige Byte 0,45 und mehr erreicht, nicht
erst bei 0,50. Binär exakt sind es 0,453125. Daher werden 0,55 addiert
und bei Überlauf aufgerundet.
RoundM16:
ldi rmp,0x4D
add rMR0,rmp
ldi rmp,0x8C
adc rMR1,rmp
ldi rmp,0
adc rMR2,rmp
adc rMR3,rmp
ret
RoundM24:
ldi rmp,0x8C
add rMR0,rmp
ldi rmp,0
adc rMR1,rmp
adc rMR2,rmp
adc rMR3,rmp
ret
4.2 Berechnung der drei Parameter a, b und c aus der Potistellung
Die Berechnung eines der drei Parameter passiert immer dann, wenn einer
der drei Potenziometerkanäle fertig ausgemessen ist und die
bAdc-Flagge gesetzt ist.
Um nicht drei Mal dasselbe zu programmieren, sind alle nötigen
Zahlen für jeden Parameter als 8-Byte-Record organisiert (von denen
2 Bytes nur nutzlose Dummies sind). Da die Reihenfolge der Messungen
immer die gleiche ist, läuft bei jedem Parameter der Zeiger XH:XL
mit und steht am Ende acht Bytes weiter. Der als nächstes
auszumessende Kanal ergibt sich dann jeweils aus dem Zeiger X, indem
von X die Basisadresse abgezogen wird, das Ergebnis durch acht geteilt
und Eins dazugezählt wird. Der X-Zeiger wird nach jeder
Temperaturmessung wieder auf den Anfang gesetzt, so dass mit dem ersten
Kanal, ADC1, begonnen wird.
Ist die bAdc-Flagge gesetzt, wird sie als Erstes wieder gelöscht.
Dann wird das ADMUX-Portregister gelesen. Steht ADMUX auf dem
Temperatur-Messkanal (beim ATtiny24 0b100010), dann wird die
Temperaturberechnung ausgeführt (siehe unten).
Die Umrechnung der Kanal-Messdaten für a, b und c beginnt mit dem
Auslesen des ersten Wortes, auf das X (XH:XL) zeigt: dieses ist die
Range des Potenziometers (cRangeX). Diese wird nach M1 (LSB und MSB)
kopiert. Die ADC-Summe in rAdcH:rAdcL kommt dann nach M2 und die
Multiplikationsroutine wird aufgerufen. Danach wird RoundM16 aufgerufen,
das das Ergebnis auf 16 Bits rundet. Danach wird dann die Untergrenze
gelesen, auf die X nun zeigt, und zum 16-Bit-Ergebnis in rMR2 und rMR3
hinzuaddiert. Beide Register haben jetzt den neuen Wert von X, der
dann an die beiden nächsten SRAM-Lokationen geschrieben wird.
Nach dem Addieren von zwei zu X zeigt X auf den nächsten Record.
Ist der nächste Record außerhalb der SRAM-Struktur, dann
muss nun die Temperatur gemessen werden und ADMUX ist entsprechend
zu setzen. Wenn nicht, wird der nächste Kanal aus X berechnet,
indem
- sParamStruct von X subtrahiert wird, und
- das Ergebnis durch 8 geteilt wird (drei mal rechts-schieben),
und
- Eins addiert, und
- das REFS1-Bit mit ORI gesetzt wird.
Damit wird nun ADMUX gefüttert, die beiden rAdcH:rAdcL-Register
werden Null gesetzt und das rAdcCnt-Register mit 64 neu gestartet.
Zuletzt wird das ADSC-Bit im ADCSRA-Portregister zu Eins gesetzt
und damit die erste AD-Wandlung angestoßen.
Die segensreiche Anordnung der Daten im SRAM erspart uns jede Menge
compares, LDS/STS und sonstigen überflüssigen Schrott.
4.3 Berechnung der Temperatur als 10*K
Alle Temperaturberechnungen basieren auf der Absoluten Temperatur
in Kelvin. °C and °F sind davon abgeleitet.
Um die Temperatur in K zu berechnen, wird diese Formel angewendet:
10*T = a * 64ADC2 + b * 64ADC + c
Zuerst wird rAdcH:rAdcL mit dem Parameter b multipliziert. Wir beginnen
mit dem zweiten Term, weil der positiv ist (a und c sind negativ).
Das 32-Bit-Ergebnis der Multiplikation b * 64ADC wird auf 24 Bits
gerundet und die drei Ergebnis-Bytes in die Temperaturregister
rT2:rT1:rT0 kopiert.
Dann wird rAdcH:rAdcL mit sich selbst multipliziert, um 64ADC2
zu erhalten. Das Ergebnis wird auf 16 Bit gerundet (und damit durch
65.536 geteilt). Die beiden Bytes werden dann mit dem Parameter a
multipliziert. Dieses Resultat wird auf 24 Bits gerundet und von
rT2:rT1:rT0 subtrahiert.
Zuletzt wird der Parameter c von rT2:rT1 subtrahiert.
Wenn K angezeigt werden sollen (Flagge bCF = 0), dann wird jetzt
rT2:rT1 auf 16 Bit gerundet. Wenn wir bei 25,0°C sind, sehen
wir nun 2.982 in rT2:rT1, was dann später als T=298.2K angezeigt
werden wird.
4.4 Berechnung der Temperatur in 10 * °C
Steht die Flagge bCF auf 1 und die Flagge bF auf 0, dann ist die Temperatur
in °C zu berechnen.
Um das hinzukriegen, subtrahieren wir 2731.5 von rT2:rT1:rT0. Das
-0.5 kriegen wir durch Subtrahieren von 0x80 von rT0, das LSB und das MSB
von 2731 wird dann beides mit SBCI (Subtract with Carry) erledigt.
Wenn nach dem Subtrahieren das Ergebnis in rT2:rT1 positiv ist, löschen
wir die T-Flagge. Ist das Ergebnis negativ, dann subtrahieren wir rT2:rT1
von Null und setzen die T-Flagge. rT2:rT1 ist nun das Zehnfache der
Temperatur in °C, z. B. bei 25,0°C ist es 250 und die T-Flagge
ist gelöscht.
4.5 Berechnung der Temperatur in 10 * °F
Wenn beide Bits, bCF als auch bF, gesetzt sind, wird die Temperatur in
°F umgerechnet.
Die Berechnung von 10 * °F aus 10 * K ist ein wenig komplizierter. Die
Original-Formel lautet:
°F = (K - 273,15) * 1,8 + 32
Aber, weil wir ja 10*K haben und 10*F brauchen, kommen wir eher bei folgender
Formal an:
10*F = 10*K * 1,8 - 2731,5 * 1,8 + 320 = 10 * K * 1,8 - 4596,7
Die 1,8 ist ein echter Show-Stopper. Wenn wir sie mit 256 multiplizieren,
kriegen wir 460,8 oder gerundet 461. Wenn wir mit diesem einige Temperaturen
berechnen, finden wir eine Genauigkeit von etwa 0,3°F. Das
nächst-höhere 65.536-fache passt dann aber nicht in das
16-Bit-Multiplikationsschema, wir müssen daher 1.024 oder 2.048 als
Multiplikator anstelle von 256 verwenden. Das bedeutet zwei oder drei
Schiebeoperationen zum Dividieren am Ende.
Tatsächlich verwenden wir 1,8 * 2.048 = 3.686 oder 0x0E66 um die
auf 16 Bit gerundete 10*K-Temperatur zu multiplizieren und wir benutzen
4596,7 * 1.024 = 9.414.042 oder 0x8FA59A als Subtraktor. Wenn wir das
machen, kriegen wir auch keine Genauigkeits-Einbuße.
Natürlich kann 10 * °F auch negativ werden, daher verfahren wir
nach der gleichen Prozedur wie bei negativen °C (setzen der T-Flagge,
Umwandlung in einen positiven Wert).
4.6 Anzeige der Temperatur auf der LCD
Die in rT2:rT1 gespeicherte Temperatur muss nun in Dezimalformat umgewandelt
werden. Das macht man durch fortgesetztes Abziehen von 1.000, 100 und letztlich
10. Dann kommt ein Kommazeichen und die letzte Ziffer der Zahl. Danach kommt
dann bei °C oder °F ein Gradzeichen und danach mit einem Zeichen die
Dimension. Die beiden Flaggen bCF und bF sind verantwortlich dafür, was
da kommt. Falls Du die drei Potis nicht brauchst oder wenn Du einen
größeren Controller mit mehr Pins verwendest, kannst Du bCF und bF
aus zwei gejumperten Pins holen und die Dimension mit den Jumpern auswählen:
einfach den Zustand der Pin-Eingänge z. B. mit einem PCINT in die
Flaggen kopieren.
Jumper | Offen | Geschlossen |
Flagge/Bit | Anzeige | Flagge/Bit | Anzeige |
CF | 1 | °C or °F | 0 | K |
F | 1 | °F | 0 | °C |
Bitte beachten, dass die Umwandlung von K in °C/°F weiter oben separat
beschrieben ist.
Das hier ist der Quellcode der Umwandlung von rT2:rT1 in dezimal:
; Wandlung Temperatur in rT2:rT1 in dezimal
; X zeigt auf den SRAM-Puffer
ldi XH,High(sDisplay)
ldi XL,Low(sDisplay)
sbrc rFlags,bCF
rjmp Convert2CF
ldi rmp,'T'
st X+,rmp
ldi rmp,'='
st X+,rmp
rjmp ConvertDec
Convert2CF:
ldi rmp,'t'
st X+,rmp
ldi rmp,'='
st X,rmp
ConvertDec:
ldi ZH,High(1000)
ldi ZL,Low(1000)
ldi rmp,'0' - 1
ConvertDec1:
inc rmp
sub rT1,ZL
sbc rT2,ZH
brcc ConvertDec1
add rT1,ZL
adc rT2,ZH
st X+,rmp
ldi ZH,High(100)
ldi ZL,Low(100)
ldi rmp,'0' - 1
ConvertDec2:
inc rmp
sub rT1,ZL
sbc rT2,ZH
brcc ConvertDec2
add rT1,ZL
adc rT2,ZH
st X+,rmp
ldi rmp,'0' - 1
ldi ZL,10
ConvertDec3:
inc rmp
sub rT1,ZL
brcc ConvertDec3
st X+,rmp
ldi rmp,'.'
.if cEN == 0
ldi rmp,','
.endif
st X+,rmp
ldi rmp,'0'+10
add rmp,rT1
st X+, rmp
sbrc rFlags,bCF
rjmp ConvertCF
ldi rmp,'K'
st X,rmp
rjmp ConvertEnd
ConvertCF:
ldi rmp,cDeg
st X+,rmp
ldi rmp,'C'
sbrc rFlags,bF
ldi rmp,'F'
st X,rmp
sbiw XL,6 ; Ersetzen fuehrender Nullen
ld rmp,X
cpi rmp,'0'
brne Convert4
ldi rmp,'='
st X+,rmp
ld rmp,X
cpi rmp,'0'
brne Convert4
ldi rmp,' '
st X+,rmp
Convert4: ; Setze Vorzeichen
brtc Convert5
ldi rmp,'-'
st -X,rmp
rjmp ConvertEnd
Convert5:
.if cPlus == 1
ldi rmp,'+'
st -X,rmp
.endif
ConvertEnd:
5.1 Der Quellcode
Die Software gibt es hier zum Download
in Assembler-Format.
Bitte beachten, dass die Software die LCD-Include-Software für den Zugriff
auf die LCD verwendet, die es hier zum Download
gibt und die hier im Detail beschrieben ist.
Die Include-Datei muss beim Assemblieren im selben Ordner sein, damit sie
gefunden wird. Diese Include-Software wird verwendet, um die LCD (1-mal-8-Format,
das Grad-Zeichen) sowie die Anschlüsse der LCD (Datenbus, Kontrollsignale)
zu konfigurieren. Ansonsten wird die Include-Software dazu verwendet, die acht
Zeichen des Ergebnisses auszugeben.
Die Software hat einige Debug-Schalter im oberen Teil. Diese müssen alle
Null sein, wenn die Software im ATtiny24 werkeln soll.
Die Debug-Schalter sind:
- DebugNoLcd: das schaltet alle LCD-bezogenen Programmteile aus,
kann zur Simulation verwendet werden,
- DebugTCalc: started mit einer Temperaturberechnung,so dass die
Abarbeitung der ADC-Zyklen entfällt, verwendet dazu die per Default
eingestellten Konstanten cMidA, cMidB und cMidC, die Konstante DebugAdc
kann auf einen gewünschten Wert eingestellt werden, dessen 64-faches
in das Registerpaar cAdcH:cAdcL geschrieben wird, endet in einer
Endlosschleife,
- DebugAbcParam: simuliert die Messungn eines einzelnen Parameters,
a/b/c kann ausgewählt werden, die Konstante DebugAdc kann mit einem
gewünschten Wert vorgegeben werden, dessen 64-faches in rAdcH:rAdcL
geschrieben wird, endet ebenfalls in einer Endlosschleife.
5.2 Einstellung der Software-Eigenschaften
Die folgenden Einstellungen können in der Sektion
"Adjustable constants" ohne Weiteres verstellt werden:
- cMode: setzt man das auf Null, werden Kelvin ausgegeben, eine
Eins macht Celsius und eine Zwei macht Fahrenheit, wird nur bei Programm-
Beginn in die Flaggen bCF und bF in rFlags geschrieben.
- cEN: setzen dieser Konstante auf Null (per Default) verwendet
das Dezimalkomma, auf Eins den Dezimalpunkt (englische Notation).
- cPlus: durch Setzen auf Eins wird bei positiven Temperaturen
das Pluszeichen vor die Temperatur gesetzt (nur bei cMode 1 oder 2), der
Vorgabewert ist Null (kein zusätzliches Pluszeichen).
- cAdcClkPresc: Das ermöglicht es, den ADC-Vorteiler auf
einen niedrigeren Wert zu setzen, wodurch die Temperaturausgabe schneller
wird (Default: ca. ein Mal pro Sekunde).
- cManAdj: Das ermöglicht es, die Justierung von den
Potenziometern auf manuell umzuschalten. Bei der Temperaturberechnung
werden dann nur noch die cMidX-Werte verwendet, die Potis werden nicht
ausgewertet. Nur jede vierte Messung wird als Temperatur auf der LCD
angezeigt.
- cHex: Wenn der cManAdj-Modus eingestellt ist, dann bewirkt
diese Konstante, dass das rAdcH:rAdcL-Registerpaar in hexadezimalem
Format auf der LCD ausgegeben wird. Diese Darstellung kann man beim
manuellen Justieren gut gebrauchen, mit drei Messpunkten kann man
mit der LibreOffice-Tabellenkalkulation dann mittels Determinanten
die Konstanten a, b und c bestimmen und in den Quellcode kopieren
(siehe Kapitel 5.3.2 unten). Vor dem Assemblieren und Programmieren
des Chips cHex wieder auf Null stellen.
5.3 Manuelle Justierung
Natürlich hat jedes ATtiny24-Einzelexemplar so seine eigenen Vorstellungen,
welche Temperatur jetzt mit welchen ADC-Messwerten daherkommt. Das kannst Du
dann entweder mit den Potenziometern justieren oder in einem speziellen
Messdurchlauf. Beides lässt sich mit einer Auflösung von 0,1°
erledigen.
5.3.1 Manuelle Justierung mit den drei Potenziometern
Für die manuelle Justierung kann man die drei Pots verwenden. Man muss
nur bei drei verschiedenen Temperaturen (im Backofen bei 80°, im Gefrierfach
bei -32° und am Küchentisch bei 20°) die angezeigte Temperatur
messen. Sind alle drei Temperaturen zu hoch oder zu niedrig, kann man den
Regler für c so weit drehen, bis die am niedrigsten abweichende Temperatur
korrekt angezeigt wird.
Nun das Spiel mit den beiden anderen Temperaturen. Ist die Temperatur in der
Hitze zu niedrig oder zu hoch, bei Raumtemperatur aber korrekt, dann ist Regler
a dran.
Die Messungen kann man beliebig oft wiederholen, bis man die optimale Einstellung
hingekriegt hat.
5.3.2 Manuelle Justierung ohne die Pots
Bei der zweiten Einstellmethode braucht man die drei Potis nicht, wir können
sie demontieren oder gar nicht erst montieren.
Das Setzen der Konstante cManAdj im Quellcode auf Eins stellt diesen Modus ein.
Es ist hilfreich, dann auch noch cHex auf Eins zu setzen, weil dann die Rohdaten
der Temperaturmessung zur Verfügung stehen (die 64*ADC-Summe).
Nun einfach bei drei verschiedenen Temperaturen, die auch ein wenig Abstand
zueinander haben sollten, die ADC-Summen ablesen.
Du kannst jetzt die Daten der drei Messungen (Temperatur in °C, 64ADC-Summe
in hex) direkt in die Zellen mit grünem Hinmtergrund im Tabellenblatt
"ManJust" der LibreOffice-Calc-Datei hier
eingeben. Das Blatt berechnet dann daraus a, b und c und gibt diese in
Assembler-gerechtem Format aus.
Nach dem Ersetzen dieser drei Zeilen, setze cHex auf 0, lasse cManAdj auf
Eins und nun kannst Du die justierten Temperaturen sehen.
5.4 Betriebsstrom und Selbsterhitzung
Die gesamte Schaltung konsummiert 2,3 mA bei 5V. Da die LCD schon alleine
2 mA braucht, liegt der Strombedarf des Controllers unter 0,3 mA.
Wenn Dir das Sekundengezappel deines Messgeräts auf den Zeiger geht:
einfach einen großen Elko mit einem kleinen Widerstand davor in die
Versorgungsleitung.
Um zu testen, ob die eigene thermische Leistung des Controllers die gemessene
Temperatur beeinflusst, habe ich die nach längerer Stromtrennung
eingeschaltet und länger beobachtet. Auf die Oberseite des ATtiny24
habe ich dabei ein Stückchen Schaumstoff aufgelegt, damit die
Wärmeabgabe nur noch über die Pins erfolgt.
Die Messwerte habe ich in einem Tabellenblatt dokumentiert, es ergab sich
daraus kein Hinweis auf eine Selbsterhitzung mit mehr als 0,4°C. Das
ist bei nur 1,5 mW auch nicht zu erwarten. Eine wichtige Rolle bei
dem niedrigen Strom und der minimalen Leistung dürfte spielen, dass
sich der Controller zu 99% im Schlafmodus befindet und nur einmal pro
Sekunde für zwei Millisekunden lang richtig viel Arbeit kriegt.
6 Schlussfolgerungen
Das Programm mit allem Schnickschnack befüllt gerade mal 60% des
Flashspeichers eines ATtiny24. Überhaupt kein Anlass, zu einem
größeren AVR-Typ zu wechseln. Alles spielt sich in den
gegebenen Grenzen recht zwanglos ab.
Versuche das bloss nicht mit C und der Fließkommabibliothek, es
bläst nur den Ressourcen-Bedarf auf. Und es ist auch nicht einfacher
oder genauer als einfach nur Temperaturen mit 10 malzunehmen und beim
Runden ein wenig Grips an den richtigen Stellen zu investieren.
Lob, Tadel, Fehlermeldungen, Genöle und Geschimpfe oder Spam bitte über
das Kommentarformular an mich.
©2023 by http://www.avr-asm-tutorial.net