📄 uart688i.asm
字号:
;**********************************************************************
; *
; Filename: LINUART688i.asm *
; Date: 05.11.18 *
; File Version: 2.0 *
; *
; Author: Chuck Simmers *
; Company: Microchip Technology, Inc. *
;
; LIN 2.0 compatible slave driver for PIC16F688-type EAUSART *
; *
;**********************************************************************
; *
; Files required: LINUART688i.inc *
;
; The following code needs to be put into the interrupt routine *
; and RCIE ansd TXIE enabled.
;Check if LIN comm channel is active
; bsf STATUS,RP0
; btfss PIE1,RCIE ; is AUSART receive interrupt enabled?
; goto CheckXmitFlag ; no, go check transmit
; bcf STATUS,RP0
; btfsc PIR1,RCIF ; did a receive inerrupt happen?
; goto LINHandler ; yes, handle it
; bsf STATUS,RP0
;CheckXmitFlag
; btfss PIE1,TXIE ; is transmit interrupt enabled?
; goto $+4 ; no, return from interrupt
; bcf STATUS,RP0
; btfsc PIR1,TXIF ; yes,
; goto PutDATAbyte ; send a byte of data
; *
;**********************************************************************
; *
; Notes: *
; 1.0 first revision *
; 2.0 Revised to support LIN 2.0 addressing *
; *
; *
;**********************************************************************
; ***********************************************************************
; * Initialization *
; ***********************************************************************
; Setup LIN USART
SetupLINUSART
movlw B'10010000' ; UART enabled,8-bit,continuous receive
movwf RCSTA
movlw B'00000100' ; 8-bit, asynchronous, high-baudrate
movwf TXSTA
movlw B'00001000' ; 16-bit BRG
movwf BAUDCTL
clrf SPBRGH
movlw 0x31 ; setup initialy for 20KBaud @ 4.0MHz, BRGH=1, BRG16=1
movwf SPBRG
movlw .12 ; message preamble is three bytes long (BREAK,SYNC,ID)
movwf MESSAGE_COUNTER
movfw RCREG ; dump any pending character, reset RCIF and FERR
bsf INTCON,PEIE ; enable peripheral interrupts
bsf STATUS,RP0
bsf PIE1,RCIE ; enable receive interrupt
bcf STATUS,RP0
bsf INTCON,GIE ; global enable interrupts
clrf ID_TEMP
call WAIT001 ; wait 1mS
bcf LINCS ; toggle LINCS
bsf LINCS ; to enable transceiver
return
; ***********************************************************************
; * Autobaud routine *
; ***********************************************************************
LINHandler
;ProcessPacket
movlw HIGH GetBREAK
movwf PCLATH
movfw MESSAGE_COUNTER ; MESSAGE_COUNTER is also used as state machine pointer
addwf PCL, f ; add to PC
goto GetCHECKSUM ;0; CHECKSUM byte
goto GetDATAbyte ;1; Data byte
goto GetDATAbyte ;2; Data byte
goto GetDATAbyte ;3; Data byte
goto GetDATAbyte ;4; Data byte
goto GetDATAbyte ;5; Data byte
goto GetDATAbyte ;6; Data byte
goto GetDATAbyte ;7; Data byte
goto GetDATAbyte ;8; Data byte
goto GetDATAbyte ;9; Data byte
goto GetIDENTIFIER ;10; ID byte
goto GetSYNC ;11; SYNC character
goto GetBREAK ;12; BREAK character
GetBREAK
; btfss RCSTA,FERR ; was BREAK character longer than 8 bits?
; goto BadBREAKchar ; no, not a valid BREAK, too short
movfw RCREG ; dump break character, reset RCIF and FERR
btfss STATUS,Z
goto BadBREAKchar ; no, not a valid BREAK, not zero
decf MESSAGE_COUNTER
btfss LINRX
goto $-1
bsf BAUDCTL,ABDEN ;enable AutoBaud
goto RestoreStatus
BadBREAKchar
movfw RCREG ; dump break character, reset RCIF and FERR
goto RestoreStatus
GetSYNC
btfsc BAUDCTL,ABDOVF ; did baud rate generator overflow?
goto BadSYNCchar ; yes, bad sync character
btfsc RCSTA,FERR ; was there a Framing Error?
goto BadSYNCchar ; yes, bad sync character
decf SPBRG
movfw RCREG ; dump sync character, reset RCIF
decf MESSAGE_COUNTER
goto RestoreStatus
BadSYNCchar
bcf BAUDCTL,ABDOVF ; clear the overflow condition
movlw .12 ; reset the state machine
movwf MESSAGE_COUNTER
goto RestoreStatus
GetIDENTIFIER
movfw RCREG ; get character, reset RCIF and FERR
movwf RXTX_REG
; The following is LIN 2.0 compliant code
movwf ID_TEMP ; copy Identifier into ID_TEMP register
; Decode ID4 and ID5. These two bits indicate how many bytes of
; data have to be transmitted or received.
call IDDecodeTable
andlw 0x0F ; mask out length data
btfsc STATUS,Z ; if length = 0
goto UnrecognisedID ; then, quit, else,
movwf MESSAGE_COUNTER ; store length of message into MESSAGE_COUNTER register
incf MESSAGE_COUNTER,f ; increment message counter by one for receiving or
; transmitting CRC byte
movfw ID_TEMP ; get identifier again
call IDDecodeTable ; lookup type and length
andlw 0xC0 ; mask out length, leave type
xorlw ReceiveData ; if this is Receive Mode
btfsc STATUS,Z
goto ReceiveMode ; go to Receive Mode, else
TransmitMode
; incf MESSAGE_COUNTER,f ; increment message counter by one for transmitting CRC byte
call CheckParityBits ; check if parity bits are correct
movlw 0x01 ; Tell CRC routine that checksum has to
movwf TEMP_TRANSFER ; be transfered
call CheckCRC ; generated CRC
movlw DATAPOINTER ; point to first data byte
movwf FSR ; initialize FSR register
bsf STATUS,RP0
bcf PIE1,RCIE ; disable receive interrupt
bsf PIE1,TXIE ;enable transmitter interrupt
bcf STATUS,RP0
bsf TXSTA,TXEN
; fall through to transmit the first byte
movfw INDF ; copy data byte into w-register
movwf TXREG
incf FSR, f ; point to next location
decf MESSAGE_COUNTER, f ; decrement Message Counter by one
goto RestoreStatus
PutDATAbyte
movfw INDF ; copy data byte into w-register
movwf TXREG
incf FSR, f ; point to next location
decfsz MESSAGE_COUNTER, f ; decrement Message Counter by one
goto RestoreStatus
btfss TXSTA,TRMT ; wait for final transmission
goto $-1
bsf STATUS,RP0
bcf PIE1,TXIE ; no more to transmit
bsf PIE1,RCIE ; get ready to receive another frame
bcf STATUS,RP0
movfw RCREG ; dump any pending character, reset RCIF
bcf RCSTA,SPEN
bsf RCSTA,SPEN
bcf RCSTA,CREN
bsf RCSTA,CREN
movlw .12
movwf MESSAGE_COUNTER
goto RestoreStatus
; Receive Mode in this sequence data is received
ReceiveMode
clrf Error_Byte ; clean slate
movlw DATAPOINTER ; point to data location
movwf FSR ; where data should be stored
decf MESSAGE_COUNTER, f ; decrement number of bytes to receive by one
goto RestoreStatus
GetDATAbyte
movfw RCREG ; get character, reset RCIF and FERR
movwf RXTX_REG ; copy data into w-register
movwf INDF ; copy data into data area
incf FSR, f ; point to next location
decf MESSAGE_COUNTER, f ; decrement number of bytes to receive by one
goto RestoreStatus
GetCHECKSUM
movfw RCREG ; get character, reset RCIF and FERR
movwf RXTX_REG ; copy data into w-register
movwf INDF ; copy data into data area
call CheckParityBits ; check if parity bits are correct
iorwf Error_Byte,f ; put any error bits into Error
clrf TEMP_TRANSFER ; Tell CRC routine to check CRC
call CheckCRC ; check if checksum is correct
iorwf Error_Byte,f ; put any error bits into Error
UnrecognisedID
movlw .12
movwf MESSAGE_COUNTER
goto RestoreStatus
ListenMode
goto RestoreStatus ; return to main
; ***********************************************************************
; * LIN checksum calculation (assumes FSR points to the first DB) *
; ***********************************************************************
CheckCRC movlw DATAPOINTER ; point to first data byte
movwf FSR ;
movfw ID_TEMP ; get Identifier
; Decode ID4 and ID5. These two bits indicate how many bytes of
; data have to be transmitted or received.
call IDDecodeTable
andlw 0x0F ; mask out length data
movwf TEMP1 ; copy number of data bytes into Temp-Counter
decf TEMP1, f ; decrement number of data bytes by one, because
; TEMP2 register is preloaded
movf INDF, w ; copy first data byte into w-register
movwf TEMP2 ; copy first data byte into temp register
NextCalc incf FSR, f ; point to next data memory location
movf INDF, w ; move data into w-register
addwf TEMP2, f ; add data byte to temp and store in temp
btfsc STATUS, C ; add with carry?
incf TEMP2, f ; yes, increment TEMP
decfsz TEMP1, f ; decrement bit counter
goto NextCalc ; calculate next
btfss TEMP_TRANSFER, 0 ; check if checksum has to be generated or checked
goto CRCCheck
comf TEMP2, f ; complement CRC value
movf TEMP2, w ; copy checksum into w-register
incf FSR, f ; point to location for checksum
movwf INDF ; copy checksum behind
return ; return from subroutine
CRCCheck incf FSR, f ; point to CRC byte
movf INDF, w ; copy received CRC value into w-register
addwf TEMP2, w ; add received CRC to calculated CRC
xorlw 0xff ; Result should be 0xFF after XOR result is zero
btfss STATUS, Z ; is result zero?
retlw CRC_ERROR ; return with CRC_ERROR
retlw CRC_OK
; ***********************************************************************
; * LIN ID parity generation *
; ***********************************************************************
CheckParityBits movf ID_TEMP, w ; copy ID value into w-register
; calculate P0
movwf TEMP1 ; move ID value into TEMP1
movwf TEMP2 ; move ID into TEMP2
rrf TEMP1, f ; rotate ID_TEMP one to the right (get ID1)
movf TEMP1, w ; copy TEMP1 to w
xorwf TEMP2, f ; TEMP2=ID0 XOR ID1
rrf TEMP1, f ; get ID2
movf TEMP1, w ; copy ID2 into w-register
xorwf TEMP2, f ; TEMP2= TEMP2 XOR ID2
bcf STATUS, C ; clear carry flag
rrf TEMP1, f ; get ID3 into bit 0
rrf TEMP1, w ; ID4 into bit 0 and store result in w-register
xorwf TEMP2, f ; TEMP2 = TEMP2 XOR ID4
btfsc TEMP2, 0 ; test if bit is zero or one
goto CheckP0 ; check if received P0=1
btfss ID_TEMP, 6 ; Check if received P0=0
goto CalcP1 ;
retlw PARITY_ERROR_P0 ; parity error occured
CheckP0 btfss ID_TEMP, 6 ; check if P0 to 1
retlw PARITY_ERROR_P0 ; P1=0 therefore parity error occrured
; calculate P1
CalcP1 movf ID_TEMP, w ; copy ID_TEMP into w-register
movwf TEMP1 ; copy ID_TEMP into TEMP1
movwf TEMP2 ; and TEMP2
rrf TEMP2, f ; ID1 into bit0
rrf TEMP1, f ; ID1 into bit0
rrf TEMP1, f ; ID2 into bit0
rrf TEMP1, f ; ID3 into bit0
movf TEMP1, w ; copy TEMP1 into w-register
xorwf TEMP2, f ; TEMP2 = ID1 XOR ID3
rrf TEMP1, f ; ID4 into bit0
movf TEMP1, w ; TEMP1 into w-register
xorwf TEMP2, f ; TEMP2 = TEMP2 XOR ID4
rrf TEMP1, w ; ID5 into bit0
xorwf TEMP2, f ; TEMP2 = TEMP2 XOR ID5
comf TEMP2, f ; negate TEMP2
btfsc TEMP2, 0 ; check if P1=1
goto CheckP1 ; check if received P1=1
btfsc ID_TEMP, 7 ; check if P1=0
retlw PARITY_ERROR_P1 ; received P1 is not 0 therefore parity error
retlw PARITY_OK ; received P1 is 0 therefore no parity error
CheckP1 btfss ID_TEMP, 7 ; set P1
retlw PARITY_ERROR_P1 ; parity error occured
testb retlw PARITY_OK ; no parity error occured
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -