Mikrocomputertechnik


Prof. Jürgen Plate

5. Peripherie des Systems M68HC11

5.1 Peripherie-Register

Standardlage (default): $1000 - $103F, Verschiebung an jede 4KByte-Grenze möglich (INIT-Register)

Adresse Register Funktion Adresse Register Funktion
$1000 PORTA port A data $1020 TCTL1  
$1001 spare   $1021 TCTL2  
$1002 PIOC parallel I/O control $1022 TMSK1  
$1003 PORTC port C data $1023 TFLG1  
$1004 PORTB port B data $1024 TMSK2 timer mask 2
$1005 PORTCL port C latch $1025 TFLG2 timer flag 2
$1006 spare   $1026 PACTL pulse accu control
$1007 DDRC port C direction $1027 PACNT pulse accu count
$1008 PORTD port D data $1028 SPCR SPI control
$1009 DDRD port D direction $1029 SPSR SPI status
$100A PORTE port E data $102A spare  
$100B CFORC   $102B BAUD SCI baud rate
$100C OC1M   $102C SCCR1 SCI control 1
$100D OC1D   $102D SCCR2 SCI control 2
$100E TCNT timer count high $102E SCSR SCI status
$100F   timer count low $102F SCDR SCI data
$1010 TIC1H   $1030 ADCTL A/D control
$1011 TIC1L   $1031 spare  
$1012 TIC2H   $1032 spare  
$1013 TIC2L   $1033 spare  
$1014 TIC3H   $1034 spare  
$1015 TIC3L   $1035 spare  
$1016 TOC1H   $1036 spare  
$1017 TOC1L   $1037 spare  
$1018 TOC2H   $1038 spare  
$1019 TOC2L   $1039 OPTION  
$101A TOC3H   $103A spare  
$101B TOC3L   $103B PPROG  
$101C TOC4H   $103C HPRIO  
$101D TOC4L   $103D INIT  
$101E TOC5H   $103E TEST1  
$101F TOC5L   $103F CONFIG  

Im Rahmen dieser Vorlesung wird nur ein ausgewählter Teil dieser Register und ihrer Funktionen besprochen. Im folgenden werden einzelne Ports und die zugehörigen Register zur Sprache kommen.

5.2 Parallele Schnittstellen

Beim Informationsaustausch des Controllers mit der "Außenwelt" müssen spezielle Eigenschaften der Peripheriegeräte berücksichtigt werden. Insbesondere sind die Peripherieeinheiten gegenüber der Prozessorgeschwindigkeit recht langsam → Die Schnittstellen müssen die ein- oder ausgehenden Daten zwischenspeichern. Zum anderen laufen CPU und Peripherie oft zeitlich asynchron. Eine weitere Aufgabe von Schnittstellen ist auch die Parallel-seriell-Wandlung (siehe Abschnitt 5.3). Allgemein gilt für alle Schnittstellen:

Der 68HC11 besitzt fünf parallele Schnittstellen, die Ports A bis E, welche mit unterschiedlichen Hardware-Eigenschaften ausgestattet sind. Im "expanded Mode" stehen die Ports B und C nicht zur Verfügung, weil sie für Adreß- und Datenleitungen verwendet werden. Durch einen Port-Expander-Baustein lassen sie sich aber wieder ergänzen.

Eine kurze Übersicht der Ports:

Die Ports B und C werden zusammen mit den Handshakeleitungen STRA und STRB als Einheit betrachtet. Den fünf Ports sind insgesamt 16 Register zugeordnet (Einstellung und E/A). Die jeweiligen Register werden bei der Besprechung der einzelnen Ports behandelt.

Port A

Ein- und Ausgabeport mit fester und für ein Bit variabler Datenrichtung.

Der Port kann auf zwei verschiedene Betriebsarten gesetzt werden:

PAIF    set by active edge on PAI, reset by writing a corresponding one to TFLG2
PAOVF   set by roll over of PACNT, reset by writing a corresponding one to TFLG2
PAII    set and reset by software, generate interrupt, if PAIF is set
PAOVI   set and reset by software, generate interrupt, if PAOVF is set

Beim Event Counting Mode (PAMOD=0) werden am PAI–Eingang (=PA7) eintreffende Impulse im pulse accu gezählt.

Beim Gated Time Mode (PAMOD=1) wird die Zeit "gemessen", wie lange der PAI-Eingang im aktiven Zustand ist. Die Messdauer ergibt sich aus der Anzahl der gezählten Impulse, die aus dem durch 64 geteilten Systemtakt abgeleitet sind, d.h. die zeitliche Auflösung beträgt 32 ms.

Der Port A bietet mit seinem Pin PAI (= PA7) außerdem die Möglichkeit, Programmunterbrechungen (Interrupts) auszulösen.

Port B und STRB

Ausgabeport mit fester Datenrichtung

Der Port kann auf zwei verschiedene Betriebsarten gesetzt werden:

Die Programmierung von Port B ist denkbar einfach. Jedes Schreiben auf die Adresse $1004 hat die Ausgabe des entsprechenden Bitmusters auf den Leitungen von Port B zur Folge.

Port C und STRA

Ein/Ausgabeport mit bitweise wählbarer Datenrichtung. Das Datenrichtungs-"Register" DDRC (Adresse $1007) legt fest, ob die Bits von Port C Eingangs- oder Ausgangsbits sind (0 = Eingang, 1 = Ausgang). Daher ist eine Initia-lisierung des Ports durch belegen von DDRC notwendig. Die folgende Abbildung zeigt das Impulsdiagramm einer typischen Anwendung des STRA-Signals. In der Abbildung sind auch die Bedingungen beschrieben, die für die einzelnen Steuer- und Statusbits in PIOC gelten.

Der Port kann auf zwei verschiedene Betriebsarten gesetzt werden:

Die Leitung STRA wird über die Bits STAI und EGA in PIOC gesteuert. STAI gibt den Interrupt für die Leitung STRA frei (wird weiter unten behandelt). EGA legt fest, ob STRA auf eine steigende oder fallende Flanke reagiert. Wird beispielsweise eine Taste an STRA angeschlossen, wird durch deren Betätigung das Bit STAF in PIOC gesetzt und falls STAI = 1 ist, ein Interrupt ausgelöst. Das Bit STAF wird durch das Lesen der Adressen PIOC und PORTCL (in dieser Reihenfolge) zurückgesetzt.

Impulsdiagramm einer typischen Anwendung des STRA-Signals

Port D

Ein/Ausgabeport mit bitweise wählbarer Datenrichtung.

Der Port kann auf zwei verschiedene Betriebsarten gesetzt werden:

Port E

Eingabeport mit fester Datenrichtung

Der Port kann auf zwei verschiedene Betriebsarten gesetzt werden:

Programmbeispiele

Beispiel 1

Lesen 4 Bit linksbündig von Port C
Ausgeben 4 Bit rechtsbündig auf Port C
Ausgeben 4 Bit rechtsbündig auf Port B mit STRB (high pulse)

Vereinbarungen:

pcdr     equ  $1003
pcdd     equ  $1007
pbdr     equ  $1004
pioc     equ  $1002

Initialisierung

init     ldaa  #$0F
         staa  pcdd     pc(3:0) = output
         ldaa  #$01
         staa  pioc     STRB high active
         rts

Datenverkehr

main     ldaa  pcdr
         lsra
         lsra
         lsra
         lsra
         staa  pcdr
         staa  pbdr
         bra   main

Beispiel 2

Warten auf steigende Flanke am Eingang STRA

Vereinbarungen:

pioc     equ  $1002
pcdl     equ  $1005

Initialisierung

init     ldaa #$02
         staa pioc      STRA rising edge expected
         rts

Daten-Abfrage

         .
         .
         .                          Alternative
wait     ldaa  pioc
         anda  #$02                 bita  #$02
         beq   wait                 beq   wait
         ldaa  pcdl  clear STAF-flag
         .
         .
         .

Beispiel 3

Realisieren eines 8-Bit-Zählers auf Port B
(Port B ist zwar ein reiner Ausgabeport, aber mit dem Befehl "inc pcdr" wird Port B erst gelesen und somit der vorherige Ausgabewert geliefert, dann der Wert erhöht und zurückgeschrieben).

Vereinbarungen:

pbdr     equ   $1004

Programm:

init     clr   pbdr          Port B = 0
main     inc   pbdr          Increment Port B
         ldx   #$4000        Warteschleife
delay    dex                 X = X - 1
         bne   delay	     solange X > 0 durchlaufe Schleife
         bra   main

Beispiel 4

Vereinbarungen:

portc    equ   $1003
pcdd     equ   $1007

Programm:

init     ldaa  #%11111111
         staa  pcdd           Port C auf Ausgabe setzen (0=in, 1=out)
         clra 
         staa  portc          Port C = 0
main     inca
         staa  portc          hochzählen
         ldx   #$4000         Warteschleife
delay    dex
         bne   delay
         bra   main

Beispiel 5

Lichtmuster ausgeben auf LEDs, die an Port C angeschlossen sind.

Vereinbarungen:

portc    equ   $1003
pcdd     equ   $1007

Programm:

init     ldaa  #$FF
         staa  pcdd           Port C auf Ausgabe setzen (0=in, 1=out)
top      ldx   #TABLE         X verweist nun auf die Daten in TABLE
loop     ldaa  0,X            Tabellenelement lesen
         beq   top            ist das Element 0 --> Tabellenende
*                             wieder zum Tabellenanfang
         staa  portc          Tabellenelement ausgeben
         bsr   delay          Warteschleife aufrufen
         inx                  naechstes Tabellenelement
         bra   loop           usw.
*
delay    ldy   #$4000         Warteschleife, diesmal als Unterprogramm
dela1    dey
         bne   dela1
         rts
*
TABLE    dc.b  $01, $02, $04, $08, $10, $20, $40, $80
         dc.b  $40, $20, $10, $08, $04, $02, $00

Beispiel 6

Lesen Port E, ausgeben auf Port B

Vereinbarungen:

pbdr     equ   $1004
pedr     equ   $100A

Programm:

main    ldaa   pedr
        staa   pbdr
        bra    main

5.3 Serielle Schnittstellen

Die SCI-Schnittstelle (serial communication interface asynchronous) ist ein Port mit langsamer, asynchroner serieller Datenübertragung (bis etwa 100 kbit/s). Mit einem Pegelwandler kann sie als RS232-Schnittstelle verwendet werden. Sie entspricht in ihrer Funktion der seriellen Schnittstelle des PC.

Die SPI-Schnittstelle ist eine synchrone serielle Peripherieschnittstelle (serial peripheral interface). Sie dient zum Datenaustausch mit einem anderen Mikrocontroller oder mit Peripheriebausteinen.

Beide Schnittstellen verwenden einige Pins von Port D, die dann nicht mehr als Parallelport-Pins zur Verfügung stehen. Für eine allgemeine Einführung in die Assemblerprogrammierung ist es nicht notwendig, alle Schnittstellen des 68HC11 zu besprechen. Daher wird nur die asynchrone serielle SCI-Schnittstelle behandelt.

SCI (serial communication interface asynchronous)

Port mit langsamer, asynchroner serieller Datenübertragung (bis etwa 100 kHz)

Um die Schnittstelle mit der Außenwelt zu verbinden, werden die beiden niederwertigen Bits des Ports D verwendet. Für die Freigabe der Signale nach außen müssen im Register SCCR2 die Bits RE (Empfang) und TE (Senden) auf 1 gesetzt werden.

Puffer und Statusbits

Statusbits:

Empfangs-Funktion:
Die Steuerungslogik erkennt ein seriell ankommendes Zeichen und schiebt es im eingestellten Takt ins Empfangs-Schieberegister (Receive Data Register, RDR). Sobald das Zeichen vollständig im Schieberegister steht, wird es parallel ins Empfangsregister kopiert; gleichzeitig wird im Statusregister (SCSR) das Bit 5 (Receive Data Register Full, RDRF) auf 1 gesetzt. Falls im Steuerregister (SCCR2) der Empfangsinterrupt zugelassen wurde (Receive Interrupt Enable, RIE), wird auch noch ein SCI-Interrupt erzeugt.

Das sofortige Kopieren eines Zeichens vom Schieberegister ins Empfangsregister (SCDR) ist notwendig, damit ein eventuell unmittelbar nachfolgendes serielles Zeichen nicht das vorherige überschreibt. Allerdings muß das Empfangsregister bis spätestens unmittelbar vor dem nächsten Kopieren vom Prozessor gelesen werden, denn sonst geht dieses Zeichen durch Überschreiben verloren. Die Steuerung erkennt ein solches Überschreiben und setzt dann das Bit 3 im Statusregister (SCSR): Overrun Error (OR). Der Zeitabstand, in dem Zeichen eintreffen können, hängt von der Baudrate ab, z. B. beträgt der Zeichenabstand bei 9600 Baud ca. 1 ms.

Sende-Funktion:
Wird ein Zeichen ins Senderegister geschrieben, so prüft die Steuerlogik, ob das Sende-Schieberegister frei ist, um es dann dorthin zu kopieren und den Schiebevorgang zu starten. Damit ist das Senderegister wieder frei und es kann erneut per Store-Befehl beschrieben werden (nächstes Zeichen). Die Tatsache, daß dieses Schreiben erlaubt ist, signalisiert das Bit 8 (Transmit Data Register Empty, TDRE) des Statusregisters (SCSR) mit einer 1. Auch hier kann ein SCI-Interrupt ausgelöst werden, wenn im Steuerregister der Sende-Interrupt per TIE-Bit = 1 (Transmit Interrupt Enable) freigegeben ist. In manchen Fällen kann auch noch das tatsächliche Ende des Schiebevorgängs von Interesse sein (Transmission complete). Für diesen Zweck gibt es auch noch die Möglichkeit, diese Tatsache sowohl am entsprechenden Statusbit (TC) zu erkennen bzw. durch einen Interrupt melden zu lassen.

Serielles Rahmenformat:

Idle: Im Ruhezustand ist die Leitung auf auf 1-Pegel.
Beim Datenformat von 9 Bit (M = 1) ist das neunte Bit im Register SCCR1 zu finden. Beim Wert M = 0 werden 8 Bit empfangen/gesendet (Normalfall).

Setzen der Datenrate

Die Erzeugung der Datenrate erfolgt mehrstufig und ist daher etwas komplex. Es spielen dabei vier Teiler für die Taktfrequenz (in der Regel 8 MHz) zusammen (Register BAUD):

Der Takt gelangt erst in einen Prescaler mit vier möglichen Divisionsfaktoren (1, 3, 4, 13), dessen Output dann nochmals durch acht Divisoren geteilt werden kann. Bei einer Taktrate von 8 MHz lassen sich folgende Raten wählen (Einstellungen für das Praktikumssystem farbig hinterlegt):

Neben den beiden schon erwähnten Bits TE und RE sind im Register SCCR2 die Steuerbits für die Interruptfreigabe enthalten.

interrupt masks (set and reset by software)

Das SCI-Statusregister SCSR liefert Informationen über den Ablauf der Kommunikation. Die Fehlerflags werden zurückgesetzt durch das Lesen von SCSR und SCDR.

error flags (set by hardware, reset by reading SCSR and SCDR)

SPI (serial peripherial interface synchronous)

Port mit schneller, synchroner serieller Datenübertragung (bis etwa 2 MHz).
Wird im Rahmen dieser Vorlesung nicht besprochen.

Programmbeispiele

Beispiel 1:

Serielles Senden und Empfangen von Zeichen mit 9600 Bd

Vereinbarungen:

scdr      equ  $102F
scsr      equ  $102E
baud      equ  $102B
sccr1     equ  $102C
sccr2     equ  $102D

Einstellungen:

init     ldaa  #$30
         staa  baud      baudrate = 9600 bit/s
         ldaa  #0
         staa  sccr1
         ldaa  #$0C
         staa  sccr2     enable transmit & receive
         rts

Datenverkehr:

* Zeichen in Speichezelle "char" ausgeben
chou     ldaa  char
         ldab  scsr      Sendereg. leer?
         andb  #$80
         beq   chou
         staa  scdr      transmit
         rts

* Zeichen nach Speicherzelle "char" einlesen
chin     ldab  scsr      Empfangsreg. leer?
         andb  #$20
         beq   chin
         ldaa  scdr      receive
         staa  char
         rts

Sendeschleife:

main     bsr   init
loop     bsr   chin      "Schreibmaschine"
         bsr   chout    
         bra   loop

Beispiel 2:

Serielles Senden von Zeichenketten mit 9600 Bd

Vereinbarungen:

scdr      equ  $102F
scsr      equ  $102E
baud      equ  $102B
sccr1     equ  $102C
sccr2     equ  $102D

Einstellungen:

init     ldaa  #$30
         staa  baud      baudrate = 9600 bit/s
         ldaa  #0
         staa  sccr1
         ldaa  #$0C
         staa  sccr2     enable transmit & receive
         rts

Zeichen in Akku A ausgeben:

chou     ldab  scsr      Sendereg. leer?
         bpl   chou
         staa  scdr      transmit
         rts

Zeichenkette senden: Die Adresse der Zeichenkette wird in X übergeben, Ende der Zeichenkette wird durch ETX markiert → definiert durch: ETX EQU 3.

saus     ldaa  0,x       Zeichen holen
         cmpa  #ETX      ETX (3) ? 
         beq   saus_e    dann fertig 
         inx             X inkrementieren 
         bsr   chou      Zeichen senden 
         bra   saus      und nächstes Zeichen 
saus_e   rts 

Sendeschleife:

main     bsr   init
loop     ldx   #TEXT
         bsr   saus
         bra   loop
*
TEXT   dc.b 'Hello World'   Meldungstext 
       dc.b $0D,$0A,ETX     Zeilenvorschub, ETX 

Beispiel 3:

Serielles Senden und Empfangen von Zeichenketten mit 9600 Bd

Vereinbarungen: - siehe oben -

Einstellungen: - siehe oben -

Zeichen in Akku A ausgeben: - siehe oben -

Zeichenkette senden: - siehe oben -

Zeichen nach Akku A einlesen

chin     ldab  scsr      Empfangsreg. leer?
         andb  #$20
         beq   chin
         ldaa  scdr      receive
         rts
Zeichenkette einlesen: Die Adresse eines Eingabepuffers wird in X übergeben. Das Eingabeende wird durch die Taste Carriage-Return (CR, $0D) signalisiert.
sein     bsr   chin      Zeichen einlesen 
         cmpa  #$0D      Carriage Return? 
         beq   sein_e    ja, Ende 
         staa  0,x       Zeichen im Puffer speichern
         inx             X inkrementieren 
         bra   sein      und nächstes 
sein_e   ldaa  #ETX      ETX anhängen (CR wird nicht mit gesp.) 
         staa  0,x
         rts 

Sendeschleife:

main     bsr   init
loop     ldx   #PUF
         bsr   sein
         ldx   #PUF
         bsr   saus
         bra   loop

Irgendwo im Programm wird ein Puffer definiert, z. B.:

         org   data
PUF      ds.b  80        80 Bytes Puffer reservieren 

Anmerkung: "sein" überprüft nicht, ob der maximale Pufferbereich überschritten wird und so eventuell andere Variablen überschrieben werden. Versuchen Sie, eine Begrenzung der Eingabe auf z. B. 80 Zeichen zu programmieren.

Beispiel 4: Kommandoauswertung. Es wird ein Befehlsbuchstabe von der seriellen Schnittstelle eingelesen und verarbeitet. Es sind die Buchstaben 'a', 'b' und 'c' erlaubt - bei anderen Eingaben erfolgt eine Fehlermeldung. Als Pseudo-Aktion dient das Unterprogramm "doit", es gibt lediglich den eingegebenen Buchstaben als Grossbuchstaben aus.

prog    equ    $8000
data    equ    $2000
stack   equ    $7FFF

scdr    equ    $102f
scsr    equ    $102e
sccr1   equ    $102c
sccr2   equ    $102d
baud    equ    $102b

reset    equ   $fffe

cr       equ   13
lf       equ   10

         org   data
buf      ds.b  100       ; Eingabepuffer

         org   prog
main     lds   #stack    ; Stackpinter setzen
         bsr   sini      ; Schnittstelle init.
loop     ldx   #hello    ; Prompt ausgeben
         bsr   saus
         bsr   chin      ; Taste einlesen
         cmpa  #'a'      ; ist es 'a'?
         bne   next1     ; nein, weiter
         bsr   doit      ; Dummy-Aktion
         bra   loop      ; und weiter
next1    cmpa  #'b'      ; ist es 'b'?
         bne   next2     ; wie oben
         bsr   doit
         bra   loop
next2    cmpa  #'c'      ; ist es 'c'?
         bne   next3     ; wie oben
         bsr   doit
         bra   loop
next3    ldx   #oops     ; keine erlaubte Taste
         bsr   saus      ; Fehlermeldung ausgeben
         bra   loop

doit                     ; Dummy-Aktion
         psha            ; Akku A retten
         ldx   #k1       ; Text ausgeben
         bsr   saus
         pula            ; Akku wieder holen (eingeg. Zeichen)
         suba  #$20      ; in Grossbuchstaben umwandeln
         bsr   chou      ; und ausgeben
         bsr   crlf      ; neue Zeile
         rts

    
crlf     ldaa  #cr       ; Carriage Return, Line Feed ausgeben
         bsr   chou
         ldaa  #lf
         bsr   chou
         rts
    
saus     ldaa  0,x       ; Stingausgabe, siehe oben
         beq   sfin
         bsr   chou
         inx
         bra   saus
sfin     rts

sini     clr   sccr1     ; Schnittstelle initialisieren, siehe oben
         ldaa  #$0C
         staa  sccr2
         ldaa  #$30
         staa  baud
         rts
    
chou     ldab  scsr      ; Zeichen ausgeben, siehe oben
         bpl   chou
         staa  scdr
         rts
    
chin     ldab  scsr      ; Zeichen einlesen, siehe oben
         andb  #$20
         beq   chin
         ldaa  scdr
         rts    

; Zeichenkettenkonstante
hello    dc.b  'Cmd: '   ; Kommandoprompt
         dc.b  0

oops     dc.b  'Oops!'   ; Fehlermeldung 
         dc.b  cr,lf,0

k1       dc.b  'Eingabe war '  ; fuer Dummy-Aktion
         dc.b  0
    
         org   reset     ; Reset-Vektor
         fdb   main
         end  

5.4 Zähler

Das Timer-System steuert Funktionen, die einen Bezug zur Echtzeit benötigen, also unabhängig von Befehlsausführungszeiten sein sollen:

Der 68HC11 hat eine recht komplexe Timer-Struktur, die mit Abstand die meisten Register im E/A-Bereich belegt. Entsprechend komplex ist seine Programmierung.

Basis des Timersystems ist ein konstant durchlaufender, nicht beeinflussbarer 16-Bit-Zähler, der im Register TCNT abgebildet ist. Das Timersystem leitet seinen Takt über Teiler vom Quarztakt ab (Abbildung 31). Die folgenden Zeitangaben beziehen sich auf eine Quarzfrequenz von 8 MHz, was einem CPU-Takt von 2 MHz entspricht. Der Vorteiler für den freilaufenden 16-Bit-Zähler wird durch die Bits PR0/PR1 im Register TMSK2 programmiert. Die folgende Tabelle zeigt, mit welchen Taktperioden der Zähler dann getriggert wird.

Die beiden Vorteiler werden durch die Bits PR0/PR1 im Register TMSK2 und RTR0/RTR1 im Register PACTL programmiert. Nach einem RESET steht hier jeweils ein Wert von 0, so daß die höchste Taktrate ausgewählt ist. Diese beiden Bits können nur direkt nach einem RESET verändert werden, danach ist jeder weitere Zugriff gesperrt. Diese besondere Eigenschaft des Mikroprozessors 68HC11 verhindert ungewollte Veränderungen an der Timer-Auflösung durch unzulässige Zugriffe, die während des Betriebs durch Störimpulse von außen ausgelöst werden könnten.

PRn
1   0
division
factor
output
period
0   0 1 32.77 ms
0   1 4 131.07 ms
1   0 8 262.14 ms
1   1 16 524.29 ms
RTRn
1   0
division
factor
output
period
0   0 1 4.096 ms
0   1 2 8.192 ms
1   0 4 16.384 ms
1   1 8 32.768 ms

TOFtimer overflow flag Wird gesetzt, wenn der frei laufende 16-Bit-Zähler von FFFF auf 0 wechselt (Zählerüberlauf). Wird zurückgesetzt durch Schreiben einer 1 in TOF.
TOItimer overflow interrupt enable Interruptfreigabe für "Timer Overflow Interrupt", 0 = Interrupt gesperrt, 1 = Interrupt freigegeben.
RTIFreal time interrupt flag Wird gesetzt, wenn der Realtime-Interrupt-Zähler auf 0 wechselt (Zählerüberlauf). Wird zurückgesetzt durch Schreiben einer 1 in RTIF.
RTIIreal time interrupt enable Interruptfreigabe für "Realtime Interrupt", 0 = Interrupt gesperrt, 1 = Interrupt freigegeben.

Der Timer

Der Timer des 68HC11 besitzt eine Länge von 16 Bit. Aus diesem Grund muß er mit einem 16-Bit-Ladebefehl gelesen werden, da nur dann die beiden Bytes des Ergebnisses wirklich zusammen gehören. Würden das obere und das untere Byte getrennt voneinander gelesen, bestände kein eindeutiger Zusammenhang.

Nach einem Reset der CPU ist der Zählerstand des Timers 0. Es gibt keine Möglichkeit, den Zählerstand des Timers auf einen bestimmten Wert zu setzen. Direkt nach dem Reset beginnt der Timer aufwärts zu zählen. Bei jedem Überlauf von $FFFF auf $0000 wird das Überlauf-Bit TOF (Timer Overflow) im Register TFLG2 gesetzt, um diesen Zustand anzuzeigen. Die Anwendersoftware kann so auf einfache Weise eine Kaskadierung des Timers auf beliebige Wortlänge durchführen, da dieses Bit auch einen Interrupt auslösen kann.

Für die meisten Anwendungsfälle ist es sinnvoll, die längste zu messende Zeit zu bestimmen und dann den Vorteiler so zu definieren, daß innerhalb dieser Zeit kein Timer-Überlauf auftreten kann. Alle Zeitpunktberechnungen können dann mit einfacher 16-Bit-Arithmetik durchgeführt werden. Man darf nicht übersehen, daß das Timer-System mit 16 Bit auflöst, der Fehler bezogen auf eine Periode ist 1/65536 entsprechend 0,0015 %. Diese Genauigkeit ist für fast alle Anwendungen ausreichend. Erhöht man die Taktrate des Timer-Systems und arbeitet mit höherer Auflösung, dann addieren sich Software-Reaktionszeiten, was häufig zu wesentlich größeren Fehlern führen.

Bei jedem Überlauf des Timers von $FFFF auf $0000 wird das Überlauf-Bit (TOF = Timer Overflow Flag) im TFLG2-Register gesetzt. Das TOF-Bit muß vom Anwenderprogramm gezielt wieder gelöscht werden. Wird das Auslösen eines Interrupts bei jedem Timer-Oberlauf gewünscht, dann kann das zum TOF-Bit korrespondierende TOI-Bit (Timer Overflow Interrupt) im TFLG2-Register auf 1 gesetzt werden.

Der frei laufende Timer

Der frei laufende Haupt-Timer des 68HC11 wird bei Reset auf 0 gesetzt und beginnt dann zu laufen. Derartige Timer findet man auch bei fast jedem anderen Controller. Der Zählerstand kann über ein 16-Bit-Register auf den Adressen $100E und $100F ausgelesen werden. Wichtig ist hierbei, dass mittels einer 16-Bit-Operation gelesen wird (LDD). Würde man zwei aufeinander folgende 8-Bit-Operationen zum Lesen nehmen (LDAA, LDAB), bekäme man einen "Versatz" von vier Taktzyklen, da die Ladeoperation so lange dauert.

Der Haupt-Timer läuft nach dem Einschalten mit dem E-Takt der CPU. Der Takt kann noch durch einen Prescaler geteilt werden, wobei die Faktoren 1, 4, 8 oder 16 möglich sind. Der Teilfaktor wird über die Bits 0 und 1 des TMASK-Registers eingestellt. Das folgende Programm illustriert den Sachverhalt, indem der Timer ständig ausgelesen und auf den Ports B und C ausgegeben wird.

data    equ   $2000   ; Datenbereich
prog    equ   $8000   ; Programmbereich
stack   equ   $7FFF   ; Stackbereich
tirqv   equ   $FFDE   ; Adresse TOF-Vektor
resetv  equ   $FFFE   ; Adresse Reset-Vektor

pcdd    equ   $1007   ; Adressen Port C
pcdr    equ   $1003
portb   equ   $1004   ; Adresse Port B
pacr    equ   $1026   ; Pulse Akku Control
tflag   equ   $1025   ; Timer Flag
tmask   equ   $1024   ; Timer Mask
tcnt    equ   $100e   ; Timer Counter

        org   data

        org   prog
main    lds   #stack  ; Init Stack
        ldab  #$FF    ; Port C auf Ausgang
        stab  pcdd
        ldab  #$03    ; Timer-Prescaler / 16
        stab  tmask   ; --> 524,3 ms 

loop    ldd   tcnt    ; Zaehler laden HIGH in A,
                      ; LOW in B
        staa  portb   ; ausgeben
        stab  pcdr
        bra   loop        

        org   resetv  ; Reset-Vektor setzen
        fdb   main

Real-Time-Interrupt

Häufig wird in einem Mikroprozessorprogramm eine feste Zeitbasis zur Steuerung bestimmter Abläufe benötigt. Dafür besitzt der 68HC11 einen speziellen Real-Time-Interrupt, der von den Bits RTII im Register TMSK2 und RTIF im Register TFLG2 gesteuert wird. Nach Ablauf einer vordefinierten Zeitspanne wird das Bit RTIF im TFLG2-Register gesetzt. Zur Auslösung eines Interrupts muß auch hier das korrespondierende RTII-Bit im TMSK2-Register auf 1 gesetzt sein. Das RTIF-Bit muß zwingend vom Interrupt-Programm durch Schreiben einer 1 an diese Stelle wieder gelöscht werden, da sonst sofort der nächste Interrupt ausgelöst würde. Die Periodendauer des Real-Time-Interrupts wird über zwei Bits im PACTL-Register vorgesehen (RTRO und RTR1) eingestellt.

Beispiel: Uhrentakt mittels RTI
(Quelle: Wallrabe: Mikrocontrollerpraxis, Hanser Verlag)
Dazu gehen wir von der kürzesten Grundperiode 4,096 ms aus, da sie die feinste Stufung erlaubt. Als Anfangsstand des Zählers wählen wir 244. Die so erzeugte Periode dauert somit 244 - 4,096 ms = 999,424 ms. An der genauen Sekunde fehlen 0,576 ms, ein Fehler, der toleriert werden kann. Nach diesen Vorgaben ist das folgende Beispiel aufgebaut, das, vom Anfangswert 244 ausgehend, nach jedem RTI-Interrupt die Variable RTIZaehl herunterzählt und bei Erreichen von 0 einen Sekunden-, Minuten- und Stundenzähler hochzählt.
Die Zeitwerte sollen natürlich dezimal und nicht binär (hexadezimal) ausgegeben werden. Daher wird nach jedem Inkrementieren eines Zählers dessen Wert mit dem Befehl DAA sofort in einen BCD-Wert umgewandelt und auch so abgespeichert.
Voraussetzung ist, daß im Hauptprogramm folgende RAM-Variablen vorab definiert und initialisiert worden sind:

RTIZaehl = Adresse des RTI-Zählers
SekZaehl = Adresse des Sekunden-Zählers
MinZaehl = Adresse des Minuten-Zählers
StdZaehl = Adresse des Stunden-Zählers
Sek_alt = Zwischenspeicher

UHR    DEC   RTIZaehl     RTI-Zähler dekrementieren.    
       BNE   UHR_E
       LDAA  #244         Wenn RTI-Zähler = 0:          
       STAA  RTIZaehl     Neu mit Ausgangswert laden. 
       LDAA  SekZaehl     Nach 1 Sekunde:               
       INCA               Sekundenzähler hochzählen,  
       DAA                in BCD-Zahl wandeln.        
       STAA  SekZaehl
       CMPA  #$60
       BNE   UHR_E
       CLRB               Nach 60 Sekunden:           
       STAB  SekZaehl     Sekundenzähler auf 0 setzen, 
       LDAA  MinZaehl     Minutenzähler hochzählen, 
       INCA
       DAA
       STAA  MinZaehl
       CMPA  #$60
       BNE   UHR_E        Nach 60 Minuten:         
       STAB  MinZaehl     Minutenzähler auf 0 setzen, 
       LDAA  StdZaehl     Stundenzähler hochzählen, 
       INCA
       DAA
       STAA  StdZaehl
       CMPA  #$24
       BNE   UHR_E        Nach 24 Stunden:       
       STAB  StdZaehl     Stundenzähler auf 0. 
UHR_E  LDAA  #$40         Rücksetzen des RTI-Flags.     
       STAA  TFLG2
       RTI
Diese Uhr tickt unsichtbar und lautlos im Inneren des 68HC11. Daher wird das Unterprogramm zu einem kompletten lauffähigen Beispielprogramm erweitert, bei dem die Zeit über die serielle Schnittstelle an den PC gesendet und Monitor sichtbar gemacht wird. Das Programm beginnt mit einem Initialisierungsteil, in dem die serielle Schnittstelle und der RTI-Interrupt vorbereitet sowie die Variablen auf ihre Ausgangswerte gesetzt werden.
VECRTI   equ  $FFEB       Real Time Interrupt
TMSK2    equ  $1024       Timer Interrupt Mask Reg.2
SCSR     equ  $102e       SCI Status Reg.
SCDR     equ  $102f       SCI Data Reg.

         BSR  INIT_SCI    Schnittstelle Init, siehe 5.3
         LDD  #UHR
         STD  VECRTI      ...RTI-Serviceroutine "UHR".       
         LDAA #$40        RTI-Interrupt freigeben.           
         STAA TMSK2       (4,096 ms ungeaendert wie Vorgabe). 
         LDAA #244        RTI-Zaehler                         
         STAA RTIZaehl    auf Ausgangswert setzen.           
         CLRB             Ebenso...                          
         STAB SekZaehl    ...Sekunden-Zaehler       
         STAB Sek_alt     ...Sekunden-Vergleichszaehler
         STAB MinZaehl    ...Minuten-Zaehler
         STAB StdZaehl    ...Stunden-Zaehler
         CLI              Interrupts aktivieren    


UhrStart LDAA SekZaehl    Warten, bis Sekunde einen neuen... 
         CMPA Sek_alt   
         BEQ  UhrStart    ...Wert hat.                        
         STAA Sek_alt     Neuen Wert in Vergleichszaehler
         LDAA StdZaehl    Stunden ausgeben          
         JSR  Hex_Tx
         LDAA #":"        Trennzeichen ":" ausgeben
         JSR  Byte_Tx
         LDAA MinZaehl    Minuten ausgeben                  
         JSR  Hex_Tx
         LDAA #":"
         JSR  Byte_Tx
         LDAA SekZaehl    Sekunden ausgeben           
         JSR  Hex_Tx
         LDAA #$0D        Carriage Return ausgeben
         JSR  Byte_Tx
         BRA  UhrStart

* Ausgabe eines Bytes hexadezimal ueber die serielle Schnittstelle
* Das zu sendende Byte muî im Akku A vorliegen.
Hex_Tx  PSHA             Zu sendendes Byte retten.          
        ANDA #$F0        Hw.-Nibble abtrennen               
        LSRA             und 4 Stellen nach rechts schieben,
        LSRA             dabei Nullen nachziehen.           
        LSRA
        LSRA
        CMPA #9          0 bis 9 oder A bis F ?             
        BHI  Buchst1
Ziff1   ADDA #"0"        0 bis 9.                           
        JSR  Byte_Tx     Zum Sender.                        
        BRA  Nibble2
Buchst1 ADDA #"A"        A bis F.                           
        JSR  Byte_Tx
Nibble2 PULA             Byte wieder holen.                 
        ANDA #$0F        Nw.-Nibble abtrennen.              
        CMPA #9
        BHI  Buchst2
Ziff2   ADDA #"0"
        JSR  Byte_Tx
        RTS
Buchst2 ADDA #"A"
        JSR  Byte_Tx
        RTS

* Ausgabe eines Bytes ueber die serielle Schnittstelle
* Das zu sendende Byte muî im Akku A vorliegen.
Byte_Tx LDAB SCSR     Statusregister TDRE abfragen, ob leer.
        ANDB #$80
        BEQ  Byte_Tx  Abfrage wiederholen, wenn nicht.      
        STAA SCDR     Byte ausgeben.                        
        RTS           

Input Capture und Output Compare

Der Zählerstand kann von drei Input-Capture-Registern zur exakten Bestimmung des Zeitpunktes einer extern erkannten Flanke und von fünf Output-Compare-Registern zur Erzeugung exakter Impulse und Kurvenformen ausgewertet werden.

Pulse-Akkumulator

Der Pulse-Akkumulator des 68HC1 ist ein 8-Bit-Zähler, der wahlweise als Ereigniszähler oder als Zeitzähler mit externer Gate-Funktion verwendet werden kann. Für beide Fälle wird der Anschluß Port A Bit 7 als Eingang für das externe Signal benutzt. Es sind zwei Möglichkeiten vorgesehen, einen Interrupt auszulösen: bei jeder aktiven Flanke dieses Eingangs oder bei Überlauf des Zählerstandes von $FF auf $00.
Wird der Pulse-Akkumulator als Zeitzähler eingesetzt, dann verarbeitet er das durch 64 geteilte Signal des internen E-Takts. Die Auflösung beträgt damit bei einer Quarzfrequenz von 8 MHz exakt 32 Mikrosekunden, die längste meßbare Periode somit 256 * 0,032 ms = 8,192 ms. Beim Einsatz als Ereigniszähler können maximal 256 Flanken gezählt werden, die zu verarbeitende Frequenz muß niedriger als der E-Takt des Mikroprozessors sein. Die für die Interruptauslösung des Pulse-Akkumulatorsystems zuständigen Konfigurations- und Flagbits sind zusammen mit anderen Funktionen im TMSK2- und TFLG2-Register untergebracht. Das PAOVF-Bit im TFLG2-Register wird immer dann gesetzt, wenn ein Überlauf des Zählers von $FF auf $00 eintritt. Durch Setzen des korrespondierenden Interrupt-Bits PAOVI im TMSK2-Register kann der Anwender bestimmen, ob durch dieses Ereignis ein Interrupt ausgelöst werden soll (0 = kein Interrupt). Der gleiche Mechanismus steuert mit den Bits PAIF und PAII einen möglichen Prozessor-Interrupt bei jeder aktiven Flanke am Eingang des Pulse-Akkumulators.

5.5 Geschützte Register

(time protected control registers)
Diese Register können nur während der ersten 64 Taktzyklen des E-Taktes nach einem RESET beschrieben werden.

INITbit 7-4:RAM3, RAM2, RAM1, RAM0
position direct page at 4k-boundaries
(default = 0000, RAM = $0000-$00FF)
bit 3-0:REG3, REG2, REG1, REG0
position Register block at 4k-boundaries
(default = 0001, REG = $1000-$103F)

TMSK2bit 1-0:PR1, PR0
prescaler of main timer
(default = 00, ps = 1)

OPTIONbit 5:IRQE
IRQ edge or level sensitive
(default = 0, level sensitive)
bit 4:DLY
delay after coming out of STOP power saving mode
(default = 1, wait 4000 cycles to stabilize crystal oscillator)
bit 1-0:CR1, CR0
COP timer rate on 215 base
(default = 00, tr = 1)

5.6 Interrupts

Beim Daten-Verkehr zwischen Computer und der Außenwelt gibt es fast immer große und vor allem unregelmäßige Zeitabstände zwischen den Transfers. Zur Synchronisation dieser Ereignisse mit den Abläufen in einem Computer dienen Steuersignale der Peripherie, die zumindest als Status-Bits in einem Status-Register eines Peripheriebausteins erkennbar sind: im einfachsten Fall muss das Programm diese Status-Information regelmäßig abfragen, und zwar so häufig, dass kein Ereignis - auch bei maximaler Rate - "übersehen" wird.

Dieser polling mode führt zu einer hohen Rechnerbelastung aufgrund von Abfragen, die auch fast immer negativ ausfallen. Alle modernen Mikroprozessoren besitzen deshalb Hardware- Mechanismen zur Programmunterbrechung durch solche Ereignisse. Das "Pollen" des Programms nach Ereignissen wird hier ersetzt durch einen von der Hardware (Ablaufsteuerung, Mikroprogramm) erzwungenen Unterprogrammsprung zu einem vorbereiteten Bearbeitungs-Programm, der sogenannten Interrupt-Service-Routine (ISR).

Die ähnlichkeit des Interrupt mit einem Unterprogrammsprung (JSR) ist tatsächlich groß. Das Auftreten des Interrupt-Request-Signals auf dem Bus wird vom Mikroprogramm am Ende jedes Befehlszyklus geprüft und führt ggf. zu einem Sprung zum Beginn der ISR. (Genaugenommen ist das regelmäßige Abfragen nach externen Ereignissen nur ins Mikroprogramm der Ablaufsteuerung verlagert worden, jedoch mit sehr hoher Effizienz).

Ein Interrupt kann - falls zugelassen - im Unterschied zu einem JSR prinzipiell nach jedem beliebigen Befehl des Programms wirksam werden, dementsprechend muss wie beim JSR der PC-Stand gerettet werden; auch das erledigt die Ablaufsteuerung bei der Annahme des Interrupt Request, genau wie beim JSR. Die Interrupt-Service-Routine wird mit einem ähnlichen Befehl wie ein Unterprogramm verlassen (RTI statt RTS), denn auch hier muss der Rücksprung wieder zur "Unterbrechungsstelle" zurückführen.

Man unterscheidet beim 68HC11 Interrupts, die (extern!) von Hardwaresignalen ausgelöst werden (XIRQ, IRQ und RESET) und den internen Interruptquellen (interne Peripheriebausteine oder "illegal Operation"). Außerdem gibt es einem Befehl (SWI), der ebenfalls einen Interrupt auslöst. Ein weiteres Unterscheidungskriterium ist die Maskierbarkeit. Der normale Interrupt ist nur dann wirksam, wenn das entsprechende Maskenbit im CC-Register gelöscht ist (=0). Die Signale RESET und XIRQ sind nicht maskierbar, sie werden deshalb auch als "nicht maskierbare Interrupts" bezeichnet.

Der XIRQ weist dabei noch eine Besonderheit auf: er ist nach einem RESET so lange gesperrt (maskiert), bis er durch Nullsetzen von Bit 6 im CC-Register zugelassen wird. Danach ist er nicht mehr sperrbar!

Der 68HC11 verfügt über insgesamt 21 externe und interne Interruptquellen. Entsprechend komplex ist seine Interruptstruktur. Hier nochmals zur Erinnerung der Ablauf eines Interrupts:

Nach einem Reset des Prozessors sind zunächst die beiden CC-Register-Flags X und I gesetzt und somit alle Interrupts gesperrt (= maskiert, disabled). Diese beiden Flags nennt man auch "Innensperren", denn mit ihnen kann im Prozessor verhindert werden, dass anstehende (pending) Interrupts tatsächlich den Programmablauf unterbrechen.

Es ist wichtig, dass zunächst die Interrupts nicht zugelassen werden, denn erst wenn per Programm einige Vorbereitungen getroffen sind (Peripheriebausteine initialisieren, Stackpointer setzen, …) kann ein eintreffender Interrupt korrekt bedient werden.

Die Interrupt-Sperren in den verschiedenen Peripherie-Bausteinen nennt man "Außensperren". Damit hat der Programmierer die Möglichkeit ganz gezielt Ereignisse sich entweder nur per Statusbit anzeigen zu lassen (polling mode) oder es sich per Interrupt melden zu lassen.

Auslösen einer Unterbrechung

SignalRESETUnbedinger Abbruch und Neustart
SignalXIRQ und (X-Bit = 0)Unbedingte Unterbrechung (non maskable interrupt)
SignalIRQ und (I-Bit = 0)Bedingte Unterbrechung (interrupt request)
(kann auch interne Ursachen haben)
BefehlSWIBefehlsgesteuerte Unterbrechung (software interrupt)
BefehlIllegal OpcodeNicht implementierter Befehl

Interrupt-Vektoren

Die Interrupt Service Routine (ISR) kann an beliebiger Stelle im Speicher abgelegt werden. Beim Eintreffen des Interrupts muss die ISR aufgerufen werden. Die ISR-Startadresse muss daher im Speicher bereitgestellt werden (Aufgabe des Programmierers!). Die Adressen des 16-Bit-Speicherworts, in dem die Adressen der ISR abgelegt werden, liegen hardwaremäßig fest. Für jeden der verschiedenen Interrupts gibt es ein fest zugeordnetes Speicherwort (Interrupt-Vektor):

PrioritätNameAdresseInterrupt-Quelle
21SCIINT$FFD6SCI serial system
20SPIINT$FFD8SPI serial system
19PAIINT$FFDAPulse Accumulator Input Edge
18PAOVINT$FFDCPulse Accumulator Overflow
17TOINT$FFDETimer Overflow
16TOC5INT$FFE0Timer Output Compare 5
15TOC4INT$FFE2Timer Output Compare 4
14TOC3INT$FFE4Timer Output Compare 3
13TOC2INT$FFE6Timer Output Compare 2
12TOC1INT$FFE8Timer Output Compare 1
11TIC3INT$FFEATimer Input Capture 3
10TIC2INT$FFECTimer Input Capture 2
9TIC1INT$FFEETimer Input Capture 1
8RTIINT$FFF0Real Time Interrupt
7IRQINT$FFF2IRQ External Interrupt
6XIRQINT$FFF4XIRQ External Interrupt
5SWIINT$FFF6Software Interrupt
4BADOPINT$FFF8Illegal Opcode Trap Interrupt
3NOCOPINT$FFFACOP Failure (Reset)
2CMEINT$FFFCCOP Clock Monitor Fail (Reset)
1RESETINT$FFFERESET Interrupt

Die nicht maskierbaren Interrupts wie RESET, CMF, COP, XIRQ, Ill. Opcode oder SWI haben eine feste Priorität. Bei den anderen Interrupts läßt sich die Priorität ändern. Die vier Bits PSEL0 bis PSEL3 im HPRIO-Register legen fest, welche Interruptquelle die höchste Priorität besitzen soll.

PSEL3PSEL2PSEL1PSEL0Interrupt-Quelle
0000Timer Overflow
0001Pulse Accumulator Overflow
0010Pulse Accumulator Input Edge
0011SPI serial system
0100SCI serial system
0101Reserve
0110IRQ External Interrupt
0111Real Time Interrupt
1000Timer Input Capture 1
1001Timer Input Capture 2
1010Timer Input Capture 3
1011Timer Output Compare 1
1100Timer Output Compare 2
1101Timer Output Compare 3
1110Timer Output Compare 4
1111Timer Output Compare 5

Eine besonders wichtige Rolle in jedem Mikroprozessorsystem spielen die nicht maskierbaren Interrupts. Sie sind speziell für das Auslösen lebenswichtiger Funktionen vorgesehen, wie zum Beispiel zur Erkennung eines Versorgungsspannungsausfalls. Da der Mikroprozessor 68HC11 über die Möglichkeit verfügt, seine interne Organisation zu modifizieren, ist für den externen nicht maskierbaren Interrupt XIRQ ein spezielles Bit im Condition-Code-Regisier vorgesehen, mit dem dieser direkt nach einem Reset-Vorgang maskiert wird. Dies ist kein Widerspruch, denn wenn das Anwenderprogramm die interne Organisation (Speicheraufteilung, Festlegung des Registerblocks, Initialisierung des Stackpointers) durchgeführt hat, kann dieses Bit nur ein einziges Mal auf 0 gesetzt werden. Ein erneutes Maskieren des XIRQ ist danach nicht mehr möglich, so daß man von diesem Zeitpunkt an von einem echten nicht maskierbaren Interrupt sprechen kann.
Während der Organisationsphase ist es in jedem Fall zwingend notwendig, keinen Interrupt zuzulassen, denn ein während dieses Zeitraumes aufgerufenes Interrupt-Programm würde auf Resourcen zurückgreifen wollen, die unter Umständen noch nicht verfügbar sind.

Eine zweite nicht maskierbare Interrupt-Quelle ist eine Erkennungsschaltung für illegale Befehlscodes (Illegal Opcode Trap). Da nicht alle möglichen Bitkombinationen mit gültigen Befehlen besetzt sind, besteht die Möglichkeit, daß die CPU durch einen Fehler im Programm oder durch einen Störimpuls von außen einen ungültigen Befehl bekommt. In einem solchen Fall wird ein spezieller Interruptvektor angesprungen, der auf eine Fehlerbehandlungsroutine zeigen sollte. Wird dieser Vektor nicht vom Anwender initialisiert, dann kann es passieren, daß er auf einen weiteren ungültigen Befehl zeigt und die CPU damit in eine Endlosschleife gerät.

Eine ähnliche Funktion hat der Softwareinterrupt SWI, der häufig während der Test- und Emulationsphase eines Programms benutzt wird. Er stellt einen normalen gültigen Befehl der CPU dar. Der Software-Interrupt wird in erster Linie von Emulations-Systemen zur Manipulation des Zielprozessors benutzt. Man kann ihn aber auch für Sytemaufrufe verwenden, wenn im 68HC11 ein Mini-Betriebssystem implementiert wird.

Alle weiteren Interrupt-Quellen des 68HC11 können durch das 1-Bit im Condition-Code-Register maskiert werden. Wenn dieses Bit gesetzt ist, sind alle diese Interrupt-Quellen gesperrt. Jeder Reset-Vorgang setzt dieses Bit. Es ist Aufgabe des Anwenderprogramms, den Interrupt nach sinnvoller Initialisierung des Systems gezielt freizugeben.
Jeder Eintritt in ein Interruptprogramm setzt das I-Bit, um eine weitere Unterbrechung durch einen neuen Interrupt zu verhindern. Nach Beendigung des Interruptprogramms durch einen RTI-Befehl wird es automatisch wieder gelöscht, so daß erneute Interrupts wieder zugelassen sind.
Zur Erweiterung der Interrupt-Struktur steht der Eingang IRQ zur Verfügung. Hier können beliebig viele externe Interrupt-Quellen angeschlossen werden. Zu diesem Zweck ist dieser Pin nach einem Reset auf Pegelabhängigkeit geschaltet ( Möglichkeit des "wired or" mehrerer Interruptquellen), um mit externen Peripherie-ICs kompatibel zu sein. Die Konfiguration als flankenempfindlicher Eingang wird seltener angewendet, da sie nur mit einer einzigen externen Interrupt-Quelle zusammenarbeiten kann.

Zusammenfassung der notwendigen Voraussetzungen zum Arbeiten mit Interrupts:

  1. Der IRQ-Ausgang eines externen Peripheriebausteins muß mit einem der Prozessor-Interrupt-Eingänge verbunden sein: IRQ, XIRQ, RESET (Hardware-Design). Interne Peripheriekomponenten sind natürlich schon verbunden.
  2. Der Stackpointer muß per LDS-Befehl gesetzt worden sein, damit die Register beim Interrupt in den beabsichtigten Stackbereich gerettet werden.
  3. Die Interrupt-Service-Routine muß programmiert sein.
    1. gegebenenfalls muß der Interrupt-Verursacher identifiziert werden, falls mehrere per "wired or" zusammengeschlossen sind.
    2. das IRQ-FF beim Interrupt-Verursacher muß darin gelöscht werden
  4. Die Startadresse der ISR muß in den entsprechenden Vektorzellen stehen. Initialsierung beispielsweise:
            ORG     $FFFE
            DC.W    main
    
  5. Im Peripheriebaustein-Kontrollregister "interrupt enable" setzen (= Außensperre öffnen).
  6. im Prozessor (CC-Register) den entsprechenden Interrupt zulassen (= Innensperre öffnen).
Im Praktikum geht es vor allem um die Aktionen 3, 4, 5, und 6.

Beispiel 1: Bedingte Unterbrechung am Eingang PA7

Am Eingang PA7 (Pulse Akku) ist ein Taster angeschlossen, mit dem eine bedingte Unterbrechung ausgelöst werden kann. Das Auftreten des Interrupts soll über eine Variable PFLAG signalisiert werden, die auch über Port C ausgegeben wird.

Alle auszuführenden Schritte werden im Folgenden ausführlich beschrieben:

Hier nun das vollständige Programm dazu:
data    equ   $2000    Datenbereich
prog    equ   $8000    Programmbereich
stack   equ   $7FFF    Stackbereich
pirqv   equ   $FFDA    Adresse PA-Vektor
resetv  equ   $FFFE    Adresse Reset-Vektor

padr    equ   $1000    Adresse Port A

pcdd    equ   $1007    Adressen Port C
pcdr    equ   $1003

pacr    equ   $1026    Pulse Akku Control
tflag   equ   $1025    Timer Flag
tmask   equ   $1024    Timer Mask

        org   data
pflag   ds.b  1

        org   prog
main    lds   #stack   Init Stack
        clr   pflag    Init Flag
        ldab  #$FF     Port C auf Ausgang
        stab  pcdd
        ldab  #$40     Init Interrupt
        stab  pacr     Pulse Akku enable
        ldab  #$10
        stab  tmask    PA7 enable
        cli            Interrupt  freigeben

loop   ldab   pflag    Ausgabeschleife
        stab  pcdr
        bra   loop        

pirq    ldaa  #$10      Interrupt Service Routine
        staa  tflg
        com   pflag     toggle 0 - FF 0 - FF - ...
        rti

        org   pirqv     Interrupt-Vektor setzen
        dc.w  pirq

        org   resetv    Reset-Vektor setzen
        dc.w  main

Beispiel 2: Bedingte Unterbrechung am Eingang STRA

Am Eingang STRA ist ein Taster angeschlossen, mit dem eine bedingte Unterbrechung ausgelöst werden kann. Das Auftreten des Interrupts soll über eine Variable TFLAG signalisiert werden, die auch über Port C ausgegeben wird. Das Verfahren für STRA ist nahezu identisch mit dem oben beschriebenen.