You are on page 1of 30

Leitor RFID

Cartes RFID so normalmente usados para controle de acesso e tickets de nibus e metrs. Eles so
convenientes porque no precisam de contato direto para transferir informaes de/para o carto. Como
estes cartes so alimentados pelos prprios leitores, dispensam o uso de baterias que precisariam ser
recarregadas.
Para os meus experimentos estou usando catres da HID ISProx. Estes cartes so os mais simples de toda
a linha de cartes RFID, que somente armazenam um nmero de srie e no usam criptografia. A
frequncia da portadora de 125kHz.
O primeiro passo descobrir como desenvolver um leitor simples. Ns sabemos que o cartes RFID
alimentado pelo campo magntico emitido pelo leitos. As tags RFID transferem informao de volta ao
leitor consumindo este campo magntico, que detectado pelo leitor como uma variao no campo.
So chamados de tags RFID todos os elementos que armazenam informaes e so mveis, como o
carto, neste caso especfico.

O projeto mais comum de um leitor RFID faz uso de um circuito ressonante srie. Ele consiste de um
indutorsimples e um capacitor, excitados por uma fonte de tenso de baixa impedncia. Se o Q do circuito
for alto o suficiente, a tenso no ponto de amostragem (Vsample) vai exceder a tenso de alimentao.
Quando o RFID alimentado por este campo magntico o Q do circuito cai. O resultado uma pequena
alterao na tenso de amostragem (Vsample no circuito mostrado).

Eu criei um leitor simples com componentes encontrados em minha sucata. Usando um gerador de funo
como fonte de sinal e um osciloscpio no ponto de amostragem, eu pude sintonizar a frequncia at
encontrar o ponto ressonante do circuito. Eu continuei substituindo os capacitores neste circuito at
encontrar a frequncia que eu estava procurando. O clculo da frequncia este:

Por alguma razo eu me confundi e iniciei o projeto tendo em mente a frequncia de 150kHz ao invs de
125kHz. As tags RFID respondem bem a uma frequncia mais alta, ento eu mantive assim para evitar
voltar a trs e redesenhar todo o circuito.
Com um ajuste simples eu verifiquei quais alteraes aconteciam quando a tag RFID era submetida a 4 ou
5 ciclos de frequncia da portadora. Uma vez que o sinal precisa ser AC e no DC, eu assumi que a
frequncia de transmisso seria 150kH/8 = 18.75kHz ou 150kHz/10 = 15kHz. Este detalhe eu encontrei
em um site que foi realmente til por conter boas informaes sobre
RFID:http://instruct1.cit.cornell.edu/courses/ee476/FinalProjects/s2006/cjr37/Website/index.htm.
A tag aparentemente codifica o dado usando FSK. As duas frequncias representam o 0 e 1 lgicos.
Com esta informaes em mos, eu avancei e iniciei o projeto do meu prprio indutor-antena. Uma vez
que eu mantive a idia de usar 150kHz como frequncia da portadora, eu fiz o clculo e fiquei com uma
indutncia de 160uH e um capacitor de 10nF. Eu utilizei a seguinte equao para estimar o nmero de

voltas que precisaria em minha bobina:

Onde x, y so o comprimento e a largura da bobina, h a altura e b a espessura da parte condutora. Eu


utilizer x=y=6cm, h=1cm e b=0.3cm. O nmero encontrado foi 34. Eu enrolei a bobina em uma caixa de
papel que encontrei, de onde eu extrai o x e y. Depois de enrolada, a bobina foi extrada e presa com fita
adesiva.

Para um ajuste fino da frequncia ressonante do sistema todo eu decidi brincar com o valor da
capacitncia. Usando o gerador de funo para variar a frequncia e visualizando o pico da sada com um
osciloscpio, eu variei os valores dos capacitores at que o pico da resposta ressonante fosse a 150kHz. O
capacitor final foi de 0.056uF. Uma vez que o meu capacitor precisa ser um valor de mercado, a bobina
que eu constru precisa ter uma indutncia maior que 160uH.

O prximo estgio era projetar o circuito analgico. Eu usei o confivel AMPOP TL062 (eu j possuia
vrios desses em casa). As frequncias envolvidas neste circuito so relativamente baixas, ento a baixa

peformace em frequncia deste AMPOP no problema. Eu havia decidido evitar um circuito complexo,
ento elegi o circuito mais simples que poderia ser usado.
Ento, a idia usar um simples diodo detector. Este detector de tenso passar por um primeiro AMPOP
configurado como amplificador inversor com uma resposta em frequncia passa baixa. Isso remover uma
boa parte do volume da portadora. O prximo estgio do circuito analgico extrair o sinal FSK. O
circuito mais simples que me veio a mente foi um filtro ressonante passa banda com frequncia central em
torno de 17kHz. Isso s me custaria um AMPOP. Este circuito foi desenhado no SPICE e o grfico da
frequncia de resposta mostrado no final desta pgina.
A sada do passa banda um sinal que pode ser diretamente conectado um microcontrolador PIC. Eu
escolhi para este projeto o bom e velho microcontrolador PIC16F628A. Com o comparador interno eu
posso receber o sinal diretamente do AMPOP e extrair o sinal digital.
A decodificao do sinal FSK feita por software, o que realmente interessante para no aumentar a
nossa lista de componentes.
Para decodificar o sinal FSK eu implementei trs subrotinas que usam o TMR0 para marcar o tempo
passado entre as mudanas detectadas na sada do comparador. Nenhuma interrupo usada. Ao invs
disso, as rotinas foram colocadas em loop at que um estado de mudana detectado. O loop que faz a
deteco leva em torno de trs ciclos de CPU para rodar; assim, dependendo de quando a mudana ocorre,
o erro mximo de 3 ciclos.
Algum que conhece como o hardware do PIC funciona poderia me perguntar porque eu no usei o
mdulo CCP (Compare and Capture). Infelismente eu utilizei o mdulo PWM para gerar a portadora de
150kHz. Como o CCP compartilha recursos com o mdulo PWM, apenas um deles pode ser ativado por
vez.
Para ter uma idia geral de como o sinal FSK aparece depois de digitalizado, eu adicionei um modo debug
onde ele ir capturar um nmero de ciclos de CPU ocorridos entre cada mudana no sinal de entrada.
Devido s limitaes da memria on-chip, somente 80+64 pontos de dados foram capturados. Isso no
grande o sufuciente para decodificar o dado, mas suficiente para ns desenharmos uma viso geral de
como o sinal se parece.

Sada do modo Debug, logo aps o final do contador de ciclos

Neste grfico, os nmeros no eixo Y representam o tempo (em ciclos de CPU) entre cada mudana de
estado no sinal de entrada. Eu decidi que 85 era um nmero bom para saber se o sinal de entrada era zero
ou um. No futuro eu acabei decidindo alterar a rotina de decodificao para contar o tempo gasto entre
cada borda de subida do sinal (uma vez que o sinal no possui componente DC, isto economizaria
memria j que eu s guardaria um bit ao invs de dois). Assim, a constante utilizada no firmware do PIC
cresceu e eu estou usando 170 (2x 85).
A sequncia decodificada dos dados se parece com:
0000000000000000000000001111111111111111000001111110000001111100000011111000000111111
... ...
1111110000011111100000011111000000111111111100000000000011111111111000000111110000000
00000 ...
0000001111110000001111111111000000111111000000000000000000000000111111111111111100000

Voc pode ver que o dado inicia com vrios zeros, seguidos de alguns nmeros 1 que so o dado atual. A
sequncia inteira continua a se repetir.
Eu conheo o sinal codificado em Manchester, ento, a partir do sinal, eu posso chegar seguinte
concluso:
1. A sinal inicia com uma sequencia de zeros, superior a vinte zeros.
2. A segunda sequncia tambm sempre uma sequncia de 1 com pelo menos 15 bits.
3. Para cada bit existem entre 10 e 12 nmeros zero ou um.
4. O bit zero se no existe nenhuma mudana no sinal durante o tempo de um bit.
Um grfico rpido pode ser desenhado:

1111110000011111100000011111000000111111111100000000000011111111111000000111110000000
00000
-----------|-----------|----------|_________|___________|
__________|----------|___________
1
1
1
0
0
0
1
0

Com essas regras em mente, eu adicionei a funo para decodificar o dado. Como um resumo de todo o
sistema eu adicionei os seguintes diagramas:

Diagrama de blocos

Esquemticos:
Analgico

Microcontrolador

Simulao Passa-Faixa:

Concluso
Atualmente eu ajustei o Vcc para 10V. A tenso se +5V extrada a partir de um regulador de tenso
78L05. O Vref setado pata a metade da tenso de alimentao, 2,5V. Isso feito utilizando um simples
divisor resistivo de 4,7k ohm.
O cdigo fonte pode ser baixado logo abaixo. Existem duas verses:
Reviso 1: 1 de Maio de 2007 Lanamento inicial
Reviso 2: 5 de Maio de 2007 Reviso 2
Recursos adicionados:
Auto start, iniciado quando o pino PB7 colocado em nvel alto;
Suporte a um buzzer, sada no pino 4
Deteco automtica do carto

Desenvolvido por Rick Huang.

Adaptado para o portugus por Eletronica.org, com autorizao do autor.

Anexos
Firmware Leitor RFID Reviso 2
Firmware Leitor RFID Reviso 1

;*******************************************************************************

;**
;**
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 <p16f628.inc>
__config
_HS_OSC
_PWRTE_ON

& _WDT_ON & _LVP_OFF & _BODEN_ON & _MCLRE_ON &

;*****************************************************************
;**
Variables
TempW
EQU
70h
;
BitLocation EQU
71h
CounterB
EQU
72h
NextFSR
EQU
73h
;
CounterW
EQU
74h

BitCount
LastBitVal
Data0
Data1
Data2
Data3
Data4
Zero
SerData
Temp
Output
Counter
TMRsample
BinCnt
Toggle
ThreeTry
FCData0
FCData1
FCData2
FCData3
FCData4
WrittenBit

EQU
EQU
EQU
EQU
EQU
EQU
EQU
EQU

75h
76h
77h
78h
79h
7ah
62h
7bh
EQU

EQU
EQU

; Zero is 0x00
7ch

7dh
7eh
EQU

EQU
EQU
EQU
EQU

7fh
60h
61h
63h
64h

EQU
EQU
EQU
EQU
EQU
EQU

; Final data output

65h
66h
67h
68h
69h

; First data captured

6ah

#define
#define
#define
#define
#define
#define
#define
#define

_POAS
PORTB, 7
_DOUT
PORTB, 6
_KEY PORTB, 5
_BEEPPORTB, 4
_PWM_O
PORTB, 3
_TXD PORTB, 2
_RXD PORTB, 1
_UNU1
PORTB, 0

#define

DecisionVal

; Power ON Auto Start


;
; Key good output
; Beeper output
; PWM - 150kHz
; UART
; UART
; Unused

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
;*****************************
StringStart:
PWelcomeMsg:
addwf PCL, F
DT
"Welcome!"
DT
H'0d', H'0a', H'00'
PCommandMsg:
DT
"Command Error?"

DATA

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
ParameterMsgEQU PParameterMsg - 1 - 5
; Strings start
NoAckMsg
EQU PNoAckMsg - 1 - 5

; 5 is the offset where the

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
call
SSpace
movlw '1'
xorwf SerData, W
btfsc STATUS, Z
goto AttemptSample
movlw '2'
xorwf SerData, W
btfsc STATUS, Z
goto DebugSample
movlw '3'
xorwf SerData, W
btfsc STATUS, Z
goto FullDecode
movlw '4'
xorwf SerData, W
btfsc STATUS, Z
goto HexTest
movlw '5'
xorwf SerData, W
btfsc STATUS, Z
goto BinTest
movlw '6'
xorwf SerData, W
btfsc STATUS, Z
goto AutoDecode
movlw '7'
xorwf SerData, W
btfsc STATUS, Z
goto TestBeep
movlw '8'
xorwf SerData, W
btfsc STATUS, Z
goto DummyNow
DummyNow:
movlw CommandMsg
call
SendString
goto WaitMore
;*********************
ClearError:
movfw RCREG
movfw RCREG

;Send it back out


;Decode command
;Start a RFID sample

;Debug run, output sampled data

;Fully capture and decode data

;Testing HEX routine

;Testing Bin dump routine

;No Debug message, auto card detection

;For all command not in use


;Send error command message
Clear receving overrun error

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
decfsz Counter, F
goto SampleLoop2
;---------------------movlw d'80'
movwf Counter
movlw 0a0h
movwf FSR

;A byte is full, move to the next one

Data is full, now dump the data out


;Do this for 80 bytes
;Use FSR to access data

SampleLoop10:
movfw INDF
call
SendBin
incf FSR, F
decfsz Counter, F
goto SampleLoop10
;---------------------movlw d'64'
movwf Counter
movlw 020h
movwf FSR
SampleLoop11:
movfw INDF

Switch bank
;Do this for 64 bytes
;Use FSR to access data

call
incf
decfsz
goto

SendBin
FSR, F
Counter, F
SampleLoop11

call
goto

NewLine
WaitMore

;*********************** Command 2 Debug mode


DebugSample:
call
CompCheck
movlw 0a0h
movwf FSR
movlw d'80'
movwf Counter

;Command 2: Sample RFID data, debug mode


;Dummy read once to setup condition
;Use FSR to store data
;Do this for 80 bytes

DebugSLoop1:
call CompCheck
movfw TMRsample
movwf INDF
incf FSR, F
decfsz Counter, F
goto DebugSLoop1

;A byte is full, move to the next one

;---------------------- 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
decfsz Counter, F
goto DebugSLoop2
;---------------------movlw d'80'
movwf Counter
movlw 0a0h
movwf FSR
DebugSLoop10:
movfw INDF
call
SendHex
call
NewLine

;A byte is full, move to the next one

Data is full, now dump the data out


;Do this for 80 bytes
;Use FSR to access data

incf FSR, F
decfsz Counter, F
goto DebugSLoop10
;---------------------movlw d'64'
movwf Counter
movlw 020h
movwf FSR

Switch bank
;Do this for 64 bytes
;Use FSR to access data

DebugSLoop11:
movfw INDF
call
SendHex
call
NewLine
incf FSR, F
decfsz Counter, F
goto DebugSLoop11
call
goto

NewLine
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
movlw d'80'
movwf Counter
FDLoop1:
call
incf
decfsz
goto

CaptureByte
FSR, F
Counter, F
FDLoop1

;---------------------movlw d'80'
movwf Counter
movlw 0a0h
movwf FSR
FDLoop10:
movfw INDF
call
SendBin
incf FSR, F
decfsz Counter, F
goto FDLoop10

;Use FSR to store data


;Do this for 80 bytes

;A byte is full, move to the next one

Data is full, now dump the data out


;Do this for 80 bytes
;Use FSR to access data

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
movlw d'7'
subwf BitCount, W
btfss STATUS, C
goto FD_Send2bit
movlw '*'
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
btfss STATUS, C
goto FD_BitLoopZ
call
NewLine

; Bitcount - 15 = Positive, Looped already, STOP

;Negative, 1 bits
;Positive, 2 bit

;NextFSR - W
;Negative, keep looping
;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
goto

NewLine
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
movlw d'80'
movwf Counter
ADLoop1:
call
incf
decfsz
goto

CaptureByte
FSR, F
Counter, F
ADLoop1

;Use FSR to store data


;Do this for 80 bytes

;A byte is full, move to the next one

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
clrf

Data4
Toggle

AD_BitLoopZ:
call
GetBitCount
movlw d'20'
subwf BitCount, W
btfsc STATUS, C
goto AD_DoneDecode
movlw d'7'
subwf BitCount, W
btfss STATUS, C
goto AD_Send2bit
bsf
STATUS, C
call
LongShift
call
LongShift
goto AD_NextBit
AD_Send2bit:
bcf
STATUS, C
call
LongShift
AD_NextBit:
incf WrittenBit, F
movlw 0efh
subwf NextFSR, W
btfss STATUS, C
goto AD_BitLoopZ
goto

AutoDecode

; Bitcount - 15 = Positive, Start condition again, STOP

;Negative, 1 bits
;Positive, 2 bit

;NextFSR - W
;Negative, keep looping
;Positive, NextFSR > 0xef, error
;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'
subwf WrittenBit, W
btfss STATUS, C
goto AutoDecode

;Check number of bit written, too little, restart

movlw h'55'
subwf WrittenBit, W
btfsc STATUS, C
goto AutoDecode

;Check number of bit written, too many, restart

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
goto

Beep
WaitMore

;*********************** Command 4,5 Serial debug


HexTest:
call
RcvHex
movfw Output
call
SendHex
call
NewLine
goto WaitMore
BinTest:
call
RcvHex
movfw Output
call
SendBin
call
NewLine
goto WaitMore
TestBeep:
call
call
goto

Beep
NewLine
WaitMore

;Command 4: Hex test

;Command 5: Bin test

;Command 7: Test beep

;*****************************
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
return

Toggle, 0

;----------------------------------------------------------------; CaptureByte, Capture a single byte of data


; Output: INDF
CaptureByte:

call CompCheck
movlw DecisionVal
subwf TMRsample, W
rlf
INDF, F

;Hard decision, 0 = 159 cycle, 1 = 198 cycle


;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
clrf
TMR0
return

;Store the result in TMRsample


;Clear TMR0 for the next bit

;----------------------------------------------------------------; 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
btfsc STATUS, C
goto Letter1
RtnLetter1:

;F-W
; Positive means letter input

swapf SerData, W
movwf Output
RcvHexLoop:
btfss PIR1, RCIF
goto RcvHexLoop
movfw RCREG
movwf SerData
movwf TXREG
movlw 30h
subwf SerData, F
movlw 10h
subwf SerData, W
btfsc STATUS, C
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
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
goto Letter2E
goto RtnLetter2
Letter2E:
movlw d'32'
subwf SerData, F
goto RtnLetter2

; Send it back out

;F-W
; Positive means letter input

; Positive means bad input

; Positive means bad input

;----------------------------------------------------------------; 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
goto SendChar
movwf TXREG
return

;Wait till buffer is empty

;----------------------------------------------------------------; 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

You might also like