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