HSG

Aktuelle Seite: HSG/Fächer/Informatik/ MSR/PIC

Uhr0

In einer Schleife wird nach einer Sekunde Wartezeit der PortB 1 hochgesetzt. wait1s ist hier ein Unterprogramm (Befehle: call, return).

           processor pic16f877a
           include   p16f877a.inc
           __config  _HS_OSC & _WDT_OFF & _PWRTE_ON

;Variablen
ZAEHL1                equ     0x20            ; Hilfsvariable für Warte-Routine
ZAEHL2                equ     0x21            ; Hilfsvariable für Warte-Routine
ZAEHL3                equ     0x22            ; Hilfsvariable für Warte-Routine

                      org     0x00

RESET:                clrf    STATUS
                      movlw   0x00
                      movwf   PCLATH
                      goto    main

                      org     0x10

;------------------------------------------------------------------
;Warte-Routine 1,000000 s bei 8,000000 MHz
wait1s:
                      movlw   d'93'
                      movwf   ZAEHL1
                      movlw   d'38'
                      movwf   ZAEHL2
                      movlw   d'11'
                      movwf   ZAEHL3      ; größte Wertigkeit
tloop1s:
                      decfsz  ZAEHL1
                      goto    tloop1s
                      decfsz  ZAEHL2
                      goto    tloop1s
                      decfsz  ZAEHL3
                      goto    tloop1s
                      return
;------------------------------------------------------------------

main:
                      ;Port-Setup
                      bsf     STATUS,5     ; wechsle zu Bank 1
                      movlw   b'00000000'  ; setze Port B, Bit 0-7
                      movwf   TRISB        ; als Ausgang
                      bcf     STATUS,5     ; wieder in Bank 0 wechseln

loop:
                      call    wait1s
                      incf    PORTB,1
                      goto    loop
                      end

Uhr1

Uhr1 zeigt wie der Sekundenzähler bei einem bestimmten Wert, hier zum Test bei 10, später bei 59 auf Null zurückgestellt werden kann. Allgemein sieht man, wie in PIC-Assembler ein Test auf Gleichheit programmiert werden kann.

           processor pic16f877a
           include   p16f877a.inc
           __config  _HS_OSC & _WDT_OFF & _PWRTE_ON

;Variablen
ZAEHL1                equ     0x20         ; Hilfsvariable für Warte-Routine
ZAEHL2                equ     0x21         ; Hilfsvariable für Warte-Routine
ZAEHL3                equ     0x22         ; Hilfsvariable für Warte-Routine

s                     equ     0x24         ; Sekunden

                      org 0x00

RESET:                clrf    STATUS
                      movlw   0x00
                      movwf   PCLATH
                      goto    main

                      org 0x10

;------------------------------------------------------------------
;Warte-Routine 1,000000 s bei 8,000000 MHz
wait1s:
                      movlw   d'93'
                      movwf   ZAEHL1
                      movlw   d'38'
                      movwf   ZAEHL2
                      movlw   d'11'
                      movwf   ZAEHL3       ; größte Wertigkeit
tloop1s:
                      decfsz  ZAEHL1
                      goto    tloop1s
                      decfsz  ZAEHL2
                      goto    tloop1s
                      decfsz  ZAEHL3
                      goto    tloop1s
                      return
;------------------------------------------------------------------


main:
                        ;Port-Setup
                      bsf     STATUS,5     ; wechsle zu Bank 1
                      movlw   b'00000000'  ; setze Port B, Bit 0-7
                      movwf   TRISB        ; als Ausgang
                      bcf     STATUS,5     ; wieder in Bank 0 wechseln
                      clrf    s            ; s -> 0
loop:
                       ; Ausgabe von s auf B
                      movf    s,0          ; s -> w
                      movwf   PORTB        ; w -> B
                        ; warten
                      call    wait1s
                        ; PORTB = d'10' ?
                      bcf     STATUS,Z     ; Zero-Flag löschen
                      movf    s,0          ; s -> w
                      sublw   d'10'        ; 10-w -> w
                      btfsc   STATUS,Z     ; Z-Flag testen, skip if clear
                      goto    s59
                      goto    sxx
s59:
                      clrf    s
                      goto    loop
sxx:
                      incf    s
                      goto    loop
                      end

Uhr2

Uhr2 erweitert Uhr1 um die Minuten und Stunden. Man sieht, wie ein Überlauf bei den Sekunden die Minuten, bei den Minuten die Stunden triggert. Die Ausgabe erfolgt immer noch auf Port B.

           processor pic16f877a
           include   p16f877a.inc
           __config  _HS_OSC & _WDT_OFF & _PWRTE_ON

;Variablen
ZAEHL1                equ     0x20         ; Hilfsvariable für Warte-Routine
ZAEHL2                equ     0x21         ; Hilfsvariable für Warte-Routine
ZAEHL3                equ     0x22         ; Hilfsvariable für Warte-Routine

s                     equ     0x24         ; Sekunden
m                     equ     0x25         ; Minuten
h                     equ     0x26         ; Stunden

                      org 0x00

RESET:                clrf    STATUS
                      movlw   0x00
                      movwf   PCLATH
                      goto    main

                      org 0x10

;------------------------------------------------------------------
;Warte-Routine 1,000000 s bei 8,000000 MHz
wait1s:
                      movlw   d'93'
                      movwf   ZAEHL1
                      movlw   d'38'
                      movwf   ZAEHL2
                      movlw   d'11'
                      movwf   ZAEHL3       ; größte Wertigkeit
tloop1s:
                      decfsz  ZAEHL1
                      goto    tloop1s
                      decfsz  ZAEHL2
                      goto    tloop1s
                      decfsz  ZAEHL3
                      goto    tloop1s
                      return
;------------------------------------------------------------------
; Sekunde hochzählen
incs:
                      ; s = d'59' ?
                      bcf     STATUS,Z     ; Zero-Flag löschen
                      movf    s,0          ; s -> w
                      sublw   d'59'        ; 10-w -> w
                      btfsc   STATUS,Z     ; Z-Flag testen, skip if clear
                      goto    s59
                      goto    sxx
s59:
                      clrf    s
                      call    incm
                      return
sxx:
                      incf    s
                      return
;------------------------------------------------------------------
; Minute hochzählen
incm:
                      ; m = d'59' ?
                      bcf     STATUS,Z     ; Zero-Flag löschen
                      movf    m,0          ; m -> w
                      sublw   d'59'        ; 10-w -> w
                      btfsc   STATUS,Z     ; Z-Flag testen, skip if clear
                      goto    m59
                      goto    mxx
m59:
                      clrf    m
                      call    inch
                      return
mxx:
                      incf    m
                      return
;------------------------------------------------------------------
; Stunde hochzählen
inch:
                      ; h = d'23' ?
                      bcf     STATUS,Z     ; Zero-Flag löschen
                      movf    h,0          ; h -> w
                      sublw   d'23'        ; 23-w -> w
                      btfsc   STATUS,Z     ; Z-Flag testen, skip if clear
                      goto    h23
                      goto    hxx
h23:
                      clrf    h
                      return
hxx:
                      incf    h
                      return
;------------------------------------------------------------------


main:
                      ;Port-Setup
                      bsf     STATUS,5     ; wechsle zu Bank 1
                      movlw   b'00000000'  ; setze Port B, Bit 0-7
                      movwf   TRISB        ; als Ausgang
                      bcf     STATUS,5     ; wieder in Bank 0 wechseln
                      clrf    s            ; s -> 0
                      clrf    m            ; m -> 0
                      clrf    h            ; h -> 0
loop:
                      ; Ausgabe von h auf B
                      movf    h,0          ; h -> w
                      movwf PORTB         ; w -> B
                      ; warten
                      call    wait1s
                      ; Sekunde hochzählen
                      call    incs
                      goto    loop
                      end

Uhr3

Uhr3 integriert die kompletten LCD-Routinen und gibt die Uhrzeit auf dem Display aus. Gleichzeitig werden die Sekunden auf Port B ausgegeben. Die Warte-Routine wurde mit Hilfe der 'Stop-watch' von MPLab auf eine loop-Zeit von etwa einer Sekunde eingestellt. Dabei wurden Mehrfach-Überträge nicht berücksichtigt. Die Muster-Uhr hatte damit eine Abweichung von weniger als 2 Sekunden pro Tag. Die Ausgabe auf dem Display macht eine Zerlegung einer Binärzahl in Zehner und Einer erforderlich. Die Unterroutine 'ascii' zeigt auch, wie eine Kleiner-Bedingung abgeprüft werden kann.

uhr3.asm, uhr3.HEX

        processor pic16f877a
        include   p16f877a.inc
        __config  _HS_OSC & _WDT_OFF & _PWRTE_ON

;Variablen
ZAEHL1                equ 0x20        ; Hilfsvariable für Warte-Routine
ZAEHL2                equ 0x21        ; Hilfsvariable für Warte-Routine
ZAEHL3                equ 0x22        ; Hilfsvariable für Warte-Routine
Save                  equ 0x23        ; zum Zwischenspeichern

s                     equ 0x24        ; Sekunden
m                     equ 0x25        ; Minuten
h                     equ 0x26        ; Stunden
byte                  equ 0x27        ; umzuwandelndes Byte
e                     equ 0x28        ; Einerstelle in ASCII
z                     equ 0x29        ; Zehnerstelle in ASCII

;Konstanten
LCDPort               equ PORTD
Enable                equ 0x3
RW                    equ 0x2
RS                    equ 0x1

        org 0x00

RESET:                clrf    STATUS
                      movlw   0x00
                      movwf   PCLATH
                      goto    main

        org 0x10

;------------------------------------------------------------------
;Warte-Routine 15,6 ms bei 8 MHz
wait15ms:             movlw   d'132'
                      movwf   ZAEHL1
                      movlw   d'41'
                      movwf   ZAEHL2
tloop15ms:
                      decfsz  ZAEHL1,F
                      goto    tloop15ms
                      decfsz  ZAEHL2,F
                      goto    tloop15ms
                      return
;-------------------------------------------------------------------
;Warte-Routine 4,2 ms bei 8 MHz
wait4ms:
                      movlw   d'232'
                      movwf   ZAEHL1
                      movlw   d'11'
                      movwf   ZAEHL2
tloop4ms:
                      decfsz  ZAEHL1,F
                      goto    tloop4ms
                      decfsz  ZAEHL2,F
                      goto    tloop4ms
                      return
;--------------------------------------------------------------------
;Warte-Routine 2ms bei 8 MHz
wait2ms:
                      movlw   d'48'
                      movwf   ZAEHL1
                      movlw   d'6'
                      movwf   ZAEHL2
tloop2ms:
                      decfsz  ZAEHL1,F
                      goto    tloop2ms
                      decfsz  ZAEHL2,F
                      goto    tloop2ms
                      return
;----------------------------------------------------------------------
;Warte-Routine 100us bei 8 MHz
wait100us:
                      movlw   d'65'
                      movwf   ZAEHL1
                      movlw   d'1'
                      movwf   ZAEHL2
tloop100us:
                      decfsz  ZAEHL1,F
                      goto    tloop100us
                      decfsz  ZAEHL2,F
                      goto    tloop100us
                      return
;-----------------------------------------------------------------------
; Warte-Routine 41us bei 8 MHz
wait40us:
                      movlw   d'27'
                      movwf   ZAEHL1
tloop40us:
                      decfsz  ZAEHL1,F
                      goto    tloop40us
                      return
;------------------------------------------------------------------------
; Inhalt von w an LCD senden (C - Control, Kommando)
LCDsendC:
                      movwf   Save          ; bewahrt das ankommende Byte auf
                                         ; obere Hälfte
                      call    LCDsndI       ; LCDsndI erledigt die Maskierung
                      call    wait40us      ; 40us warten
                                         ; untere Hälfte
                      swapf   Save,W         ; D0-D3 aus Save --> D4-D7 in w
                      call    LCDsndI        ; LCDsndI erledigt die Maskierung
                      call    wait2ms        ; 2ms warten
                      return
;-----------------------------------------------------------------------
; Inhalt von w an LCD senden (D - Daten)
LCDsendD:
                      movwf   Save           ; bewahrt das ankommende Byte auf
                                             ; obere Hälfte
                      call    LCDsndD        ; LCDsndD erledigt die Maskierung
                      call    wait40us       ; 40us warten
                                       ; untere Hälfte
                      swapf   Save,W         ; D0-D3 aus Save --> D4-D7 in w
                      call    LCDsndD        ; LCDsndD erledigt die Maskierung
                      call    wait2ms        ; 2ms warten
                      return
;------------------------------------------------------------------------
; sendet ein Daten-Nibble zum Display
LCDsndD:
                      andlw    b'11110000'    ; nur die oberen 4 Bits nutzen, RW=0
                      iorlw    b'00000010'    ; RS=1 (Daten)
                      goto     $+2            ; LCDsndI überspringen
; ------------------------------------------------------------------------
; sendet ein Kommando-Nibble zum Display
LCDsndI:
                      andlw    b'11110000'    ; nur die oberen 4 Bits nutzen, RW=0, RS=0
; ------------------------------------------------------------------------
; jetzt werden die Daten gesendet
                      movwf    LCDPort        ; Daten --> LCDPort
                      bsf      LCDPort,Enable ; Enable-Bit setzen
                      nop                     ; 450ns warten
                      bcf      LCDPort,Enable ; Enable-Bit löschen
                      nop                     ; 450ns warten
                      return
;--------------------------------------------------------------------------
; Display löschen
LCDclr:
                      movlw    b'00000001'
                      call     LCDsendC
                      call     wait2ms
                      return
;--------------------------------------------------------------------------
;Initialisierung des LCD-Displays
LCDinit:
                        errorlevel        -302        ; unterdrücke Fehlermeldung
; PORTD Bit 1-7 als Ausgang
                      bsf      STATUS,5        ; wechsle zu Bank1
                      movlw    b'00000001'     ; setze Port D, Bit 1-7
                      movwf    TRISD           ; als Ausgang
                      bcf      STATUS,5        ; wieder in Bank 0 wechseln
                         errorlevel        +302       ; erlaube Fehlermeldung
; 15ms warten
                      call     wait15ms
; 8-Bit-Modus einschalten
                      movlw    b'00110000'        ;0011 senden, D1=RS=0, D2=RW=0
                      movwf    LCDPort
                      bsf      LCDPort,Enable
                      nop
                      bcf      LCDPort,Enable
; 4,1ms warten
                      call     wait4ms
; 8-Bit-Modus einschalten
                      movlw    b'00110000'        ;0011 senden, D1=RS=0, D2=RW=0
                      movwf    LCDPort
                      bsf      LCDPort,Enable
                      nop
                      bcf      LCDPort,Enable
; 100us warten
                      call     wait100us
; 8-Bit-Modus einschalten
                      movlw    b'00110000'        ;0011 senden, D1=RS=0, D2=RW=0
                      movwf    LCDPort
                      bsf      LCDPort,Enable
                      nop
                      bcf      LCDPort,Enable
; 100us warten
                      call     wait100us          ;100us warten
; 4-Bit-Modus einschalten
                      movlw    b'00100000'        ;0010 senden, D1=RS=0, D2=RW=0
                      movwf    LCDPort
                      bsf      LCDPort,Enable
                      nop
                      bcf      LCDPort,Enable
; 100us warten
                      call     wait100us          ;100us warten
; 2-zeilig, 5x8-Matrix
                      movlw    b'00101000'
                      call     LCDsendC
; Display aus
                      movlw    b'00001000'
                      call     LCDsendC
; Display löschen
                      call     LCDclr
; Cursor nach rechts wandernd, kein Shift
                      movlw    b'00000010'
                      call     LCDsendC
; Display ein
                      movlw    b'00001100'
                      call     LCDsendC
                      return
;------------------------------------------------

;-------------------------------------------------

;Port-Setup
                      errorlevel        -302      ; unterdrücke Fehlermeldung
                      bsf      STATUS,5           ; wechsle zu Bank1
                      movlw    b'00000000'        ; setze Port B, Bit 0-7
                      movwf    TRISB              ; als Ausgang
                      bcf      STATUS,5           ; wieder in Bank 0 wechseln
                      errorlevel        +302      ; erlaube Fehlermeldung


;------------------------------------------------------------------
;Warte-Routine ca. 0,98 s bei 8,000000 MHz
wait1s:
                      movlw    d'208'             ; 93 für 1s
                      movwf    ZAEHL1
                      movlw    d'240'             ; 38 für 1s
                      movwf    ZAEHL2
                      movlw    d'10'              ; 11 für 1s
                      movwf    ZAEHL3             ; größte Wertigkeit
tloop1s:
                      decfsz   ZAEHL1
                      goto     tloop1s
                      decfsz   ZAEHL2
                      goto     tloop1s
                      decfsz   ZAEHL3
                      goto     tloop1s
                      return

;------------------------------------------------------------------
; Sekunde hochzählen
incs:
                       ; s = d'59' ?
                      bcf      STATUS,Z           ; Zero-Flag löschen
                      movf     s,0                ; s -> w
                      sublw    d'59'              ; 10-w -> w
                      btfsc    STATUS,Z           ; Z-Flag testen, skip if clear
                      goto     s59
                      goto     sxx
s59:
                      clrf     s
                      call     incm
                      return
sxx:
                      incf     s
                      return
;------------------------------------------------------------------
; Minute hochzählen
incm:
                        ; m = d'59' ?
                      bcf      STATUS,Z            ; Zero-Flag löschen
                      movf     m,0                 ; m -> w
                      sublw    d'59'               ; 10-w -> w
                      btfsc    STATUS,Z            ; Z-Flag testen, skip if clear
                      goto     m59
                      goto     mxx
m59:
                      clrf     m
                      call     inch
                      return
mxx:
                      incf     m
                      return
;------------------------------------------------------------------
; Stunde hochzählen
inch:
                        ; h = d'23' ?
                      bcf      STATUS,Z            ; Zero-Flag löschen
                      movf     h,0                 ; h -> w
                      sublw    d'23'               ; 23-w -> w
                      btfsc    STATUS,Z            ; Z-Flag testen, skip if clear
                      goto     h23
                      goto     hxx
h23:
                      clrf     h
                      return
hxx:
                      incf     h
                      return
;------------------------------------------------------------------
; byte in ASCII
ascii:
                      movlw    d'0'                ; z -> 0
                      movwf    z
                      movf     byte,0              ; byte -> e
                      movwf    e
                      bsf      STATUS,C            ; Carry-Flag setzen
ascloop:
                      movlw    d'10'               ; 10 -> w
                      subwf    e,0                 ; e-w -> w
                      btfsc    STATUS,C            ; Carry-Flag wird bei Unterlauf gelöscht
                      goto     ascweiter
                      goto     ascunterlauf
ascweiter:
                      movlw    d'10'               ; 10 -> w
                      subwf    e,1                 ; e-w -> e
                      incf     z                   ; z+1 -> z
                      goto     ascloop
ascunterlauf:
                      movlw    d'48'               ; ASCII-Offset
                      addwf    e,1
                      addwf    z,1
                      return
; --------------------------------------------


main:
                      call     LCDinit
                      movlw    a'U'
                      call     LCDsendD
                      movlw    a'h'
                      call     LCDsendD
                      movlw    a'r'
                      call     LCDsendD

                      ;Port-Setup
                      bsf      STATUS,5            ; wechsle zu Bank 1
                      movlw    b'00000000'         ; setze Port B, Bit 0-7
                      movwf    TRISB               ; als Ausgang
                      bcf      STATUS,5            ; wieder in Bank 0 wechseln
                      ; Uhr stellen
                      movlw    d'13'               ;
                      movwf    h                   ; 00 -> h
                      movlw    d'10'               ;
                      movwf    m                   ; 00 -> m
                      movlw    d'00'               ;
                      movwf    s                   ; 00 -> s

loop:
                      ; Ausgabe von s auf PortB
                      movf     s,0
                      movwf    PORTB
                      ; Ausgabe von h:m:s auf LCD
                      movf     h,0                 ; s -> w
                      movwf    byte                ; w -> byte
                      call     ascii
                      movf     z,0                 ; e -> w
                      call     LCDsendD
                      movf     e,0                 ; z -> w
                      call     LCDsendD
                      ; Ausgabe von ':'
                      movlw    a':'
                      call     LCDsendD
                      ; Ausgabe von m auf LCD
                      movf     m,0                 ; s -> w
                      movwf    byte                ; w -> byte
                      call     ascii
                      movf     z,0                 ; e -> w
                      call     LCDsendD
                      movf     e,0                 ; z -> w
                      call     LCDsendD
                      ; Ausgabe von ':'
                      movlw    a':'
                      call     LCDsendD
                      ; Ausgabe von s auf LCD
                      movf     s,0                 ; s -> w
                      movwf    byte                ; w -> byte
                      call     ascii
                      movf     z,0                 ; e -> w
                      call     LCDsendD
                      movf     e,0                 ; z -> w
                      call     LCDsendD
                      ; warten
                      call     wait1s
                      ; LCD löschen
                      call     LCDclr
                      ; Sekunde hochzählen
                      call     incs
                      goto     loop
                      end

Links