![]() |
|||
| HSG |
|
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 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 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 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.
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