|
Die Aufgabe der PIC-Software besteht bei der Wanduhr hauptsächlich aus der DCF- Dekodierung. Diese wiederum besteht aus mehreren Teilaufgaben:
Die zweite wichtige Aufgabe der PIC-Software ist die Anzeige der Uhrzeit. Für die
Anzeige dient das gleichnamige Unterprogramm (ANZEIGE). Dieses Unterprogramm
wird ebenfalls zyklisch alle 4ms aufgerufen. Dazu wird die gleiche 4-ms-Zeitbasis wie
für die DCF-Dekodierung verwendet. Der Grund für diese Zeitbasis ist, dass das
Unterprogramm ANZEIGE abwechselnd die Minute und die Sekunde ausgibt. (zur
Erinnerung: Die Minute und die Sekunde werden ja auf einem gemeinsamen
"Leuchtdioden-Kreis" angezeigt). Man spricht hier also von einer einfachen
Multiplexansteuerung. Für den Betrachter entsteht so der Eindruck, dass gleichzeitig die
Sekunde und die Minute leuchten. Dazu eignet sich die 4-ms-Zeitbasis, und diese ist ja
ohnehin schon vorhanden.
Für die Stundenanzeige stehen 12 eigene Leuchtdioden, welche über den Port A
angesteuert werden, zur Verfügung. Daher ist hier keine Multiplexansteuerung notwendig.
Der PIC-I/O-Eingang, an dem das DCF-Empfangsmodul (mit einer Anpasschaltung) angeschlossen ist (hier bei der Wanduhr der Portpin RA0), wird zyklisch (ca. alle 4 ms) vom Unterprogramm DCFROUTINE abgefragt. Als Zeitbasis für den 4-ms-Takt dient der Timer-0-Interrupt. Der Aufruf des Unterprogramms DCFROUTINE erfolgt hier aber nicht von der ISR (Interrupt-Service-Routine), sondern vom Hauptprogramm. Die ISR setzt nur alle 4 ms ein Flag zur Kennzeichnung, dass das Hauptprogramm das Unterprogramm DCFROUTINE aufrufen soll.
Die Aufgabe des Unterprogramms DCFROUTINE besteht darin, aus dem vom DCF-
Empfangsmodul empfangenen Datenstrom die Informationen LOW, HIGH und den
Minutenwechsel (also das Ausbleiben der 59. Sekunde) gemäß dem im Abschnitt
2. Grundlegendes zu DCF gewonnen Erkenntnisse zu dekodieren. Für diese
Informationen befinden sich im DCF-Statusregister (DCFSTATUS) entsprechende
Flags. (Siehe Abschnitt 4.2. Benötigte Register, Konstanten, Portdefinition,
Makros und Tabellen.)
Weiters beinhaltet das Register DCFSTATUS noch den Zustand des DCF-Eingangs 4ms vor dem
Aufruf des Unterprogramms DCFROUTINE. Mit Hilfe des aktuellen Zustands und des Zustands vor 4 ms
kann nun erkannt werden, ob sich der Pegel am DCF-Eingang geändert hat.
Das Hauptprogramm prüft nun ständig die Flags DCFNEUESEK (wird zusätzlich zu
DCFLOW bzw. DCFHIGH gesetzt, wenn eine gültige Sekunde empfangen wurde) und
DCFNEUEMIN, und ruft die zugehörigen Unterprogramme DCFUPSEKUNDE bzw.
DCFUPMINUTE auf. Die Aufgabe des Unterprogramms DCFUPSEKUNDE ist es, die
empfangenen Low- und High-Pegel in den Register DCFTELEGRAMM1 bis
DCFTELEGRAMM8 zwischenzuspeichern.
Die Aufgabe des Unterprogramms DCFUPMINUTE ist dagegen etwas umfangreicher: Zunächst
die Zeit und das Datum aus den in den Registern DCFTELEGRAMM1 bis DCFTELEGRAMM8
zwischengespeicherten Werten entsprechend der Tabelle im Abschnitt
2. Grundlegendes zu DCF die Zeit- und Datumswerte zusammensetzen.
Anschließend die soeben gewonnen Zeit- und Datumsinformationen
mit den Zeit- und Datumsinformationen der vorhergehenden Minute vergleichen. Die
Zeit- und Datumswerte der soeben empfangenen Minute sind nur dann gültig, wenn
sich die Minute um maximal 1 von der vorhergehenden Minute unterscheidet, während
sich die restlichen Zeit- und Datumsinformationen mit denen der vorhergehenden
Minute nicht unterscheiden. Dies ist nur eine einfache Überprüfung, die aber manche
richtigen Telegramme als falsch auswertet.
(Siehe Abschnit 4.5.4. Unterprogramm DCFUPMINUTE)
Parallel zur Dekodierung des DCF-Eingangs erzeugt das Unterprogramm INNEREUHR eine reine Softwareuhr. Für diesen Zweck ist eine genaue 1-Sekunden-Zeitbasis notwendig. Diese Zeitbasis wird von der schon erwähnten Timer-0-ISR (Interrupt Service Routine) zusätzlich zur 4ms-Zeitbasis erzeugt. Auch für diese Zeitbasis wird in der ISR ein entsprechendes Flag gesetzt, und das Hauptprogramm ruft das Unterprogramm INNEREUHR auf, wenn dieses Flag gesetzt ist. Diese zusätzliche Softwareuhr mag auf dem ersten Blick unnötig erscheinen. Es hat sich aber gezeigt, dass ein DCF-Empfang oft auch über eine längere Zeit nicht möglich ist. In diesem Fall würde die Uhr "stehen". Diese Zeit wird mit einer zusätzlichen Softwareuhr so überbrückt, dass der Betrachter der Uhr davon nichts bemerkt.
Register:
Für die Wanduhr sind neben einigen internen Register (SFR, Spezielle Funktions-
Register) noch eine ganze Menge eigener Register notwendig, wobei der Großteil für
die DCF-Dekodierung notwendig sind:
Bit Flagname Funktion
0 DCFPORTNEU Akt. Zustand DCF-Porteingang
1 DCFPORTALT Vorhergehender Zustand am DCF-Porteingang
2 DCFNEUESEK gesetzt, wenn neue Sekunde begonnen
3 DCFNEUEMIN gesetzt, wenn neue Minute begonnen
4 DCFLOW gesetzt, wenn Low-Signal erkannt
5 DCFHIGH gesetzt, wenn High-Signal erkannt
6 DCFFEHLER gesetzt, wenn ein Fehler erkannt
7 DCFSYNC gesetzt, wenn Uhr mit DCF synchronisiert
Wert Bedeutung
1 Montag
2 Dienstag
3 Mittwoch
4 Donnerstag
5 Freitag
6 Samstag
7 Sonntag
Bit Flagname Funktion
0 DCFRESANT Ist dieses Bit gesetzt so wurde die Reserveantenne zum
Versenden des DCF-Telegramms verwendet
1 DCFSOMWIN Ist dieses Bit gesetzt, so kündigt es eine Umstellung
zwischen Sommer- und Winterzeit an. Dieses Bit wird eine
Stunde vor der Zeitumstellung gesetzt. Ab der Zeitumstellung
enthält es wieder den Wert 0
2 DCFSOMMER Während der Sommerzeit ist dieses Bit gesetzt
3 DCFWINTER Während der Winterzeit ist dieses Bit gesetzt
4 DCFSCHALTSEK Ist dieses Bit gesetzt, so kündigt es eine Schaltsekunde an
Konstanten:
Die Konstante KONSTISR1SEK gibt die Anzahl der notwendigen ISR-Aufrufe für die 1-
Sekunden Zeitbasis an.
Hier wird die ISR alle 4ms aufgerufen, daher ergibt sich für diese Konstanten der Wert
250 (250 x 4ms = 1000ms = 1 Sekunde)
Bei einem LOW dauert die Absenkung des Trägers zwischen 80ms und 120ms, für ein
High dauert die Absenkung des Trägers zwischen 160ms und 240ms (siehe auch Abschnitt
2. Grundlegendes zu DCF). Die Konstanten DCFLOWMIN,
DCFLOWMAX, DCFHIGHMIN und DCFHIGHMAX dienen zur Ermittlung
eines LOW oder eines HIGH.
Das Unterprogramm DCFROUTINE wird alle 4ms aufgerufen, daher ergeben sich für die
Konstanten folgende Werte:
Portdefinition:
Im allgemeinen wird bei jeder Anwendung der Eingangspin für die DCF-Dekodierung an
einem anderen Portpin verwendet. Damit dies in der Software nur an einer Stelle
berücksichtigt werden muss befindet sich in der Software eine Portdefinition für den
DCF-Eingang. Diese besteht aus den folgenden 3 Parametern:
Achtung: Wird für DCFINPORT der Port A verwendet, so muss für DCFINTRIS das zum Port A zugehörige TRIS-Register definiert werden. Bei der hier beschriebenen Wanduhr ergeben sich aufgrund der Hardwarebeschaltung folgende Definitionen
DCFINPORT equ PORTA DCFINTRIS equ TRISA DCFIN equ 0
Makros:
;Umschalten zu Registerbank 0
bank0 MACRO
bcf STAT,RP0
ENDM
;Umschalten zu Registerbank 1
bank1 MACRO
bsf STAT,RP0
ENDM
Tabellen:
Die bei der Wanduhr verwendeten Tabellen dienen zur Anzeige der Uhrzeit:
Aufgaben des Hauptprogramms:
Zuerst wird der Mikrocontroller initialisiert. Diese Tätigkeit wird von einem
Unterprogramm (INIT) ausgeführt. Danach wird der Timer0-Interrupt und der globale
Interrupt freigegeben. Dafür ist das Register INTCON zuständig. Je nach benötigten
Interrupts werden die entsprechenden Freigabebits (im Englischen: Enable) gesetzt. Wird
ein Interrupt verwendet so muss zusätzlich zum verwendeten Interrupt auch die globale
Interruptfreigabe GIE (General Interrupt Enable) gesetzt werden. Er ist sozusagen der
Hauptschalter, der Interrupts ermöglicht. Das INTCON-Register kann einfach mit den
Befehlen movlw b‘10100000‘ und movwf INTCON beschrieben werden. Der
Timer0-Interrupt ist jetzt eingeschaltet. Er sorgt hier bei der Wanduhr für eine
4-ms-Zeitbasis und für eine1-Sekunden-Zeitbasis.
Nun befindet sich die Software in einer Endlosschleife. Diese Schleife besitzt die Aufgabe ständig die so genannten Botschaftsflags abzufragen. Ist eines dieser Botschaftsflags gesetzt, so muss vom Hauptprogramm eine bestimmte Aufgabe ausgeführt werden. Diese Aufgaben sind in Form von Unterprogrammen vorhanden. Zwei dieser Botschaftsflags werden in der Timer-ISR gesetzt. Und zwar wird alle 4ms ein Flag gesetzt. Das zweite Flag von der ISR wird jede Sekunde gesetzt.
Hier Zusammenfassend die Tätigkeiten in der Endlosschleife, welche durch die Botschaftsflags ausgelöst werden:
Eine ISR (Interrupt Service Routine) ist im Prinzip ein Unterprogramm, welches aber im Gegensatz zu normalen Unterprogrammen, "unvorhergesehen" aufgerufen wird. Hier, beim Timer 0-Interrupt jedes Mal, wenn der Timer 0 überläuft, also von 255 auf 0 wechselt. Würde zum Beispiel ein RB-Interrupt verwendet werden, so würde bei jeder Pegeländerung von RB4 bis RB7 ein Interrupt auftreten und die entsprechende ISR wird ausgeführt. Eine ISR sollte daher so kurz wie möglich sein.
Ein weiterer wichtiger Punkt bei einer ISR ist, dass das w-Register (Working- oder Arbeitsregister) und das STATUS-Register in andere Registern zwischengespeichert werden müssen, falls diese in der ISR ihren Registerinhalt verändern. Der Grund dafür ist, dass eine ISR eben unvorhergesehen aufgerufen wird, und die angesprochenen Register unter Umständen zu diesem Zeitpunkten gerade benötigte Werte enthalten. Nach Ausführung der ISR springt diese zwar wieder genau an die Stelle zurück, wo sie war, bevor der Interrupt auftauchte, aber mit einem möglicherweise falschen Wert im w-Register (bzw. STATUS-Register). Das Zwischenspeichern des w-Register bzw. des STATUS-Registers wird häufig auch als PUSH bezeichnet. Das Widerherstellen von w-Register und STATUS-Register nennt man POP.
Woher weiß das Programm, dass ein Interrupt aufgerufen werden muss? Dazu gibt es für jede Interruptquelle ein Kontroll-Flag. Dies wird vom Controller gesetzt wenn dieser Interrupt auftritt. (Vorausgesetzt, dass diese Interruptquelle freigegeben ist). Damit aber die ISR nicht ständig aufgerufen wird, muss dieses Bit in der ISR wieder gelöscht werden.
Nun aber zur wanduhrspezifischen Timer 0-ISR. Diese hat lediglich die Aufgabe eine Zeitbasis für 4ms und eine Zeitbasis für 1 Sekunde zu erzeugen. Eine Zeitbasis für 4ms ist hier besonders einfach zu erzeugen, da ja diese ISR ohnehin schon zu genau diesen Zeitabständen aufgerufen wird. Es ist also nur notwendig ein Flag zu setzen. Dieses Flag trägt hier den Namen FLAG4MSEK und befindet sich im Register FLAGSISRHP. Die Generierung für die 1-Sekunden-Zeitbasis ist dagegen schon etwas "umfangreicher". Damit eine Zeit von einer Sekunde entsteht muss die ISR 250 mal aufgerufen werden (250 x 4ms = 1000ms = 1 Sekunde). Bei jedem ISR-Aufruf muss also ein Zählregister um 1 vermindert werden. Besitzt es danach den Wert 0, so ist eine Sekunde vergangen. Nun wird das Botschaftsflag FLAG1SEK im Register FLAGSISRHP gesetzt, und das Zählregister muss mit dem Wert 250 neu geladen werden. Der Wert 250 wird hier durch die Konstante KONSTISR1SEK ersetzt.
Die ISR wird, wie schon mehrmals erwähnt, alle 4ms aufgerufen Diese 4ms ergeben sich folgendermaßen: TMR0 wird mit dem Wert 0 geladen – es dauert also 256 Taktzyklen bis das Register wieder den Wert 0 besitzt, der Vorteiler besitzt den Wert 16 (vgl. Unterprogramm INIT, Abschnitt. 4.5.1). Der Taktzyklus ergibt sich aus dem verwendeten Quarz (X1). Dieser ist bei der PIC-Familie wie folgt definiert:
![]()
Daraus ergibt sich folgender Zusmmenhang:

Also ein ISR-Aufruf alle 4000µs, was gleichbedeutend mit 4ms ist.
Eine ISR muss mit dem Befehl retfie beendet werden. Beim Aufruf der ISR wird automatisch das Bit GIE gelöscht, damit während der Ausführung der ISR kein weiterer Inerrupt ausgelöst werden kann, was bei mehreren freigegebenen Interruptquellen durchaus möglich sein kann. Mit dem Befehl retfie wird zunächst an die Stelle im Programm zurückgesprungen, wo sich die Programmabarbeitung befand bevor die ISR aufgerufen wurde, und die verwendeten Interrupts werden wieder freigegeben (hier bei der Wanduhr der Timer0-Interrupt)
Die insgesamt sieben Unterprogramme lassen sich folgendermaßen einteilen:
Dieses Unterprogramm dient zur Initialisierung des Mikrocontrollers. Der Portpin an
dem der DCF-Empfänger angeschlossen ist muss als Eingang definiert werden,
während die Portpins zur Anzeige der Stunde, Minute und Sekunde als Ausgang
definiert werden.
In der Initialisierungsroutine muss für den erste Aufruf des Unterprogramms
DCFROUTINE der aktuelle Zustand dieses Portpins gelesen, und im Register
DCFSTATUS kopiert werden.
Da das Unterprogramm DCFROUTINE zyklisch (alle 4ms) aufgerufen wird, ist eine entsprechende Zeitbasis notwendig. Diese wird mit Hilfe eines Timer-Interrups erzeugt. Für die Definition der Zeitbasis ist hier das mikrocontrollerinterne Funktions-Register OPTREG (in der Registerbank 1) zuständig. Damit bei einer PIC-Taktfrequenz von 4,096MHz eine Zeitbasis von 4ms erzeugt wird, muss das Register OPTREG mit dem binären Wert b‘00000011‘ geladen werden. Das Zählregister für dies Zeitbasis (Funktions-Register TMR0, in Registerseite 0) muss gelöscht werden.
Weiters müssen einige Register vorbelegt (gelöscht) werden.Das Unterprogramm DCFROUTINE ist für die DCF-Dekodierung die wichtigste Komponente.
Diese Routine wird ca. alle 4 ms aufgerufen
Aufgabe und Vorgehensweise:
Die Aufgabe des Unterprogramms DCFROUTINE besteht darin aus den Abtastungen
herauszufinden, ob ein Low, ein High oder ein Minutenwechsel gesendet wurde. Dazu
wird bei jedem Aufruf des Unterprogramms DCFROUTINE entweder das Zählregister
DCFPULS oder das Zählregister DCFPAUSE um 1 erhöht (inkrementiert), wenn sich
der Pegel vom DCF-Eingang zum vorhergehenden Aufruf dieses Unterprogramms nicht
verändert hat. Ist der DCF-Eingang Low (also logisch 0), so wird das Zählregister
DCFPULS um 1 erhöht, ist der DCF-Eingang High (also logisch 1), so wird das
Zählregister DCFPAUSE um 1 erhöht. Beide Zählregister können maximal den Wert
255 aufnehmen, was einer Zeit von 1020 ms (oder 1,02 Sekunden) entspricht (=255 *
4ms).
Unterscheidet sich der aktuelle Pegel des DCF-Eingangs mit dem Pegel vom
vorhergehenden Aufruf, so spricht man von einer Flanke, wobei hier zwischen einer
fallenden und einer steigenden Flanke unterschieden werden muss. Bei einer fallenden
Flanke (der aktuelle Pegel des DCF-Eingangs ist logisch 0, während der Pegel beim
vorhergehenden Aufruf noch logisch 1 war), erfolgt zunächst eine Auswertung des
Zählregisters DCFPULS. Beinhaltet dieses Zählregister einen Wert zwischen den
Konstanten DCFLOWMIN und DCFLOWMAX, so wurde ein LOW des DCF-Telegramms ermittelt.
Im DCF-Statusregister (DCFSTATUS) werden daher die Flags
DCFLOW und DCFNEUESEK gesetzt. Das Flag DCFNEUESEK dient als Zeichen einer
neu empfangenen und gültigen Sekunde. Anschließend wird das Zählregister
DCFPULS gelöscht. Beinhaltet das Zählregister DCFPULS einen Wert zwischen den
Konstanten DCFHIGHMIN und DCFHIGHMAX, so wurde ein HIGH des DCF-Telegramms ermittelt.
Im DCF-Statusregister (DCFSTATUS) werden daher die Flags
DCFHIGH und DCFNEUESEK gesetzt. Das Flag DCFNEUESEK dient auch hier als
Zeichen einer neu empfangenen und gültigen Sekunde, und auch das Zählregister
DCFPULS wird anschließend gelöscht. Beinhaltet das Zählregister DCFPULS einen
Wert der weder zwischen den Konstanten DCFLOWMIN und DCFLOWMAX noch
zwischen den Konstanten DCFHIGHMIN und DCFHIGHMAX liegt, so handelt es sich
um einen Übertragungsfehler. In diesem Fall wird das Fehlerflag (DCFFEHLER) im
DCF-Statusregister (DCFSTATUS) gesetzt und auch das Zählregister DCFPULS wird
anschließend gelöscht. Das Flag DCFNEUESEK wird hier aber nicht gesetzt, da es sich
in diesem Fall um keine gültige Sekunde handelt. Das Fehlerflag wird erst bei der
Erkennung einer neuen Minute wieder gelöscht. Achtung: Solange das Fehlerflag
gesetzt ist erfolgt keine Auswertung des Zählregisters DCFPULS. Dieses
Zählregister wird aber dennoch bei jeder fallenden Flanke zurückgesetzt.
Bei einer steigenden Flanke (der aktuelle Pegel des DCF-Eingangs ist logisch 1,
während der Pegel beim vorhergehenden Aufruf noch logisch 1 war) wird das
Zählregister DCFPAUSE gelöscht.
Entsprechend dem im 2. Grundlegendes zu DCF beschriebenen
Protokoll erfolgt in der 59. Sekunde keine Absenkung des Trägers. Da es also in der
59. Sekunde keine fallende Flanke gibt, gibt es auch keine steigende Flanke. Das
Zählregister DCFPAUSE "läuft über", da es nur einen Zählbereich von 0 bis
255 besitzt. Dieser Überlauf wird hier ausgenützt. Zur Bestimmung einer neuen Minute bzw.
zur Bestimmung des Telegrammbeginns. Ist das Fehlerflag gesetzt, so wird es nun gelöscht.
War es nicht gesetzt, so wird das Flag DCFNEUEMIN im DCF-Statusregister (DCFSTATUS) gesetzt.
Das im Abschnitt 7. Download downloadbare Flussdiagramm soll das soeben beschriebene und umfangreiche Unterprogramm verdeutlichen. In den grau hinterlegten Bereichen erfolgt das Setzen oder Rücksetzen der zur weiteren Verwendung notwendigen Übergabeflags im DCF-Statusregister (DCFSTATUS). Die Unterprogramme DCFUPSEKUNDE und DCFUPMINUTE greifen auf diese Flags zu.
Anmerkung:
Die temporären Register TEMP1 und TEMP2 werden hier nur als Hilfsregister benötigt.
Sie können daher auch in anderen Unterprogrammen verwendet werden.
Aufgaben:
Vorgehensweise:
Ist das Flag DCFLOW (im Register DCFSTATUS) gesetzt das Carryflag (im SFR STAT)
löschen, ist aber das Flag DCFHIGH (ebenfalls im Register DCFSTATUS) gesetzt das
Carryflag setzten. Dieses Carryflag nun dem Telegramm hinzufügen. Dieser Vorgang
erfolgt mit einem so genannten Schiebebefehl. Dabei werden alle Bits des Registers
DCFTELEGRAMM1 auf die nächst höhere Position verschoben. (Bit 6 wandert ins Bit 7,
Bit 5 wandert ins Bit 6 usw. Bit 0 wandert ins Bit 1). Der Inhalt vom Carryflag wandert
ins Bit 0. Der Inhalt von Bit 7 wird ins Carryflag geschoben. Bei den Registern
DCFTELEGRAMM2 bis DCFTELEGRAMM6 erfolgt der selbe Vorgang. (Der Inhalt von
Bit 7 des Registers DCFTELEGRAMM1 wird ins Carry geschoben, und das Carry aber
weiter in das Bit 0 des Registers DCFTELEGRAMM2)
Anmerkung:
Die Flags DCFLOW und DCFHIGH können nie gleichzeitig gesetzt sein. Es ist nur
möglich, dass entweder nur DCFLOW oder nur DCFHIGH gesetzt ist, aber nie beide
gleichzeitig.
Aufgaben:
Anmerkung:
Das temporäre Register TEMP1 wird hier nur als Hilfsregister benötigt, und kann daher
auch in anderen Unterprogrammen verwendet werden.
Aufgaben:
Für den Fall dass kein gültiges DCF-Telegramm empfangen werden kann sorgt dieses
Unterprogramm dafür, dass die Uhrzeit trotzdem jede Sekunde aktualisiert wird. Ist für
eine längere Zeit kein korrekter DCF-Empfang möglich, so würden die Minuten,
Stunden, Tage usw. stehen bleiben, da ja im Unterprogramm DCFUPMINUTE nur
gültige DCF-Telegramme übernommen werden.
Dieses Unterprogramm wird also parallel zu den Unterprogrammen für die DCF-
Dekodierung aufgerufen.
Vorgehensweise:
Die Sekunden (Register UHRSEKUNDE) um 1 erhöhen. Beinhalte dieses Register nun
den Wert 60, so beginnt eine neue Minute. Daher die Sekunden löschen und die
Minuten (Register UHRMINUTE) um 1 erhöhen. Beinhaltet dieses Register nun den
Wert 60, so beginnt eine neue Stunde. Daher die Minuten löschen und die Stunden
(Register UHRSTUNDE) um 1 erhöhen. Beinhaltet dieses Register nun den Wert 24, so
beginnt ein neuer Tag. Daher die Stunden löschen. Ist das Mitzählen des Datums
notwendig, so muss nun ein Register für den Tag (z.B. DATUMTAG) um 1 erhöht
werden und dieses Überprüft werden, wobei diese Prüfung nun nicht mehr so einfach
ist, da ja jeder Monat unterschiedlich viele Tage besitzt. Erschwerend kommt auch noch
hinzu, dass auch die Schaltjahre miteinbezogen werden müssen!
Achtung:
Dieses Unterprogramm muss daher jede Sekunde aufgerufen werden.
Dieses Unterprogramm wird vom Hauptprogramm alle 4ms aufgerufen.
Aufgabe:
Wenn die mitlaufende Uhr mit der DCF-Uhr synchronisiert ist (Flag DCFSYNC im
Register DCFSTATUS gesetzt) die Uhrzeit wie folgt ausgeben. Andenfalls dieses
Unterprogramm vorzeitig beenden: Die Stunde am Port A und abwechselnd Minute und
Sekunde am Port B ausgeben. Abwechselnd bedeutet hier, dass beim Aufruf dieses
Unterprogramms entweder die Minuten am Port B ausgegeben werden oder die
Sekunden. Diese Methode entspricht einer einfachen Multiplex-Ansteuerung. Die
Unterscheidung, ob die Minuten oder die Sekunden ausgegeben werden hängt vom Bit
0 des Registers FLAGS ab. Dieses Bit wird bei jedem Aufruf invertiert (getoggelt).
Besitzt es danach den Wert 1, so werden die Minuten angezeigt. Beim nächsten Aufruf
dieses Unterprogramms (in ca. 4ms) werden dann die Sekunden angezeigt, da dieses
Bit ja wieder invertiert wurde und daher den Wert 0 besitzt.
Mit Hilfe der beiden Tabellen TABSTUNDEN und TABMINUTENSEKUNDEN erfolgt
eine Anpassung an die Hardware (Umwandlung von 24 Stunden auf 12 Stunden, LED-
Matrix am Port B).
Aufgabe:
Die im w-Register stehende 2-stellige-BCD-Zahl nach Binär umwandeln. Das Ergebnis
befindet sich wieder im w-Register.
Vorgehensweise:
zB: BCD-Zahl: 0 0 1 0 0 1 1 0 (= 26)
| | | | | | | |
| | | | | | | - 0 ( = 0 x 1)
| | | | | | --- + 2 ( = 1 x 2)
| | | | | ----- + 4 ( = 1 x 4)
| | | | ------ + 0 ( = 0 x 8)
| | | ---------- + 0 ( = 0 x 10)
| | ------------ + 20 ( = 1 x 20)
| --------------- + 0 ( = 0 x 40)
----------------- + 0 ( = 0 x 80)
----------------------------
= 26
Anmerkung:
Das temporäre Register TEMP1 wird hier nur zum Zwischenspeichern benötigt, und
kann daher auch in anderen Unterprogrammen verwendet werden.
|