zurück weiter

3 Beschreibung der Firmware

Der Meßablauf und die Datenübetragung zum Rechner werden von einem Microcontroller durchgeführt. Das in AVR-RISC-Assembler geschriebene Programm ist in Anhang G zu finden.
Nach der Initialisierung des Prozessors bleibt das Programm in einer Endlosschleife. Alle weiteren Operationen werden durch Interrupts ausgelöst. Dazu gehören die Steuerung des Meßablaufs, die Erzeugung einer internen Prozessorzeit, das Senden der Meßdaten zusammen mit einem Zeitstempel, sowie das Empfangen von Befehlen und deren Auswertung.

3.1 Port- und Variablendefinitionen

Am Anfang des Quellcodes wird eine Include-Datei eingebunden, die einige Portdefinitionen enthält. Diese Datei gehört zum Lieferumfang des Assemblers. Da die Include-Datei für den AT90S4433 zum Zeitpunkt der Entwicklung des Kompasses nicht verfügbar war, wird hier die für den AT90S2313 verwendet und um die nicht enthaltenen Definitionen ergänzt (»definition of some ports«).
Der Prozessor stellt 32 8-Bit Register zur Verfügung, daher sind bis auf den 10 Byte großen Sendepuffer alle Variablen als Registervariablen angelegt. Die Zuweisung von Variablennamen zu Registern findet in der Sektion »register definitions« statt. TXTEMP ist eine im Sendeinterrupt benötigte temporäre Variable. MEASNUMBER enthält die Anzahl der Messungen, die nach jedem Ummagnetisierungspuls durchgeführt werden sollen.

CLOCK1 bis CLOCK5 sind Zähler, welche die Prozessorzeit enthalten. CLOCKDIV, CLOCKONE und CLOCKZERO werden als Konstanten verwendet, die 18, 1 bzw 0 enthalten. Das ist notwendig, da die Register mit Nummern kleiner als 16 nicht mit einer Konstanten verglichen werden können und der Befehlssatz keinen Assembler-Befehl für die Addition eines Registers mit einer Konstanten enthält.

TEMP stellt eine allgemeine temporäre Variable dar.

Das letzte Bit von POSNEG enthält die Information, ob der nächste Ummagnetisierungspuls positiv (0) oder negativ (1) sein soll.

Die Anzahl der durchgeführten Messungen steht in MEASCOUNTER. SENDCOUNTER enthält die aktuelle Anzahl der über die serielle Schnittstelle übertragenen Bytes.

RXCOMMAND trägt das letzte empfangene Komando, in RXVALUE wird der zugehörige Parameter gespeichert. RXTEMP wird als temporäre Variable von der Empfangsroutine benötigt.

Das vorletzte Bit im STATUS-Register gibt an, ob das nächste Byte, das empfangen wird ein Komanndo oder ein Parameter ist. Das letzte Bit gibt an, ob eine kontinuierliche Messung oder Messung auf Anfrage betrieben wird.

TEMPHI und TEMPLO sind zwei Hilfsvariablen, die für die Summen- bzw. Differenzbildung der Meßwerte benötigt werden. MEASNSHI, MEASNSLO, MEASEWHI, MEASEWLO enthalten schließlich die eigentlichen Meßwerte.

3.2 Initialisierung des Microcontrollers

Wird bei dem AT90S4433 ein Interrupt ausgelöst, so führt der Prozessor die Speicherzelle aus, deren Adresse (im Wort-Format) der Interruptnummer entspricht. Ein Interrupt mit niedriger Nummer besitzt eine höhere Priorität. Der Interrupt mit Nummer 0, also mit der höchsten Priorität, ist der Reset-Interrupt. Dieser wird ausgeführt, wenn der Prozessor gestartet wird.
In der Sektion »definition of interrupts« werden die Interruptroutinen den zugehörigen Interrupts zugewiesen.

IRQ0 wird nach dem Einschalten ausgeführt und springt ins Hauptprogramm.

Sobald der 16-Bit-Zähler einen einstellbaren Vergleichswert erreicht, wird IRQ4 ausgelöst. Dieser wird dazu verwendet, um die Messung zu steuern.

IRQ6 wird aktiv, wenn im 8-Bit-Zähler ein Überlauf auftritt, damit wird die Prozessorzeit generiert.

Wird ein Byte von der seriellen Schnittstelle empfangen, wird IRQ8 ausgelöst. IRQ9 zeigt an, daß das Senderegister leer ist und ein weiteres Byte geschrieben werden kann.

Im MAIN-Programm wird der Microcontroller und seine Peripherie konfiguriert. Zunächst wird der Stack-Pointer gesetzt, damit eine spätere Interruptverarbeitung einwandfrei ablaufen kann.

Als nächstes werden die IO-Ports entsprechend ihrer Beschaltung als Ein- bzw. Ausgänge festgelegt, die LED auf gelb geschaltet und DSR auf low gelegt.

Es folgt die Konfiguration des prozessorinternen UARTs. Empfangs- und Sendeeinheit werden eingeschaltet, der Empfangsinterrupt wird aktiviert und die Baudrate auf 19200 festgelegt. Weitere Teilerfaktoren für andere Baudraten finden sich in in der Dokumentation des AT90S4433 .

Anschließend werden die Timer konfiguriert. Der 8-Bit-Timer erhält den durch 8 geteilten CPU-Takt. Außerdem wird der Timer-Overflow-Interrupt aktiviert, der bei jedem Zählerüberlauf einen Interrupt auslöst, so daß die CLOCKTICK-Routine 1800 mal pro Sekunde aufgerufen wird.

Des weiteren werden die Zählvariablen auf null gesetzt und die Konstanten zugewiesen.

Der 16-Bit-Timer wird so konfiguriert, daß er mit 1/8 des CPU-Taktes angesteuert wird, bei Erreichen eines Vergleichswertes einen Interrupt auslöst und gleichzeitig den Zähler wieder auf null setzt. Der voreingestelle Wert für den Vergleichswert beträgt 0x4000, das entspricht einer Meßrate von ca. 0.9 1/s bei voller Auflösung.

Gegen Ende des Bootvorgangs werden noch die Meßvariablen und der Messungszähler auf null gesetzt, sowie dem Status, dem POSNEG-Flag und MEASNUMBER Standartwerte zugewiesen.

Nun wird dem Computer durch setzen der DSR-Leitung mitgeteilt, daß der Kompaß bereit ist. Der Microcontroller wartet seinerseits nun auf das DTR-Signal vom Computer. Liegt dieses an, so werden die Interrupts freigegeben, die LED ausgeschaltet und das Programm verweilt in einer Endlosschleife. Diese enthält ein SLEEP, um den Prozessor zwischen den Interrupts anzuhalten. Sollte DTR während des Betriebs auf low gehen, wird der Programmanfang angesprungen und so ein Reset ausgeführt.

3.3 Meßroutine

Die Meßroutine wird ausgeführt, sobald der 16-Bit-Timer den eingestellten Vergleichswert erreicht hat. Dort wird zunächst überprüft, ob es sich um eine positive oder eine negative Messung handelt. Im Falle einer positiven Messung wird zunächst die LED grün geschaltet. Ist MEASCOUNTER noch null, so wird er auf eins gesetzt und ein positiver Ummagnetisierungspuls wird erzeugt. Eine kurze Verzögerung verhindet das gleichzeitige Leiten der Endstufentransistoren. Danach wird die Interruptroutine beendet.

Ist MEASCOUNT aber größer als null, so findet eine Messung statt. Dazu wird der Multiplexer des AD-Wandlers zuerst auf den Nord-Süd-Sensor geschaltet, die Wandlung gestartet und deren Ende abgewartet. Das Meßergebnis wird zu dem bisherigen Nord-Süd-Meßwert addiert.

Anschließend findet der gleiche Vorgang mit dem Ost-West-Sensor statt. Danach wird überprüft, ob die gewünschte Anzahl Messungen bereits erfolgt ist. Wenn nicht, wird der Messungszähler um eins erhöht und die Interruptroutine beendet.

Falls ja wird der Meßzähler wieder auf null und das Polaritätsflag POSNEG gesetzt, um anzuzeigen, daß die nächste Messung negativ ist und wieder mit einem Ummagnetisierungspuls beginnt.

Bei der negativen Messung wird die Leuchtdiode wieder ausgeschaltet, dadurch ergibt sich ein Blinken der Leuchtdiode im Takt der Messungen.

Danach wird wieder der Sensor ummagnetisiert und anschließend der Nord-Süd- und der Ost-West-Wert ermittelt, aber diesmal wird der Wert vom aktuellen Meßwert abgezogen. Durch diese Differenzbildung wird der Offsetfehler der Operationsverstärker eliminiert.

Wurde die entsprechende Anzahl Messungen durchgeführt, wird der Meßzähler wieder auf null gesetzt und das POSNEG-Flag gelöscht. Dieses Aufsummieren über mehrere Messungen erhöht die Genauigkeit der Messung, da zum einen Rauschen ausgemittelt und zum anderen die Auflösung der AD-Wandler dadurch gesteigert wird.

Danach wird ein Präfix (0x41) zusammen mit den Meßdaten und dem aktuellen Zeitstempel in den Puffer für die zu sendenden Daten geschrieben und die Senderoutine ausgeführt. Die Zeitangabe entspricht also dem Zeitpunkt des Meßendes, nicht dem des Meßanfangs. Sobald alle Daten an den Computer übertragen sind, werden die Variablen für den Meßwert wieder auf null gesetzt und, falls nur eine Messung auf Anfrage durchgeführt wurde, der Timer-Compare-Interrupt abgeschaltet.

3.4 Senderoutine

In der Senderoutine wird das erste Byte aus dem Sendepuffer ausgelesen und in das UART-Data-Register geschrieben. Danach wird der UART-Data-Register-Empty-Interrupt aktiviert und die Interruptroutine wieder verlassen.

Sobald das erste Byte gesendet wird, wird vom Prozessor der Data-Register-Empty-Interrupt ausgelöst, der, wenn noch nicht alle Bytes geschickt wurden, das nächste Byte aus dem Sendepuffer liest und dem UART-Data-Register zuführt.

3.5 Empfangsroutine

Wird ein Byte von der seriellen Schnittstelle empfangen, so wird der RX-Complete-Interrupt ausgeführt. Da diese Interruptroutine aufgrund ihrer Priorität unterbrochen werden könnte, was nicht gewünscht ist, werden während ihrer Ausführung alle Interrupts gesperrt.

Ein Befehl vom Computer an den Microcontroller besteht immer aus zwei Bytes. Zuerst kommt ein Befehl, bestehend aus einem Buchstaben zwischen A und F und danach das Argument. Dazu wird anhand des letzten Bits im STATUS-Flag bestimmt, ob das empfangene Byte einen Befehl oder ein Argument darstellt.

Ist es ein Befehl, so wird dessen Gültigkeit sichergestellt, die LED auf rot geschaltet und Bit 0 im STATUS-Flag gesetzt um anzuzeigen, daß das nächste empfangene Byte ein Argument sein wird. Da der Befehl erst später benötigt wird, wird er in RXCOMMAND abgelegt.

Wird ein Argument empfangen, so wird es in RXVALUE gespeichert und Bit 0 von STATUS wieder gelöscht. Erst jetzt wird das Programm anhand des vorher empfangenen Befehls verzweigt:

zurück weiter