![]() |
MikrocomputertechnikProf. Jürgen Plate |
| 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.
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:
Schnittstelle programmierbar
Initialisierung notwendig
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:

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

Der Port kann auf zwei verschiedene Betriebsarten gesetzt werden:


Der Port kann auf zwei verschiedene Betriebsarten gesetzt werden:


Der Port kann auf zwei verschiedene Betriebsarten gesetzt werden:


Der Port kann auf zwei verschiedene Betriebsarten gesetzt werden:

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
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
.
.
.
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
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
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 Elemnt 0 --> Tabellenende
* wieder zum Tabellenanfang
staa portc Tabellenelement ausgeben
bsr delay Warteschleife aufrufen
inx naechstes Tabellenelement
bra loop usw.
*
delay ldx #$4000 Warteschleife, diesmal als Unterprogramm
dela1 dex
bne dela1
rts
*
TABLE dc.b $01, $02, $04, $08, $10, $20, $40, $80
dc.b $40, $20, $10, $08, $04, $02, $00
Vereinbarungen:
pbdr equ $1004 pedr equ $100A
Programm:
main ldaa pedr
staa pbdr
bra main

Betriebsart:
Puffer und Statusbits

Statusbits:
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.

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).

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.

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

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
bsr delay NUR FUER PRAKTIKUMSSYSTEM:
* Wartenzeit fuer Umschalten auf
* Terminalprogramm
loop bsr chin "Schreibmaschine"
bsr chout
bra loop
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
bsr delay NUR FUER PRAKTIKUMSSYSTEM:
* Wartenzeit fuer Umschalten auf
* Terminalprogramm
loop ldx #TEXT
bsr saus
bra loop
*
TEXT dc.b 'Hello World' Meldungstext
dc.b $0D,$0A,ETX Zeilenvorschub, ETX
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
bsr delay NUR FUER PRAKTIKUMSSYSTEM:
* Wartenzeit fuer Umschalten auf
* Terminalprogramm
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.

Basis des Timersystems ist ein 16-Bit-Zähler mit programmierbarem Vorteiler.

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öhrimpulse von außen ausgelöst werden könnten.
|
|
| TOF | timer 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. |
|---|---|---|
| TOI | timer overflow interrupt enable | Interruptfreigabe für "Timer Overflow Interrupt", 0 = Interrupt gesperrt, 1 = Interrupt freigegeben. |
| RTIF | real 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. |
| RTII | real time interrupt enable | Interruptfreigabe für "Realtime Interrupt", 0 = Interrupt gesperrt, 1 = Interrupt freigegeben. |
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.
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 ins = 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
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.

| EDGxB | EDGxA | Aktivierte Flanke |
| 0 | 0 | Keine, Kanal ausgeschaltet |
| 0 | 1 | Ansteigende Flanke |
| 1 | 0 | Abfallende Flanke |
| 1 | 1 | Beide Flanken |
| OMx | OLx | Reaktion |
| 0 | 0 | Keine |
| 0 | 1 | Polarität ändern (toggle) |
| 1 | 0 | auf 0 setzen |
| 1 | 1 | auf 1 setzen |
Mit dem Output Compare Register 1 kann man alle OC-Pins gleichzeitig manipulieren. Der OC-Pn 1 hat dabei Priorität über die anderen. Der OC1-Funktion sind zwei spezielle Register zugeordnet, OC1M und OC1D. Die Bits 3 bis 7 dieser Register entsprechen direkt den Leitungen von Port A, auf denen die OC-Werte ausgegeben werden. Für jede Leitung von Port A, die durch die OC-Funktion beinflußt werden soll, muß das entsprechende Bit in OC1M auf 1 gesetzt werden. Das Bitmuster für die Ausgabe wird dann in OC1D eingetragen. Auf diese Weise lassen sich fünf Pins exakt zeitgleich mit einem einzigen Output-Compare-Register beeinflussen.
| INIT | bit 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) | |
TMSK2 | bit 1-0: | PR1, PR0 prescaler of main timer (default = 00, ps = 1) |
OPTION | bit 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) |

| Signal | RESET | Unbedinger Abbruch und Neustart |
| Signal | XIRQ und (X-Bit = 0) | Unbedingte Unterbrechung (non maskable interrupt) |
| Signal | IRQ und (I-Bit = 0) | Bedingte Unterbrechung (interrupt request) (kann auch interne Ursachen haben) |
| Befehl | SWI | Befehlsgesteuerte Unterbrechung (software interrupt) |
| Befehl | Illegal Opcode | Nicht implementierter Befehl |

| Priorität | Name | Adresse | Interrupt-Quelle |
|---|---|---|---|
| 21 | SCIINT | $FFD6 | SCI serial system |
| 20 | SPIINT | $FFD8 | SPI serial system |
| 19 | PAIINT | $FFDA | Pulse Accumulator Input Edge |
| 18 | PAOVINT | $FFDC | Pulse Accumulator Overflow |
| 17 | TOINT | $FFDE | Timer Overflow |
| 16 | TOC5INT | $FFE0 | Timer Output Compare 5 |
| 15 | TOC4INT | $FFE2 | Timer Output Compare 4 |
| 14 | TOC3INT | $FFE4 | Timer Output Compare 3 |
| 13 | TOC2INT | $FFE6 | Timer Output Compare 2 |
| 12 | TOC1INT | $FFE8 | Timer Output Compare 1 |
| 11 | TIC3INT | $FFEA | Timer Input Capture 3 |
| 10 | TIC2INT | $FFEC | Timer Input Capture 2 |
| 9 | TIC1INT | $FFEE | Timer Input Capture 1 |
| 8 | RTIINT | $FFF0 | Real Time Interrupt |
| 7 | IRQINT | $FFF2 | IRQ External Interrupt |
| 6 | XIRQINT | $FFF4 | XIRQ External Interrupt |
| 5 | SWIINT | $FFF6 | Software Interrupt |
| 4 | BADOPINT | $FFF8 | Illegal Opcode Trap Interrupt |
| 3 | NOCOPINT | $FFFA | COP Failure (Reset) |
| 2 | CMEINT | $FFFC | COP Clock Monitor Fail (Reset) |
| 1 | RESETINT | $FFFE | RESET 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.
| PSEL3 | PSEL2 | PSEL1 | PSEL0 | Interrupt-Quelle |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | Timer Overflow |
| 0 | 0 | 0 | 1 | Pulse Accumulator Overflow |
| 0 | 0 | 1 | 0 | Pulse Accumulator Input Edge |
| 0 | 0 | 1 | 1 | SPI serial system |
| 0 | 1 | 0 | 0 | SCI serial system |
| 0 | 1 | 0 | 1 | Reserve |
| 0 | 1 | 1 | 0 | IRQ External Interrupt |
| 0 | 1 | 1 | 1 | Real Time Interrupt |
| 1 | 0 | 0 | 0 | Timer Input Capture 1 |
| 1 | 0 | 0 | 1 | Timer Input Capture 2 |
| 1 | 0 | 1 | 0 | Timer Input Capture 3 |
| 1 | 0 | 1 | 1 | Timer Output Compare 1 |
| 1 | 1 | 0 | 0 | Timer Output Compare 2 |
| 1 | 1 | 0 | 1 | Timer Output Compare 3 |
| 1 | 1 | 1 | 0 | Timer Output Compare 4 |
| 1 | 1 | 1 | 1 | Timer 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.
ORG $FFFE
DC.W main
data equ $2000 Datenbereich
prog equ $8000 Programmbereich
stack equ $7FFF Stackbereich
irqv equ $FFF2 Adresse IRQ-Vektor
resetv equ $FFFE Adresse Reset-Vektor
pioc equ $1002 Adressen Port C
portcl equ $1005
pcdd equ $1007
pcdr equ $1003
org data
tflag ds.b 1
org prog
main lds #stack Init Stack
clr tflag Init Flag
ldab #$FF Port C auf Ausgang
stab pcdd
ldab #$40 Init Interrupt
stab pioc STRA enable
cli Interrupt freigeben
loop ldab tflag Ausgabeschleife
stab pcdr
bra loop
sirq ldaa pioc Interrupt Service Routine
ldaa portcl
com tflag toggle 0 - FF 0 - FF - ...
rti
org irqv Interrupt-Vektor setzen
dc.w sirq
org resetv Reset-Vektor setzen
dc.w main
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
data equ $2000 Datenbereich
prog equ $8000 Programmbereich
stack equ $7FFF Stackbereich
tirqv equ $FFDE Adresse TOF-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
count ds.b 1 Zaehler
cflag ds.b 1 Clock Flag
org prog
main lds #stack Init Stack
clr count Init Flag
ldab #$FF Port C auf Ausgang
stab pcdd
ldab #$80 Init Interrupt
stab tmask TOF-Interrupt enable
ldab #$40
stab pacr
cli Interrupt freigeben
loop ldab cflag Ausgabeschleife
cmpb #3 Trigger-Zeitpunkt?
bne loop Nein
clr cflag Gotcha!
inc count Zaehler erhoehen
ldab count ...und ausgeben
stab pcdr
bra loop
tirq ldaa #$80 Interrupt Service Routine
staa tflg
inc cflag
rti
org tirqv Interrupt-Vektor setzen
dc.w tirq
org resetv Reset-Vektor setzen
dc.w main
Zum vorhergehenden Abschnitt |
Zum Inhaltsverzeichnis |
Zum nächsten Abschnitt |