Mikrocomputertechnik


Prof. Jürgen Plate

Programmbeispiel-Sammlung

Den folgenden "Programmschnipseln" fehlt noch das "Drumrum" (Definitionen von Variablen, Hauptprogramm, usw.). Sie dienen der Illustration verschiedener Programmiertechniken in Assembler.

Allgemeiner Vorspann für's Praktikum

data      equ      $2000      ; data area     (e-ram)
stak      equ      $7FFF      ; stack area    (e-ram)
prog      equ      $8000      ; programm area (e-eerom)
rvec      equ      $FFFE      ; reset vector

porta     equ      $1000      ; port a data
portb     equ      $1004      ; port b data
portc     equ      $1003      ; port c data reg.
ddrc      equ      $1007      ; port c data dir. reg.
portd     equ      $1008      ; port d data reg.
ddrd      equ      $1009      ; port d data dir. reg.
porte     equ      $100A      ; port e data
pioc      equ      $1002      ; parallel i/o control
portcl    equ      $1005      ; port c data latch
tmsk      equ      $1024      ; timer mask
tflg      equ      $1025      ; timer flag
pacr      equ      $1026      ; pulse accu control
baud      equ      $102B      ; SCI-baudrate
sccr1     equ      $102C      ; SCI-control1
sccr2     equ      $102D      ; SCI-control2
scsr      equ      $102E      ; SCI-status
scdr      equ      $102F      ; SCI-data

***************************
*        data area        *
***************************

          org      data


***************************
*      program area       *
***************************

          org      prog

main      lds      #stak      ; load stackpointer


***************************
*   Nachspann: Vektoren   *
***************************
          org      reset
          fdb      main
          end

Speicherbereich Kopieren

* Parameter: A Länge (Anzahl Bytes), X Quelle, Y Ziel
move  pshb
mov1  ldab     0,x	; hole Quellbyte
      stab     0,y  ; speichern im Zielbereich
      inx           ; Adressen erhöhen
      iny
      deca          ; runterzählen bis 0
      bne      mov1
      pulb
      rts

Die größere von zwei Zahlen finden

Vergleichen ($2000) und ($2001), Ergebnis in $2002
          LDAA $2000       ; 1. Zahl holen
          CMPA $2001       ; 2. Zahl größer?
          BHS  WEITER      ; 1. Zahl ist größer
          LDAA $2001       ; 2. Zahl laden
WEITER    STAA $2002       ; Abspeichern

Quadrate von 0 - 15 über Tabelle ermitteln

Wert in $2001, Ergebnis in $2002
          LDAB $2001     ; Operanden holen
          LDX  #TABELLE  ; X-Register auf Tabellenanfang
          ABX            ; X und B addieren
          LDAA 0,X       ; B-ten Eintrag aus Tabelle holen
          STAA $2002     ; und abspeichern

TABELLE   DC.B           0,1,4,9,16,25,36,49,64,81,100
          DC.B           121,144,169,196,225

16-Bit-Addition (Prüfsumme)

Addition eines Feldes von 8-Bit-Werten. Die Anzahl der Werte steht in Speicherbyte $42, die zu addierenden Werte folgen ab Adresse $43. Das 16-Bit-Ergebnis wird in $40 (MSB) und $41 (LSB) abgelegt.
          ORG  DTA
Summe     DS.B 2         ; Summe, 16-Bit-Wert
Anzahl    DS.B 1         ; Anzahl Werte, 8-Bit-Wert
Daten     DS.B 255       ; Datenfeld

          ORG  PROG
           .
           .
           .
CHECKSUM  CLRA           ; Summe in A und B, Register
          CLRB           ; zuerst mal löschen
          LDX  #Daten    ; Adresse erster Summand (Feldanfang)
CSUM      ADDB ,X        ; Feldelement addieren
          ADCA #0        ; Übertrag im MSB aufaddieren
          INX            ; X inkrementieren
          DEC  Anzahl    ; Elementezähler vermindern
          BNE  CSUM      ; Wiederholen, solange Zähler > 0 ist
          STD  Summe     ; Checksumme speichern
          RTS

Addieren von 24-Bit-Zahlen

      org       data
eins  dc.b      04,82,40      ; 1. Summand
zwei  dc.b      02,37,98      ; 2. Summand
drei  dc.b      $00,$00,$00   ; Ergebnis

      org      prog
       .
       .
       .
      ldaa      eins+2
      adda      zwei+2
      staa      drei+2
      ldaa      eins+1
      adca      zwei+1
      staa      drei+1
      ldaa      eins+0
      adca      zwei+0
      staa      drei+0
       .
       .
       .

Addition von 8-stelligen BCD-Zahlen

Die 1. BCD-Zahl lautet 12345678 (MSB zuerst)
Die 2. BCD-Zahl lautet 21436587 -"-
Das Ergebnis wird auf die erste Zahl gespeichert
          ORG  DTA
Zahl1     DC.B $12,$34,$56,$78   ; Speicherung Nibble-weise, daher
Zahl2     DC.B $21,$43,$65,$87   ; Hexadezimal-Zahlen

          ORG  PROG
           .
           .
          LDAB #4        ; Zahlen sind 4 Byte lang = 8 Stellen
          LDX  #Zahl1+3  ; 1. Operand, LSB
          LDY  #Zahl2+3  ; 2. Operand, LSB
          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
          DAA            ; Dezimalkorrektur für BCD
          STAA 0,X       ; Ergebnis abspeichern
          DEY
          DEX
          DECB
          BNE  BCDADD    ; solange, bis alle Stellen bearbeitet

Zählen der negativen Elemente in einem Feld

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

Ein- und Ausgabe auf Ports

Das folgende Programm liest die unteren 4 Bits von Port C ein und gibt sie auf Port B wieder aus, gleichzeitig blinken die oberen 4 Bits von Port C.
          .
          .
	        .
        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
         .
         .
         .

Taste an PA7 einlesen

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

pioc    equ    $1002    ; parallel i/o control
portb   equ    $1004    ; port b data
portc   equ    $1005    ; port c data latch
portcl  equ    $1005    ; port c data latch
tmsk    equ    $1024    ; timer mask
tflg    equ    $1025    ; timer flag
pacr    equ    $1026    ; pulse accu control
baud    equ    $102B    ; SCI-baudrate
sccr1   equ    $102C    ; SCI-control1
sccr2   equ    $102D    ; SCI-control2
scsr    equ    $102E    ; SCI-status
scdr    equ    $102F    ; SCI-data

reset   equ    $fffe

        org    data
key     ds.b   1

        org    prog
main    lds    #stack      ; load stackpointer
        clr    key
        ldaa   #%01010000 ; pa7 freigabe pos. flanke
        staa   pacr
        clra

loop    bsr    taste
        ldaa   key
        staa   portb
        bra    loop

taste   psha
        ldaa   tflg      ; taste gedrueckt?
        anda   #$10
        beq    tend      ; nix gewesen
        ldaa   #$10
        staa   tflg      ; Anforderung loeschen
        com    key       ; Ereignis melden
tend    pula
        rts

        org    reset
        fdb    main
        end

16-Bit Schieberegister, Richtung per PA7-Taste umschaltbar

data	equ	$2000	; data area     (e-ram)
stak	equ	$7FFF	; stack area    (e-ram)
prog	equ	$8000	; programm area (e-eerom)
rvec	equ	$FFFE	; reset vector

pioc	equ	$1002	; parallel i/o control
portb	equ	$1004	; port b data
portcl	equ	$1005	; port c data latch
portc	equ	$1003	; port c data reg.
ddrc	equ	$1007	; portc data dir. reg.
tmsk	equ	$1024	; timer mask
tflg	equ	$1025	; timer flag
pactl	equ	$1026	; pulse accu control
baud	equ	$102B	; SCI-baudrate
sccr1	equ	$102C	; SCI-control1
sccr2	equ	$102D	; SCI-control2
scsr	equ	$102E	; SCI-status
scdr	equ	$102F	; SCI-data

***************************
*        data area        *
***************************

	org	data

flag	ds.b	1
shift	ds.b	2

***************************
*      program area       *
***************************

      org    prog

main  lds     #stak   ; load stackpointer
      clr     flag
      ldaa    #%01010000 ; pa7 Eingang, Freigabe, pos. Flanke
      staa    pactl
      ldaa    #$FF    ; portc als Ausgabe
      staa    ddrc
      clr     shift   ; Schieberegister mit 1 laden
      ldab    #1
      stab    shift+1

loop  bsr     taste   ; Tastenstatus abfragen
      ldaa    flag    ; flag = 0 - links, flag = ff - rechts
      bne     rechts
links ldd    shift    ; nach links schieben
      lsld
      bne     raus    ; falls 0, neu laden mit 1 im LSB
      ldab    #1
      bra     raus    ; zur Ausgabe
rechts ldd   shift    ; rechts schieben
      lsrd
      bne     raus    ; falls 0 mit 1 laden im MSB
      ldaa    #$80
raus  std     shift   ; akt. Wert speichern
      staa    portb   ; und ausgeben (auf zwei 8-Bit-Ports)
      stab    portc

      bsr     delay
      bra     loop
      rts

taste psha            ; Akku retten
      ldaa    tflg    ; Taste gedrueckt?
      anda    #$10
      beq     tend    ; nix gewesen
      ldaa    tflg
      oraa    #$10
      staa    tflg    ; Anforderung loeschen
      com     flag    ; Ereignis melden
tend  pula            ; Akku restore
      rts

delay ldy    #$ffff
dely1 nop
      nop
      nop
      nop
      nop
      nop
      nop
      dey
      bne    dely1
      rts

***************************
*         vectors         *
***************************

      org    rvec
      fdb    main    ; FFFE reset
      end

Auf-/Abwärtszähler, Taste an STRA

Der folgende Zähler zählt abhängig von der Variablen "tflag" aufwärts oder abwärts. Die Zählrichtung wird durch eine Taste am Eingang STRA umgeschaltet.
; 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
         .
         .
         .

Alternativlösung mit bedingter Verzweigung

loop  bsr      delay
      tst      updn
      bne      decr
      inc      count
      ldaa     count
      cmpa     #$FF
      bne      endf
      com      updn
      bra      endf
decr  dec      count
      ldaa     count
      tsta
      bne      endf
      com      updn
endf  ldaa     count
      staa     portb
      jmp      loop

BCD-Zähler mit Rücksetzen per STRA

data      equ      $2000      ; data area     (e-ram)
stak      equ      $7FFF      ; stack area    (e-ram)
prog      equ      $8000      ; programm area (e-eerom)
rvec      equ      $FFFE      ; reset vector

pioc      equ      $1002      ; parallel i/o control
portb     equ      $1004      ; port b data
portcl    equ      $1005      ; port c data latch
portc     equ      $1003      ; port c data reg.
ddrc      equ      $1007      ; portc data dir. reg.
tmsk      equ      $1024      ; timer mask
tflg      equ      $1025      ; timer flag
pacr      equ      $1026      ; pulse accu control
baud      equ      $102B      ; SCI-baudrate
sccr1     equ      $102C      ; SCI-control1
sccr2     equ      $102D      ; SCI-control2
scsr      equ      $102E      ; SCI-status
scdr      equ      $102F      ; SCI-data

***************************
*        data area        *
***************************

      org      data
flag  ds.b     1

***************************
*      program area       *
***************************

      org      prog

main  lds      #stak      ; load stackpointer
      clra
      clr      flag
      bsr      init

schl  adda     #1         ; BCD hochzaehlen
      daa
      anda     #$0F
      bsr      taste      ; Taste abfragen
      psha                ; a auf den stack
      lsla                ; 4 x schieben
      lsla
      lsla
      lsla
      staa     portc      ; ausgeben
      pula                ; a restore
      ldab     flag       ; Tastendruck bearbeiten
      stab     portb      ; auf Port B ausgeben
      bne      schl1      ; wenn nicht 0
      clra                ; Zaehler loeschen
      com      flag       ; flag wieder setzen -> sonst "haengt" es

schl1 bsr      delay
      bra      schl

init  ldaa     #$02       ; hands=0, raising edge 00000010
      staa     pioc
      ldaa     #%11110000
      staa     ddrc
      rts

delay ldy      #$ffff
dely1 nop
      nop
      nop
      nop
      nop
      nop
      nop
      dey
      bne      dely1
      rts

taste psha
      ldaa     pioc       ; taste gedrueckt (Bit 7)?
      bpl      tend       ; nix gewesen
      ldaa     portcl     ; dummy read --> Reset STAF
      com      flag       ; ereignis melden
tend  pula
      rts

***************************
*         vectors         *
***************************

      org      rvec
      fdb      main      ; FE reset
      end

Software-Uhr

Eine Software-Uhr wird in der Regel durch einen periodischen Interrupt (z. B. vom Timer) unterstützt. Bei jedem Interrupt wird ein Zähler incrementiert. Die Zählung erfolgt in Sekunden, Minuten und Stunden. Das im Vordergrund arbeitende Programm kann auf die Zeitinformation zugreifen.

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

Nützliche Unterprogramme

Die folgenden Unterprogramme lassen sich in eigenen Programmen verwenden.

Ergänzen eines ASCII-Codewortes auf gerade Parität

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

Binärwert (0 - 15) zu ASCII konvertieren

Unterprogramm zur Konvertierung eines Binärwertes (0 - 15) in die ASCII-Darstellung (z.B. für die Ausgabe am Terminal). Der Wert wird in Register A an das UP übergeben und das entsprechende ASCII-Zeichen wird vom UP wieder in A zurückgegeben.
Der Abstand zwischen der Ziffer "9" und dem Buchstaben "A" beträgt im ASCII-Zeichensatz 7 Zeichen, weshalb zwischen den Eingangswerten 0 - 9 und 10 - 15 unterschieden werden muss. Bei Werten größer 10 muss daher 7 addiert werden.
*
* 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

ASCII-Zeichen zu Binär konvertieren

Unterprogramm zur Konvertierung eines ASCII-Zeichens (0 - 9, A - F) in einen Binärwert, z.B. bei der Eingabe von Zahlen über das Terminal. Das Zeichen wird in Akku A übergeben und der Wert wieder in A zurückgegeben. Das UP arbeitet invers zum obigen UP. Bei Fehleingabe (keine Ziffer) wird Akku A auf $FF gesetzt.
*
* 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

Binär zu ASCII-Decodierung (1, 2 oder 4 Stellen)

Im Speicher liegen die Werte bekanntermaßen binär vor. Um einen Speicherinhalt oder eine Adresse auf der seriellen Schnittstelle (Terminal) oder einem LC-Display ausgeben zu können, müsen die Werte als ASCII-Zeichen dargestellt werden.
Die folgenden vier miteinander verbundenen Unterprogramme erweitern das Beispiel oben und wandeln einen 16-Bit-Wert, einen 8-Bit-Wert (Byte) oder einen 4-Bit-Wert (Nibble) in eine Hexadezimalzahl in ASCII-Darstellung um (4, 2, oder 1 Stelle): Diese Unterprogramme werden beim vierten Praktikumstermin benötigt.
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

Überlesen von Leerzeichen am Anfang einer Zeichenkette

Nach Ausführung zeigt X auf das erste Zeichen != ' '. Der String muß mit einem Zeichen != ' ' abgeschlossen sein.
          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

Beispiel: Vergleich zweier Zeichenketten (Strings)

Die Adressen der beiden Zeichenketten werden in X und Y übergeben. Als Ergebnis wird Akku A verwendet - 0: Strings sind ungleich, FF: Strings sind gleich
; 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-Routine

Das folgende Unterprogramm erlaubt längere Verzögerungszeiten als das in Kapitel 3 vorgestellte, da hier das 16-Bit-Register X verwendet wird. "delay" dauert 4 + 3 + $f422*16 + 4 + 5 + 5 Taktzyklen, was einer Wartezeit von 8,5 + $f422*8 μs = 499992,5 μs entspricht - also ungefähr 0,5 s.
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

Delay-Routine - Angabe der Frequenz

Die Frequenz wird in Akku B übergeben (Werte zwischen 1 und 15).
delay   clra            ; Akku D: Akku A = 0, Akku B = Wert
        andb   #$0F
        beq    del_end  ; Division durch 0 verhindern
        ldx    #$FF00   ; Wert fuer 1 Hz --> X
        xgdx            ; Schalter in X, 1-Hz-Wert in D
        idiv            ; D/X

delay1  nop
        nop
        nop
        nop
        nop
        nop
        nop
        dex
        bne    delay1
del_end rts

Demo 16-Bit-Tabellenzugriff

Die Variablen sek und zsek werden gemeinsam aus einer Tabelle belegt. Die Auswahl des Tabellenelementes erfolgt über 4 Schalter an Port C.
        org    data
sek     ds.b   1
zsek    ds.b   1

        org    prog
main    lds    #stack        ; Initialisierung
        clr    portb
        ldaa   #%11110000    ; Bits 0-3 als Eingang
        staa   ddrc

loop    ldab   portc         ; Schalter einlesen
        andb   #$0F
        lslb                 ; Akku B * 2, weil 16-Bit-Zugriff
                             ; (jeweils 2 Byte)
        ldx    #tabelle      ; Tabellenzugriff: X zeigt aus Tab.-Anfang
        abx                  ; aktuelle Position:  B + X
        ldd    0,X           ; Wert laden
        std    sek           ; Sekunden in sek, 1/10 in zsek
        jmp    loop

*               0    1    2     3     4     5     6     7
tabelle dc.b   0,0, 2,5, 4,0, 10,0, 15,5, 20,0, 25,3, 31,4,
*                8     9    10    11    12    13    14     15
        dc.b   40,0, 51,2, 60,0, 65,8, 72,4, 80,1, 85,7, 95,3

Zufallszahlen

Bei C gibt es in der Regel eine Random-Funktion, die Pseudo-Zufallszahlen liefert. In Assembler muss man, sofern es keine passende Bibliothek gibt, selbst eine entsprechende Funktion programmieren. Im Folgenden wird eine typische Form der Implementierung verwendet, um 8-Bit-Zufallszahlen zu generieren. Es handelt sich um die 16-Bit-Variante der klassischen Formel S' = S * M + A. Als Zufallswert wird das Highbyte der 16-Bit-"Seed" des Zufallsgenerators im Akku A zurückgegeben. Für die Konstanten werden die Werte M = 181 und A = 359 aus folgenden Gründen gewählt: Die Funktion benötigt wenig Speicherplatz und nur 4 Byte RAM. Mit dem Unterprogramm RndInit wird der Anfangswert der "Seed" auf Null gesetzt. Sie können aber auch jeden beliebigen Anfangswert verwenden - etwa den Eingangswert eines A/D-Wandler-Ports.
data    equ   $2000   ; Datenbereich
prog    equ   $8000   ; Programmbereich
stack   equ   $7FFF   ; Stackbereich
resetv  equ   $FFFE   ; Adresse Reset-Vektor

pcdd    equ   $1007   ; Adressen Port C
pcdr    equ   $1003

* Random-Constants:
RndMult equ   181     ; Multiplikationsfaktor
RndAdd  equ   359     ; zu addierender Offset

        org   data
RndSeed ds.b  2       ; 2 Byte Random Seed
RndTmp  ds.b  2       ; temporaerer Speicher

        org   prog
main    lds   #stack  ; Init Stack
        ldaa  #$FF
        staa  pcdd    ; Port C als output
        clr   pcdr
        bsr   RndInit ; Seed = 0

loop    bsr   Random  ; A = random number
        staa  pcdr    ; A -> Port C
        bsr   Delay   ; wait
        bra   loop

* Initialize the random number generator
RndInit clr   RndSeed
        clr   RndSeed+1
        rts

* Return the next 8-bit pseudo random number
* Berechnet SEED = SEED * 181 + 359
* return high byte of the new SEED in A
* Return value: The A register.
Random  pshb              ; save B
* scratch = seed * RndMult
       ldaa    #RndMult  ; A = #181
       ldab    RndSeed+1 ; B = low byte of the seed
       mul               ; D = A x B
       std     RndTmp    ; scratch = D
       ldaa    #RndMult  ; A = #181
       ldab    RndSeed   ; B = high byte of the seed
       mul               ; D = A x B
* low byte of mult. result is added to the high byte of scratch
       addb    RndTmp    ; B = B + scratch_high
       stab    RndTmp    ; scratch = seed * 181
       ldd     RndTmp    ; D = scratch
       addd    #RndAdd   ; D = D + 359
       std     RndSeed   ; save new seed value
* A holds RndSeed from addition
       pulb              ; retore B
       rts

* Delay wie ueblich ...
Delay  LDX   #$FFFF
LoopX  DEX
       BNE   LoopX
       RTS

       org   resetv  ; Reset-Vektor setzen
       dc.w  main

Komplette Programmbeispiele

Die folgenden Programme sind vollständig und lassen sich direkt assemblieren, simulieren und im Zielsystem ausführen.

Ausgabe beliebiger Bitmuster

Es wird ein Array mit Bitmustern angelegt ("muster"), die nacheinander auf Port B ausgegeben werden. Ein Nullbyte markiert das Ende des Arrays. Wenn dies erreicht ist, beginnt die Ausgabe wieder beim ersten Element. Das Array ist beliebig erweiterbar.
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

Dezimal zu Siebensegment Codierung

Der Inhalt von Akkumulator B soll in die Siebensegmentdarstellung gemäß untenstehender Abbildung umcodiert werden. Der erzeugte Code wird ebenfalls in Akku B zurückgegeben. Bei Werten größer 9, soll B mit $FF besetzt werden.

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

Serielle Eingabe mit Backspace und Ignorieren von Zeichen < " "

gets  stx      pufanf
gets0 bsr      recv
      cmpb     #cr
      beq      gets1
      cmpb     #bs
      beq      gets2
      cmpb     #' '     ; Zeichen < ' ' ignorieren
      blo      gets0
      bsr      send
      stab     0,x
      inx
      bra      gets0
gets1 clrb              ; Newline - Eingabeende
      stab     0,x      ; Nullbeit als Abschluss
      bsr      crlf     ; cr + lf ausgeben
      rts
gets2 cpx      pufanf   ; Backspace
      beq      gets0    ; nur bis Pufferanfanng zurück
      dex
      ldab     #bs      ; BS , Leer, BS ausgeben
      bsr      send
      ldab     #' '
      bsr      send
      ldab     #bs
      bsr      send
      bra      gets0

; cr+lf ausgeben
crlf  ldab     #cr
      bsr      send
      ldab     #lf
      bsr      send
      rts

Serielle Fortschrittsanzeige

Die Anzeige erfolgt in Form eines ASCII-"Propellers". Bei jedem Aufruf des Unterprogramms wird das nächste ASCII-Zeichen einer vorgegebenen Liste, gefolgt von einem Backspace-Zeichen, seriell ausgegegeben. Durch die Wahl der Zeichen ergibt sich der Eindruck eines Propellers, der sich dreht. Wegen des folgenden Backspace-Zeichens, bleibt der Coursor auch immer an derselben Stelle. Hauptprogramm und Delay-Routine dienen nur als Demo.
data      equ      $2000      ; data area     (e-ram)
stak      equ      $7FFF      ; stack area    (e-ram)
prog      equ      $8000      ; programm area (e-eerom)
rvec      equ      $FFFE      ; reset vector

baud      equ      $102B      ; SCI-baudrate
sccr1     equ      $102C      ; SCI-control1
sccr2     equ      $102D      ; SCI-control2
scsr      equ      $102E      ; SCI-status
scdr      equ      $102F      ; SCI-data

cr        equ      $0D
lf        equ      $0A
bs        equ      $08

***************************
*        data area        *
***************************

          org      data
pflag     ds.b     1

***************************
*      program area       *
***************************
      org      prog

main  lds      #stak      ; load stackpointer
      jsr      init

loop  bsr      prop
      jsr      delay
      bra      loop

; Serieller "Propeller"
prop  pshx
      pshb
      ldx      #pchar
      ldab     pflag
      abx
      ldab     0,x
      bsr      send
      ldab     #bs
      bsr      send
      ldab     pflag
      incb
      andb     #%00000011
      stab     pflag
      pulb
      pulx
      rts
pchar dc.b     '|/-\\'

; seriell byte senden
; Parameter: Zeichen in Akku B
send  psha
send1 ldaa     scsr
      anda     #%10000000  ; $80 (bpl)
      beq      send1
      stab     scdr
      pula
      rts

; seriell init
init  clr      SCCR1
      ldaa     #$0C
      staa     SCCR2
      ldaa     #$30
      staa     BAUD
      clr      pflag
      rts

; Warteschleife
delay ldx      #30000
dely  nop
      nop
      dex
      bne      dely
      rts

***************************
*         vectors         *
***************************

      org      rvec
      fdb      main      ; FE reset

      end

Kommandoeingabe über die serielle Schnittstelle

; 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

Demo für den Timer-Interrupt

Das Programm zählt eine Variable "count" interruptgesteuert hoch.
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

Demo für Interrupt an STRA

data    equ    $2000    ; data area     (e-ram)
stak    equ    $7FFF    ; stack area    (e-ram)
prog    equ    $8000    ; programm area (e-eerom)

pvec    equ    $FFDA    ; vector pa7
tvec    equ    $FFDE    ; vector timer
svec    equ    $FFF2    ; sirq vector
rvec    equ    $FFFE    ; reset vector

pioc    equ    $1002    ; parallel i/o control
pbdr    equ    $1004    ; port b data
portcl  equ    $1005    ; port c data latch
tmsk    equ    $1024    ; timer mask
tflg    equ    $1025    ; timer flag
pacr    equ    $1026    ; pulse accu control

***************************
*        data area        *
***************************

        org    data
flag    ds.b   1    ; irq flag

***************************
*      program area       *
***************************

        org    prog
main    lds    #stak    ; load stackpointer
        bsr    init     ; data init
        cli             ; enable irq

loop    ldaa   flag
        staa   pbdr     ; display
        bra    loop     ; close main loop

***************************
*       subroutines       *
***************************

init    clr    flag
        ldab   #$40     ; enable STRA interrupt
        stab   pioc
        rts

***************************
*    interrupt handler    *
***************************

sirq    ldaa   pioc     ; stra isr
        ldaa   portcl   ; clear interrupt
        com    flag
        rti

***************************
*         vectors         *
***************************

        org    svec
        fdb    sirq     ; STRA

        org    rvec
        fdb    main     ; FE reset

        end

Demo für Interrupts an STRA und PA7

data    equ    $2000    ; data area     (e-ram)
stak    equ    $7FFF    ; stack area    (e-ram)
prog    equ    $8000    ; programm area (e-eerom)

pvec    equ    $FFDA    ; vector pa7
tvec    equ    $FFDE    ; vector timer
svec    equ    $FFF2    ; sirq vector
rvec    equ    $FFFE    ; reset vector

pioc    equ    $1002    ; parallel i/o control
pbdr    equ    $1004    ; port b data
pcdl    equ    $1005    ; port c data latch
tmsk    equ    $1024    ; timer mask
tflg    equ    $1025    ; timer flag
pacr    equ    $1026    ; pulse accu control
baud    equ    $102B    ; SCI-baudrate
sccr1   equ    $102C    ; SCI-control1
sccr2   equ    $102D    ; SCI-control2
scsr    equ    $102E    ; SCI-status
scdr    equ    $102F    ; SCI-data

***************************
*        data area        *
***************************

        org    data
flag    ds.b   1    ; irq flag

***************************
*      program area       *
***************************

        org    prog
main    lds    #stak    ; load stackpointer
        bsr    init     ; data init
        cli             ; enable irq

loop    ldaa    flag
        staa    pbdr    ; display
        bra     loop    ; close main loop

***************************
*       subroutines       *
***************************

init    clr    flag
        ldab   #$40     ; enable STRA interrupt
        stab   pioc
        ldab   #$40     ; enable PA7 interrupt
        stab   pacr
        ldab   #$10
        stab   tmsk
        rts

***************************
*    interrupt handler    *
***************************

sirq    ldaa    pioc    ; stra isr
        ldaa    pcdl    ; clear interrupt
        ldaa    flag
        eora    #$0F    ; toggle lower nibble
        staa    flag
        rti

pirq    ldaa    #$10    ; pa7 isr
        staa    tflg    ; clear interrupt
        ldaa    flag
        eora    #$F0    ; toggle upper nibble
        staa    flag
        rti

***************************
*         vectors         *
***************************

        org    pvec
        fdb    pirq    ; PA7 interrupt

        org    svec
        fdb    sirq    ; STRA

        org    rvec
        fdb    main    ; FE reset

        end

Demo für Interrupts an STRA, PA7 und Timer

data    equ    $2000    ; data area     (e-ram)
stak    equ    $7FFF    ; stack area    (e-ram)
prog    equ    $8000    ; programm area (e-eerom)

pvec    equ    $FFDA    ; vector pa7
tvec    equ    $FFDE    ; vector timer
svec    equ    $FFF2    ; sirq vector
rvec    equ    $FFFE    ; reset vector

pioc    equ    $1002    ; parallel i/o control
pbdr    equ    $1004    ; port b data
pcdl    equ    $1005    ; port c data latch
tmsk    equ    $1024    ; timer mask
tflg    equ    $1025    ; timer flag
pacr    equ    $1026    ; pulse accu control

***************************
*        data area        *
***************************

        org    data

coun    ds.b   1    ; counter
cflg    ds.b   1    ; clock flag
updn    ds.b   1    ; direction flag
stop    ds.b   1    ; stop flag

***************************
*      program area       *
***************************

        org    prog
main    lds    #stak    ; load stackpointer
        bsr    init     ; data init
        cli             ; enable irq

loop    ldaa    cflg    ; get clock flag
        cmpa    #20     ; trigger point?
        bne    loop     ; no, wait
        clr    cflg     ; yes, clear clock flag

        tst    stop     ; stop active?
        bne    loop     ; yes, wait
        bsr    count    ; update counter
        bra    loop     ; close main loop

***************************
*       subroutines       *
***************************

count   ldaa    coun    ; load counter
        adda    updn    ; inc/dec counter
        staa    coun    ; save counter
        staa    pbdr    ; display counter
        rts

init    clr    coun    ; counter default
        clr    cflg    ; no clock seen
        clr    stop
        ldaa   #1
        staa   updn    ; default count up


        ldab   #$40    ; enable STRA interrupt
        stab   pioc

        ldab   #$40    ; enable PA7 interrupt
        stab   pacr    ; enable pulse accu
        ldab   #$90    ; $80 (Timer) + $10 (PA7)
        stab   tmsk
        rts

***************************
*    interrupt handler    *
***************************

tirq    ldaa   #$80    ; timer isr
        staa   tflg    ; clear interrupt
        inc    cflg    ; count interrupts
        rti

sirq    ldaa   pioc    ; stra isr
        ldaa   pcdl    ; clear interrupt
        neg    updn    ; toggle direction
        rti

pirq    ldaa   #$10    ; pa7 isr
        staa   tflg    ; clear interrupt
        com    stop    ; toggle stop flag
        rti

***************************
*         vectors         *
***************************

        org    pvec
        fdb    pirq    ; PA7

        org    tvec
        fdb    tirq    ; timer overflow

        org    svec
        fdb    sirq    ; STRA

        org    rvec
        fdb    main    ; FE reset

        end

Statemachine

Kochrezeptartig kann man dabei folgenden Aufbau vornehmen:

Die folgendeGaragentorsteuerung demonstriert die Programmierung einer State Machine (Zustandsautomaten). Sehr vereinfacht gibt es nur vier Phasen: Tor offen (oben), Tor geschlossen (unten), Tor bewegt sich nach oben und Tor bewegt sich nach unten.

Im Hauptprogramm wird festgestellt, welcher Zustand aktuell eingenommen wird und dann das zugehörige "Aktions"-Unterprogramm aufgerufen. Im Unterprogramm erfolgen dann nicht nur die Ein- und Ausgaben, sondern es wird abhängig vom aktuellen Zustand und den äußeren Bedingungen (Eingabe von Port C) der Folgezustand eingestellt.

data      equ      $2000      ; data area     (e-ram)
stak      equ      $7FFF      ; stack area    (e-ram)
prog      equ      $8000      ; programm area (e-eerom)
rvec      equ      $FFFE      ; reset vector

pioc      equ      $1002      ; parallel i/o control
portb     equ      $1004      ; port b data
portcl    equ      $1005      ; port c data latch
portc     equ      $1003      ; port c data reg.
ddrc      equ      $1007      ; portc data dir. reg.

* Zustaende
oben      equ      0
abwaerts  equ      1
aufwaerts equ      2
unten     equ      3

* Ausgaenge Motor an Port B
Mup       equ      %00000001   ; Motor RL
Mdown     equ      %00000010   ; Motor LL

* Taster an Port C
Tup       equ      %00000001   ; Taste "auf"
Tdown     equ      %00000010   ; Taste "ab"
Eup       equ      %00000100   ; Endstellung "oben"
Edown     equ      %00001000   ; Endstellung "unten"

***************************
*        data area        *
***************************

          org      data
state     ds.b     1

***************************
*      program area       *
***************************
      org      prog
main  lds      #stak       ; init stack
      clr      ddrc        ; Port C Eingang    
      ldaa     portc
      anda     #Eup        ; Tor offen oder zu?
      beq      m2          ; nicht offen
      ldaa     #oben
      bra      m3
m2    ldaa     #unten      ; nicht offen = zu
m3    staa     state

; mainloop = statemachine
loop  jsr       display    ; Anzeige zum Testen
      jsr       delay
      ldaa      state      ; aktueller Status      
      cmpa      #oben      ; Tor offen?
      bne       abw        ; nein, weiter
      bsr       DoTop      ; Aktion und Statuswechsel ausfuehren
      bra       loop       
      
abw   cmpa      #abwaerts  ; Tor schliesst?
      bne       aufw       ; nein, weiter
      bsr       DoDown     ; Aktion und Statuswechsel ausfuehren
      bra       loop
      
aufw  cmpa      #aufwaerts ; Tor oeffnet?
      bne       tzu        ; nein, weiter
      bsr       DoUp       ; Aktion und Statuswechsel ausfuehren
      bra       loop
      
tzu   cmpa      #unten     ; Tor geschlossen?
      bne       loop       ; nein, zu loop (keine Fehlerbehandlung)
      bsr       DoBottom   ; Aktion und Statuswechsel ausfuehren
      bra       loop


* Aktion und Statuswechsel fuer "oben"
DoTop
      ldaa     portc       ; Schliessen gewuenscht?
      anda     #Tdown
      beq      Tope        ; nein
      ldaa     #Mdown      ; sonst Motor auf LL
      staa     portb
      ldaa     #abwaerts   ; Statuswechsel
      staa     state
Tope  rts

* Aktion und Statuswechsel fuer "unten"
DoBottom
      ldaa     portc       ; Oeffnen gewuenscht?
      anda     #Tup
      beq      Bote        ; nein
      ldaa     #Mup        ; sonst Motor auf RL
      staa     portb
      ldaa     #aufwaerts  ; Statuswechsel
      staa     state
Bote  rts

* Aktion und Statuswechsel fuer "abwaerts"
DoDown
      ldaa     portc       ; Oeffnen gewuenscht?
      anda     #Tup
      beq      Dow1        ; nein
      ldaa     #Mup        ; sonst Motor auf RL
      staa     portb
      ldaa     #aufwaerts  ; Statuswechsel
      staa     state
      rts
Dow1  ldaa     portc       ; Endstellung erreicht?
      anda     #Edown      
      beq      Dow2        ; nein
      clr      portb       ; Motor stopp
      ldaa     #unten      ; Statuswechsel
      staa     state
Dow2  rts
      
* Aktion und Statuswechsel fuer "aufwaerts"
DoUp
      ldaa     portc       ; Schliessen gewuenscht?
      anda     #Tdown
      beq      Up1         ; nein
      ldaa     #Mdown      ; sonst Motor auf LL
      staa     portb
      ldaa     #abwaerts   ; Statuswechsel
      staa     state
      rts
Up1   ldaa     portc       ; Endstellung erreicht?
      anda     #Eup      
      beq      Up2         ; nein
      clr      portb       ; Motor stopp
      ldaa     #oben       ; Statuswechsel
      staa     state
Up2   rts

* Zur Kontrolle den Status in den oberen 4 Bits von 
* Port B ausgeben
display                  
      ldaa     portb
      anda     #$0F        ; alten Wert ausblenden
      staa     portb       ; jetzt nur die Mototbits gesetzt
      ldaa     state       ; state shiften
      lsla
      lsla
      lsla
      lsla
      oraa     portb       ; state dazu-odern
      staa     portb
      rts
      
      
* Warteschleife, zentraler takt
delay pshx
      ldx       #$ffff
dely1 nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      dex
      bne      dely1
      pulx
      rts

* Reset-Vektor      
      org      rvec
      fdb      main    ; dc.w
      end

Zum vorhergehenden Abschnitt Zum Inhaltsverzeichnis Zum nächsten Abschnitt


Copyright © FH München, FB 04, Prof. Jürgen Plate
Letzte Aktualisierung: 01. Mai 2012