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.
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.
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.
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.
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:
Kommando »C« stellt die Zeit zwischen dem Ummagnetisieren und der ersten Messung bzw. zwischen den einzelnen Messungen ein. Dazu wird RXVALUE in das obere Byte des Vergleichswertes für den 16-Bit-Timer geschrieben. Die resultierende Intervallzeit beträgt 0,56ms*RXVALUE.
Kommando »D« stellt die Anzahl der Messungen ein, die nach jedem Ummagnetisierungspuls ausgefürt werden sollen. Werte größer als 32 sind zwar möglich, aber nur in Spezialfällen sinnvoll, da es bei einer Vollaussteuerung des AD-Wandlers und mehr als 32 Messungen zu einem Zahlenüberlauf kommt und damit die Meßwerte unsinnige Größen annehmen können. Null ist als Wert nicht erlaubt.
Kommando »E« schaltet die Status-LED ein (RXVALUE=1) oder aus (RXVALUE=0). Das kann benutzt werden, falls die Schaltung aus einer Batterie versorgt wird und Strom gespart werden soll, oder wenn eine flackernde Leuchtdiode andere Messungen stört.
Kommando »F« setzt die Prozessoruhr zurück.