![]() |
MikrocomputertechnikProf. Jürgen Plate |
LDAA $40 ; 1. Zahl holen
CMPA $41 ; 2. Zahl größer?
BHS WEITER ; 1. Zahl ist größer
LDAA $41 ; 2. Zahl laden
WEITER STAA $42 ; Abspeichern
CHECKSUM CLRA ; Summe in A und B, Register
CLRB ; zuerst mal löschen
LDX #$0043 ; Adresse erster Summand (Feldanfang)
CSUM ADDB ,X ; Feldelement addieren
ADCA #0 ; Übertrag im MSB aufaddieren
INX ; X inkrementieren
DEC $42 ; Elementezähler vermindern
BNE CSUM ; Wiederholen, solange Zähler > 0 ist
STD $40 ; Checksumme speichern
RTS
LDAB $41 ; Operanden holen
LDX #TABELLE ; X-Register auf Tabellenanfang
ABX ; X und B addieren
LDAA 0,X ; B-ten Eintrag aus Tabelle holen
STAA $42 ; und abspeichern
TABELLE DC.B 0,1,4,9,16,25,36,49,64,81,100
DC.B 121,144,169,196,225
LDAB #4 ; Zahlen sind 4 Byte lang = 8 Stellen
LDX #$41 ; 1. Operand
LDY #$51 ; 2. Operand
CLRA ; Akku A (und Carry-Flag) löschen
BCDADD LDAA 0,X ; zwei Ziffern des 1.Operanden holen
ADCA 0,Y ; zwei Ziffern des 2.Operanden addieren
INY
DAA ; Dezimalkorrektur für BCD
STAA 0,X ; Ergebnis abspeichern
INX
DECB
BNE BCDADD ; solange, bis alle Stellen bearbeitet
ANZAHL EQU 20 ; z.B. 20 Feldelemente
FELD DS.B 20 ; Platz für 20 Werte
COUNT DS.B 1 ; 1 Byte Zähler
.
.
.
CLRB ; Zähler für neg. Elemente löschen
LDX #FELD ; X auf Feldanfang
LDAA ANZAHL
STAA COUNT ; Zähler setzen
LOOP LDAA 0,X ; nächstes Feldelement
BPL WEITER ; wenn positiv weiter
INCB ; negative Elemente zählen
WEITER INX
DEC COUNT
BNE LOOP ; bis alle Elemente getestet sind
STAB COUNT ; Ergebnis in COUNT speichern
.
.
.
clr portb ; Portb auf 0 setzen
ldab #%1010 ; Register B setzen
ldaa #%11110000 ; Port C Richtungsregister setzen:
staa ddrc ; Bits 0-3 Eingabe, 4-7 Ausgabe
loop ldaa portc ; Port C lesen
anda #$0F ; untere 4 Bits ausmaskieren
staa portb ; auf Port B ausgeben
stab portc ; Register B ausgeben
eorb #%11110000 ; und Bits 4-7 invertieren
bsr delay ; 0,5 s warten (siehe unten)
jmp loop ; endlosschleife
.
.
.
; Vereinbarungen
prog equ $8000
data equ $2000
stack equ $7FFF
portb equ $1004
portc equ $1003
portcl equ $1005
pioc equ $1002
ddrc equ $1007
reset equ $fffe
.
.
org data ; Datenbereich
tflag ds.b 1
.
.
org prog ; Programmbereich
main lds #stack ; Stackpointer laden
clr portb ; Ports/Variablen init.
ldaa #1 ; tflag = 1
staa tflag
loop bsr count ; Hauptschleife, nur zwei UP-Aufrufe
bsr taste ; Taste abfrage
jmp loop ; auf/ab zaehlen
; Zaehl-Unterprogramm
; tflag wird addiert (tflag kann 1 oder -1 sein)
count adda tflag ; zaehlen
staa portb ; ausgeben
bsr delay ; 0,5 s warten (siehe unten)
rts
; Tasten-Abfrage-UP
; bei jedem Tastendruck wird tflag negiert (+1
-1, -1
+1)
taste psha ; Akku A retten
ldaa pioc ; Taste gedrueckt
bpl njet ; nein
fertig
ldaa portcl ; dummy-read zum Ruecksetzend es Tastenbits in pioc
neg tflag ; tflag negieren
njet pula ; Akku A restaurieren
rts
.
.
.
Die Bedienung des Timer-Interrupts wird hier nur angedeutet (da noch nicht behandelt). Der CLOCK-Interrupt wird im Beispiel alle 100 ms ausgelöst = 10 Tics/s.
ZEHNTEL DS.B 1 ; 1/10 Sekunden
SEKUNDEN DS.B 1 ; Sekunden
MINUTEN DS.B 1 ; Minuten
STUNDEN DS.B 1 ; Stunden
.
.
.
CLOCK
* An dieser Stelle muß die
* Timer-Hardware bedient werden
INC ZEHNTEL ; 1/10 Sekunden erhöhen
LDAA #10
CMPA ZEHNTEL ; Sekunde erreicht?
BNE ENDCLOCK ; nein - fertig
CLR ZEHNTEL ; sonst 1/10 Sekunden auf 0 setzen
INC SEKUNDEN ; und Sekunden erhöhen
LDAA #60
CMPA SEKUNDEN ; Minute erreicht?
BNE ENDCLOCK ; nein - fertig
CLR SEKUNDEN ; sonst Sekunden auf 0 setzen
INC MINUTEN ; und Minuten erhöhen
CMPA MINUTEN ; Stunden erreicht?
BNE ENDCLOCK ; nein - fertig
CLR MINUTEN ; sonst Minuten auf 0 setzen
INC STUNDEN ; und Stunden erhöhen
LDAA #24
CMPA STUNDEN ; Tageswechsel?
BNE ENDCLOCK ; nein - fertig
CLR STUNDEN ; sonst Stunden auf 0 setzen
ENDCLOCK RTI ; Rücksprung
Die Dauer der ISR beträgt im schlechtesten Fall weniger als 150 Taktzyklen. Da die ISR nur alle 100 ms ausgelöst wird, ist die zusätzliche Belastung des Systems relativ gering (ca. 0,1%).

EVENPAR PSHB ; Codewort zwischenspeichern
CLRA ; Zaehler = 0
ZHL LSRB ; naechstes Bit ins Carry holen
ADCA #0 ; Carry zu A ddieren
TSTB ; Restwort = 0?
BNE ZHL ; nein, weiter
PULB ; Codewort holen
ASLB ; links schieben
LSRA ; Parity-Bit ins Carry
RORB ; Parity-Bit ins MSB vom Codewort
RTS
*
* Konvertierung Binär zu ASCII
* Parameter in Akku A
*
BINASC ANDA #0F ; auf Werte zwischen 0 und 15 begrenzen
CMPA #9 ; Wert 0 bis 9 ?
BLS ZIF ; ja, dann direkt umwandeln
ADDA #7 ; "A" - "9" - 1 = $41 - $39 - 1 = 7
ZIF ADDA #$30 ; $30 = "0" (ASCII-Wert)
RTS
*
* Unterprogramm ASCII-Binär-Konvertierung (0 - 9, A - F)
* Parameter in A
*
ASCBIN SUBA #$30 ; $30 = ASCII "0"
BLO FEHL ; Erg. negativ
keine Ziffer
CMPA #9 ; kleiner oder gleich 9?
BLS DONE ; dann fertig
SUBA #7 ; "A" - "F"
10 - 15
CMPA #10 ; kleiner als 10?
BLO FEHL ; dann Fehler
CMPA #15 ; größer 15?
BLS DONE ; nein, fertig
FEHL LDAA #$FF ; Fehlerflag setzen
DONE RTS
hx4a psha ; Akku A auf dem Stack ablegen
bsr hx2a ; Akku B umwandeln (Stelle 3 und 4)
pulb ; Akku A vom Stack holen, in Akku B ablegen
; Nun einfach in hx2a fallen und Akku B
; umwandeln (Stelle 1 und 2)
hx2a pshb ; Akku B aud dem Stack sichern
bsr hx1a ; Bits 0-3 von Akku B umwandeln
pulb ; Original-Akku B wieder holen
lsrb ; viermal schieben (Bits 4-7 --> 0-3)
lsrb
lsrb ; und nun die obere Haelfte umwandeln
lsrb ; indem einfach in hx1a gefallen wird
; Nun wird die eigentliche Arbeit gemacht:
hx1a andb #$0F ; die oberen 4 Bita ausmaskieren
addb #48 ; ASCII-Wert von "0" addieren
cmpb #57 ; groesser als "9"?
bls hx1b ; nein, dann speichern
addb #7 ; sonst die Distanz zwischen "9" und "a" addieren
hx1b stab 0,y ; Im Speicher ablegen, auf den Y zeigt
dey ; Y zeigt jetzt auf die Stelle davor
rts ; und weg
LDX #STRING ; Beginn der Zeichenkette
CHECK LDAA 0,X ; Zeichen lesen
INX ; X erhoehen
CHECK CMPA #$20 ; Leerzeichen?
BEQ CHECK ; Ja, weiter testen
DEX ; nein, Zeiger korrigieren
.
.
.
STRING DC.B ' Zeichenkette mit 4 Leerzeichen am Anfang'
DC.B 0 Abschlußzeichen
; Vergleich zweier Strings, Anfangsadressen in X und Y
; Ergebnis wird in Akku A zurueckgegeben (0: ungleich, FF: gleich)
vergl ldaa 0,X ; Zeichen aus String 1 vergleichen
cmpa 0,Y ; mit Zeichen aus String 2
bne ver0 ; Strings ungleich, fertig
cmpa #0 ; Stringende
beq ver1 ; Strings sind gleich, fertig
inx ; naechstes Zeichen
iny
bra vergl
ver1 ldaa #$ff
rts
ver0 clra
rts
delay pshx ; Register x retten, 4 cycl
ldx #$f211 ; Anfangswert laden, 3 cycl
delay1 nop ; 5 x nop = 10 cycl
nop
nop
nop
nop
dex ; X runterzaehlen, 3 cycl
bne delay1 ; 3 cycl
pulx ; Register restaurieren, 5 cycl
rts ; 5 cycl
prog equ $8000 ; Vereinbarungen
data equ $2000
stack equ $7FFF
portb equ $1004
reset equ $fffe
org prog
main lds #stack
ldx #muster ; X verweist auf das erste Feldelement
loop ldaa 0,x ; erstes Feldelement laden
bne ausg ; wenn nicht 0, ausgeben
ldx #muster ; sonst wieder zum ersten Element
bra loop ; ohne Ausgabe
ausg staa portb ; Bitmuster ausgeben
jsr delay ; 0,5 s warten
inx ; naechstes Element
bra loop
delay pshx ; Delay, siehe oben
ldx #$f422
delay1 nop
nop
nop
nop
nop
dex
bne delay1
pulx
rts
muster dc.b %11110000, %01111000, %00111100, %00011110
dc.b %00001111, %00011110, %00111100, %01111000
dc.b %0
org reset ; Reset-Vektor setzen
fdb main
end

prog equ $8000
data equ $2000
stack equ $7FFF
portb equ $1004
reset equ $fffe
org data
count ds.b 1
org prog
main lds #stack
clr count ; Speicher loeschen
loop ldab count ; Schleifenbeginn, count mod 16 hochzaehlen
incb
andb #$0F
stab count
bsr umco ; Count in Akku B wird umcodiert, Ergebnis in Akku B
stab portb ; und ausgeben
jsr delay ; 0,5 s warten
bra loop
; Umcodierung binaer --> 7-Segment, eingabe und Ausgabe in Akku B
umco ldx #umcotab ; Tabellenadresse laden
andb #$0F ; fuer B nur Werte 0 - F zulassen
abx ; X = X + B
ldab 0,x ; 7-Sement-Wert holen, Adressierung durch X-Register
rts
delay pshx ; Delay, siehe oben
ldx #$f422
delay1 nop
nop
nop
nop
nop
dex
bne delay1
pulx
rts
; Siebensegment-Tabelle (Segmentanordnung: -abcdefg)
; Die Ziffern "0" bis "9" sind decodiert, fuer "A" bis "F"
; wird nur ein "-" angezeigt --> noch zu ergaenzen
umcotab dc.b %01111110, %00110000, %01101101, %01111001
dc.b %00110011, %01011011, %01011111, %01110000
dc.b %01111111, %01111011, %00000001, %00000001
dc.b %00000001, %00000001, %00000001, %00000001
org reset
fdb main
end
; Vereinbarungen
prog equ $8000
data equ $2000
stack equ $7FFF
portb equ $1004
portc equ $1003
portcl equ $1005
pioc equ $1002
ddrc equ $1007
scdr equ $102f
scsr equ $102e
sccr1 equ $102c
sccr2 equ $102d
baud equ $102b
reset equ $fffe
; ASCII-Zeichen
cr equ 13
lf equ 10
org prog
main lds #stack ; Initialisierungen
bsr sini
loop ldx #cmd ; Prompt ausgeben
bsr ssend
bsr recv ; Befehl (1 Zeichen) einlesen
cmpa #'a' ; ist es 'a'?
bne next1 ; nein, weiter
bsr doit ; Kommando 'a' verarbeiten
bra loop
next1 cmpa #'b' ; ist es 'b'?
bne next2 ; nein, weiter
bsr doit ; Kommando 'b' verarbeiten
bra loop
next2 cmpa #'c' ; ist es 'c'?
bne next3 ; nein, weiter
bsr doit ; Kommando 'c' verarbeiten
bra loop
next3 ldx #oops ; falsche Eingabe: "Oops" ausgeben
bsr ssend
bra loop
; Kommandobearbeitungsroutine, hier als Dummy
doit psha ; Kommandobearbeitung, erst Akku A retten
ldx #k1 ; Text "Eingabe war" ausgeben
bsr ssend
pula ; Akku A wiederherstellen
suba #$20 ; Kleinbuchstaben in Grossbuchstaben wandeln
bsr send ; ausgeben
bsr crlf ; "neue Zeile" ausgeben
rts
; Carriage Return und Line Feed ausgeben
crlf ldaa #cr
bsr send
ldaa #lf
bsr send
rts
; String ausgeben (ohne cr/lf am Ende), Stringadresse (erstes Zeichen)
; muss in Register X uebergeben werden (siehe Kapitel 5)
ssend ldaa 0,x
beq sfin
bsr send
inx
bra ssend
sfin rts
; serielle Schnittstelle initialisieren (siehe Kapitel 5)
sini clr sccr1
ldaa #$0C
staa sccr2
ldaa #$30
staa baud
rts
; Zeichen seriell ausgeben (siehe Kapitel 5)
send ldab scsr
bpl send
staa scdr
rts
; Zeichen seriell empfangen (siehe Kapitel 5)
recv ldab scsr
andb #$20
beq recv
ldaa scdr
rts
; String-Konstanten (Strings werden durch ein 0-Byte abgeschlossen)
cmd dc.b 'Kommando: '
dc.b 0
oops dc.b 'Oops!'
dc.b cr,lf,0
k1 dc.b 'Eingabe war '
dc.b 0
org reset ; Reset-Vektor setzen
fdb main
end
prog equ $8000
data equ $2000
stack equ $7FFF
portb equ $1004
portc equ $1003
ddrc equ $1007
reset equ $fffe
tvec equ $FFDE ; interrupt vector of timer
tmsk equ $1024 ; timer mask
tflg equ $1025 ; timer flag
pacr equ $1026 ; pulse accu control
org data
count ds.b 1
cflg ds.b 1
org prog
main lds #stack ; init variables
clr portb
clr count
clr cflg
ldab #$40 ; enable PA7 interrupt
stab pacr ; enable pulse accu
ldab #$80
stab tmsk
cli ; enable interrupts
loop ldaa cflg ; get clock flag
cmpa #20 ; trigger point?
bne loop ; no, wait
clr cflg ; yes, clear clock flag
inc count ; count up
ldaa count
staa portb ; display counter
bra loop
; interrupt service routine
tirq ldaa #$80
staa tflg ; clear interrupt
inc cflg ; count interrupts
rti
org tvec ; set interrupt vector
fdb tirq ; DE timer overflow
org reset ; set reset vector
fdb main
end
Zum vorhergehenden Abschnitt |
Zum Inhaltsverzeichnis |
Zum nächsten Abschnitt |