;******************************************************************************* ;** ;** RFID reader section, generate 150KHz carrier frequency ;** and decode the basic data stream ;** ;** Written by Rick Huang, Copyright (C) 2007 ;** Revision YYYY/MM/DD ;** Rev 1. 2007/04/29 - Initial release ;** Rev 2. 2007/05/05 - Add automatic card detect ;** ;** Command Functions ;** '1' Basic decode, binary data output ;** '2' Debug capture, 8bit data output ;** '3' Full capture and decode ;** '4' Hex test - echo any hex input ;** '6' Auto card detect mode ;** '7' ;** ;** ;** This program is free software; you can redistribute it and/or modify ;** it under the terms of the GNU General Public License as published by ;** the Free Software Foundation; either version 2 of the License, or ;** (at your option) any later version. ;** ;** This program is distributed in the hope that it will be useful, ;** but WITHOUT ANY WARRANTY; without even the implied warranty of ;** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;** GNU General Public License for more details. ;** ;** You should have received a copy of the GNU General Public License ;** along with this program; if not, write to the Free Software ;** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;******************************************************************************* ;**************************************************************************** ;** NOTE: Disable the WDT when debugging the code, however, make sure ;** the WDT is enabled when putting the system into lift time test ;** The timeout for WDT is about 2 seconds with 128:1 prescaler ;**************************************************************************** include __config _HS_OSC & _WDT_ON & _LVP_OFF & _BODEN_ON & _MCLRE_ON & _PWRTE_ON ;***************************************************************** ;** Variables TempW EQU 70h ; BitLocation EQU 71h CounterB EQU 72h NextFSR EQU 73h ; CounterW EQU 74h BitCount EQU 75h LastBitVal EQU 76h Data0 EQU 77h ; Final data output Data1 EQU 78h Data2 EQU 79h Data3 EQU 7ah Data4 EQU 62h Zero EQU 7bh ; Zero is 0x00 SerData EQU 7ch Temp EQU 7dh Output EQU 7eh Counter EQU 7fh TMRsample EQU 60h BinCnt EQU 61h Toggle EQU 63h ThreeTry EQU 64h FCData0 EQU 65h ; First data captured FCData1 EQU 66h FCData2 EQU 67h FCData3 EQU 68h FCData4 EQU 69h WrittenBit EQU 6ah #define _POAS PORTB, 7 ; Power ON Auto Start #define _DOUT PORTB, 6 ; #define _KEY PORTB, 5 ; Key good output #define _BEEP PORTB, 4 ; Beeper output #define _PWM_O PORTB, 3 ; PWM - 150kHz #define _TXD PORTB, 2 ; UART #define _RXD PORTB, 1 ; UART #define _UNU1 PORTB, 0 ; Unused #define DecisionVal d'170' ;Hard decision, 0 = 159 cycle, 1 = 198 cycle ;***************************************************************** ;** Program code here goto Start ORG 4 ;waiting for <0004> ;interrupt vector ;goto Interrupt ORG 5 ;***************************** DATA StringStart: PWelcomeMsg: addwf PCL, F DT "Welcome!" DT H'0d', H'0a', H'00' PCommandMsg: DT "Command Error?" DT H'0d', H'0a', H'00' PParameterMsg: DT "Parameter Error?" DT H'0d', H'0a', H'00' PNoAckMsg: DT "Missing Ack" DT H'0d', H'0a', H'00' StringEnd: WelcomeMsg EQU 0 CommandMsg EQU PCommandMsg - 1 - 5 ; 5 is the offset where the ParameterMsg EQU PParameterMsg - 1 - 5 ; Strings start NoAckMsg EQU PNoAckMsg - 1 - 5 HexTable: addwf PCL, F DT "0123456789ABCDEF" ;***************************************************************** ;******************** Program Starts here Start: ;********************* Setup WDT ;********************** Setting up TMR0, used to decode FSK bcf _BEEP clrwdt bsf STATUS, RP0 movlw b'00001111' ;Prescaler to WDT, 1:128 movwf OPTION_REG clrwdt ;********************* Setting up environment movlw b'10000010' ;Serial port in too movwf TRISB ;Set port B I/O movlw b'00000111' movwf TRISA ;Set port A I/O bcf STATUS, RP0 clrf PORTA ;********************** Disable 16f628 specific features movlw b'00000110' ;Setup comparator movwf CMCON ;********************** Setting up PWM module for 150KHz signal movlw b'00001100' ;Enable PWM module, duty = 2 movwf CCP1CON movlw b'00000010' ;Using source frequency = 12MHz movwf CCPR1L movlw b'00000101' ;Setting up TMR2, Prescale = 1:4 movwf T2CON bsf STATUS, RP0 movlw b'00000100' movwf PR2 ;Setting the period = 4 bcf STATUS, RP0 ;********************** Setup UART bsf STATUS, RP0 movlw d'12' ;57600 for 12MHz Clock, High speed movwf SPBRG ;The only rate with low mismatch movlw b'10100111' ;Async 8-bit @ High speed movwf TXSTA bcf STATUS, RP0 movlw b'10110000' ;Enable serial port movwf RCSTA clrf Zero movlw WelcomeMsg ;Display welcome string on startup call SendString ;----------------------- Debug insert goto SkipDebug movlw 0a0h movwf FSR movlw b'00000011' movwf INDF incf FSR, F movlw b'11111111' movwf INDF incf FSR, F movlw b'11111100' movwf INDF incf FSR, F movlw b'00011111' movwf INDF incf FSR, F movlw b'10000001' movwf INDF incf FSR, F movlw b'11110000' movwf INDF incf FSR, F movlw b'00111110' movwf INDF incf FSR, F movlw b'00000111' movwf INDF incf FSR, F goto FD_DecodeEntry SkipDebug: ;----------------------- Wait for command WaitMore: btfsc _POAS goto AutoDecode clrwdt btfsc RCSTA, OERR goto ClearError btfss PIR1, RCIF goto WaitMore movfw RCREG movwf SerData movwf TXREG ;Send it back out call SSpace movlw '1' ;Decode command xorwf SerData, W btfsc STATUS, Z goto AttemptSample ;Start a RFID sample movlw '2' xorwf SerData, W btfsc STATUS, Z goto DebugSample ;Debug run, output sampled data movlw '3' xorwf SerData, W btfsc STATUS, Z goto FullDecode ;Fully capture and decode data movlw '4' xorwf SerData, W btfsc STATUS, Z goto HexTest ;Testing HEX routine movlw '5' xorwf SerData, W btfsc STATUS, Z goto BinTest ;Testing Bin dump routine movlw '6' xorwf SerData, W btfsc STATUS, Z goto AutoDecode ;No Debug message, auto card detection movlw '7' xorwf SerData, W btfsc STATUS, Z goto TestBeep movlw '8' xorwf SerData, W btfsc STATUS, Z goto DummyNow DummyNow: ;For all command not in use movlw CommandMsg call SendString ;Send error command message goto WaitMore ;********************* Clear receving overrun error ClearError: movfw RCREG movfw RCREG bcf RCSTA, CREN bsf RCSTA, CREN goto WaitMore ;---------------------- Commands execution ;********************** Command 1: AttemptSample: ;Command 1: Sample RFID data, do 1024 bits call CompCheck ;Dummy read once to setup condition movlw 0a0h movwf FSR ;Use FSR to store data movlw d'80' ;Do this for 80 bytes movwf Counter SampleLoop1: call CaptureByte incf FSR, F ;A byte is full, move to the next one decfsz Counter, F goto SampleLoop1 ;---------------------- Switch memory bank movlw 020h movwf FSR ;Use FSR to store data movlw d'64' ;Do this for 64 bytes movwf Counter SampleLoop2: call CaptureByte incf FSR, F ;A byte is full, move to the next one decfsz Counter, F goto SampleLoop2 ;---------------------- Data is full, now dump the data out movlw d'80' ;Do this for 80 bytes movwf Counter movlw 0a0h movwf FSR ;Use FSR to access data SampleLoop10: movfw INDF call SendBin incf FSR, F decfsz Counter, F goto SampleLoop10 ;---------------------- Switch bank movlw d'64' ;Do this for 64 bytes movwf Counter movlw 020h movwf FSR ;Use FSR to access data SampleLoop11: movfw INDF call SendBin incf FSR, F decfsz Counter, F goto SampleLoop11 call NewLine goto WaitMore ;*********************** Command 2 Debug mode DebugSample: ;Command 2: Sample RFID data, debug mode call CompCheck ;Dummy read once to setup condition movlw 0a0h movwf FSR ;Use FSR to store data movlw d'80' ;Do this for 80 bytes movwf Counter DebugSLoop1: call CompCheck movfw TMRsample movwf INDF incf FSR, F ;A byte is full, move to the next one decfsz Counter, F goto DebugSLoop1 ;---------------------- Switch memory bank movlw 020h movwf FSR ;Use FSR to store data movlw d'64' ;Do this for 64 bytes movwf Counter DebugSLoop2: call CompCheck movfw TMRsample movwf INDF incf FSR, F ;A byte is full, move to the next one decfsz Counter, F goto DebugSLoop2 ;---------------------- Data is full, now dump the data out movlw d'80' ;Do this for 80 bytes movwf Counter movlw 0a0h movwf FSR ;Use FSR to access data DebugSLoop10: movfw INDF call SendHex call NewLine incf FSR, F decfsz Counter, F goto DebugSLoop10 ;---------------------- Switch bank movlw d'64' ;Do this for 64 bytes movwf Counter movlw 020h movwf FSR ;Use FSR to access data DebugSLoop11: movfw INDF call SendHex call NewLine incf FSR, F decfsz Counter, F goto DebugSLoop11 call NewLine goto WaitMore ;*********************** Command 3 Full capture and decode FullDecode: ;Wait for start sequence, than start capture call CompCheck ;Dummy read once to setup condition call WaitTillStart ;Wait for start movlw 0a0h movwf FSR ;Use FSR to store data movlw d'80' ;Do this for 80 bytes movwf Counter FDLoop1: call CaptureByte incf FSR, F ;A byte is full, move to the next one decfsz Counter, F goto FDLoop1 ;---------------------- Data is full, now dump the data out movlw d'80' ;Do this for 80 bytes movwf Counter movlw 0a0h movwf FSR ;Use FSR to access data FDLoop10: movfw INDF call SendBin incf FSR, F decfsz Counter, F goto FDLoop10 call NewLine FD_DecodeEntry: ;---------------------- Collaspe data bits movlw d'8' ;Set up for bit read movwf BitLocation movlw 0a0h movwf NextFSR ;---------------------- Start extraction clrf Data0 ;Clear data holder clrf Data1 clrf Data2 clrf Data3 clrf Data4 clrf Toggle FD_BitLoopZ: call GetBitCount movfw BitCount movlw d'20' subwf BitCount, W btfsc STATUS, C goto FD_DoneDecode ; Bitcount - 15 = Positive, Looped already, STOP movlw d'7' subwf BitCount, W btfss STATUS, C goto FD_Send2bit ;Negative, 1 bits movlw '*' ;Positive, 2 bit call SendChar call SendChar bsf STATUS, C call LongShift call LongShift goto FD_NextBit FD_Send2bit: movlw '_' call SendChar bcf STATUS, C call LongShift FD_NextBit: movlw 0efh subwf NextFSR, W ;NextFSR - W btfss STATUS, C goto FD_BitLoopZ ;Negative, keep looping call NewLine ;Positive, NextFSR > 0xef ;----------------------- Final data output FD_DoneDecode: call NewLine movfw Data4 call SendHex movfw Data3 call SendHex movfw Data2 call SendHex movfw Data1 call SendHex movfw Data0 call SendHex call NewLine goto WaitMore ;*********************** Command 6: Auto detection of card AutoDecode: clrwdt movlw 03h ;Three trys movwf ThreeTry AD_CaptureAgain: clrf WrittenBit clrwdt call CompCheck ;Dummy read once to setup condition call WaitTillStart ;Wait for start condition movlw 0a0h movwf FSR ;Use FSR to store data movlw d'80' ;Do this for 80 bytes movwf Counter ADLoop1: call CaptureByte incf FSR, F ;A byte is full, move to the next one decfsz Counter, F goto ADLoop1 AD_DecodeEntry: ;---------------------- Collaspe data bits movlw d'8' ;Set up for bit read movwf BitLocation movlw 0a0h movwf NextFSR ;---------------------- Start extraction clrf Data0 ;Clear data holder clrf Data1 clrf Data2 clrf Data3 clrf Data4 clrf Toggle AD_BitLoopZ: call GetBitCount movlw d'20' subwf BitCount, W btfsc STATUS, C goto AD_DoneDecode ; Bitcount - 15 = Positive, Start condition again, STOP movlw d'7' subwf BitCount, W btfss STATUS, C goto AD_Send2bit ;Negative, 1 bits bsf STATUS, C ;Positive, 2 bit call LongShift call LongShift goto AD_NextBit AD_Send2bit: bcf STATUS, C call LongShift AD_NextBit: incf WrittenBit, F movlw 0efh subwf NextFSR, W ;NextFSR - W btfss STATUS, C goto AD_BitLoopZ ;Negative, keep looping ;Positive, NextFSR > 0xef, error goto AutoDecode ;Restart... ;----------------------- Check data is the same for three times AD_DoneDecode: movlw d'30' ;Error check, if too many zero bits, restart subwf BitCount, W btfsc STATUS, C goto AutoDecode ;Too many bits movlw h'46' ;Check number of bit written, too little, restart subwf WrittenBit, W btfss STATUS, C goto AutoDecode movlw h'55' ;Check number of bit written, too many, restart subwf WrittenBit, W btfsc STATUS, C goto AutoDecode movlw d'3' xorwf ThreeTry, W btfss STATUS, Z ;First try indicator goto AD_NotFirstTry movfw Data0 movwf FCData0 movfw Data1 movwf FCData1 movfw Data2 movwf FCData2 movfw Data3 movwf FCData3 movfw Data4 movwf FCData4 decf ThreeTry, F goto AD_CaptureAgain AD_NotFirstTry: movfw Data0 xorwf FCData0, W btfss STATUS, Z goto AutoDecode ;Not matched, restart movfw Data1 xorwf FCData1, W btfss STATUS, Z goto AutoDecode ;Not matched, restart movfw Data2 xorwf FCData2, W btfss STATUS, Z goto AutoDecode ;Not matched, restart movfw Data3 xorwf FCData3, W btfss STATUS, Z goto AutoDecode ;Not matched, restart movfw Data4 xorwf FCData4, W btfss STATUS, Z goto AutoDecode ;Not matched, restart decfsz ThreeTry, F goto AD_CaptureAgain ;----------------------- Final data output call NewLine movfw Data4 call SendHex movfw Data3 call SendHex movfw Data2 call SendHex movfw Data1 call SendHex movfw Data0 call SendHex call NewLine call Beep goto WaitMore ;*********************** Command 4,5 Serial debug HexTest: call RcvHex ;Command 4: Hex test movfw Output call SendHex call NewLine goto WaitMore BinTest: call RcvHex ;Command 5: Bin test movfw Output call SendBin call NewLine goto WaitMore TestBeep: call Beep ;Command 7: Test beep call NewLine goto WaitMore ;***************************** SUBROUTINE ;----------------------------------------------------------------- ; LongShift, Shift 1 bit of the data into Data[0:4] register ; Shift only 1 bit per two calls ; Input: C LongShift: btfss Toggle, 0 goto ToggleNotSet rlf Data0, F rlf Data1, F rlf Data2, F rlf Data3, F rlf Data4, F bcf Toggle, 0 return ToggleNotSet: bsf Toggle, 0 return ;----------------------------------------------------------------- ; CaptureByte, Capture a single byte of data ; Output: INDF CaptureByte: call CompCheck movlw DecisionVal ;Hard decision, 0 = 159 cycle, 1 = 198 cycle subwf TMRsample, W rlf INDF, F ;Store the data into pointed address call CompCheck ;Do this for 8 times to fill up a byte movlw DecisionVal subwf TMRsample, W rlf INDF, F call CompCheck movlw DecisionVal subwf TMRsample, W rlf INDF, F call CompCheck movlw DecisionVal subwf TMRsample, W rlf INDF, F call CompCheck movlw DecisionVal subwf TMRsample, W rlf INDF, F call CompCheck movlw DecisionVal subwf TMRsample, W rlf INDF, F call CompCheck movlw DecisionVal subwf TMRsample, W rlf INDF, F call CompCheck movlw DecisionVal subwf TMRsample, W rlf INDF, F return ;----------------------------------------------------------------- ; WaitTillStart, Wait until the start sequence is detected ; This is marked by 20 or more zeros WaitTillStart: movlw d'20' movwf CounterW WTS_next: clrwdt call CompCheck movlw DecisionVal subwf TMRsample, W btfsc STATUS, C ;Check for a 0 value goto WaitTillStart ;If 1, restart decfsz CounterW, F goto WTS_next ;Loop until done return ;----------------------------------------------------------------- ; CompCheck, Check the comparator output and store the informtion in ; Output: TMRsample CompCheck: ;Process: Loop until a transition, clear TMR0, ;wait till next 0-1 transition SCSampleL3: btfsc CMCON, C1OUT goto SCSampleL3 SCSampleL2: ;Was a low, wait for a high btfss CMCON, C1OUT goto SCSampleL2 movfw TMR0 movwf TMRsample ;Store the result in TMRsample clrf TMR0 ;Clear TMR0 for the next bit return ;----------------------------------------------------------------- ; GetBitCount, Count number of bits until the next change ; Output: BitCount ; Address: BitLocation, NextFSR ; Use: LastBitVal, BitCount, NextFSR, BitLocation, TempW GetBitCount: clrf BitCount btfss LastBitVal, 0 goto GBC_lastbit0 ; goto GBC_lastbit1 ;Last bit is a 1 GBC_loop1: call GetNextBit btfss STATUS, Z goto GBC_done1 incf BitCount, F ;Continue if value is a zero goto GBC_loop1 GBC_done1: ;Done if bit change to one bcf LastBitVal, 0 return GBC_lastbit0: ;Last bit is a 0 GBC_loop0: call GetNextBit btfsc STATUS, Z goto GBC_done0 incf BitCount, F ;Continue if value is a one goto GBC_loop0 GBC_done0: ;Done if bit change to one bsf LastBitVal, 0 return ;----------------------------------------------------------------- ; GetNextBit, Get a bit from the buffer ; Output: Z ; Address: BitLocation, NextFSR, BitLocation = 1 for LSB GetNextBit: movfw NextFSR movwf FSR movfw BitLocation movwf CounterB decfsz BitLocation, F ;Go to the next bit goto GNB_nextStep movlw d'8' movwf BitLocation incf NextFSR, F ;Rollover for the next read GNB_nextStep: clrf TempW bsf STATUS, C GNB_loop: rlf TempW, F ;TempW contain bit mask decfsz CounterB, F goto GNB_loop movfw TempW andwf INDF, W ;Result in Z return ;***************************** SUBROUTINE ;----------------------------------------------------------------- ; SendHex, Send a single byte out of serial port, hex format ; Input: data stored in W SendHex: movwf Temp swapf Temp, W andlw 00fh call HexTable HexWaitLoop1: btfss PIR1, TXIF ;Wait till buffer is empty goto HexWaitLoop1 movwf TXREG movf Temp, W andlw 00fh call HexTable HexWaitLoop2: btfss PIR1, TXIF ;Wait till buffer is empty goto HexWaitLoop2 movwf TXREG return ;----------------------------------------------------------------- ; SendBin, Send a single byte out of serial port, binary format ; Input: data stored in W SendBin: movwf Temp movlw 8h movwf BinCnt BinWaitLoop1: btfss PIR1, TXIF ;Wait till buffer is empty goto BinWaitLoop1 movlw '0' btfsc Temp, 7 movlw '1' movwf TXREG rlf Temp, F decfsz BinCnt, F goto BinWaitLoop1 return ;----------------------------------------------------------------- ; RcvHex, Receive a single byte from serial port in hex format ; Output: data stored in Output RcvHex: btfss PIR1, RCIF goto RcvHex movfw RCREG movwf SerData movwf TXREG ; Send it back out movlw 30h subwf SerData, F movlw 10h subwf SerData, W ; F - W btfsc STATUS, C ; Positive means letter input goto Letter1 RtnLetter1: swapf SerData, W movwf Output RcvHexLoop: btfss PIR1, RCIF goto RcvHexLoop movfw RCREG movwf SerData movwf TXREG ; Send it back out movlw 30h subwf SerData, F movlw 10h subwf SerData, W ; F - W btfsc STATUS, C ; Positive means letter input goto Letter2 RtnLetter2: movfw SerData iorwf Output, F call SSpace return Letter1: movlw 07h subwf SerData, F movlw 10h subwf SerData, W btfsc STATUS, C ; Positive means bad input goto Letter1E goto RtnLetter1 Letter1E: movlw d'32' subwf SerData, F goto RtnLetter1 Letter2: movlw 07h subwf SerData, F movlw 10h subwf SerData, W btfsc STATUS, C ; Positive means bad input goto Letter2E goto RtnLetter2 Letter2E: movlw d'32' subwf SerData, F goto RtnLetter2 ;----------------------------------------------------------------- ; LongDelay, 15 cycles, 3ins/cycle 22.5uS for 8Mhz clock long_delay: movlw d'15' movwf Counter long_delay_L: decfsz Counter, F goto long_delay_L return ;----------------------------------------------------------------- ; SendString, send the string out to serial port ; Input: String location in W SendString: movwf Counter SendLoop: btfss PIR1, TXIF ;Wait till buffer is empty goto SendLoop call StringStart iorwf Zero, W btfsc STATUS, Z ;Zero is the end of string return movwf TXREG incf Counter, F movfw Counter goto SendLoop ;----------------------------------------------------------------- ; NewLine, send s newline character into serial port ; Input: None NewLine: btfss PIR1, TXIF ;Wait till buffer is empty goto NewLine movlw 0dh movwf TXREG movlw 0ah NewLineLoop: btfss PIR1, TXIF ;Wait till buffer is empty goto NewLineLoop movwf TXREG return ;----------------------------------------------------------------- ; Space, send a space character into serial port ; Input: None SSpace: btfss PIR1, TXIF ;Wait till buffer is empty goto SSpace movlw ' ' movwf TXREG return ;----------------------------------------------------------------- ; SendChar, send a character into serial port ; Input: W SendChar: btfss PIR1, TXIF ;Wait till buffer is empty goto SendChar movwf TXREG return ;----------------------------------------------------------------- ; Beep, genertate a 0.5 sec beeper signal, 2KHz ; Using: Data0, 1, 2, 3 Beep: clrf Toggle movlw d'200' movwf Data0 movlw d'100' movwf Data2 movlw d'10' movwf Data3 BeepLoop: decfsz Data0, F goto BeepLoop movlw d'200' movwf Data0 movlw b'00010000' xorwf PORTB, F clrwdt decfsz Data2, F goto BeepLoop movlw d'100' movwf Data2 decfsz Data3, F goto BeepLoop bcf _BEEP return ;----------------------------------------------------------------- ; End of program end