;************************ Hauptprogramm************
main
movf porta,0 ;lade w mit porta
movwf portb ;kopiere w nach portb
goto main
Eine Alternative zum polling bildet die sog. Interrupt-Technik, bei der eine
unabhängige Quelle eine Unterbrechung des Hauptprogramms auslöst und in eine
sog. Interrupt-Routine springt, die dann die eigentliche Ereignis-Behandlungsroutine
(interrupt handler) darstellt. So könnte z.B. eine Änderung eines Schalters einen
sog. Hardware-Interrupt auslösen. Eine weiter Möglichkeit besteht darin, durch einen
Timer-Interrupt porta regelmäßig (aber unabhängig vom Hauptprogramm) abfragen
zu lassen.
Der 16C84 besitzt Möglichkeiten, einen Hauptprozess durch sogenannte Interrupts
unterbrechen zu lassen. Es gibt verschiedene Interruptquellen, eine davon ist der
sogenannte Timerüberlauf. Der Timer ( rtcc = equ 2 : rttc : Real Time
Clock/Counter) ist ein 8 Bit breites Register, daß im Hintergrund zählt. Läuft der
Timer beim Hochzählen über (0FF 00 Timer overflow), so kann er einen Interrupt
auslösen, falls das Intcon-Register ( intcon equ 0B )entsprechend initialisiert
war. Der Wert des Programmzählers wird gerettet, so dass der unterbrochene
Prozess nach Abarbeiten der Interruptroutine fortgesetzt werden kann.
Allerdings muss dem Prozessor mitgeteilt werden, an welche Stelle des Programms
er verzweigen soll, falls ein Interrupt erfolgt. Komplexere Prozessoren haben ganze
Tabelle von Interruptvektoren (Sprungadressen), die die Zieladressen solcher
Sprünge enthalten. Beim 16C84 besteht diese Tabelle nur aus einer Adresse (004):
Hier muss ein Sprungbefehl zur Interrupt-Routine stehen, z.B. goto
interrupt.
Normalerweise kümmert man sich beim Brennen eines Programms ins Programm-EEPROM nicht darum, wo der Programmcode hingeschrieben wird. Bei der
Interrupt-Programmierung muß man dafür sorgen, dass der Sprungbefehl tatsächlich
bei Adresse 004 steht. Da macht man am besten mit der Assembleranweisung: org
004 unmittelbar vor dem Sprungebefehl.
; *********übliche Variablen-Deklaration
goto init
; Startadresse des Hauptprogramms
org 4
; Erzwingt den nächsten Befehl in Adresse 04
goto interrupt ; adr 004 : Sprung zurInterrupt-Routine
;************* übliche Initialisierungen
clrf intcon ; Interrupt-Register initialisieren
bsf intcon,7 ; Interrupts zulassen
bsf intcon,5 ; TimerInterrupt zulassen
;************************ Hauptprogramm************
main
goto main
;****** Interruptroutine: wird bei Timerüberlauf angesprungen
interrupt
movf porta,1
movwf portb
bcf intcon,2 ; timer neu auf 0ff setzen
retfie
; Return mit Interrupt enable
Das intcon-Register (0b) ermöglicht das Konfigurieren verschiedener Interruptquellen. Die Registertabelle zeigt, welcheBits für welche Funktionen zuständig sind. Ein weiteres wichtiges Register in diesem Zusammenhang ist das option-Register. Der Häufigkeit des Timerinterrupt kann mit den ersten drei Bits beeinflusst werden. Je nach Wert, den man dem Optionregister in diesen drei Bits gibt ( n = 0 .. 7) beträgt die Zugriffhäufigkeit 2n+1. Den Vorteiler 1 erhält man, wenn man das Watchdog-Timer-Bit setzt und 0 in die untersten drei Bits des intcon-Registers schreibt. Wählt man den Vorteiler für den Timerinterrupt zu klein, so kann es passieren, dass im obigen Beispiel während einer Tasterbetätigung der Schalter mehrere Male abgefragt wird. Umgekehrt kann man die Häufigkeit der Ausführung der Interruptroutine noch erniedrigen, indem man einen Zähler in dieser Prozedur herunter zählt und nur dann die eigentliche Interruptbehandlung ausführt, wenn der Zähler den Wert 0 erreicht hat. Vor Verlassen der Interruptroutine wird das Timerflag, das den Überlauf angezeigt hat wieder gelöscht: bcf intcon,2. Während einer Interruptroutine kann kein weiterer Interrupt ausgelöst werden, sie wird mit retfie (interrupt enable) verlassen.
Timer in Echtzeit
Es gibt verschiedene Möglichkeiten, die Häufigkeit des Aufrufs einer Interruptbehandlung zu beeinflussen:
a) Den sog. Vorteiler stellt man, indem man die Werte n = 0,..,7 in die untersten drei Bits des
option-Registers schreibt. Der Timer wird dann um den Faktor 2n+1 heruntergetaktet. Setzt
man zusätzlich auch noch das WDT-Bit, so kann man mit n = 0 im Vorteiler erreichen, daß
der Timer nicht heruntergetaktet wird, sondern mit der Frequenz 1MHz (bei einem Quarz
mit
4 Mhz Takt) zählt. Man kann also die Dauer für einen Zählerschritt von 11µs bis 2561µs
variieren, d.h. die Zeit von einem Timerüberlauf zum nächsten beträgt 256 µs bis 65535µs.
b) Eine weitere Möglichkeit, die Häufigkeit der Interruptbehandlung zu beeinflussen, ist ein
softwaremäßiger Vorteiler. Zu Beginn der Interruptroutine wird eine Zähler heruntergezählt
und die eigentliche Interruptbehandlung nur dann vorgenommen, wenn dieser Zähler auf 0
steht.
c) Man kann nach jedem Interruptaufruf den Startwert des Timers auf einen definierten Wert
setzen, indem man eine bestimmte Zahl ins RTCC schreibt.
Zusammenfassend wird die Zeit zwischen zwei aufeinanderfolgenden Ausführungen der
Interruptbehandlung wie folgt berechnet:
T = Software-Vorteiler Hardwarevorteiler RTCC-Startwert.
Beispiel: Eine Zähler soll im Zehntel-Sekunden-Takt zählen:
T = 100.000 µs = 32 *3125 µs = 25* 24+1 125 µs.
Man würde also dem Software-Vorteiler den Wert 25 = 19h geben, den Wert 4 ins
option-Register schreiben uns beim Verlassen der Interruptroutine den Timer mit
dem Wert 256-125 = 131 = 83h starten lassen, so dass er nach 125 Schritten
überläuft und einen Interrupt auslöst.