Pfad:
Home =>
AVR-DE =>
Anwendungen =>
tn24-Thermometer => Temperatur über serielles Infrarot mit ATtiny45
This page in english:
 |
AVR-Anwendungen
Thermometer über serielles Infrarot mit zwei (drei, vier, ...) ATtiny45 |
Entwicklungsprojekt! Enthält noch ungetestete
Hardware, Software noch in Arbeit!
ATtiny45-Thermometer über serielles Infrarot
Wer kennt das nicht? Man will ein schönes Außenthermometer bauen und
montieren. Aber wie das Kabel durch das Fenster tun, ohne das Fenster kaputt zu
machen?
Hier ist die Lösung: Infrarot geht, ohne Lochbohren, durch das Fenster.
Und auf der anderen Seite des Fensters steht ein Umsetzer für die
IR-Signale, der diese in serielle Signale umsetzt, sowie ein Laptop herum. Der
hat eine serielle Schnittstelle und möchte gerne die Außentemperatur
anzeigen - heute mal in Kelvin, morgen in °Celsius und übermorgen in
°Fahrenheit (weil gerade mal Besuch aus den USA da ist). Kein Problem: hier
ist die universelle Thermosensor-serielles-Interface-via-IR-Wollmilchsau.
Wir brauchen zwei Außentemperatur-Messteilen? Kein Problem, solange
die zwei oder drei sich gegenseitig und alle die Umsetzer-LED sehen, einfach
welche dazu bauen. Mit dem in der Software eingebauten
Prioritätsmechanismus stören die sich gegenseitig nicht und senden
nur dann, wenn genau sie dran sind.
Und weil wir gerne die Innenraum-Temperatur mit der Außentemperatur
vergleichen wollen, können wir auch noch einen (oder zwei oder drei)
Innentemperatur-Messteile verbauen.
Die Schaltbilder gibt es wie fast immer in der LibreOffice-Draw-Datei
hier, die Berechnungen in der LibreOffice-
Calc-Datei hier.
1.1 Was man braucht
Auf jeden Fall braucht man:
- einen Rechner, auf dem ein Terminalprogramm, z. B RealTerm,
seinen Dienst tut, und
- einen USB-zu-Seriell-Umsetzer, den man auf 1200 Baud oder weniger
einstellen kann,
- die Infrarot-zu-Seriell-Umsetzer-Platine, die mit einer DB9-Buchse
ausgestattet ist und serielle Signale über Infrarot empfängt
und serielle Signale mittels einer IR-LED auch aussenden kann (das
macht ein ATtiny25), wozu auch ein Trafo-Netzteil gehört, und
- einen oder mehrere Thermosensoren, entweder akkubetrieben für
Outdoor oder an das Trafonetzteil des Umsetzers angeschlossen für
den In-door-Betrieb.
1.2 Ablauf
Ein ATtiny45 misst auf Anforderung die Temperatur und gibt das Ergebnis als
Textstring in serieller RS232-Kodierung mit 1k2 an einer Infrarot-Diode aus.
Auf der Innenraum-Seite nimmt ein IR-Empfänger die Signale auf und sendet
sie über einen RS232-Pegelwandler an eine DB9-Buchse. An die kann der
Rechner mit einem DS9-Stecker (mit DS9-zu-USB-Wandler) das Ergebnis mitlesen.
Der ATtiny45 hat eine quarzgetriebene Uhr, die in einem wählbaren Intervall
zwischen einer und 65.535 Sekunden (ca. 18 Stunden) die Temperaturmessung
automatisch startet und dann Datum, Uhrzeit und Temperatur sendet.
Der ATtiny45 hat auch eine serielle Schnittstelle, die mit 1k2 empfangen kann.
Über diese serielle Schnittstelle kann eingestellt werden:
- Datum und Uhrzeit,
- die Dimension der Temperatur (Kelvin, °Celsius, °Fahrenheit),
- die drei Parameter, mit denen die Temperatur in Kelvin aus den
ADC-Messwerten errechnet wird (T = a * 128ADC2 + b * 128ADC + c),
alle Thermometer sind also eichfähig,
- deutsche oder angelsächsische Notation,
- und noch vieles anderes mehr, siehe weiter unten im Detail.
Alle wichtigen Parameter (Dimension der Temperatur, a, b und c) müssen nur
einmal eingestellt werden, denn sie werden in das EEPROM geschrieben und beim
Programmstart (z. B. nach einem Akku-Wechsel) daraus ausgelesen.
1.3 Ablaufdetails
Der IR-zu-Seriell-Umsetzer lauscht auf eingehende Infrarot-Signale. Entdeckt
er welche, dann sendet es sie an die RXD-Leitung der DB9-Buchse. Sie werden
dann vom Terminalprogramm angezeigt.
Der IR-zu-Seriell-Umsetzer setzt die von der TXD-Leitung der DB9-Buchse
kommenden seriellen Signale in Infrarot-Signale um, d. h. bei
Low-Signalen gibt die Infrarot-LED ein aktives Signal mit 40 kHz
ab, bei High-Signalen bleibt sie ausgeschaltet.
Die via Infrarot angeschlossenen Thermosensoren
- haben eine individuelle Kennung zwischen 0 und 9, die sie
Meldungen voranstellen, die Kennung gibt auch die Priorität
an, mit der der Sensor seine Meldungen sendet,
- melden sich beim Einschalten mit ihrer jeweiligen Kennung,
- warten auf Sendesignale, die sie wie folgt auswerten:
- Alle Leerzeichen und ASCII-Kontrollzeichen werden aus
der Zeichenkette entfernt, alle Kleinbuchstaben in
Großbuchstaben umgewandelt.
- Wenn die Sendung mit einer Ziffer zwischen 0 und 9 beginnt,
dann reagieren sie auf den Befehl nur dann, wenn die Ziffer
mit ihrer Kennung identisch ist (bei anderen Ziffern wird
der Befehl ignoriert). Beginnt die Sendung nicht mit einer
Ziffer, dann wird der Befehl auf jeden Fall ausgeführt.
Da die Kennung optional ist, wird sie im Folgenden mit [n]
oder [n-] symbolisiert.
- Alle an die Sensoren gesendeten Zeichenfolgen enden mit
einem Wagenrücklauf- und einem Seitenvorschub-Zeichen.
- Mit [n-]D=23.2.23 wird das Datum auf den 23.02.2023
eingestellt. Außerdem wird die Ausgabe auf die deutsche
Notation beim Datums-, Zeit- und Zahlenformat eingestellt.
[n]D=2/23/23 stellt die Notation auf das angelsächsische
Format um. Der Sensor antwortet mit seiner Nummer, dem
Datum, der Uhrzeit und der Temperatur.
- Mit [n-]T=12:34:56 wird die Uhrzeit auf 13:34:56 eingestellt.
Der Sensor antwortet wieder mit seiner Kennung, dem Datum und
der eingestellten Uhrzeit sowie mit der Temperatur.
- Mit [n-]TK, [n-]TC oder [n-]TF wird die Dimension der Temperatur
festgelegt. Default ist Kelvin.
- Mit [n-]M=12345 wird der Sensor aktiviert und sendet alle
12345 Sekunden die Temperatur im Format
"n-23.02.23-12:34:56=-15,4C". [n-]M=0 schaltet
die Messungen aus. Das Intervall beginnt sofort nach dem
Absetzen des Befehls.
- Mit [n-]A=1234, [n-]B=1234 und [n-]C=1234 werden die drei
Konstanten für die Eichung des Thermometers eingestellt.
Wie diese aus drei Messpunkten bestimmt werden, geht aus der
Tabellenkalkulation hervor. Diese drei Konstanten werden
auch im EEPROM abgelegt und müssen daher nur ein
einziges Mal oder bei Änderungen an den Sensor gesendet
werden.
- Mit n-H oder n-? oder mit undefinierten Befehlen erhält
man einen Hilfetext. Bitte diesen Befehl immer mit n beginnen,
da sonst jeder Sensor seinen eigenen Hilfetext sendet.
- Mit n alleine wird nur mit der aktuellen Temperatur
geantwortet, das eingestellte Intervall bleibt dabei erhalten.
Die Hardware besteht aus den zwei verschiedenen Typen an
Temperatursensoren und aus der IR-zu-Seriell-Umsetzer-Platine (mit dem
Trafonetzteil).
2.1 Die Hardware der Temperatursensoren
Die Hardware für Innen- und Außensensoren ist ein wenig
unterschiedlich, daher erfolgt eine separate Beschreibung.
2.1.1 Die Hardware des Outdoor-Temperatursensors
So sieht der Temperatursensor für Draußen aus. Der ATtiny45
wird von einem Quarz getaktet (entweder 7,68 oder 4 MHz oder beliebige
andere, siehe Tabellenkalukation).
Die Speisung der Schaltung erfolgt entweder aus einem Li-Ionen-Akku mit
3,7 Volt oder aus drei hintereinandergeschalteten NiMH-Akkus zu
je 1,2 Volt. Der Strombedarf ist nur beim Senden recht hoch, daher
sollte der Messrhythmus mit Bedacht gewählt werden (z. B.
alle 60 Sekunden oder alle 5 Minuten), er kann während des laufenden
Betriebs eingestellt werden. Mit einer Seite in der Tabellenkalkulation
kann man die Akku-Lebensdauer bei Vollladung abschätzen.
Der ATtiny45 misst regelmäßig (einstellbar zwischen 0 -
keine Messung - bis 65535 - Messung alle 18,2 Stunden) die
Temperatur seines Innensensors, rechnet diese in Temperaturen um,
fügt Datum und Uhrzeit hinzu und sendet die Zeichenkette mit
dem Ergebnis über die Infrarot-Diode an den Umsetzer, der sie
wiederum in serielle Signale umwandelt und an den Laptop sendet.
Der Infrarot-Sensor TSOP31240 stellt fest, ob ein anderer Sensor gerade
sendet. Falls das der Fall ist, wartet der Sendealgorithmus für eine
voreingestellte Zeit, nachdem das letzte IR-Signal einging, und startet
das Aussenden der Zeichenkette danach.
Liegt kein Sendevorgang an, dann wartet der Infrarot-Sensor auf eingehende
Signale, liest diese ein und speichert sie in einem Pufferbereich im SRAM.
Geht ein Zeilenvorschub-Zeichen ein, dann wird die empfangene Zeile
ausgewertet. Falls der Befehl an den betreffenden Sensor gerichtet ist,
führt er diesen aus.
Die Infrarot-Diode LD274-3 wird aus einer Konstantstromquelle angetrieben.
Der ATtiny45-Ausgang PB0 taktet dazu ein 40kHz-Signal. Dieses schaltet eine
rote 2mA-Leuchtdiode ein und aus. Die Durchlassspannung der Leuchtdiode
treibt die Basis des Transistors, der den Strom durch seine CE-Strecke
so einstellt, dass am Emitter die Basisspannung abzüglich der
BE-Spannung abfällt. Der Emitter-Widerstand kontrolliert dabei
den LED-Strom.
Ist die IR-LED nicht angeschlossen oder kaputt, dann leuchtet auch die
rote LED nicht, da die Basis des Transistors und der Emitterwiderstand
die Basisspannung dann unter die Brennspannung der roten LED zieht.
Dies sind in blau die gemessenen Spannungen der Konstantstrom-Schaltung.
Daraus resultieren die in rot eingezeichneten Ströme und die in
violett angegebenen thermischen Leistungen im dauerhaft eingeschalteten
Zustand (real sind die Leistungen im Endeffekt halb so hoch).
Die Konstantstromquelle arbeitet mindestens ab 3,3V Betriebsspannung
sehr stabil und gleichbleibend. Nur wenn an der LED-Kathode +10V
anliegen, wird es für den BC547 etwas eng und er muss eine zu
hohe thermische Leistung verbraten. Daher dann der Wechsel zu einem
BD439.
Warum ein ATtiny45 und nicht ein ATtiny25? Nun, das Assemblerprogramm ist
recht umfangreich, vor allem wegen der RS232-Kommunikation und der vielen
Einstellmöglichkeiten. Das hat alles nicht mehr in einen ATtiny25
reingepasst. Selbstverständlich kann auch ein ATtiny85 verwendet
werden.
2.1.2 Die Hardware von Indoor-Temperatursensoren
Prinzipiell können beliebig viele zusätzliche Thermosensoren
hinzugebaut werden, nur müssen sich alle Sensoren
Infrarot-mäßig sehen, damit keine Sendekollissionen auftreten.
Die für zusätzliche Innenraum-Temperatursensoren nötige
Hardware sieht ganz ähnlich aus. Unterschiede gibt es nur in
folgender Hinsicht:
- Der Betrieb erfolgt aus dem gleichen Trafo-Netzteil, das auch den
IR-Seriell-Umsetzer versorgt. Batterien oder Akkus sind daher nicht
nötig. Die Versorgungsspannung des ATtiny45 ist auf +5V aus
einem Spannungsregler eingestellt.
- Da der Betrieb der IR-LED aus der ungeregelten Versorgungsspannung
mit ca. 10 V erfolgt, hat die Spannungsversorgung drei
Anschlüsse (GND, +5V geregelt, +10V ungeregelt).
- Da der Transistor bis zu 10V bei maximal 100mA Konstantstrom
verbraten muss, also bis zu einem halben Watt (50% An-Zeit), wird ein
etwas größerer Typ eingesetzt.
- Statt der Niedrig-Strom-LEDs können normale LEDs eingesetzt
werden, die mit einem höheren Strom versorgt werden.
Jeder Sensor kriegt seine eigene Device-Nummer, die er beim Senden und
Empfangen auch auswertet, so dass die Sensoren individuell eingestellt
werden können.
Man beachte, dass bei der niedrigen Baudrate der Sensoren jeder Sensor
etwas Zeit für das Senden der langen Zeichenketten braucht. Stellt
man daher sehr kurze Messdauern ein, wie z. B. eine Sekunde, und
hat man die Baudrate auf 300 Baud eingestellt, dann kommt nur der
Sensor mit der Nummer 0 zum Senden, alle anderen Sensoren verhungern,
weil Nummer Null sie nachhaltig am Senden hindert.
2.1.3 Auswahl der Quarze
Mit dem Quarz müssen in Temperatursensoren folgende zeitrelevante Dinge
erledigt werden:
- Die interne Uhr des Temperatursensors muss im Sekundentakt getaktet werden.
Dazu dient der Counter/Timer TC1, der über einen umfangreichen Park an
Vorteilern verfügt. Der Vorteiler wird so eingestellt, dass der Quarztakt
durch den gewählten Vorteiler eine Ganzzahl ergibt. Diese wird dann
durch einen ganzzahligen CTC-Wert geteilt, aus dem sich ebenfalls eine
Ganzzahl ergibt. Diese wird dann in einem Register durch eine weitere
Ganzzahl geteilt, woraus sich dann genau Eins ergeben muss.
- Beim Senden muss die IR-Diode mit der IR-Sendefrequenz (Default: 40 kHz)
getaktet werden. Abweichungen vom Sollwert sind dabei um +/- 0,5 kHz noch
tolerabel. Darüber wird es mulmig, ob der Empfänger das Signal
noch erkennt.
- Beim Empfang der seriellen Signale muss die Baudrate stimmen (Default:
1.200 Baud). Abweichungen um +/- 1% sind ok, darüber wird es ebenfalls
mulmig, weil der Einfachheit halber auf eine Nachjustierung der Flanken
verzichtet wurde und die gesamte Dauer des Zeichens (Startbit plus acht
Datenbits = 9 Bit) nur über den Standardtakt (bei 1,200 Baud
sind das 833 µs) abgetastet wird.
- Nur bei der Uhr ist der Quarz wirklich nötig, schließlich
will man die Uhr nicht täglich neu stellen müssen.
Da die Temperatursensoren mit 3,7 V aus einer Li-Zelle arbeiten, kommen
Quarze oberhalb von 10 MHz nicht in Betracht, da diese erst ab 4,5 V
Betriebsspannung zuverlässig den Tiny takten. Außerdem wollen wir
ja so viel Strom sparen wie möglich.
Die entsprechende Taktung wurde im Tabellenblatt "Taktung_Thermometer"
der LibreOffice-Calc-Tabelle hier
gerechnet. Für handelsübliche Quarze in Spalte G (rot markierte
Frequenzen sind keine Quarze!) wird in Spalte I die resultierende IR-Frequenz
gerechnet, Werte von 39,5 bis 40,5 kHz sind noch tolerabel (was mit allen
hier abgebildeten Quarzen hinkommt).
Spalte K berechnet die resultierenden Baudraten beim Empfang. Man sieht, dass
auch die Baudraten noch innerhalb der Toleranz liegen. Nur bei Quarzen mit sehr
niedriger Frequenz ist Vorsicht geboten.
Die Spalten J und L berechnen das Quadrat der Abweichung von der Sollfrequenz,
die Spalte M addiert beides. Mit Hilfe des Minimums in Zelle M2 kann man den
optimalen Quarz für seine eigenen gewählten Bedingungen herausfinden.
Die Spalten N bis Q berechnen die für den TC1 erforderlichen Zahlen, die
zur Taktung des 1-Hz-Signals für Uhrzeit und Datum gebraucht werden. Der
Prescaler in Spalte N nutzt das erweiterte Spektrum des TC1 im ATtiny45.
Der ausgewählte Quarz gilt für die Temperatursensoren. Wie man sieht,
ist nur der 7,68-MHz-Quarz ideal für alle drei Aufgaben. Nur mit dieser
Frequenz treffen wir alle drei benötigten Frequenzen ganz genau. Wer will,
kann aber auch abweichende Frequenzen verwenden, man muss es nur der Software
beibringen.
Damit das ganz bequem geht, gibt es noch den gelb markierten Kopierbereich in
diesem Tabellenblatt. Einfach alles einstellen, was hellgrün ist und
dann den gelben Bereich mit Strg-C kopieren und mit Strg-V im Quellcode
ablegen.
2.2 Die Hardware des IR-Seriell-Umsetzers
Der IR-Seriell-Umsetzer empfängt die IR-Signale der Thermosensoren
und wandelt sie in serielle Signale auf RS232-Spannungsniveau um. Umgekehrt
setzt er von der seriellen Schnittstelle kommende Zeichen in Infrarot-Signale
um und sendet diese mittels IR-Leuchtdiode an die Sensoren.
2.2.1 Schaltbild des IR-Seriell-Umsetzers
Der IR-zu-Seriell-Umsetzer besteht aus
- einer DB9-Buchse, die der zweiseitigen Kommunikation mit dem Rechner
über einen USB-Seriell-Wandler dient,
- einem MAX232, der die Signalpegel sende- und empfangsmäßig
auf RS232-Niveau bringt,
- dem Infrarot-Empfänger-Modul TSOP31240, das Infrarot-Signale
empfängt, nach Frequenz filtert und an seinem Ausgang ausgibt,
- einem quarzgetakteten ATtiny25, der bei aktivem Sendesignal mittels
eines Konstantstromreglers - mit einer roten Leuchtdiode und dem
Transistor BD439 - eine IR-Sende-Diode im 40kHz-Rhythmus taktet,
- einer 6-poligen ISP-Schnittstelle, über die der ATtiny25
in der Schaltung programmiert werden kann.
Für den IR-zu-Seriell-Umsetzer ist nur das 40-kHz-Signal der IR-Diode
zeitkritisch. Es kann daher fast jeder Quarz verwendet werden, er muss nur
im Quellcode des Umsetzers angegeben werden. Bei mir ist es ein 4 MHz,
das passt ganz genau. Ohne Quarz, also nur mit dem internen RC-Oszillator
als Taktgeber, habe ich bei 5V Betriebsspannung 43 kHz gemessen. Das
stellt nicht mehr sicher, dass 40kHz-Sensoren da noch ansprechen. Es darf
also ruhig ein Quarz als Taktgeber sein.
2.2.2 Trafo-Netzteil für den IR-Seriell-Umsetzer
Das ist das Trafonetzteil. Es liefert ungeregelte 10V für den Betrieb
der Infrarot-LED sowie geregelte 5V für den ATtiny25 und den MAX232.
Unter Last mit zwei Infrarot-Dioden im Gegentakt muss das Netzteil bis zu
110 mA Laststrom bringen. Das Bild zeigt, dass es dieses
Maximal-Szenario glatt übersteht.
An die Anschlussbuchse für weitere Innenraum-Thermosensoren können
weitere Sensoren aus diesem Netzteil versorgt werden. Da die IR-LEDs dieser
Sensoren immer nur dann senden, wenn die IR-LED des Umsetzers inaktiv ist
und wenn auch kein anderer Sensor gerade sendet, kann man recht viele Sensoren
gleichzeitig an diesem Netzteil betreiben, ohne dass es zu Überlastung
kommt. Ab etwa fünf wird es wegen der vielen grünen LEDs, die bei
der Indoor-Variante immer an sind, aber kitzlig auf der 5V-Leitung. Dann
diese in der Sensor-Software lieber als Outdoor-Variante konfigurieren,
dann bleibt die grüne LED aus und geht nur beim Blinken kurz an.
Ich habe alle Schaltungen auf Lochrasterplatinen aufgebaut. Daher gibt es
hier auch keine gedruckten Schaltungen. Da alle Teile sehr einfach gestrickt
sind, sollte ein PCB-Layout einfach zu erstellen sein.
3.1 Aufbau der Temperatursensoren
So sieht der Sensor in echt während der Aussendung aus.
Das ist die Bestückung der Temperatursensoren für draußen.
Die Innenraum-Sensoren sind genauso aufgebaut, die drei Unterschiede
sind:
- Die Stromversorgung von +5V für den Prozessor und +10V für
die IR-LED werden separat zugeführt, dafür entfällt der
teure Akku mit seiner Halterung.
- Wegen der höheren Leistung des Transistors wird ein BD439 anstelle
des BC547 eingesetzt.
- Die beiden Widerstände vor der grünen und der roten LED
sind ein wenig kleiner.
- Das Blinken ist nun umgekehrt: die grüne LED ist dauernd an und
geht beim Blinken aus.
Von den Abmessungen her ist die Platine üppig dimensioniert. Wer unter
chronischem Platzmangel leidet, kann es noch viel, viel kleiner realisieren.
Soll der Sensor draußen aufgestellt werden, dann ist, falls Regen auf
die Schaltung fallen könnte, noch eine Regenabdeckung nötig. Falls
man die Schaltung in eine Plastikschachtel verpacken will: das verzögert
natürlich das Ansprechen des Sensors bei raschen Temperaturwechseln ein
wenig. Und man sollte den IR-Sensor und die IR-LED außerhalb des
Gehäuses anbringen, weil (auch durchsichtiges) Plastik die IR-Strahlung
merklich absorbiert und damit Sende- und Empfangssignale abdämpft.
3.2 Stückliste der Sensoren
Dies ist die Stückliste für alle Bauteile des Außen-Thermometers.
Drei Viertel des Gesamtpreises von 23€ gehen für die Lithium-Zelle
und deren Halterung drauf. Wer sparen will: bei diesen beiden Teilen macht es
dann mal wirklich Sinn, der Rest sind Peanuts. Ich habe die Li-Zelle und die
Halterung für umme gekriegt (umme = südhessisch für umsonst),
daher bitte bissige Bemerkungen über die gelogenen 9800 mAh unterlassen,
denn einem geschenkten Gaul ...
3.3 Aufbau des Umsetzers
Das ist die Bestückung des Umsetzers mit Trafonetzteil auf einer
Viertel-Euro-Platine. Die externen Verbindungen zu dem IR-Sensor-Modul
und der IR-LED sind mit zwei Schraubklemmen realisiert, die Verbindung
zur DB9-Buchse mit einer zweireihigen Stiftleiste. Für den Anschluss
von In-door-Sensoren sind die Betriebsspannungen +5V und +10V an einer
weiteren Schraubklemme verfügbar. Die Netzspannung wird an einer
weiteren Schraubklemme zugeführt.
3.4 Stückliste für Umsetzer und Trafonetzteil
Das hier ist die Stückliste für den IR-zu-Seriell-Umsetzer mit
seinem Trafonetzteil. Ganz schön viele Kleinteile, mit knapp 20
Euronen sind Sie dabei.
Die Software für den Umsetzer und die Temperatursensoren befinden
sich noch in der Entwicklung. Ich werde sie hier posten, wenn sie fertig
sind.
Die Software ist für den ATtiny45 optimiert. Mit einem ATtiny25
erwies sich das Flash als zu eng. Insbesondere die RS232-Kommunikation
benötigt ziemlich umfangreichen Code, daher hier der 45.
Bitte nach dem Brennen des Flash unbedingt auch noch die Fuses für
den Quarzbetrieb noch beachten und setzen, sonst stimmt das ganze Timing
rein gar nicht.
In den folgenden Kapiteln sind die Algorithmen beschrieben, die bei der
Software verwendet werden.
5.1 Algorithmen beim Umsetzer
Der Umsetzer arbeitet mit einem ATtiny25. Seine Aufgabe ist recht einfach:
wenn das Sendesignal von der DB9-Buchse auf Low (nach dem MAX232-Inverter
auf High) geht, sendet er mit 40 kHz über die IR-LED. Wenn nicht,
macht er die IR-LED aus.
Verantwortlich für diese Umschaltung (IR-LED aus oder an) ist der
INT0-Interrupt, der bei jedem Flankenwechsel anschlägt. Findet dieser
eine Null am INT0-Eingang (PB2) vor, stellt er den OC0A-Ausgang auf Clear,
die IR-LED geht aus. Ist es eine Eins, stellt er den OC0A-Ausgang auf Toggle
um und die IR-LED geht an.
Für dieses Teil habe ich mir aber ein nettes Gimmick ausgedacht: die
grüne LED an Pin PB1 (OC1A) blinkt im inaktiven Zustand mit einer
niedrigen Frequenz (Default: 2 Hz). Geht der INT0-Eingang an PB2 aber
auf Eins, weil am seriellen Eingang mindestens eine einzige Eins eintrifft,
wird die Blinkfrequenz der LED auf den höheren Wert (5 Hz)
umgestellt. Diese höhere Frequenz wird für einen einstellbaren
Zeitraum nach dem Eintreffen des letzten Mark-Impulses von der seriellen
Schnittstelle fortgesetzt.
Der Ausgang OC1A wird dazu dauerhaft auf Toggle eingestellt, der
Compare-A-Wert bleibt auf Null. Damit bewirkt jeder Null-Durchgang von TC1
ein Umschalten des Blinkeingangs. Die Frequenz dieses Umschaltens wird bei
4 MHz Takt mittels eines Vorteilers von 4.096 und einem Compare-C-Wert
von 243 eingestellt. Das teilt die Quarzfrequenz 4.000.000 / 4.096 / (243 + 1),
so dass der OC1A-Ausgang mit 4 Hz torkelt, was einer Blinkfrequenz
von 2 Hz entspricht. Bei 5 Hz Blinkfrequenz erledigt das ein
Vorteiler von 2.048 und ein CTC-Wert von 195 (Compare C = 194), so dass
OC1A mit 4.000.000 / 2.048 / (194 + 1) = 10 Hz torkelt.
Erscheint eine Eins am INT0-Eingang, wird auf jeden Fall schon mal der
Torkelzähler rTgl auf seinen voreingestellten Wert gesetzt. Ist die
Toggle-Flagge T im Statusregister schon auf Eins, ist die Routine fertig.
Ist sie noch Null (beim ersten Eintreffen einer Eins am INT0-Eingang),
dann wird der Zähler TC1 auf die höhere Blinkfrequenz umgestellt
und der OCIE1B-Interrupt eingeschaltet.
Dieser Interrupt (rechts im Flussdiagramm) vermindert rTgl. Erreicht
dieser Null, wird die T-Flagge auf Null gesetzt, der OCIE1B-Interrupt
abgestellt und der Zähler TC1 wieder auf die langsamere Blinkfrequenz
umgestellt.
5.2 Algorithmen beim Thermosensor
Dass die Software der Thermosensoren ziemlich komplex ist, sieht man an den
aktiven Interrupt-Vektoren. Sie sehen so aus:
;
; **********************************
; R E S E T & I N T - V E C T O R S
; **********************************
rjmp Main ; Reset vector
rjmp Int0Isr ; INT0
reti ; PCI0
rjmp Oc1aIsr ; OC1A
reti ; OVF1
reti ; OVF0
rjmp ErdyIsr ; ERDY
reti ; ACI
rjmp AdccIsr ; ADCC
reti ; OC1B
rjmp Oc0aIsr ; OC0A
reti ; OC0B
reti ; WDT
reti ; USI_START
reti ; USI_OVF
Sechs der 15 Vektoren sind in Gebrauch, hinter dem Oc0aIsr stecken dabei in
Wirklichkeit drei verschiedene Arten von Reaktionen, je nachdem ob gerade
gesendet, empfangen oder auf den Sendestart gewartet wird.
Die einzelnen Bestandteile der Thermosensoren sind im Folgenden nacheinander
im Detail beschrieben.
5.2.1 Die Uhr im Thermosensor
Jeder Thermosensor hat eine eingebaute Quarzuhr. Das ermöglicht
es, dass alle gesendeten Temperaturen mit Datum und Uhrzeit gestempelt
sind. Das Datum aller Quarzuhren kann mit dem Befehl
"D=26.02.23" über die serielle Schnittstelle eingestellt
werden, die Uhrzeit mit "T=12:34:56". Danach gehen alle
Sensoren auf gleiches Datum und Uhrzeit.
Zur Taktung der Uhr teilt der Timer TC1 den Prozessortakt durch einen
Vorteiler und im CTC-Modus durch den Compare-A-Wert. Erreicht der Timer
den Compare-A-Wert, wird der OC1A-Interrupt ausgelöst.
In der entsprechenden Interrupt-Service-Routine wird, abhängig
von der Anzahl an cTc1Bits folgendes ausgeführt:
- cTc1Bits = 0: Die Flagge bSec im Flaggenregister wird gesetzt.
- cTc1Bits = 8: Ein 8-Bit-Zähler im SRAM, sTc1Cnt, wird
erniedrigt. Erreicht er Null, wird die Flagge bSec gesetzt und
der Zähler neu mit cTc1Cnt gestartet.
- cTc1Bits > 8: Ein 16-Bit-Zähler im SRAM, sTc1Cnt+1:sTc1Cnt,
wird um Eins erniedrigt. Erreichen beide Bytes Null, wird die
Flagge bSec gesetzt und der Zeiger neu mit cTc1Cnt gestartet.
Der solchermaßen durch den Vorteiler, durch den CTC-Compare-A-Wert
und den Null-/Acht-/16-Bit-Teiler geteilte Wert ergibt den Taktwert, mit
dem die grüne LED blinken soll. Dies kann eine Sekunde, eine halbe
Sekunde, eine Viertel-Sekunde oder jeden Wert in der Zelle B57 der
Tabellenkalkulation in der Tabelle "Taktung_Thermometer" sein.
Die weitere Bearbeitung der Zeitinformation erfolgt außerhalb der
ISR in der Routine HdlSec:.
Die Taktung der grünen LED erfolgt mit diesem Takt. Die Flagge
bBlk zeigt an, ob gerade aktiv geblinkt wird. Ist sie gesetzt, dann
wird durch Ausgabe an das PINB-Portregister der Portausgang invertiert
und der Blinkzähler um Eins reduziert. Erreicht dieser Null, wird
die bBlk-Flagge abgeschaltet.
In den Zähler Z+dBlink muss immer ein geradzahliger Wert eingetragen
werden, denn nach dem Ende des Blinkens muss sowohl die netzbetriebene
als auch die akku-betriebene Version wieder bei ihrem Ausgangs-Ruhestand
ankommen.
Der 8-Bit-Zähler in Z+dSecCnt zählt die Teile der Sekunde ab,
die bis zu einer Sekunde nötig ist.
Das Erhöhen der Uhr um eine Sekunde beginnt mit der Abfrage, ob
das aktuelle Messintervall ungleich Null ist. Ist das der Fall, wird
der 16-Bitzähler in sMeasCnt+1:sMeasCnt um Eins erniedrigt. Wenn
er Null erreicht, wird er neu mit dem Messintervall in
sMeasInt+1:sMeasInt gestartet und die nächste Messung gestartet.
Sind 128 Messungen ausgeführt, wird die Temperatur berechnet, in
eine Zeichenkette umgeformt und diese über die serielle
Schnittstelle ausgesendet (siehe die nächsten drei Unterkapitel).
Das Erhöhen der Sekunde der Uhrzeit setzt, wenn der Tag zu Ende
ist, auch das Datum um Eins höher.
Das hier ist der Algorithmus, um die Zeit und eventuell das Datum um eine
Sekunde zu erhöhen. Links die Uhrzeit-Erhöhung, rechts am Ende
des Tages die Datumserhöhung. Der umfangreiche Verhau rechts dient
dazu, zu erkennen, ob schon der nächste Monat anbricht. Irgendwelche
Beschwerden zur Kompliziertheit bitte an Papst Gregor in 15.-ten Jahrhundert
richten, der diese Kompliziertheit gebraucht hat, um das nervöse Eiern
der Erde um die Sonne korrekt abzubilden.
Da der Messzyklus schon zu Beginn gestartet worden ist, stellt sich die Frage,
ob der nächste Messzyklus nun den alten oder den neuen Zeitstempel
tragen wird (was ein Unterschied von bis zu einem Jahr sein kann). Nun,
diese Sekundenerhöhung wird erst ganz und in allen gregorianischen
Verästelungen durchgezogen, bevor die eventuell schon gesetzte
bAdc-Flagge ausgewertet werden wird. Irgendwelche Schutzmaßnahmen
gegen erst teilweise Zeit-und-Datums-Setzungen sind daher nicht
vonnöten.
5.2.2 Messen der Temperatur im Sensor
Der Temperatursensor im ATtiny45 ist an der Multiplex-Adresse 0b1111
in ADMUX verfügbar. Da zum Temperaturmessen der AD-Wandler auf
die interne Referenzspannung von 1,1V eingestellt werden muss, sind
auch die REF-Bits in ADMUX entsprechend einzustellen.
Das Handbuch des ATtiny45 gibt folgenden Zusammenhang zwischen der
Temperatur und dem ADC-Resultat an:
Dahinter steckt alles andere als eine glatte lineare Funktion, wie das
Diagramm rechts zeigt. Aus den gemessenen ADC-Werten soll die Temperatur
in K errechnet werden. Hier sind die beiden linearen Funktionen zu sehen,
wie sie sich aus den beiden unteren und den beiden oberen Daten ergeben.
Weder die Steigungen noch die Ordinatenabschnitte sind bei beiden
Funktionen irgendwie gleich. Auf einer solchen Basis lässt sich
allenfalls ein grobes Schätzometer basteln, aber nix mit einer
irgendwie genaueren Kommastelle bei der Temperatur.
Wie schon in einem anderen Projekt (siehe
hier) habe ich daher eine
quadratische Gleichung entwickelt, mit der diese Werte viel besser zu
interpolieren sind: T = a * ADC2 + b * ADC + c. Wobei
T die Temperatur in Kelvin sein sollte. Mit den Originalwerten von
ATMEL sind die im Diagramm angegebenen Werte für die drei
Parameter der Funktion erkennbar.
Der Parameter a, der quadratische Teil, ist negativ, d.h. die Kurve
ist leicht nach unten durchgebogen. Auch der Parameter c ist negativ.
Aber der lineare Anteil b ist alles andere als 1, wie ATMEL es
vorschlägt.
Nun ist die Multiplikation mit 0,000510 oder mit 1,198980 nicht so ganz
nach dem Geschmack von Assembler-Programmierern: das schreit zu sehr
nach der Fließkommabibliothek, und die passt nicht in den Flash
vom ATtiny45. Aber im Gegensatz zum C-Abhängigen weiß sich
der Assembler-Programmierer auch anders zu helfen. Und das geht so.
Die resultierende Temperatur soll mit 0,1° Auflösung ausgegeben
werden. Wenn wir T mit 10 multiplizieren, kriegen wir schon mal hier
die Kommazahl weg und wir müssen bei der Ausgabe der Temperatur
nur vor der letzten Ziffer ein Dezimalkomma einschmuggeln.
Und natürlich müssen wir die Temperatur mehrfach messen, damit
wir das zufallsbedingte Klappern des letzten ADC-Bits loswerden. Um noch
genauer zu werden, können wir sogar 128 Messungen vollführen
und aufsummieren, ohne dass ein 16-Bit-Addierer überzulaufen droht.
Ein Überlauf träte dann erst bei 191°C auf, aber da ist
der Prozessor schon anderweitig kaputt und verschmolzen.
Auch das Aufsummieren steigert noch mal die Genauigkeit. Unsere Gleichung
lautet daher eher
10*T = a * 128*ADC2 + b * 128*ADC + c
Im Blatt "Temp-Skalierung" der LibreOffice-Calc-Datei
hier kriegen wir a, b und c
ausgerechnet.
Das hier demonstriert den Unterschied zwischen der Linearfunktion und der
Quadratfunktion bei einer Temperatur zwischen 45 und 50°C. Das Delta
(rote Kurve, rechte Skala) beläuft sich durchgängig auf mehr
als ein halbes Grad, so ist eine Auflösung von +/-0,2° linear
nicht erreichbar, nur die quadratische Funktion bietet das. Das bisschen
Differenz lohnt schon den erhöhten Aufwand, damit unser Temperatursensor
mit gutem Gewissen 0,1° vermelden kann und seine echte Auflösung
unter ein Grad kommt.
5.2.3 Umrechnen der Messungen in Temperaturen
Noch eine weitere Hürde ist das Multiplizieren mit 3,114E-07 und mit
0,093670. Damit wir damit weiterkommen, hat der Assembler-Programmierer
noch einen Trick in petto: er multipliziert die 3,114E-7 einfach mit
65.536 * 65.536, was 1.337 gibt, und lässt dafür die vier
unteren Bytes des Ergebnisses einfach wegfallen. Genauso mit 0,093670:
mit 65.536 malgenommen gibt das gerundet 6139, dafür ignoriert er die
beiden unteren Bytes des Ergebnisses.
Das ergibt die in der Spalte L versammelten Assembler-Codezeilen:
; Parameters, export from spreadsheet to source code
.equ cParA = 1337 ; 65536*65536*a in 10*T=-a*128ADC*128ADC+b*128ADC-c
.equ cParB = 6139 ; 65536*b in 10*T=-a*128ADC*128ADC+b*128ADC-c
.equ cParC = 156 ; c in 10*T=-a*128ADC*128ADC+b*128ADC-c
Mit diesen generischen Werten rechnet der Temperatursensor so lange, bis
er über die serielle Schnittstelle andere Werte geschrieben kriegt.
Sowohl die 128-er ADC-Summe als auch die drei Parameter passen in 16 Bits.
Man braucht daher nur
- den Parameter b mit der 128-er-Summe multiplizieren und speichern,
und dann
- den Parameter a mit der 128-er-Summe multiplizieren, durch 65.536
teilen und erneut mit der 128-er-Summe multiplizieren, sowie dieses
Ergebnis vom vorherigen abziehen, und
- den Parameter c vom vorherigen Ergebnis abziehen (von den obersten
zwei Bytes), und
- von den vier Bytes die untersten beiden zum Runden zu verwenden
und schon hat man die Temperatur in Kelvin (mal 10).
In Abhängigkeit von den beiden Flaggen bTC und bTF muss man daraus
eventuell noch die Celsius oder Fahrenheit ermitteln, indem man 273,15
(mal 10) abzieht und, bei Fahrenheit noch zusätzlich mit 1,8 (mal
10) malnimmt und 32 (mal 10) hinzuaddiert. Falls dieses Ergebnis negativ
ist, muss man eine Flagge setzen und die Differenz aus 65536 - Wert bilden.
Die 16-Bit-Zahl ist das Ergebnis in 10*Temperatur.
5.2.4 Eintrag der Temperatur in den Sendepuffer
Der Rest ist nun schlichtes Handwerk:
- den Sendezeiger X auf den Anfang des Puffers setzen,
.
- das Kennzeichen des Sensors (0 bis 9) und ein Minus-Zeichen rein,
- das Datum in der richtigen Formatierung (deutsch/englisch) in den
Sendepuffer, gefolgt von einem Minus,
- die Uhrzeit, getrennt mit ":", in den Sendepuffer, gefolgt
von einem "=",
- falls die Temperatur negativ ist, ein Minuszeichen dazu,
- die Temperatur als positive Ganzzahl mit einem Punkt oder Komma vor
der letzten Ziffer,
- Wagenrücklauf, Zeilenvorschub, das Cursorzeichen und die
abschließende Null rein,
- den Sendezeiger X wieder auf Anfang, und
- die Warteflagge setzen, um den Sendepuffer auszusenden.
Ab jetzt ist der Sender für 250 ms lang damit befasst, das Ergebnis
an die serielle Schnittstelle zu senden (siehe nächstes Unterkapitel).
5.2.5 Senden des Sendepuffers
Das hier zeigt die Taktung eines seriellen Zeichens am Sende-Ausgang
OC0A: die IR-LED ist entweder mit 40kHz am Torkeln (TGL), wenn das Startbit
oder ein Eins-Bit gesendet wird, oder es wird Null, wenn Stop-Bits oder
Null-Bits gesendet werden (CLR). Man beachte noch, dass das DB9-Signal
TXD im MAX232 einmal invertiert wird, bevor es zum INT0-Eingang des
ATtiny25 gelangt.
Unmittelbar nach dem Senden des zweiten Stop-Bits beginnt das Aussenden
des Startbits für das n&auchl;chste Byte.
Ist die Flagge bTx gesetzt, dann sendet der Sensor gerade.
Beim Senden wird der X-Zeiger dazu verwendet, um auf das nächste zu
sendende Zeichen im Sendepuffer sTx zu zeigen. Der Sendepuffer ist
null-terminiert, bei Null wird die Sendung beendet.
Der Sende-Algorithmus wird vom TC0-Compare-A-Interrupt angetrieben. Da dieser
Interrupt auch beim Warten vor dem Senden (siehe nächstes Unterkapitel)
und beim Empfang (siehe übernächstes Unterkapitel) verwendet wird,
erfolgt zunächst die Abfrage, ob die bTx-Flagge gesetzt ist. Falls das
der Fall ist, wird zum Sendezweig verzweigt (links) und der 16-Bit-Zähler
rCntH:rCntL abwärts gezählt. Dieser Zähler zählt die Anzahl
an Torkelvorgängen, die für das Senden eines Bits nötig sind.
Bei 1.200 Baud sind das 67. Ist diese Anzahl noch nicht erreicht, ist
die ISR vorzeitig zu Ende und es darf weiter getoggelt werden.
Falls das Zählergebnis Null ist, wird der 16-Bit-Zähler wieder mit
der Zähldauer neu geladen. Nun wird die Anzahl gesendeter Bits um Eins
vermindert. Ist diese Null, dann wird das nächste Zeichen aus dem Puffer
gelesen. Ist dieses Zeichen Null, wird das Senden beendet, indem
- die Sendeflagge bTx gelöscht wird, und
- der Timer-Interrupt für TC0 gel&aouml;scht wird (so dass nur noch
der Uhren-Interrupt in TC1 aktiv bleibt), und
- die OC0A-Ausgabe auf Clear geschaltet wird.
Wenn das Zeichen nicht Null war, wird rBit auf 11 gesetzt (1 Startbit, 8
Datenbits, 2 Stop-Bits) und OC0A auf Torkeln eingestellt (was das Startbit
sendet).
War rBit beim Dekrementieren nicht Null, wird rimp auf OC0A-Clear eingestellt
und geprüft, ob Stopbits gesendet werden (rBits<3). Falls dies nicht
der Fall ist, wird das nächste zu sendende Bit aus dem Register rTx in
das Carry geschoben. Handelt es sich um eine Eins, wird rimp auf OC0A-Toggle
eingestellt. Der Wert von rimp wird schließlich in das Kontrollregister
A von TC0 geschrieben.
Alle Ausführungszeiten, als Taktzyklen in rot dargestellt, bleiben
unterhalb der Schwelle von 38 Taktzyklen, die bei einem Quarztakt von nur
3 MHz und einer IR-Frequenz von 40 kHz bis zum nächsten
TC0-CompA-Interrupt verbleiben. Einzig im Falle, dass der Wartezyklus gerade
beendet wird und das Senden des ersten Zeichens im Puffer beginnt, wird
diese Schwelle erreicht. Da für die nächste Interrupt-Auslösung
aber noch fünf Takte nötig sind, ist auch dies keine Verzögerung
von Relevanz. Da ein Interrupt-Verlust erst nach weiteren 38 Taktzyklen
einträte, ist auch dies sehr unwahrscheinlich und nahezu ausgeschlossen.
Da während des Senden andere Interrupts ausgeschaltet sind (INT0-Interrupt,
ADC-Interrupts) oder nur sehr kurz sind (nur sehr selten auftretende
TC1-Compare-Matches), kann es auch nicht durch andere Interrupts zu Konflikten
kommen. Weil der Quarz statt 3 aber 4 MHz hat, sind es ohnehin
55 Taktzyklen bis zum Eintritt des nächsten Interrupts und über
90 bis zum Verlust eine Interrupts.
Das hier ist das Impulsdiagramm am OC0A-Ausgang, wenn das Startbit gesendet
wird. Die Anzahl Torkeleien passt dabei exakt zur Baudrate (1 / 1200 =
833µs).
Das hier zeigt das Torkeln des OC0A-Ausganges, wenn ein Startbit und das
oberste Nibble des Datenbytes 0x55 mit 1.200 Baud gesendet wird. Die
IR-Sendefrequenz von 40 kHz wird genau eingehalten, die LED ist 50%
der Zeit an. Das erste Bit, das Startbit, wird gefolgt von dem obersten
Sendebit, einer Null. Danach kommt eine Eins, wieder eine Null und noch
eine Eins. Alle Signaldauern dauern gleich lang. So mag es der
IR-Empfänger.
Das ist nun das ganze 0x55-Byte und der Beginn des nächsten Startbits.
Man erkennt das doppelte Stopbit (8N2) zwischen diesem und dem nächsten
übertragenen Zeichen.
Das ganze nun zwei Male. Der Zwischenraum der beiden Stopbits dauert die
halbe Baudrate, bei ca. 1.200 Baud sind das knapp 600 Hz.
5.2.6 Wartezeit vor dem Senden
Damit sich die Temperaturmeldungen mehrerer Sensoren nicht gegenseitig
stören, wartet der Prozessor mit dem Senden eine Zeit lang ab,
während keiner der anderen Sender senden darf. Wird in dieser
Zeit ein Sendesignal eines anderen Sensors bemerkt, beginnt diese
Abtastzeit von vorne.
Da der Abtastzeitraum jedes Sensors eine individuell lange Zeitdauer
andauert, ist gewährleistet, dass alle Sensoren nacheinander in
der vorgewählten Reihenfolge mit dem Senden drankommen.
Das ist der Ablauf der Wartezyklen. Er ist als weiterer Teil in der
TC0-Compare-A-Interrupt-Service-Routine eingebaut und wird dann
angesteuert, wenn sowohl die bTx- als auch die bRx-Flagge aus sind
und wenn die bRq-Flagge (Rq = Request TX) gesetzt ist. Wenn alle
drei Flaggen Null sind, wird der OCIE0-Interrupt ausgeschaltet.
Ist der Infrarot-Empfänger-Ausgang am PB2-Eingang auf Null,
dann sendet gerade ein anderer Sensor. Dann wird der Zähler
wieder mit seinem Ausgangswert neu gestartet und die Wartezeit
beginnt von vorne.
Wenn nicht, dann wird der Zähler um Eins vermindert. Ist er
noch nicht Null, wird einfach weiter gewartet. Der Abtastzeitraum
(Taktung von TC0, Anzahl Interrupts) erfolgt mittels Konstanten,
die von der Taktfrequenz, der eingestellten Baudrate und der ID des
Sensors abhängig ist, ihre Berechnung erfolgt in der
Tabellenkalkulation.
Hat der Zähler Null erreicht, dann wird mit dem Senden
begonnen. Dazu wird
- die Request-Flagge gelöscht, und
- die Sende-Flagge gesetzt, und
- der X-Zeiger auf den Beginn des Textpuffers gesetzt, und
- das erste Zeichen in das Senderegister eingelesen, und
- der INT0-Interrupt ausgeschaltet, da ja jetzt das Senden
beginnt und der Interrupt schaden würde, und
- der Zähler auf die Anzahl IR-Signale pro seriellem
Bit eingestellt, und
- der CompareA-Wert von TC0 auf den IR-Sende-Wert eingestellt,
und
- der Prescaler von TC0 auf Eins umgestellt.
Danach wird das Startbit gesendet, wozu an die entsprechende
Teilroutine des Sende-Algorithmus gesprungen wird.
Alle weiteren Bits des ersten Bytes werden bei gesetzter
bTx-Flagge ausgesendet.
5.2.7 Empfang in den Empfangspuffer
Beim Empfang ist die Flagge bRx im Flaggenregister gesetzt. In diesem Fall
tastet jeder TC0-Compare-Match-A-Interrupt den IR-Sensor-Eingang auf das
nächste eingehende Bit ab.
Da der Tipper beim seriellen Senden viele, viele Millisekunden braucht, bis
er die nächste Taste gefunden (beim System Kolumbus: jede Taste eine
Entdeckung) und betätigt hat, beginnt der Empfang jedes einzelnen
Zeichens, wenn das Startbit am INT0/PB2-Eingang eintrifft. Dann stellt sich
der INT0-Interrupt wieder aus und es beginnt das Einsammeln der 11 Bits.
Das Sammeln erfolgt jeweils zu einem Zeitpunkt um die Mitte des Bits herum,
weshalb der Zeitraum zwischen INT0 und dem Abtasten des siebten Datenbits
etwa ein-ein-halb Bits Dauer andauert. Danach erfolgt jeweils das Abtasten
nach dem Ablauf einer Bitdauer.
Sind Startbits plus acht Datenbits plus das erste Stopbit abgetastet, ist
das Zeichen komplett, der Empfangsmodus wird wieder verlassen und der
INT0-Interrupt wird wieder aktiviert.
Weil der IR-Seriell-Umsetzer durch die Infrarot-Kopplung vom Computer gesendete
Zeichen auf der seriellen Schnittstelle zurücksendet, und damit einen Loop
darstellt, brauchen eingegangene Zeichen vom Thermosensor nicht mit einem Echo
zurückgespielt werden. Das vereinfacht das Programm, da daher nicht
ständig von Empfang auf Senden umgestellt werden muss. Es wäre
möglich (z. B. sich die Sende-LED und das Empfangsmodul beim
Umsetzer nicht sehen würden), aber meistens ist das unnötig, weil
das Fensterglas genug IR-Strahlung zurückspiegelt.
Vor dem Empfang wartet der IR-Empfänger TSOP31240 auf den Eingang von
10 IR-Impulsen und aktiviert danach seinen Ausgang, indem er ihn auf Null
zieht. Der ist an PB2=INT0 angeschlossen. Der negative Impuls an PB2 löst
einen INT0-Interrupt aus. Dies schaltet den INT0-Interrupt aus, setzt die
bRx-Flagge im Flaggenregister, setzt den Bitzähler rBits auf 9 und
startet TC0 mit folgenden Einstellungen:
- Compare-Match A auf cTc0RxStrt (78), denn zwischen dem Eingang des
Startbits und der Mitte des ersten Datenbits liegen 1,5 serielle
Taktzeiten,
- CTC-Modus (WGM01 auf 1) und COM0A1/0 auf Clear (kein Senden bei Empfang),
- Vorteiler auf cTc0RxCs (normalerweise 64),
- TC0-Compare-Match-A-Interrupt enabled.
Nun läuft folgendes ab:
- Der Zähler rBit wird um Eins erniedrigt. Wird er Null, dann ist
der Empfang eines Zeichens zu Ende. Wenn nicht geht es wie folgt weiter.
- Immer, wenn die Zeit im Zähler rum ist, wird der Zustand des
Eingangs abgefragt. Ist er Null, wird eine Eins in das Register rRx von
rechts nach links eingeschoben. Ist er Eins, wird eine Null eingeschoben.
- Das Vergleichsregister wird auf die Dauer cTc0Rx bis zum Einlesen des
nächsten Bits eingestellt (bei 4 MHz und 1200 Baud sind
das 52, denn 4.000.000 / 64 / 1200 = 52, wegen der Verzögerung durch
den Interrupt bleibt es dabei).
Wenn der Empfang eines 8-Bit-Zeichens beendet ist, was etwa in der Mitte des
ersten Stop-Bits eintritt, dann geht folgendes ab:
- Das empfangene Zeichen wird im SRAM-Puffer sRx gespeichert, auf den
der Y-Zeiger zeigt.
- Es wird getestet, ob sich der Empfangszeiger danach auf dem Ende des
Empfangspuffers befindet. Ist das der Fall, wird der Y-Zeiger auf den
Anfang des Empfangspuffers gestellt und ein unbekannter Befehlscode
an den Anfang geschrieben, was bei der Auswertung eine Fehlermeldung
provoziert.
- Danach wird ein Zeichenkette-Ende-Zeichen an die nächste Position
im Empfangspuffer geschrieben.
- Weitere Interrupts von TC0-Compare-A werden unterbunden, nur die
Uhr in TC1 läuft weiter.
- Die bRx-Flagge wird gelöscht, der weitere Empfang dadurch
unterbunden. Er wird erst wieder eingeschaltet, sobald das nächste
Startbit eintrifft.
- Dann wird getestet, ob es sich bei dem empfangenen Zeichen um einen
Zeilenvorschub handelte. Falls das der Fall ist, wird die Flagge bRxL
gesetzt, die die Auswertung der empfangenen Zeile veranlasst.
- Ist das Zeichen kein Wagenrücklauf, werden die INT0-Interrupts
wieder zugelassen und der Prozessor wartet auf das nächste
Startbit.
Noch eine Überlegung zu Empfangsfehlern durch Fehlzeiten. Ein Fehler
bei der Taktung tritt ein, wenn sich der Abtasttakt um eine halbe Bitzeit
nach vorne oder hinten verschöbe. Da neun Bits zu lesen sind, wäre
das der Fall, wenn der Takt sich um 52 / 9 pro Bit verschöbe. Das sind
knapp mehr als fünf Takte pro Empfangs-Bit. Da der Vorteiler mit 64
läuft, machen da wenige Prozessortakte Verzögerung praktisch
gar nichts aus.
Der Empfänger spricht erst nach 10 IR-Takten an, bleibt dafür
aber noch etwas nach Verschwinden des Signals eine Weile lang an. Dadurch
werden alle Signale etwas später erkannt, der Unterschied bleibt
aber der Gleiche. 10 IR-Takte entsprechen bei 40 kHz einem Zeitraum von
250 µs. Der Abtastzeitraum liegt hingegen bei 896 µs,
für ein halbes Bit 498 µs. Also ist da ebenfalls noch jede
Menge Platz dazwischen.
Insgesamt ist da also noch viel Luft für Fehltakte, bis ein echter
Lesefehler einträte.
5.2.8 Auswertung der empfangenen Zeile
Stellt der Prozessor nach dem Bearbeiten der Interrupts fest, dass das
Flaggenbit bRxL gesetzt ist, muss die eingegangene empfangene Zeile
ausgewertet werden.
Zunächst wird die eingegangene Zeile umformatiert:
- Alle ASCII-Kontrollzeichen, Leerzeichen und Minussymbole werden
aus der Empfangszeile entfernt.
- Alle Kleinbuchstaben werden in Großbuchstaben umgewandelt.
Dann wird die verbleibende Zeile ausgewertet:
- Ist das erste eingegangene Zeichen eine Ziffer zwischen Null und
Neun, dann wird geprüft, ob es sich um die eigene Sensornummer
handelt. Ist das nicht der Fall, wird die weitere Auswertung
abgebrochen.
- Dann wird das Zeichen auf folgende Zeichen überprüft:
"D, T, M, K, C, F, A, B, ?, H". Auf die Zeichen "D,
T, M, A, B, C" KANN ein "=" folgen. Ist das der Fall,
werden, kann bei den folgenden Zeichen folgendes veranlasst werden:
- D: wird das Datum ausgewertet. Ist das erste Trennzeichen
ein Punkt, wird die deutsche Datums- und Zahlennotation eingestellt,
ist es ein "/" die englische.
- T: wird die Zeit gesetzt. Die Stunden, Minuten und
Sekunden MÜSSEN mit ":" getrennt sein. Folgt dem
"T" statt des "=" ein "K", wird auf
Kelvin umgestellt, bei "C" auf °Celsius, bei
"F" auf Fahrenheit.
- M: die Anzahl Sekunden bis zum Auslösen der
Temperaturmessung wird eingestellt (0 schaltet den Sensor aus).
- A: Der Parameter a der Temperaturgleichung wird
eingestellt, wenn "=" folgt, ansonsten wird a ausgegeben.
- B: Der Parameter b der Temperaturgleichung wird
eingestellt oder ausgegeben.
- C: Der Parameter c der Temperaturgleichung wird eingestellt
oder ausgegeben.
- ? oder H: Es wird ein Hilfetext ausgegeben.
- Wird ein Fehler festgestellt, kommt eine aussagekräftige
Fehlermeldung zurück und die grüne LED blinkt einmal,
ansonsten wird entweder mit Datum, Uhrzeit und aktueller Temperatur
oder mit dem aktuellen Parameterwert geantwortet und die grüne
LED blinkt drei mal.
Bitte beachten: bei Umstellungen mit "TK/TC/TF, M, A, B, C" werden
die geänderten Werte in das EEPROM geschrieben. Sie werden bei
nachfolgenden Prozessorstarts von dort jeweils mit ihrem letzten Stand
eingelesen. Diese Befehle müssen daher beim Neustart nicht erneut
gesendet werden.
Viel Erfolg bei der Kommunikation mit den Teilen.
Lob, Tadel, Fehlermeldungen, Genöle und Geschimpfe oder Spam bitte per
Email an mich (info und die Web-URL-Adresse), ich freue mich über alle
Arten von Rückmeldungen.
©2023 by http://www.avr-asm-tutorial.net