| Assembler-Beispiele für PIC-Controller
|
|
Das Prinzip des gesamtes Programms:
Jede Millisekunde wird von Timer 0 und Timer 2 ein Interrupt ausgelöst. Einige PIC's haben keinen
Timer 2; es geht auch mit nur einem Timer. Timer 0 muss in der ISR immer neu geladen werden,
Timer 2 verfügt über ein Reload-Register, welches nur 1 mal geladen wird.
Dieses Programm kann mit jedem ASCII-Terminal-Programm kommunizieren. Die Kommunikation erfolgt über die
asynchrone serielle Schnittstelle des PIC mit 9600 Baud, 8 Bit, ohne Parität
und besteht aus Kommandos, beginnend mit einem Kennbuchstaben oder Kennwort, gefolgt
von weiteren Parametern. Ein Kommando ohne Parameter führt zur Ausgabe der aktuellen Werte.
Alle ankommenden Bytes lösen einen Interrupt aus und werden von der ISR in einem Empfangs-Ring-Puffer
abgelegt. Von dort können sie "bei Gelegenheit" entnommen und weiter verarbeitet werden.
Ausgabe-Bytes werden in einem Sende-Ring-Puffer abgelegt. Jede Millisekunde wird in der ISR
überprüft, ob Bytes zum Versenden abgelegt wurden und ggf. an die USART übergeben.
|
; Programm-Anfang
|
list P=16f877, E=1, R=DEC ; Prozessortyp, Errorlevel und Zahlenformat
include "p16f877.inc" ; Registerdefinitionen einbinden
errorlevel 1 ; Meldungen ignorieren
__CONFIG _CP_OFF & _WDT_OFF & _XT_OSC & _PWRTE_ON & _LVP_OFF
Debug set 0 ; 0 = Debug aus
; 1 = Debug ein
;1234567 Stellen
#DEFINE Version "Prog_10 " ; <=== hier die Version aendern
;tt.mm.jj
#DEFINE Datum "14.10.05" ; <=== hier das Datum aendern
; ===============================================================
; Makros
; ===============================================================
M_Bank0 macro
bcf STATUS,RP0 ; Bank 0
bcf STATUS,RP1
endm
M_Bank1 macro
bsf STATUS,RP0 ; Bank 1
bcf STATUS,RP1
endm
M_Page0 macro
bcf PCLATH,3 ; Rom-Page 0
bcf PCLATH,4
endm
M_Page1 macro
bsf PCLATH,3 ; Rom-Page 1
bcf PCLATH,4
endm
; ---------------------------
; Makro: MOV FileReg to FileReg
; ---------------------------
M_movff macro VonFileReg,NachFileReg
movfw VonFileReg
movwf NachFileReg
endm
; ---------------------------
; Makro: MOV Literal to FileReg
; ---------------------------
M_movlf macro Literal,NachFileReg
movlw Literal
movwf NachFileReg
endm
; ---------------------------
; Makro: Bit-Toggle
; ---------------------------
M_BitTog macro VarAdr,BitNr
movlw 1<<BitNr ; 1 auf Bit-Position schieben
xorwf VarAdr
endm
; ===============================================================
; Definitionen
; ===============================================================
#DEFINE D_GlobIntEin bsf INTCON,GIE ; Globaler Interrupt Ein
#DEFINE D_GlobIntAus bcf INTCON,GIE ; Globaler Interrupt Aus
#DEFINE D_PeriIntEin bsf INTCON,PEIE ; Peripherer Interrupt Ein
#DEFINE D_PeriIntAus bcf INTCON,PEIE ; Peripherer Interrupt Aus
#DEFINE _C STATUS,0
#DEFINE _Z STATUS,2
#DEFINE skip_0 btfsc ; ... Bit ; Ueberspringe, wenn Bit = 0
#DEFINE skip_1 btfss ; ... Bit ; Ueberspringe, wenn Bit = 1
#DEFINE skip_NC btfsc STATUS,0 ; Ueberspringe, wenn Carry = 0
#DEFINE skip_C btfss STATUS,0 ; Ueberspringe, wenn Carry = 1
#DEFINE skip_NZ btfsc STATUS,2 ; Ueberspringe, wenn Zero = 0
#DEFINE skip_Z btfss STATUS,2 ; Ueberspringe, wenn Zero = 1
; ===============================================================
; Konstanten
; ===============================================================
cr EQU 0x0D ; Return
lf EQU 0x0A ; LineFeed
hk EQU 0x22 ; Hochkommas
klauf EQU "<"
klzu EQU ">"
Ptime EQU 50 ; 50 ms Prellzeit
; ===============================================================
; Variablen-Deklarationen
; ===============================================================
RamBeg0 EQU 0x20 ; Beginn Ram-Bereich
; ---------------------------
; Register fuer Mathe-Routinen
; ---------------------------
MathErgA0 EQU 0x20 ; Ergebnis (DoubleWord)
MathErgA1 EQU 0x21
MathArgA0 EQU 0x22 ; Argument A (Word)
MathArgA1 EQU 0x23
MathArgB0 EQU 0x24 ; Argument B (Word)
MathArgB1 EQU 0x25
MathTemp0 EQU 0x26 ; Temporaer
MathTemp1 EQU 0x27
MathZlr EQU 0x28 ; SchleifenZaehler
; ---------------------------
; Zaehl-Register fuer Datum und Uhrzeit
; ---------------------------
zSek EQU 0x2A ; Sekunden 0...59
zMin EQU 0x2B ; Minuten 0...59
zStd EQU 0x2C ; Stunden 0...23
zTag EQU 0x2D ; Tag 0...28/29/30/31
zMon EQU 0x2E ; Monat 0...12
zJahr EQU 0x2F ; Jahr 0...99
; ---------------------------
; Zaehler- und Timer-Register
; ---------------------------
z1ms EQU 0x30 ; Inc-Zaehler 1 ms-Takt
z10ms EQU 0x31 ; Dec-Zaehler 10 ms-Takt
z100ms EQU 0x32 ; Dec-Zaehler 100 ms-Takt
t10ms EQU 0x35 ; Dec-Timer 10 ms
t100ms EQU 0x36 ; Dec-Timer 100 ms
t1Sek EQU 0x37 ; Dec-Timer 1 Sek
zTast1 EQU 0x38 ; PrellZaehler fuer Taster
zTast2 EQU 0x39 ; PrellZaehler fuer Taster
; ... usw.
; ---------------------------
; Flag-Deklarationen
; ---------------------------
Flags0 EQU 0x40
#DEFINE F_OK Flags0,0 ; Flag OK = 1 / nicht OK = 0
#DEFINE F_Ret Flags0,1 ; Flag CR
#DEFINE F_Semi Flags0,2 ; Flag Semikolon
#DEFINE F_CmdE Flags0,3 ; Flag Cmd-Puffer Ende
#DEFINE F_Fmt Flags0,4 ; 1=Ziffern formatiert senden
#DEFINE F_Zif Flags0,5 ; 1=Ziffer 1...9 gesendet
#DEFINE F_Neg Flags0,6 ; 1=Negativer Wert
Flags1 EQU 0x41
#DEFINE F_Sek Flags1,0 ; 1=Uhr / Datum aktualisieren
F_Blink EQU 1 ; Flag Blinker 100 ms
FlgTast EQU 0x42
#DEFINE fTast1 FlgTast,1 ; Flag Taster betaetigt = 1
#DEFINE fTast2 FlgTast,2
; ... usw.
; ---------------------------
; Register fuer Aktuelle Ein-/Ausg-Zustaende
; ---------------------------
aAdw1 EQU 0x43 ; Akt Analog/Digital-Wert 1
aAdw2 EQU 0x44 ; Akt Analog/Digital-Wert 2
aAdw3 EQU 0x45 ; Akt Analog/Digital-Wert 3
; ---------------------------
; Temporaere Register
; ---------------------------
Temp1 EQU 0x49 ; Temporaer (nicht fuer Interrupt)
Temp2 EQU 0x4A
Temp3 EQU 0x4B
Para1 EQU 0x4C ; Temporaer Parameter
Para2 EQU 0x4D
Para3 EQU 0x4E
CmdByte EQU 0x4F ; Temporaer bei Cmd-Auswertung
; ---------------------------
; Konfigurations-Daten
; ---------------------------
RamParam EQU 0x50
; ---------------------------
; Zeiger-Register
; ---------------------------
RxDOfs EQU 0x60 ; Offset RxD-RingPuffer
RxDPos EQU 0x61 ; Position RxD-RingPuffer
TxDOfs EQU 0x62 ; Offset TxD-RingPuffer
TxDPos EQU 0x63 ; Position TxD-RingPuffer
TxDAnz EQU 0x64 ; Anzahl Bytes im TxD-Puffer
CmdPos EQU 0x65 ; Position Cmd-Puffer
; ---------------------------
; Von Bank 0 erreichbar
; ---------------------------
iBakSTAT EQU 0x6D ; Interrupt Backup Status
iBakPCL EQU 0x6E ; Interrupt Backup Rom-Page (PCLATH)
iBakFSR EQU 0x6F ; Interrupt Backup Ind-Adresse
RamEnd0 EQU 0x70 ; Ende Ram-Bereich
; ---------------------------
; General Purpose Register
; Von Bank 0...3 erreichbar (0x71...0x7F) !
; ACHTUNG !!! 0x70 ist bei Verwendung von MPLAB ICD belegt
; ---------------------------
iBakW EQU 0x71 ; Interrupt Backup W-Register
izUni EQU 0x72 ; Interrupt Universeller Zaehler
zUni EQU 0x73 ; Universeller Zaehler
AddrL EQU 0x74 ; Addresse Low fuer Flash & Eeprom
AddrH EQU 0x75 ; Addresse High fuer Flash
EepByte EQU 0x76 ; Byte aus Flash & Eeprom
iTemp1 EQU 0x7A ; Temporaer im Interrupt
iTemp2 EQU 0x7B
iTemp3 EQU 0x7C
; ===============================================================
; Register in Bank 1
; ===============================================================
; ---------------------------
; Kommando-Puffer fuer max 60 Byte
; ---------------------------
CmdLen EQU 60 ; Puffer fuer 60 Byte
CmdPuf EQU 0xB4 ; Adresse 0xB4 bis 0xEF
; ===============================================================
; Register in Bank 2
; ===============================================================
; ---------------------------
; RingPuffer fuer RxD
; ---------------------------
RxDLen EQU 80 ; Puffer fuer 80 Byte
RxDPuf EQU 0x110 ; Adresse 0x110 bis 0x16F
; ===============================================================
; Register in Bank 3
; ===============================================================
; ---------------------------
; RingPuffer fuer TxD
; ---------------------------
TxDLen EQU 80 ; Puffer fuer 80 Byte
TxDPuf EQU 0x190 ; Adresse 0x190 bis 0x1EF
| ; ***************************************************************
; PROGRAMM-BEGINN
; ***************************************************************
org 0x0000 ; 00h Reset-Vektor |
Reset clrf STATUS ; 00h Page 0, Bank 0
goto Init ; 01h Initialisierung / ProgrammBeginn
goto Reset ; 02h Reset-Vektor
goto Reset ; 03h Reset-Vektor
;; goto Interrupt ; 04h Interrupt-Vektor
;; Kein GOTO !!!, falls Int in Rom-Page <> 0 ausgeloest wurde
; ACHTUNG ! Hier muss die InterruptServiceRoutine beginnen !! |
org 0x0004 ; 04h Interrupt-Vektor
; ***************************************************************
; Interrupt-Service-Routine ISR
; Ausloesung durch Receive
; Ausloesung durch Timer 2 / PR2 (Ausloesung jede MilliSekunde)
; Ausloesung durch Timer 0 (Ausloesung jede MilliSekunde)
; Benutzt: iBakW, iBakSTAT (iBakPCL, iBakFSR)
; *************************************************************** |
Isr ; W und STATUS immer retten
movwf iBakW ; W retten nach iBakW
swapf STATUS,W ; Status mit swap nach W
clrf STATUS ; Bank 0
movwf iBakSTAT ; Status retten ohne Veraenderung
; wenn PCLATH in der ISR benutzt wird:
movfw PCLATH ; Rom-Page (PCLATH) retten
movwf iBakPCL
clrf PCLATH ; Auf Rom-Page 0 schalten
; wenn FSR in der ISR benutzt wird:
movfw FSR
movwf iBakFSR
; ---------------------------
; Die Isr wird erst verlassen, wenn auch die Interrupts
; verarbeitet sind, deren xxxIF waehrend der Isr gesetzt wurde.
; Weitere Backup und Restore von W, STATUS, etc. werden damit eingespart.
; ---------------------------
Isr_TestIF bcf STATUS,RP0 ; Bank 0, falls nach xxxIE-Abfrage auf Bank 1
skip_0 INTCON,T0IF ; ... T0IF ist nicht gesetzt
goto Isr_TMR0 ; ... ist gesetzt
skip_0 PIR1,TMR2IF ; ... TMR2IF ist nicht gesetzt
goto Isr_TMR2 ; ... ist gesetzt
skip_0 PIE1,RCIF ; ... RCIF ist nicht gesetzt
goto Isr_RC ; ... ist gesetzt
Isr_Ende
; wenn FSR in der ISR benutzt wird:
movfw iBakFSR
movwf FSR
; wenn PCLATH in der ISR benutzt wird:
movfw iBakPCL ; Rom-Page (PCLATH) zurueck
movwf PCLATH
; STATUS und W immer restaurieren
swapf iBakSTAT,W ; Statusregister und W zurueck
movwf STATUS
swapf iBakW,F ; swapf veraendert kein Flag
swapf iBakW,W
retfie
; ===============================================================
; ISR Timer 0 (Aufruf jede Millisekunde)
; ===============================================================
Isr_TMR0 bcf INTCON,T0IF ; Int-Flag ruecksetzen
M_movlf 256-yyy,TMR0 ; Timer 0 neu laden
; yyy: siehe Tabelle bei Init Timer 0
skip_1 INTCON,T0IE ; ... Timer 0-Interrupt ist enabled
goto Isr_TestIF ; ... ist nicht enabled
call SioTxD ; evtl. Byte seriell ausgeben
call RdAdw ; A/D-Wandler einlesen
; ... weitere Befehle (1 ms)
decfsz z1ms,F ; ... 1 ms-Zaehler - 1 = 0
goto Isr_TestIF ; ... sonst Ende
; ---------------------------
; Aufruf alle 10 ms
; ---------------------------
Int10ms M_movlf 10,z1ms ; 1 ms-Zaehler = 10 (= 10 ms)
movfw t10ms ; 10 ms-Timer = 0 ?
skip_Z ; ... ja
decf t10ms ; ... sonst - 1
; ... weitere Befehle (10 ms)
decfsz z10ms,F ; ... 10 ms-Zaehler - 1 = 0
goto Isr_TestIF ; ... sonst Ende
; ---------------------------
; Aufruf alle 100 ms
; ---------------------------
M_movlf 10,z10ms ; 10 ms-Zaehler = 10 (= 100 ms)
movfw t100ms ; 100 ms-Timer = 0 ?
skip_Z ; ... ja
decf t100ms ; ... sonst - 1
; ---------------------------
; 100 ms-Blinker
; ---------------------------
M_BitTog Flags1,F_Blink ; Blinker-Flag togglen
; ... weitere Befehle (100 ms)
decfsz z100ms ; ... 100 ms-Zaehler - 1 = 0
goto Isr_TestIF ; ... sonst Ende
; ---------------------------
; Aufruf jede Sekunde
; ---------------------------
M_movlf 10,z100ms ; 100 ms-Zaehler = 10 (= 1 Sek)
movf t1Sek ; 1 Sek-Timer laden
skip_Z ; ... = 0
decf t1Sek ; ... sonst - 1
bsf F_Sek ; Uhrzeit und Datum aktualisieren
movfw TxDAnz ; Evtl. Anzahl verringern, falls nichts gesendet wird
skip_Z ; ... ist schon 0
decf TxDAnz ; ... sonst - 1
; ... weitere Befehle (1 Sek)
goto Isr_TestIF
; ===============================================================
; ISR Timer 2 (Aufruf jede MilliSekunde)
; Beispiel zum Entprellen von Tastern
; Fuer jeden Taster muss ein Zaehler (zTast1...x) und ein Flag (fTast1...x) definiert werden
;
; xxxIE braucht nur dann getestet werden, wenn der Interrupt zeitweise deaktiviert wird
; ===============================================================
Isr_TMR2 bcf PIR1,TMR2IF ; Int-Flag ruecksetzen
bsf STATUS,RP0 ; Bank 1
skip_1 PIE1,TMR2IE ; ... Timer 2-Interrupt ist enabled
goto Isr_TestIF ; ... ist nicht enabled
bcf STATUS,RP0 ; Bank 0
EntprTast1 skip_0 PORTB,1 ; ... Taster 1 ist betaetigt (Eing = 0)
goto EntprTast1_1 ; ... Taster 1 ist nicht betaetigt (Eing = 1)
; ---------------------------
; Taster ist betaetigt; Zaehler bis 76 incrementieren
; ---------------------------
movlw 75
subwf zTast1,W ; Ist Zaehler > 75 / Carry = 1 ?
skip_C ; ... ja
incf zTast1 ; ... sonst: Zaehler + 1
goto EntprTast2
; ACHTUNG !!! Bei SUB ist C und DC invertiert !!!
; Berechnung: F bzw. L minus W genauer gesagt: F bzw. L plus 2-er-Complement von W
; Wenn W > L bzw. F, dann Carry = 0 / Wenn L bzw. F <= W, dann Carry = 0
; Wenn W <= L bzw. F, dann Carry = 1 / Wenn L bzw. F > W, dann Carry = 1
; ---------------------------
; Taster ist nicht betaetigt; Zaehler bis 0 decrementieren
; ---------------------------
EntprTast1_1 movfw zTast1 ; Ist Zaehler auf 0 / Zero = 1 ?
skip_Z ; ja
decf zTast1 ; ... sonst: Zaehler - 1
; ---------------------------
; Taster-Flag bei <= 50 ruecksetzen / > 50 setzen
; ---------------------------
EntprTast1_2 bcf fTast1 ; Flag erst mal ruecksetzen
movlw 50
subwf zTast1,W ; Ist Zaehler <= 50 / Carry = 0 ?
skip_NC ; ja
bsf fTast1 ; ... sonst: Flag setzen
; ---------------------------
; Naechster Taster
; ---------------------------
EntprTast2 skip_0 PORTB,2 ; ... Taster 2 ist betaetigt (Eing = 0)
goto EntprTast2_1 ; ... Taster 2 ist nicht betaetigt (Eing = 1)
; ...
EntprTast2_1
; ... usw. fuer jeden Taster
; ... weitere Befehle
goto Isr_TestIF
; ===============================================================
; ISR Receive (Sio RxD)
; ===============================================================
Isr_RC ;; bcf PIR1,RCIF ; geht nicht ! RCIF und TXIF sind nur zum Lesen
movfw RCREG ; Empfangsbyte laden, dabei wird RCIF geloescht
movwf iTemp1 ; Byte retten
bsf STATUS,RP0 ; Bank 1
btfss PIE1,RCIE ; ... Receive-Interrupt ist enabled ?
goto Isr_TestIF ; ... ist nicht enabled
bcf STATUS,RP0 ; Bank 0
call SioRxD ; Byte im Ringpuffer ablegen
goto Isr_TestIF
| ; ===============================================================
; Initialisierung
; =============================================================== |
Init M_Bank0 ; Bank 0
clrf INTCON ; Alle Interrupts sperren
M_Page0 ; auf Rom-Page 0 schalten
clrwdt ; Clear WDT and postscaler
movlw 255 ; Alle Ports auf 1 setzen,
movwf PORTB ; damit beim Setzen der TRIS-Register
; definierte Zustaende am Port sind
; ... weitere Port-Pins setzen
; -----------------------------------------------
; USART Receive (Bank 0)
; ------76543210---------------------------------
movlw 10010000b ; (Bank 0) Receive Status
movwf RCSTA ; bit 7 = 1 SPEN (RC7=Rx und RC6=Tx)
; bit 4 = 1 CREN
; -----------------------------------------------
; ADCON0 (Bank 0) AD Control-Register 0 :
; 7-6 A/D Conversion Clock 00=Fosc/2 / 01=Fosc/8 / 10=Fosc/32 / 11=RCosci
; 5-3 Analog Channel 000=AN0 (RA0) ... 111=AN7
; 2 A/D Conversion bit 0=DONE# / 1=GO
; 1 -
; 0 A/D On bit
; ------76543210---------------------------------
movlw 10000101b
; 10 = Fosc/32
; 000 = Analog Channel 0
; 1 = GO
; 1 = ADON
movwf ADCON0
M_Bank1 ; Bank 1
; -------------------------------------
; RA0/ANA0 In/Analog
; RA1/ANA1 In/Analog
; RA2 ST-In
; RA3/ANA3 In/Analog
; RA4/T0CKI ST-In
; RA5 ST-In
; RA6 ---
; RA7 ---
; ------76543210---------------------------------
movlw 00111111b ; PortA 6 x Eingang
movwf TRISA
; -----------------------------------------------
; ADCON1 (Bank 1) AD Control-Register 1 :
; 7 Result Format 8 Bits in ADRESH / 2 Bits in ADRESL(7..6 000000)
; 6-4 -
; 3-0 Port Config
; an7 an6 an5 AN4 AN3 AN2 AN1 AN0 Ref+ Ref-
; Bits re2 re1 re0 RA5 RA3 RA2 RA1 RA0
; 0000 A A A A A A A A Vdd Vss
; 0001 A A A A Ref+ A A A RA3 Vss
; 0010 D D D A A A A A Vdd Vss
; 0011 D D D A Ref+ A A A RA3 Vss
; ** 0100 D D D D A D A A Vdd Vss
; 0101 D D D D Ref+ D A A RA3 Vss
; 011x D D D D D D D D Vdd Vss
; 1000 A A A A Ref+ Ref- A A RA3 RA2
; 1001 D D A A A A A A Vdd Vss
; 1010 D D A A Ref+ A A A RA3 Vss
; 1011 D D A A Ref+ Ref- A A RA3 RA2
; 1100 D D D A Ref+ Ref- A A RA3 RA2
; 1101 D D D D Ref+ Ref- A A RA3 RA2
; 1110 D D D D D D D A Vdd Vss
; 1111 D D D D Ref+ Ref- D A RA3 RA2
; ------76543210---------------------------------
movlw 00000010b
; 0 = Result format = Left
; 0100 = Analog RA0,RA1&RA3
movwf ADCON1
; -----------------------------------------------
; TRISB (Bank 1) Richtungen
; RB0/INT In Eingang Int
; RB1 Out Ausgang 1
; RB2 Out Ausgang 2
; RB3/PGM In ICD1
; RB4 Out Ausgang 3
; RB5 Out Ausgang 4
; RB6/PGC In ICD1
; RB7/PGD In ICD1
; ------76543210---------------------------------
movlw 11001001b ; 0=Ausgang / 1=Eingang
movwf TRISB
; ... weitere Richtungen konfigurieren
; -----------------------------------------------
; USART, Timer, IntEnable (Bank 1)
; ------76543210---------------------------------
movlw 00100100b ; (Bank 1) Transmit Status
movwf TXSTA ; bit 5 = 1 TXEN Transmitter Freigabe
; bit 4 = 0 SYNC Asynchronous
; bit 2 = 1 BRGH High Speed
; bit 0 = 0 no Parity
movlw 64 ; Baudrate = 10,24 MHz / (16 * (65 + 1)) = 9696,969697 Baud
movwf SPBRG ; (Bank 1) BaudrateGenerator
movlw K_1msT2
movwf PR2 ; (Bank 1) 1 ms-Wert fuer Timer 2 setzen
; ------76543210---------------------------------
movlw 00100010b ; (Bank 1) Interrupt enable = 1 / disable = 0
movwf PIE1 ; bit 7 = 0 PSIPIE Parallel Slave Port
; bit 6 = 0 ADIE A/D Converter
; bit 5 = 1 RCIE USART Receive
; bit 4 = 0 TXIE USART Transmit
; bit 3 = 0 SSPIE Synch Serial Port
; bit 2 = 0 CCP1IE CCP1
; bit 1 = 1 TMR2IE Timer 2
; bit 0 = 0 TMR1IE Timer 1
bsf PCON,NOT_POR ; (Bank 1) PowerOnReset Bit ruecksetzen (=1)
; -----------------------------------------------
; OPTION_REG (Bank 1) Options-Register:
; 7 GPIO pull up 0=enabled / 1=disabled
; 6 Int Edg Sel 0=fallende / 1=steigende Flanke an GP2/INT
; 5 T0 Clk Source 0=intern CLKOUT / 1=extern GP2/T0CKI
; 4 T0 Src Edg Sel 0=Low to High / High to Low Increment an GP2/T0CKI pin
; 3 Prescaler Ass 0=TMR0 / 1=WDT
; 2-0 Prescaler 000=1:2 ... 111=1:256 TMR0
; 000=1:1 ... 111=1:128 WDT
; -----------------------------------------------
; 1 ; Pull Up = disabled
; 0 ; Interrupt = fallende Flanke
; 0 ; TMR0-Quelle = intern CLKOUT
; 0 ; Flanke = Low To High
; 0 ; Prescaler Ass = TMR0
; xxx ; Prescaler
; -----------------------------------------------
movlw 10000xxxb ; Select TMR0, prescale, and clock source
; Quarz-Frequenz ... Timer 0 Prescaler xxx ... Timer 0 Wert yyy (256 - yyy)
; Quarz F/4 Prescaler TMR0 ISR
; [Hz] [Hz] = [us] xxx = [ms] yyy [ms]
; 20.000.000 5.000.000 0,2 100 = /32 0,0064 156 0,9984
; 10.240.000 2.560.000 0,390625 011 = /16 0,00625 160 1
; 10.000.000 2.500.000 0,4 011 = /16 0,0064 156 0,9984
; 4.000.000 1.000.000 1 001 = / 4 0,004 250 1
; 2.000.000 500.000 2 000 = / 2 0,004 250 1
yyy EQU 160 ; Quarz 10,24 MHz
movwf OPTION_REG
bcf STATUS,RP0 ; Bank 0
; ... sonst noch was in Bank 1 ?
M_Bank0 ; Bank 0
clrf TMR0 ; Timer 0 loeschen
clrf TMR1L ; Timer 1 loeschen
clrf TMR1H
; -----------------------------------------------
; T2CON (Bank 0) Timer 2 Control-Register:
; 7 -
; 6-3 Postscale 0000=1:1 ... 1111=1:16 Postscale
; 2 TimerOnBit 1=On / 0=Off
; 1-0 Prescale 00=1:1 / 01=1:4 / 1x=1:16
; (Fosc / 4 = 10,24 MHz / 4 = 2,56 MHz = 0,390625 µs)
; Timer 2 / PR2 (8 Bit) wird fuer 1 ms-Interrupt benutzt
; ------76543210---------------------------------
movlw 00100101b
; 01 ; Prescale = 4 * 0,3906250 µs = 0,0015625 ms
; 0100 ; Postscale = 5 * 0,0015625 ms = 0,0078125 ms
K_1msT2 EQU 128 ; Timer-Wert = 128 * 0,0078125 ms = 1,0000000 ms
; 1 ; TimerOn = Ein
movwf T2CON
; -----------------------------------------------
; T1CON (Bank 0) Timer 1 Control-Register:
; 7-6 -
; 5-4 Prescale 11=1:8 / 10=1:4 / 01=1:2 / 00=1:1
; 3 Osci Enable 1=enabled / 0=shut off
; 2 Ext Clk Sync
; 1 Clk Source 1=Extern (RC0) / 0=Intern
; 0 TimerOnBit 1=On / 0=Off
; (Fosc / 4 = 10,24 MHz / 4 = 2,56 MHz = 0,390625 µs)
; Timer 1 (16 Bit)
; ------76543210---------------------------------
movlw 00100100b
; 10 ; Prescale = 4 * 0,390625 µs = 1,5625 µs
; 0 ; Osci = shut off
; 1 ; Ext Clk Sync = Aus
; 0 ; Clk Source = Intern
; 0 ; TimerOn = Aus
movwf T1CON
; ... weitere Initialisierungen
call ResRam ; Ram-Bereich auf 0 setzen
call ResCmdPuf ; Cmd-Puffer ruecksetzen
call RdEepKonf ; Konfig-Daten aus Eeprom lesen
M_movlf 9,z1ms
M_movlf 1,z10ms
M_movlf 1,z100ms
; ... weitere Variablen setzen
movlw 256-yyy ; Timer 0 setzen
; yyy: siehe Tabelle bei Init Timer 0
movwf TMR0
bcf INTCON,T0IF ; Timer 0 IntFlag ruecksetzen
bsf INTCON,T0IE ; Timer 0 IntEnable setzen
; ... weitere Peripherie und Interrupts aktivieren
D_PeriIntEin ; Periphere Interrupts freigeben
D_GlobIntEin ; Globalen Interrupt freigeben
movlw LOW(TxtSysErr_1) ; Kalt-Start
movwf AddrL
movlw HIGH(TxtSysErr_1)
movwf AddrH
call PrnCrLf ; cr/lf senden
call PrnStrF ; String senden
call PrnCrLf ; cr/lf senden
; ===============================================================
; HauptProgramm-Schleife
; ===============================================================
Main skip_0 F_Sek ; ... noch keine Sekunde vorbei
call UpdUhrDat ; ... sonst Sekunden + 1
; ---------------------------
; Command-Byte auswerten
; ---------------------------
movfw RxDPos ; CmdByte empfangen ?
subwf RxDOfs,W
skip_NZ ; ... ja
goto Main_5 ; ... nein
; ---------------------------
; ACHTUNG !!! Aufruf mit "goto Cmd_Ausw" und
; Ruecksprung mit "goto Main_5" wegen StackTiefe
; ---------------------------
goto Cmd_Ausw ; RxD-Byte speichern, evtl. Cmd-Puffer auswerten
Main_5
; ... weitere Befehle in der HauptProgramm-Schleife
goto Main ; Zum Anfang der Schleife
| ; ***************************************************************
; DIVERSE ROUTINEN
; ***************************************************************
| ; ===============================================================
; Ram-Bereich indirekt loeschen
; ===============================================================
ResRam movlw RamBeg0 ; Ram-Anfang
movwf FSR
bcf STATUS,IRP ; Bank 0 / 1
movlw RamEnd0-RamBeg0 ; Anzahl Adressen
movwf zUni
ResRam_3 clrf INDF ; Ram indirekt loeschen
incf FSR
decfsz zUni ; ... Zaehler - 1 = 0
goto ResRam_3
return
; ===============================================================
; A/D-Wandler einlesen und naechsten Kanal setzen
; A/D-Wandler starten
; Aufruf jede ms im Interrupt
; an7 an6 an5 AN4 AN3 AN2 AN1 AN0 Ref+ Ref-
; Bits re2 re1 re0 RA5 RA3 RA2 RA1 RA0
; ** 0100 D D D D A D A A Vdd Vss
; ===============================================================
RdAdw movlw HIGH(TblAdw)
movwf PCLATH
movfw z1ms ; Test auf 256 Byte Grenz-Überschreitung
addwf PCL,W
skip_NC ; ... kein Uebertrag
incf PCLATH ; ... PCH + 1
addlw 6 ; + 6 Befehle
skip_NC ; ... kein Uebertrag
incf PCLATH ; ... PCH + 1
movfw z1ms
TblAdw addwf PCL
return ; 0
goto RdAdw_1 ; 1
return ; 2
goto StartAdw ; 3
goto RdAdw_3 ; 4
return ; 5
goto StartAdw ; 6
goto RdAdw_0 ; 7
return ; 8
goto StartAdw ; 9
return ; 10
; ---------------------------
StartAdw bsf ADCON0,GO ;A/D-Wandler starten
return
; ---------------------------
RdAdw_0 movfw ADRESH ; AD-Wert laden
movwf aAdw1 ; und speichern
movlw 10000001b ; AD-Quelle auf Kanal RA0
; 10 = Fosc/32 A/D-Conversion
; 000 = Kanal 0
; 0 = Not GO
; 1 = ADON
movwf ADCON0 ; AD-Quelle setzen
return
; ---------------------------
RdAdw_1 movfw ADRESH ; AD-Wert laden
movwf aAdw2 ; und speichern
movlw 10001001b ; AD-Quelle auf Kanal RA1
; 001 = Kanal 1
movwf ADCON0 ; AD-Quelle setzen
return
; ---------------------------
RdAdw_3 movfw ADRESH ; AD-Wert laden
movwf aAdw3 ; und speichern
movlw 10011001b ; AD-Quelle auf Kanal RA3
; 011 = Kanal 3
movwf ADCON0 ; AD-Quelle setzen
return
; ===============================================================
; EmpfangsByte im RxD-Ringpuffer ablegen
; ===============================================================
SioRxD movfw iTemp1
sublw 0x0D ; Return ?
skip_NZ ; ... nein
goto SioRxD_1 ; ... ja: Return speichern
movfw iTemp1
sublw 0x0FF ; = 0x0FF ?
skip_NZ ; ... nein
return ; ... ja: verwerfen
movfw iTemp1
sublw 0x1F ; Byte > 0x1F ?
skip_NC ; ... ja
return ; ... nein: verwerfen
SioRxD_1 movlw LOW(RxDPuf) ; Puffer-Adresse
addwf RxDOfs,W ; plus Offset
movwf FSR ; fuer indirekte Adressierung
bsf STATUS,IRP ; Bank 2 / 3
movfw iTemp1 ; EmpfangsByte laden
movwf INDF ; und im Puffer ablegen
incf RxDOfs ; Offset + 1
movfw RxDOfs
sublw RxDLen-1 ; RxDOfs > RxDLen-1 ?
skip_C ; ... nein
clrf RxDOfs ; ... ja: Offset = 0
return
; ===============================================================
; SendeByte evtl. aus TxD-RingPuffer zum Senden in Transmit-Buffer ablegen
; Aufruf jede ms im Interrupt
; ===============================================================
SioTxD movfw TxDPos ; Byte zum Senden ?
subwf TxDOfs,W
skip_NZ ; ... ja
return ; ... nix zum Senden
skip_1 PIR1,TXIF ; ... sendebereit
return ; ... nicht sendebereit
movlw LOW(TxDPuf) ; Puffer-Adresse
addwf TxDOfs,W ; plus Offset
movwf FSR ; fuer indirekte Adressierung
bsf STATUS,IRP ; Bank 2 / 3
movfw INDF ; SendeByte aus Ringpuffer laden
movwf TXREG ; Byte senden (TXIF=0)
incf TxDOfs ; Offset + 1
movfw TxDOfs
sublw TxDLen-1 ; TxDOfs > TxDLen-1 ?
skip_C ; ... nein
clrf TxDOfs ; ... ja: Offset = 0
movfw TxDAnz ; 1 Byte weniger im TxD-Puffer
skip_Z ; ... ist schon 0
decf TxDAnz ; ... sonst - 1
return
; ===============================================================
; Datum und Uhrzeit + 1 Sekunde
; ===============================================================
UpdUhrDat bcf F_Sek ; Flag ruecksetzen
incf zSek ; Sekunden + 1
movfw zSek
sublw 59 ; zSek > 59 ?
skip_NC ; ... ja
return
clrf zSek ; Sekunden = 0
incf zMin ; Minuten + 1
movfw zMin
sublw 59 ; zMin > 59 ?
skip_NC ; ... ja
return
clrf zMin ; Minuten = 0
incf zStd ; Stunden + 1
movfw zStd
sublw 23 ; zStd > 23 ?
skip_NC ; ... ja
return
clrf zStd ; Stunden = 0
incf zTag ; Tage + 1
call AnzTage ; Anzahl Tage des Monats laden
subwf zTag,W ; zTag > Monatsende ?
skip_NC ; ... ja
return
M_movlf 1,zTag ; Tag = 1
incf zMon ; Monat + 1
movfw zMon
sublw 12 ; zMon > 12 ?
skip_NC ; ... ja
return
M_movlf 1,zMon ; Monat = 1
incf zJahr ; Jahr + 1
movfw zJahr
sublw 99 ; zJahr > 99 ?
skip_NC ; ... ja
return
clrf zJahr ; Jahr = 0
return
; ---------------------------------------------------------------
; Computed GOTO
; Anzahl Tage des Monats
; Eingang: zMon Monat 1...12
; zJahr Jahr 0...99
; Ausgang: W Anzahl Tage des Monats 28...31
; ---------------------------------------------------------------
AnzTage movwf Temp0 ; Monat retten
movlw HIGH(TblTage)
movwf PCLATH
movfw Temp0 ; Test auf 256 Byte Grenz-Überschreitung
addwf PCL,W
skip_NC ; ... kein Uebertrag
incf PCLATH ; ... PCH + 1
addlw 6 ; + 6 Befehle
skip_NC ; ... kein Uebertrag
incf PCLATH ; ... PCH + 1
movfw Temp0
TblTage addwf PCL
retlw 31
goto GetTageFeb
retlw 31
retlw 30
retlw 31
retlw 30
retlw 31
retlw 31
retlw 30
retlw 31
retlw 30
retlw 31
GetTageFeb movfw zJahr
andlw 00000011b ; Schaltjahr ?
btfss STATUS,Z ; ... ja
retlw 28
retlw 29
| ; ***************************************************************
; KOMMANDO-STRING-AUSWERTUNG
; ***************************************************************
| ; ===============================================================
; Cmd-Puffer ruecksetzen
; ===============================================================
ResCmdPuf M_Bank1
clrf CmdPuf
M_Bank0
clrf CmdPos
return
; ===============================================================
; RxD-Byte in Cmd-Puffer ablegen
; Bei CR Cmd-Puffer auswerten
; ===============================================================
Cmd_Ausw call GetRxDByte ; Byte aus RxD-Puffer laden
; ---------------------------
; Byte auf CR testen
; ---------------------------
movfw CmdByte ; Byte laden
sublw 0x0D ; CR ?
skip_NZ ; ... nein
goto Cmd_Ret
; ---------------------------
; Byte auf Doppelpunkt testen
; ---------------------------
movfw CmdByte ; Byte laden
sublw ":" ; Doppelpunkt ?
skip_NZ ; ... nein
goto Cmd_Ret
; ---------------------------
; Byte auf Semikolon testen
; ---------------------------
movfw CmdByte ; Byte laden
sublw ";" ; Semikolon ?
skip_NZ ; ... nein
goto Cmd_Semi
; ---------------------------
; Kommentar verwerfen
; ---------------------------
skip_0 F_Semi ; ... kein Kommentar
goto Cmd_Ausw_E ; ... sonst verwerfen
goto Cmd_Ausw_1 ; Byte speichern
; ---------------------------
; Bei CR Flag setzen und 0 speichern
; ---------------------------
Cmd_Ret bsf F_Ret ; Kommando ausfuehren
bcf F_Semi ; Alles ruecksetzen
clrf CmdByte ; Null anfuegen
goto Cmd_Ausw_1
; ---------------------------
; Bei Semikolon Flag setzen
; ---------------------------
Cmd_Semi bsf F_Semi ; Ab jetzt Kommentar, alles verwerfen
goto Cmd_Ausw_E
; ---------------------------
; Byte im Cmd-Puffer ablegen
; ---------------------------
Cmd_Ausw_1 movlw CmdPuf ; Cmd-Puffer-Adresse
addwf CmdPos,W ; plus Offset
movwf FSR ; fuer indirekte Adressierung
bcf STATUS,IRP ; Bank 0 / 1
movfw CmdByte ; Cmd-Byte laden
movwf INDF ; und im Cmd-Puffer ablegen
movfw CmdPos
sublw CmdLen-2 ; CmdPos > CmdLen-2 ?
skip_NC ; ... ja
incf CmdPos ; ... nein: Offset + 1
; ---------------------------
; Nach CR oder Doppelpunkt Kommando ausfuehren
; ---------------------------
skip_1 F_Ret ; ... es war CR / Doppelpunkt
goto Cmd_Ausw_E
bcf F_Ret ; Flag ruecksetzen
clrf CmdPos ; Offset = 0
call SuchA_Z ; Cmd-Buchstabe suchen
skip_1 F_OK ; ... gefunden
goto PrnCmdErr_1 ; ... nicht gefunden
movlw HIGH(TblCmd)
movwf PCLATH
movlw "A" ; Test auf 256 Byte Grenz-Überschreitung
subwf CmdByte,W ; Offset berechnen
addlw 8 ; + 8 Befehle
skip_NC ; ... kein Uebertrag
incf PCLATH ; ... PCH + 1
addwf PCL,W ; + PCL
skip_NC ; ... kein Uebertrag
incf PCLATH ; ... PCH + 1
movlw "A" ; Tabellen-Offset berechnen
subwf CmdByte,W ; F - W --> W
TblCmd addwf PCL
goto PrnCmdErr_2 ; A
goto PrnCmdErr_2 ; B
goto PrnCmdErr_2 ; C
goto Cmd_Datum ; D Datum
goto PrnCmdErr_2 ; E
goto PrnCmdErr_2 ;*F -- Fehler
goto PrnCmdErr_2 ; G
goto Cmd_Hilfe ; H Hilfe
goto PrnCmdErr_2 ; I
goto PrnCmdErr_2 ; J
goto PrnCmdErr_2 ; K
goto PrnCmdErr_2 ; L
goto PrnCmdErr_2 ; M
goto PrnCmdErr_2 ; N
goto PrnCmdErr_2 ; O
goto PrnCmdErr_2 ; P
goto PrnCmdErr_2 ; Q
goto PrnCmdErr_2 ; R
goto PrnCmdErr_2 ; S
goto PrnCmdErr_2 ; T
goto Cmd_Uhr ; U Uhrzeit
goto Cmd_Vers ; V Version des Programms
goto PrnCmdErr_2 ; W
goto PrnCmdErr_2 ; X
goto PrnCmdErr_2 ; Y
goto PrnCmdErr_2 ; Z
; ---------------------------------------------------------------
Cmd_Fertig call ResCmdPuf
Cmd_Ausw_E goto Main_5
; ---------------------------------------------------------------
; FehlerMeldungen
; ---------------------------------------------------------------
PrnCmdErr_1 movlw LOW(TxtCmdErr_1) ; Kommando fehlt
movwf AddrL
movlw HIGH(TxtCmdErr_1)
goto PrnCmdErr
PrnCmdErr_2 movlw LOW(TxtCmdErr_2) ; Kommando falsch
movwf AddrL
movlw HIGH(TxtCmdErr_2)
goto PrnCmdErr
PrnCmdErr_3 movlw LOW(TxtCmdErr_3) ; Parameter falsch
movwf AddrL
movlw HIGH(TxtCmdErr_3)
goto PrnCmdErr
PrnCmdErr_4 movlw LOW(TxtCmdErr_4) ; Parameter zu klein
movwf AddrL
movlw HIGH(TxtCmdErr_4)
goto PrnCmdErr
PrnCmdErr_5 movlw LOW(TxtCmdErr_5) ; Parameter zu gross
movwf AddrL
movlw HIGH(TxtCmdErr_5)
goto PrnCmdErr
PrnCmdErr_6 movlw LOW(TxtCmdErr_6) ; Bestaetigung falsch
movwf AddrL
movlw HIGH(TxtCmdErr_6)
goto PrnCmdErr
PrnCmdErr_7 movlw LOW(TxtCmdErr_7) ; frei
movwf AddrL
movlw HIGH(TxtCmdErr_7)
PrnCmdErr movwf AddrH
call PrnStrF ; String senden
call PrnCrLf ; cr/lf senden
goto Cmd_Fertig
; ===============================================================
; D - Datum D Tag Mon Jahr
; ===============================================================
Cmd_Datum call Such0_9 ; Tag
skip_1 F_OK ; ... gefunden
goto Cmd_Datum_7 ; ... Uhrzeit senden
movwf Para1 ; Tag retten
movfw Para1 ; = 0 ?
skip_NZ ; ... nein
goto PrnCmdErr_4 ; ... Parameter zu klein
sublw 31 ; > 31 ?
skip_C ; ... nein
goto PrnCmdErr_5 ; ... Parameter zu gross
; ---------------------------
call Such0_9 ; Monat
skip_1 F_OK ; ... gefunden
goto PrnCmdErr_3
movwf Para2 ; Monat retten
movfw Para2 ; = 0 ?
skip_NZ ; ... nein
goto PrnCmdErr_4 ; ... Parameter zu klein
sublw 12 ; > 12 ?
skip_C ; ... nein
goto PrnCmdErr_5
; ---------------------------
call Such0_9 ; Jahr
skip_1 F_OK ; ... gefunden
goto PrnCmdErr_3
movwf Para3 ; Jahr retten
sublw 99 ; > 99 ?
skip_C ; ... nein
goto PrnCmdErr_5
; ---------------------------
M_movff Para1,zTag ; Tag speichern
M_movff Para2,zMon ; Monat speichern
M_movff Para3,zJahr ; Jahr speichern
; ---------------------------
; Datum senden
; ---------------------------
Cmd_Datum_7 call PrnDDatum
call PrnCrLf ; CR / LF senden
goto Cmd_Fertig
; ---------------------------
; "D" und Datum senden
; ---------------------------
PrnDDatum movlw "D"
call PrnChr ; D senden
call PrnSpc ; Leerzeichen senden
PrnDatum movfw zTag ; Tag senden
call PrnZif2
call PrnPkt ; Punkt senden
movfw zMon ; Monat senden
call PrnZif2
call PrnPkt ; Punkt senden
movfw zJahr ; Jahr senden
goto PrnZif2
; ===============================================================
; H - Hilfe
; ===============================================================
Cmd_Hilfe movlw LOW(TxtHilfe)
movwf AddrL
movlw HIGH(TxtHilfe)
movwf AddrH
call PrnStrF
goto Cmd_Fertig
; ===============================================================
; U - Uhrzeit U Std Min Sek
; ===============================================================
Cmd_Uhr call Such0_9 ; Stunden
skip_1 F_OK ; ... gefunden
goto Cmd_Uhr_7 ; ... Uhrzeit senden
movwf Para1 ; Stunden retten
sublw 23 ; > 23 ?
skip_C ; ... nein
goto PrnCmdErr_5
; ---------------------------
call Such0_9 ; Minuten
skip_1 F_OK ; ... gefunden
goto Cmd_Uhr_3 ; Minuten und Sek = 0
movwf Para2 ; Minuten retten
sublw 59 ; > 59 ?
skip_C ; ... nein
goto PrnCmdErr_5
; ---------------------------
call Such0_9 ; Sekunden
skip_1 F_OK ; ... gefunden
goto Cmd_Uhr_4 ; Sekunden = 0
movwf Para3 ; Sekunden retten
sublw 59 ; > 59 ?
skip_C ; ... nein
goto PrnCmdErr_5
goto Cmd_Uhr_5
; ---------------------------
Cmd_Uhr_3 clrf Para3 ; Sekunden = 0
Cmd_Uhr_4 clrf Para2 ; Minuten = 0
Cmd_Uhr_5 M_movff Para1,zStd ; Stunden speichern
M_movff Para2,zMin ; Minuten speichern
M_movff Para3,zSek ; Sekunden speichern
; ---------------------------
; Uhrzeit senden
; ---------------------------
Cmd_Uhr_7 call PrnUUhr ; U und Uhrzeit senden
call PrnCrLf ; CR / LF senden
goto Cmd_Fertig
; ---------------------------
; "U" und Uhrzeit senden
; ---------------------------
PrnUUhr movlw "U"
call PrnChr ; Cmd senden
call PrnSpc ; Leerzeichen senden
PrnUhr movfw zStd ; Stunden senden
call PrnZif2
call PrnPkt ; Punkt senden
movfw zMin ; Minuten senden
call PrnZif2
call PrnPkt ; Punkt senden
movfw zSek ; Sekunden senden
goto PrnZif2
; ===============================================================
; V - Version des Programms
; ===============================================================
Cmd_Vers movlw LOW(TxtVers)
movwf AddrL
movlw HIGH(TxtVers)
movwf AddrH
call PrnStrF
goto Cmd_Fertig
; ===============================================================
; Buchstabe suchen
; Eingang: CmdPos Cmd-Position
; Ausgang: W & CmdByte ASCII-Buchstabe A...Z
; F_OK 0=kein Buchstabe / 1=Buchstabe gefunden
; F_CmdE 1=Cmd-Puffer zu Ende
; ===============================================================
SuchA_Z bcf F_OK ; Erst mal nix gefunden
SuchA_Z_1 call GetCmdByte ; Cmd-Byte aus Cmd-Puffer laden
skip_0 F_CmdE ; ... Cmd-Puffer noch nicht zu Ende
retlw 0x0FF
movfw CmdByte ; Cmd-Byte zurueck
sublw "?" ; = "?"
skip_NZ ; ... nein
goto SuchA_Z__ ; ... ja: Cmd gefunden
movfw CmdByte ; Cmd-Byte zurueck
sublw "A"-1 ; > "A"-1
skip_NC ; ... ja
goto SuchA_Z_1 ; ... nein: Naechster
movfw CmdByte ; Cmd-Byte zurueck
sublw "Z" ; > "Z"
skip_NC ; ... ja
goto SuchA_Z_Ok ; ... nein: A...Z
movfw CmdByte ; Cmd-Byte zurueck
sublw "a"-1 ; > "a"-1
skip_NC ; ... ja
goto SuchA_Z_1 ; ... nein: Naechster
movfw CmdByte ; Cmd-Byte zurueck
sublw "z" ; > "z"
skip_C ; ... nein
goto SuchA_Z_1 ; ... ja: Naechster
SuchA_Z_Ok movfw CmdByte ; Cmd-Byte zurueck
andlw 01011111b ; Klein nach Gross
movwf CmdByte
SuchA_Z__ bsf F_OK ; OK
return
; ===============================================================
; Ziffer suchen (0...255)
; Eingang: CmdPos Cmd-Position
; Ausgang: W & CmdByte Wert 0...255
; F_OK 0=keine Ziffern / 1=Ziffern gefunden
; F_CmdE 1=Cmd-Puffer zu Ende
; ===============================================================
Such0_9 bcf F_OK ; Erst mal nix gefunden
clrf MathArgA0 ; Wert erst mal 0
; ---------------------------
; 1. Ziffer suchen
; ---------------------------
Such0_9_1 call GetCmdByte ; Cmd-Byte aus Cmd-Puffer laden
skip_0 F_CmdE ; ... Cmd-Puffer noch nicht zu Ende
retlw 0x0FF
movfw CmdByte
sublw "0"-1 ; > "0"-1
skip_NC ; ... ja
goto Such0_9_1 ; ... nein: Naechster
movfw CmdByte
sublw "9" ; > "9"
skip_C ; ... nein
goto Such0_9_1 ; ... ja: Naechster
; ---------------------------
; Bisheriger Wert * 10
; Neuen Wert addieren
; ---------------------------
Such0_9_2 call Mulu0810 ; Bisheriger Wert * 10
movfw MathErgA1 ; HighByte = 0 ?
skip_Z ; ... ja
goto PrnCmdErr_5 ; ... Wert zu gross
movlw "0" ; F - W
subwf CmdByte,W ; ASCII nach Bin
addwf MathErgA0,W ; Bisheriger Wert + neuer Wert
movwf MathArgA0 ; und retten
skip_NC ; ... kein Übertrag
goto PrnCmdErr_5 ; ... Wert zu gross
; ---------------------------
; Naechste Ziffer suchen
; ---------------------------
call GetCmdByte ; Cmd-Byte aus Cmd-Puffer laden
skip_0 F_CmdE ; ... Cmd-Puffer noch nicht zu Ende
goto Such0_9_Ok ; ... ja: Ende
movfw CmdByte
sublw "0"-1 ; > "0"-1
skip_NC ; ... ja
goto Such0_9_Ok ; ... nein: Ende
movfw CmdByte
sublw "9" ; > "9"
skip_NC ; ... ja
goto Such0_9_2 ; ... nein: addieren
Such0_9_Ok bsf F_OK ; OK
movfw MathArgA0 ; Wert nach W & CmdByte
movwf CmdByte
return
; ===============================================================
; Byte aus Cmd-Puffer laden
; Eingang: CmdPos Cmd-Position
; Ausgang: CmdByte Byte
; F_CmdE 1=Cmd-Puffer Ende
; Benutzt: FSR, INDF
; ===============================================================
GetCmdByte bsf F_CmdE ; Puffer erst mal zu Ende
movfw CmdPos
sublw CmdLen-1 ; CmdPos > CmdLen-1 ?
skip_C ; ... nein
retlw 0x0FF
movlw CmdPuf ; Cmd-Puffer-Adresse
addwf CmdPos,W ; plus Offset
movwf FSR ; fuer indirekte Adressierung
bcf STATUS,IRP ; Bank 0 / 1
movfw INDF ; Cmd-Byte laden
movwf CmdByte ; und retten
skip_NZ ; ... Cmd-Byte <> 0: kein Cmd-Ende
retlw 0x0FF
bcf F_CmdE ; Puffer nicht zu Ende
incf CmdPos ; Offset + 1
return
; ===============================================================
; Byte aus RxD-Puffer laden
; Eingang: RxDPos RxD-Position
; Ausgang: CmdByte Byte
; RxDPos + 1 oder 0
; Benutzt: FSR, INDF
; ===============================================================
GetRxDByte movlw LOW(RxDPuf) ; RxD-Puffer-Adresse
addwf RxDPos,W ; plus Offset
movwf FSR ; fuer indirekte Adressierung
bsf STATUS,IRP ; Bank 2 / 3
movfw INDF ; Byte aus RxD-Puffer laden
movwf CmdByte ; und retten
incf RxDPos ; Offset + 1
movfw RxDPos
sublw RxDLen-1 ; RxDPos > RxDLen-1 ?
skip_C ; ... nein
clrf RxDPos ; ... ja: Offset = 0
return
; ===============================================================
; ASCII-ZEICHEN-AUSGABE
; ===============================================================
PrnTrenn movlw " " ; Leerzeichen senden
call PrnChr
movlw ":" ; Doppelpunkt senden
call PrnChr
movlw " " ; Leerzeichen senden
goto PrnChr
PrnCrLf movlw 0x0D ; CR
call PrnChr
movlw 0x0A ; LF
goto PrnChr
; ---------------------------
; Ziffern-Ausgabe in ASCII
; ---------------------------
PrnZif0_9 bsf F_Zif ; 1...9 gesendet
addlw "0" ; + ASCII-0
goto PrnChr ; Ziffer senden
; ---------------------------
; Ziffern-Ausgabe formatiert / unformatiert
; ---------------------------
FmtZif addlw 0 ; Wert = 0 ?
skip_Z ; ... ja
goto PrnZif0_9 ; ... sonst Ziffer senden
skip_0 F_Zif ; ... noch keine Ziffer gesendet
goto PrnZif0_9 ; ... sonst Ziffer senden
FmtSpc skip_1 F_Fmt ; ... Leerzeichen senden
return ; ... sonst nix senden
PrnSpc movlw " " ; Leerzeichen
goto PrnChr
; ---------------------------
PrnPkt movlw "." ; Punkt
goto PrnChr
PrnDpkt movlw ":" ; DoppelPunkt
goto PrnChr
PrnSemi movlw ";" ; Semikolon
goto PrnChr
PrnStern movlw "*" ; Stern
goto PrnChr
PrnKlauf movlw klauf ; Klammer auf
goto PrnChr
PrnKlzu movlw klzu ; Klammer zu
goto PrnChr
; ===============================================================
; Byte senden (im TxD-Puffer ablegen)
; Eingang: W Charakter (Byte)
; Ausgang: TxDPos + 1 oder 0
; TxDAnz + 1
; Benutzt: MathTemp1, FSR, INDF
; ===============================================================
PrnChr movwf MathTemp1 ; Byte retten
PrnChr_1 movfw TxDAnz ; TxD-Puffer voll ?
sublw TxDLen-4 ; TxDAnz > TxDLen-4 ?
skip_C ; ... nein
goto PrnChr_1 ; ... sonst warten
incf TxDAnz ; Anzahl TxD + 1
movlw LOW(TxDPuf) ; Puffer-Adresse
addwf TxDPos,W ; plus Offset
movwf FSR ; fuer indirekte Adressierung
bsf STATUS,IRP ; Bank 2 / 3
movfw MathTemp1 ; Byte zurueck
movwf INDF ; und im Ringpuffer speichern
incf TxDPos ; Offset + 1
movfw TxDPos
sublw TxDLen-1 ; TxDPos > TxDLen-1 ?
skip_C ; ... nein
clrf TxDPos ; ... ja: Offset = 0
return
; ===============================================================
; String aus FlashSpeicher senden
; Eingang: AddrL FlashAdresse Low
; AddrH FlashAdresse High
; ===============================================================
PrnStrF call RdFlash ; Byte aus FlashSpeicher lesen
skip_NZ ; ... kein StringEnde
return
call PrnChr ; Byte senden
incf AddrL ; Addresse + 1
skip_NZ
incf AddrH
goto PrnStrF
; ===============================================================
; Ziffer 1-stellig dezimal senden
; Eingang: W Byte 0...9
; Wenn Byte > 9 ist, dann wird 1 Stern gesendet
; ===============================================================
PrnZif1 movwf MathArgA0 ; Byte ablegen
call Divu0810 ; MathArgA0 / 10
movfw MathErgA1 ; 100-er > 0 ?
skip_Z ; ... nein
goto PrnStern ; ... sonst Stern senden
movfw MathErgA0 ; 10-er > 0 ?
skip_Z ; ... nein
goto PrnStern ; ... sonst Stern senden
movfw MathArgA0 ; 1-er senden
goto PrnZif0_9
; ===============================================================
; Ziffer 2-stellig dezimal senden
; Eingang: W Byte 0...99
; Wenn Byte > 99 ist, dann werden 2 Sterne gesendet
; ===============================================================
PrnZif2 movwf MathArgA0 ; Byte ablegen
call Divu0810 ; MathArgA0 / 10
bcf F_Zif ; Erst mal keine 1...9 gesendet
movfw MathErgA1 ; 100-er = 0 ?
skip_Z ; ... ja
goto PrnZif2_8 ; ... sonst 2 Sterne senden
movfw MathErgA0 ; 10-er evtl. senden
call FmtZif
movfw MathArgA0 ; 1-er senden
goto PrnZif0_9
PrnZif2_8 call PrnStern
goto PrnStern
; ===============================================================
; Ziffer 3-stellig dezimal senden
; Eingang: W Byte 0...255
; ===============================================================
PrnZif3 movwf MathArgA0 ; Byte ablegen
call Divu0810 ; MathArgA0 / 10
bcf F_Zif ; Erst mal keine 1...9 gesendet
movfw MathErgA1 ; 100-er evtl. senden
call FmtZif
movfw MathErgA0 ; 10-er evtl. senden
call FmtZif
movfw MathArgA0 ; 1-er senden
goto PrnZif0_9
; ===============================================================
; Ziffer hexadezimal senden
; Eingang: W Byte 0...255
; ===============================================================
PrnZifH movwf MathArgA0 ; Byte retten
movlw "0" ; "0" senden
call PrnChr
movlw "x" ; "x" senden
call PrnChr
swapf MathArgA0,W ; HighNibbl laden
andlw 00001111b ; Bit 3...0 maskieren
addlw "0" ; = AsciiHighNibbl
movwf MathArgA1 ; und retten
sublw "9" ; > "9" ?
skip_NC ; ... ja
goto PrnZifH_1
movfw MathArgA1 ; AsciiHighNibbl zurueck
movlw 7 ; A...F
addwf MathArgA1 ; und retten
PrnZifH_1 movfw MathArgA1 ; AsciiHighNibbl senden
call PrnChr
movfw MathArgA0 ; LowNibbl laden
andlw 00001111b ; Bit 3...0 maskieren
addlw "0" ; = AsciiLowNibbl
movwf MathArgA1 ; und retten
sublw "9" ; > "9" ?
skip_NC ; ... ja
goto PrnZifH_2
movfw MathArgA1 ; AsciiLowNibbl zurueck
movlw 7 ; A...F
addwf MathArgA1 ; und retten
PrnZifH_2 movfw MathArgA1 ; AsciiLowNibbl senden
goto PrnChr
; ===============================================================
; 8 Bit Multiplikation mit 10d
; Eingang: MathArgA0 Multiplikant
; Ausgang: MathErgA1..0 Multiplikant * 10
; ===============================================================
Mulu0810 clrf MathErgA1
bcf _C ; C=0
rlf MathArgA0,W ; Multiplikant * 2
movwf MathErgA0
movwf MathTemp0
rlf MathErgA1,W ; HighByte Uebertrag
movwf MathErgA1
movwf MathTemp1
bcf _C ; C=0
rlf MathErgA0 ; * 4
rlf MathErgA1
rlf MathErgA0 ; * 8
rlf MathErgA1
movfw MathTemp0 ; *8 + *2 = *10
addwf MathErgA0
skip_NC ; ... kein Uebertrag
incf MathErgA1
movfw MathTemp1
addwf MathErgA1
return
; ===============================================================
; 8 Bit Division durch 10d
; Eingang: MathArgA0
; Ausgang: MathErgA0 Ergebnis 10-er
; MathErgA1 Ergebnis 100-er
; MathArgA0 Rest
; ===============================================================
Divu0810 movlw 255
movwf MathErgA0 ; Ergebnis 10-er = 255
movwf MathErgA1 ; Ergebnis 100-er = 255
movlw 100
Divu0810_1 incf MathErgA1 ; Ergebnis 100-er + 1
bcf _C ; Carry = 0
subwf MathArgA0 ; Divident - 100
btfsc _C ; ... Unterlauf
goto Divu0810_1
addwf MathArgA0 ; Rest 10-er
movlw 10
Divu0810_2 incf MathErgA0 ; Ergebnis 10-er + 1
bcf _C ; Carry = 0
subwf MathArgA0 ; Divident - 10
btfsc _C ; ... Unterlauf
goto Divu0810_2
addwf MathArgA0 ; Rest 1-er
return
| ; ***************************************************************
; EEPROM- und FLASH-ROUTINEN
; ***************************************************************
| ; ---------------------------------------------------------------
; Daten aus Eeprom in Ram kopieren
; ---------------------------------------------------------------
RdEepKonf movlw 16 ; 16 Parameter
movwf zUni
movlw LOW(EepParam) ; Adr setzen
movwf AddrL
movlw RamParam
movwf FSR
bcf STATUS,IRP ; Bank 0 / 1
RdEepKonf_1 call RdEeprom ; Eeprom lesen
movwf INDF
incf AddrL ; Adr + 1
incf FSR
decfsz zUni ; ... Zlr - 1 = 0
goto RdEepKonf_1
return
; ---------------------------------------------------------------
; Byte aus EEPROM lesen
; Eingang: AddrL Eeprom-Adresse Low
; Ausgang: W & EepByte Daten-Byte aus Eeprom
; ---------------------------------------------------------------
RdEeprom bsf STATUS,RP0 ; Bank 3
bsf STATUS,RP1
RdEeprom_1 btfsc EECON1,WR ; ... letzter Schreibvorgang ist fertig
goto RdEeprom_1 ; ... sonst warten
bcf STATUS,RP0 ; Bank 2
clrf EEADRH ; Eeprom-Adr High = 0
movfw AddrL ; AddrL speichern
movwf EEADR
bsf STATUS,RP0 ; Bank 3
bcf EECON1,EEPGD ; Zugriff auf Eeprom
bsf EECON1,RD ; Lesezugriff freigeben
bcf STATUS,RP0 ; Bank 2
movfw EEDATA ; Daten-Byte aus Eeprom lesen
bcf STATUS,RP1 ; Bank 0
movwf EepByte ; Daten-Byte nach EepByte
return
; ---------------------------------------------------------------
; Byte in EEPROM schreiben (ohne Verify)
; Eingang: W Daten-Byte
; AddrL Eeprom-Adresse
; Ausgang: Daten-Byte im Eeprom
; Benutzt: EepByte
; ---------------------------------------------------------------
WrEeprom movwf EepByte ; Daten-Byte retten
bsf STATUS,RP0 ; Bank 3
bsf STATUS,RP1
WrEeprom_1 btfsc EECON1,WR ; ... letzter Schreibvorgang ist fertig
goto WrEeprom_1 ; ... sonst warten
bcf STATUS,RP0 ; Bank 2
clrf EEADRH ; Eeprom-Adr High-Byte = 0
movfw AddrL ; Eeprom-Adresse in EEADR ablegen
movwf EEADR
; ---------------------------
; Byte aus Eeprom lesen und mit neuem Byte vergleichen.
; Wenn Eeprom-Byte und Neues Byte gleich sind,
; ist kein Schreibvorgang erforderlich.
; ---------------------------
bsf STATUS,RP0 ; Bank 3
bcf EECON1,EEPGD ; Zugriff auf Eeprom
bsf EECON1,RD ; Lesezugriff freigeben
bcf STATUS,RP0 ; Bank 2
movfw EEDATA ; Byte aus Eeprom nach W-Register
bcf STATUS,RP1 ; Bank 0
subwf EepByte,W ; Eeprom-Byte = neues Byte ?
btfsc STATUS,Z ; ... nein
return ; ... sonst kein Schreibvorgang
; ---------------------------
; Eeprom-Byte <> neues Byte:
; Schreibvorgang starten
; ---------------------------
movfw EepByte ; Byte zurueck
bsf STATUS,RP1 ; Bank 2
movwf EEDATA ; Byte in Eeprom-Data ablegen
bsf STATUS,RP0 ; Bank 3
bcf EECON1,EEPGD ; Zugriff auf Eeprom
bsf EECON1,WREN ; Schreibzugriff freigeben
bcf INTCON,GIE ; Globaler Int aus
movlw 0x55 ; SchreibZyklus initialisieren
movwf EECON2
movlw 0xAA
movwf EECON2
bsf EECON1,WR ; Schreibzugriff beginnen
nop
bsf INTCON,GIE ; Globaler Int wieder ein
bcf EECON1,WREN ; Schreibzugriff sperren
bcf STATUS,RP0 ; Bank 0
bcf STATUS,RP1
return
; ---------------------------------------------------------------
; Byte aus FlashSpeicher lesen
; Eingang: AddrL FlashAdresse Low
; AddrH FlashAdresse High
; Ausgang: W & EepByte Daten-Byte aus FlashSpeicher
; ---------------------------------------------------------------
RdFlash bsf STATUS,RP0 ; Bank 3
bsf STATUS,RP1
RdFlash_1 btfsc EECON1,WR ; ... letzter Schreibvorgang ist fertig
goto RdFlash_1 ; ... sonst warten
bcf STATUS,RP0 ; Bank 2
movfw AddrH ; AddrH speichern
movwf EEADRH
movfw AddrL ; AddrL speichern
movwf EEADR
bsf STATUS,RP0 ; Bank 3
bsf EECON1,EEPGD ; Zugriff auf FlashSpeicher
bsf EECON1,RD ; FlashSpeicher lesen
nop
nop
bcf STATUS,RP0 ; Bank 2
movfw EEDATA ; Daten-Byte aus FlashSpeicher lesen
; EEDATH wird nicht benutzt
bcf STATUS,RP1 ; Bank 0
movwf EepByte ; Daten-Byte nach EepByte
return
; ***************************************************************
; ZEIT- UND WARTESCHLEIFEN
; ***************************************************************
| ; ---------------------------------------------------------------
; Timer 0 setzen und Interrupt-Flag ruecksetzen
; Eingang: W Timer-Wert
; ---------------------------------------------------------------
SetTimer0 movwf TMR0 ; Timer 0 setzen
bcf INTCON,T0IF ; Int-Flag ruecksetzen
return
; ---------------------------------------------------------------
; Timer 0 setzen und den Ablauf von Timer 0 abwarten
; Eingang: W Timer-Wert
; ---------------------------------------------------------------
SetWaitTimer0 movwf TMR0 ; Timer 0 setzen
bcf INTCON,T0IF ; Int-Flag ruecksetzen
WaitTimer0 skip_1 INTCON,T0IF ; ... Timer ist abgelaufen
goto WaitTimer0 ; ... sonst warten
bcf INTCON,T0IF ; Int-Flag ruecksetzen
return
; ---------------------------------------------------------------
; Timer 1 starten und Ablauf von Timer 1 abwarten
; ---------------------------------------------------------------
StartWaitTimer1 bcf PIR1,TMR1IF ; Timer 1 Interrupt-Flag ruecksetzen
M_movlf 00000101b,T1CON ; Prescaler 1:1, Timer 1 an
WaitTimer1 skip_1 PIR1,TMR1IF ; ... Timer ist abgelaufen
goto WaitTimer1 ; ... sonst warten
return
| ; ***************************************************************
; Text im Programmspeicher Page 3 (0x1800...0x1FFF)
; ***************************************************************
org 0x1800
TxtSysErr_0 de "F 00 ; Kein Fehler", 0
TxtSysErr_1 de "F 01 ; KaltStart", 0
TxtSysErr_2 de "F 02 ; WarmStart", 0
TxtSysErr_7 de "F 07 ; TimeOut Eeprom", 0
TxtCmdErr_1 de "F 21 ; Kommando fehlt", 0
TxtCmdErr_2 de "F 22 ; Kommando falsch", 0
TxtCmdErr_3 de "F 23 ; Parameter fehlt / falsch", 0
TxtCmdErr_4 de "F 24 ; Parameter zu klein", 0
TxtCmdErr_5 de "F 25 ; Parameter zu gross", 0
TxtCmdErr_6 de "F 26 ; Bestaetigung fehlt / falsch", 0
TxtCmdErr_7 de "F 27 ; frei", 0
TxtVers de "V ", klauf, Version, Datum, klzu, cr, lf, 0
TxtHilfe de cr, lf
de "; V = Version des Programms abfragen", cr, lf
de "; D 24.06.05 = Datum setzen / abfragen", cr, lf
de "; U 13.45.00 = Uhrzeit setzen / abfragen", cr, lf
de cr, lf, 0
; ***************************************************************
; Daten im Eeprom
; ***************************************************************
org 0x2100
; -------------------------------------
; VersionsEintrag ab Eeprom Adr. 0x2100...0x210F (max 16 Byte)
de Version
de Datum
; -------------------------------------
; Konfiguration ab Eeprom-Adr. 0x2110...0x211F (max 16 Byte)
org 0x2110
EepParam de 2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
de 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
end
| ; Was fehlt hier noch ?
| |
|