37
Leitor RFID Cartões RFID são normalmente usados para controle de acesso e tickets de ônibus e metrôs. Eles são convenientes porque não precisam de contato direto para transferir informações de/para o cartão. Como estes cartões são alimentados pelos próprios leitores, dispensam o uso de baterias que precisariam ser recarregadas. Para os meus experimentos estou usando catrões da HID ISProx. Estes cartões são os mais simples de toda a linha de cartões RFID, que somente armazenam um número de série e não usam criptografia. A frequência da portadora é de 125kHz. O primeiro passo é descobrir como desenvolver um leitor simples. Nós sabemos que o cartões RFID é alimentado pelo campo magnético emitido pelo leitos. As tags¹ RFID transferem informação de volta ao leitor consumindo este campo magnético, que é detectado pelo leitor como uma variação no campo. ¹ São chamados de “tags” RFID todos os elementos que armazenam informações e são móveis, como o cartão, neste caso específico.

Leitor RFID

Embed Size (px)

DESCRIPTION

Leitor eletrônico de rfid

Citation preview

Leitor RFID

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. Astags 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. AstagsRFID 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.

Atagaparentemente 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 ... ...

111111000001111110000001111100000011111111110000000000001111111111100000011111000000000000 ...

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:

111111000001111110000001111100000011111111110000000000001111111111100000011111000000000000

-----------|-----------|----------|_________|___________|__________|----------|___________

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 4Deteco automtica do carto

Desenvolvido porRick 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

__config_HS_OSC& _WDT_ON & _LVP_OFF & _BODEN_ON & _MCLRE_ON & _PWRTE_ON

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

;**Variables

TempW

EQU

70h

;

BitLocationEQU

71h

CounterBEQU

72h

NextFSR

EQU

73h

;

CounterWEQU

74h

BitCountEQU

75h

LastBitValEQU

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

TMRsampleEQU

60h

BinCnt

EQU

61h

Toggle

EQU

63h

ThreeTryEQU

64h

FCData0

EQU

65h

; First data captured

FCData1

EQU

66h

FCData2

EQU

67h

FCData3

EQU

68h

FCData4

EQU

69h

WrittenBitEQU

6ah

#define

_POASPORTB, 7

; Power ON Auto Start

#define

_DOUTPORTB, 6

;

#define

_KEYPORTB, 5

; Key good output

#define

_BEEPPORTB, 4

; Beeper output

#define

_PWM_OPORTB, 3

; PWM - 150kHz

#define

_TXDPORTB, 2

; UART

#define

_RXDPORTB, 1

; UART

#define

_UNU1PORTB, 0

; Unused

#define

DecisionVal

d'170' ;Hard decision, 0 = 159 cycle, 1 = 198 cycle

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

;** Program code here

gotoStart

ORG4

;waiting for

;interrupt vector

;gotoInterrupt

ORG5

;*****************************DATA

StringStart:

PWelcomeMsg:

addwfPCL, F

DT"Welcome!"

DTH'0d', H'0a', H'00'

PCommandMsg:

DT"Command Error?"

DTH'0d', H'0a', H'00'

PParameterMsg:

DT"Parameter Error?"

DTH'0d', H'0a', H'00'

PNoAckMsg:

DT"Missing Ack"

DTH'0d', H'0a', H'00'

StringEnd:

WelcomeMsg

EQU0

CommandMsg

EQUPCommandMsg - 1 - 5

; 5 is the offset where the

ParameterMsgEQUPParameterMsg - 1 - 5

; Strings start

NoAckMsg

EQUPNoAckMsg - 1 - 5

HexTable:

addwfPCL, F

DT"0123456789ABCDEF"

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

;********************Program Starts here

Start:

;*********************Setup WDT

;********************** Setting up TMR0, used to decode FSK

bcf

_BEEP

clrwdt

bsf

STATUS, RP0

movlwb'00001111'

;Prescaler to WDT, 1:128

movwfOPTION_REG

clrwdt

;*********************Setting up environment

movlwb'10000010'

;Serial port in too

movwfTRISB

;Set port B I/O

movlwb'00000111'

movwfTRISA

;Set port A I/O

bcf

STATUS, RP0

clrfPORTA

;********************** Disable 16f628 specific features

movlw b'00000110'

;Setup comparator

movwfCMCON

;********************** Setting up PWM module for 150KHz signal

movlwb'00001100'

;Enable PWM module, duty = 2

movwfCCP1CON

movlwb'00000010'

;Using source frequency = 12MHz

movwfCCPR1L

movlwb'00000101'

;Setting up TMR2, Prescale = 1:4

movwfT2CON

bsf

STATUS, RP0

movlwb'00000100'

movwfPR2

;Setting the period = 4

bcf

STATUS, RP0

;********************** Setup UART

bsf

STATUS, RP0

movlwd'12'

;57600 for 12MHz Clock, High speed

movwfSPBRG

;The only rate with low mismatch

movlwb'10100111'

;Async 8-bit @ High speed

movwfTXSTA

bcf

STATUS, RP0

movlwb'10110000'

;Enable serial port

movwfRCSTA

clrfZero

movlwWelcomeMsg

;Display welcome string on startup

callSendString

;----------------------- Debug insert

gotoSkipDebug

movlw0a0h

movwfFSR

movlwb'00000011'

movwfINDF

incfFSR, F

movlwb'11111111'

movwfINDF

incfFSR, F

movlwb'11111100'

movwfINDF

incfFSR, F

movlwb'00011111'

movwfINDF

incfFSR, F

movlwb'10000001'

movwfINDF

incfFSR, F

movlwb'11110000'

movwfINDF

incfFSR, F

movlwb'00111110'

movwfINDF

incfFSR, F

movlwb'00000111'

movwfINDF

incfFSR, F

goto FD_DecodeEntry

SkipDebug:

;----------------------- Wait for command

WaitMore:

btfsc_POAS

gotoAutoDecode

clrwdt

btfscRCSTA, OERR

gotoClearError

btfssPIR1, RCIF

gotoWaitMore

movfwRCREG

movwfSerData

movwfTXREG

;Send it back out

callSSpace

movlw'1'

;Decode command

xorwfSerData, W

btfscSTATUS, Z

gotoAttemptSample;Start a RFID sample

movlw'2'

xorwfSerData, W

btfscSTATUS, Z

gotoDebugSample

;Debug run, output sampled data

movlw'3'

xorwfSerData, W

btfscSTATUS, Z

gotoFullDecode

;Fully capture and decode data

movlw'4'

xorwfSerData, W

btfscSTATUS, Z

gotoHexTest

;Testing HEX routine

movlw'5'

xorwfSerData, W

btfscSTATUS, Z

gotoBinTest

;Testing Bin dump routine

movlw'6'

xorwfSerData, W

btfscSTATUS, Z

gotoAutoDecode

;No Debug message, auto card detection

movlw'7'

xorwfSerData, W

btfscSTATUS, Z

gotoTestBeep

movlw'8'

xorwfSerData, W

btfscSTATUS, Z

gotoDummyNow

DummyNow:

;For all command not in use

movlwCommandMsg

callSendString

;Send error command message

gotoWaitMore

;*********************Clear receving overrun error

ClearError:

movfwRCREG

movfwRCREG

bcf

RCSTA, CREN

bsf

RCSTA, CREN

gotoWaitMore

;----------------------Commands execution

;********************** Command 1:

AttemptSample:

;Command 1: Sample RFID data, do 1024 bits

callCompCheck

;Dummy read once to setup condition

movlw0a0h

movwfFSR

;Use FSR to store data

movlwd'80'

;Do this for 80 bytes

movwfCounter

SampleLoop1:

callCaptureByte

incfFSR, F

;A byte is full, move to the next one

decfszCounter, F

gotoSampleLoop1

;---------------------- Switch memory bank

movlw020h

movwfFSR

;Use FSR to store data

movlwd'64'

;Do this for 64 bytes

movwfCounter

SampleLoop2:

callCaptureByte

incfFSR, F

;A byte is full, move to the next one

decfszCounter, F

gotoSampleLoop2

;----------------------Data is full, now dump the data out

movlwd'80'

;Do this for 80 bytes

movwfCounter

movlw0a0h

movwfFSR

;Use FSR to access data

SampleLoop10:

movfwINDF

callSendBin

incfFSR, F

decfszCounter, F

gotoSampleLoop10

;----------------------Switch bank

movlwd'64'

;Do this for 64 bytes

movwfCounter

movlw020h

movwfFSR

;Use FSR to access data

SampleLoop11:

movfwINDF

callSendBin

incfFSR, F

decfszCounter, F

gotoSampleLoop11

callNewLine

gotoWaitMore

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

DebugSample:

;Command 2: Sample RFID data, debug mode

callCompCheck

;Dummy read once to setup condition

movlw0a0h

movwfFSR

;Use FSR to store data

movlwd'80'

;Do this for 80 bytes

movwfCounter

DebugSLoop1:

callCompCheck

movfwTMRsample

movwfINDF

incfFSR, F

;A byte is full, move to the next one

decfszCounter, F

gotoDebugSLoop1

;---------------------- Switch memory bank

movlw020h

movwfFSR

;Use FSR to store data

movlwd'64'

;Do this for 64 bytes

movwfCounter

DebugSLoop2:

callCompCheck

movfwTMRsample

movwfINDF

incfFSR, F

;A byte is full, move to the next one

decfszCounter, F

gotoDebugSLoop2

;----------------------Data is full, now dump the data out

movlwd'80'

;Do this for 80 bytes

movwfCounter

movlw0a0h

movwfFSR

;Use FSR to access data

DebugSLoop10:

movfwINDF

callSendHex

callNewLine

incfFSR, F

decfszCounter, F

gotoDebugSLoop10

;----------------------Switch bank

movlwd'64'

;Do this for 64 bytes

movwfCounter

movlw020h

movwfFSR

;Use FSR to access data

DebugSLoop11:

movfwINDF

callSendHex

callNewLine

incfFSR, F

decfszCounter, F

gotoDebugSLoop11

callNewLine

gotoWaitMore

;*********************** Command 3 Full capture and decode

FullDecode:

;Wait for start sequence, than start capture

callCompCheck

;Dummy read once to setup condition

callWaitTillStart;Wait for start

movlw0a0h

movwfFSR

;Use FSR to store data

movlwd'80'

;Do this for 80 bytes

movwfCounter

FDLoop1:

callCaptureByte

incfFSR, F

;A byte is full, move to the next one

decfszCounter, F

gotoFDLoop1

;----------------------Data is full, now dump the data out

movlwd'80'

;Do this for 80 bytes

movwfCounter

movlw0a0h

movwfFSR

;Use FSR to access data

FDLoop10:

movfwINDF

callSendBin

incfFSR, F

decfszCounter, F

gotoFDLoop10

callNewLine

FD_DecodeEntry:

;---------------------- Collaspe data bits

movlwd'8'

;Set up for bit read

movwfBitLocation

movlw0a0h

movwfNextFSR

;---------------------- Start extraction

clrfData0

;Clear data holder

clrfData1

clrfData2

clrfData3

clrfData4

clrfToggle

FD_BitLoopZ:

callGetBitCount

movfwBitCount

movlwd'20'

subwfBitCount, W

btfscSTATUS, C

gotoFD_DoneDecode; Bitcount - 15 = Positive, Looped already, STOP

movlwd'7'

subwfBitCount, W

btfssSTATUS, C

gotoFD_Send2bit

;Negative, 1 bits

movlw'*'

;Positive, 2 bit

callSendChar

callSendChar

bsf

STATUS, C

callLongShift

callLongShift

gotoFD_NextBit

FD_Send2bit:

movlw'_'

callSendChar

bcf

STATUS, C

callLongShift

FD_NextBit:

movlw0efh

subwfNextFSR, W

;NextFSR - W

btfssSTATUS, C

gotoFD_BitLoopZ

;Negative, keep looping

callNewLine

;Positive, NextFSR > 0xef

;----------------------- Final data output

FD_DoneDecode:

callNewLine

movfwData4

callSendHex

movfwData3

callSendHex

movfwData2

callSendHex

movfwData1

callSendHex

movfwData0

callSendHex

callNewLine

gotoWaitMore

;*********************** Command 6: Auto detection of card

AutoDecode:

clrwdt

movlw03h

;Three trys

movwfThreeTry

AD_CaptureAgain:

clrfWrittenBit

clrwdt

callCompCheck

;Dummy read once to setup condition

callWaitTillStart;Wait for start condition

movlw0a0h

movwfFSR

;Use FSR to store data

movlwd'80'

;Do this for 80 bytes

movwfCounter

ADLoop1:

callCaptureByte

incfFSR, F

;A byte is full, move to the next one

decfszCounter, F

gotoADLoop1

AD_DecodeEntry:

;---------------------- Collaspe data bits

movlwd'8'

;Set up for bit read

movwfBitLocation

movlw0a0h

movwfNextFSR

;---------------------- Start extraction

clrfData0

;Clear data holder

clrfData1

clrfData2

clrfData3

clrfData4

clrfToggle

AD_BitLoopZ:

callGetBitCount

movlwd'20'

subwfBitCount, W

btfscSTATUS, C

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

movlwd'7'

subwfBitCount, W

btfssSTATUS, C

gotoAD_Send2bit

;Negative, 1 bits

bsf

STATUS, C

;Positive, 2 bit

callLongShift

callLongShift

gotoAD_NextBit

AD_Send2bit:

bcf

STATUS, C

callLongShift

AD_NextBit:

incfWrittenBit, F

movlw0efh

subwfNextFSR, W

;NextFSR - W

btfssSTATUS, C

gotoAD_BitLoopZ

;Negative, keep looping

;Positive, NextFSR > 0xef, error

gotoAutoDecode

;Restart...

;----------------------- Check data is the same for three times

AD_DoneDecode:

movlwd'30'

;Error check, if too many zero bits, restart

subwfBitCount, W

btfscSTATUS, C

gotoAutoDecode

;Too many bits

movlwh'46'

;Check number of bit written, too little, restart

subwfWrittenBit, W

btfssSTATUS, C

gotoAutoDecode

movlwh'55'

;Check number of bit written, too many, restart

subwfWrittenBit, W

btfscSTATUS, C

gotoAutoDecode

movlwd'3'

xorwfThreeTry, W

btfssSTATUS, Z

;First try indicator

gotoAD_NotFirstTry

movfwData0

movwfFCData0

movfwData1

movwfFCData1

movfwData2

movwfFCData2

movfwData3

movwfFCData3

movfwData4

movwfFCData4

decfThreeTry, F

gotoAD_CaptureAgain

AD_NotFirstTry:

movfwData0

xorwfFCData0, W

btfssSTATUS, Z

gotoAutoDecode

;Not matched, restart

movfwData1

xorwfFCData1, W

btfssSTATUS, Z

gotoAutoDecode

;Not matched, restart

movfwData2

xorwfFCData2, W

btfssSTATUS, Z

gotoAutoDecode

;Not matched, restart

movfwData3

xorwfFCData3, W

btfssSTATUS, Z

gotoAutoDecode

;Not matched, restart

movfwData4

xorwfFCData4, W

btfssSTATUS, Z

gotoAutoDecode

;Not matched, restart

decfszThreeTry, F

gotoAD_CaptureAgain

;----------------------- Final data output

callNewLine

movfwData4

callSendHex

movfwData3

callSendHex

movfwData2

callSendHex

movfwData1

callSendHex

movfwData0

callSendHex

callNewLine

callBeep

gotoWaitMore

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

HexTest:

callRcvHex

;Command 4: Hex test

movfwOutput

callSendHex

callNewLine

gotoWaitMore

BinTest:

callRcvHex

;Command 5: Bin test

movfwOutput

callSendBin

callNewLine

gotoWaitMore

TestBeep:

callBeep

;Command 7: Test beep

callNewLine

gotoWaitMore

;*****************************SUBROUTINE

;-----------------------------------------------------------------

; LongShift, Shift 1 bit of the data into Data[0:4] register

; Shift only 1 bit per two calls

; Input: C

LongShift:

btfssToggle, 0

gotoToggleNotSet

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:

callCompCheck

movlwDecisionVal

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

subwfTMRsample, W

rlf

INDF, F

;Store the data into pointed address

callCompCheck

;Do this for 8 times to fill up a byte

movlwDecisionVal

subwfTMRsample, W

rlf

INDF, F

callCompCheck

movlwDecisionVal

subwfTMRsample, W

rlf

INDF, F

callCompCheck

movlwDecisionVal

subwfTMRsample, W

rlf

INDF, F

callCompCheck

movlwDecisionVal

subwfTMRsample, W

rlf

INDF, F

callCompCheck

movlwDecisionVal

subwfTMRsample, W

rlf

INDF, F

callCompCheck

movlwDecisionVal

subwfTMRsample, W

rlf

INDF, F

callCompCheck

movlwDecisionVal

subwfTMRsample, W

rlf

INDF, F

return

;-----------------------------------------------------------------

; WaitTillStart, Wait until the start sequence is detected

; This is marked by 20 or more zeros

WaitTillStart:

movlwd'20'

movwfCounterW

WTS_next:

clrwdt

callCompCheck

movlwDecisionVal

subwfTMRsample, W

btfscSTATUS, C

;Check for a 0 value

gotoWaitTillStart;If 1, restart

decfszCounterW, F

gotoWTS_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:

btfscCMCON, C1OUT

gotoSCSampleL3

SCSampleL2:

;Was a low, wait for a high

btfssCMCON, C1OUT

gotoSCSampleL2

movfwTMR0

movwfTMRsample

;Store the result in TMRsample

clrfTMR0

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

clrfBitCount

btfssLastBitVal, 0

gotoGBC_lastbit0

;gotoGBC_lastbit1;Last bit is a 1

GBC_loop1:

callGetNextBit

btfssSTATUS, Z

gotoGBC_done1

incfBitCount, F

;Continue if value is a zero

gotoGBC_loop1

GBC_done1:

;Done if bit change to one

bcf

LastBitVal, 0

return

GBC_lastbit0:

;Last bit is a 0

GBC_loop0:

callGetNextBit

btfscSTATUS, Z

gotoGBC_done0

incfBitCount, F

;Continue if value is a one

gotoGBC_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:

movfwNextFSR

movwfFSR

movfwBitLocation

movwfCounterB

decfszBitLocation, F;Go to the next bit

gotoGNB_nextStep

movlwd'8'

movwfBitLocation

incfNextFSR, F

;Rollover for the next read

GNB_nextStep:

clrfTempW

bsf

STATUS, C

GNB_loop:

rlf

TempW, F

;TempW contain bit mask

decfszCounterB, F

gotoGNB_loop

movfwTempW

andwfINDF, W

;Result in Z

return

;*****************************SUBROUTINE

;-----------------------------------------------------------------

; SendHex, Send a single byte out of serial port, hex format

; Input: data stored in W

SendHex:

movwfTemp

swapfTemp, W

andlw00fh

callHexTable

HexWaitLoop1:

btfssPIR1, TXIF;Wait till buffer is empty

gotoHexWaitLoop1

movwfTXREG

movfTemp, W

andlw00fh

callHexTable

HexWaitLoop2:

btfssPIR1, TXIF;Wait till buffer is empty

gotoHexWaitLoop2

movwfTXREG

return

;-----------------------------------------------------------------

; SendBin, Send a single byte out of serial port, binary format

; Input: data stored in W

SendBin:

movwfTemp

movlw8h

movwfBinCnt

BinWaitLoop1:

btfssPIR1, TXIF;Wait till buffer is empty

gotoBinWaitLoop1

movlw'0'

btfscTemp, 7

movlw'1'

movwfTXREG

rlf

Temp, F

decfszBinCnt, F

gotoBinWaitLoop1

return

;-----------------------------------------------------------------

; RcvHex, Receive a single byte from serial port in hex format

; Output: data stored in Output

RcvHex:

btfssPIR1, RCIF

gotoRcvHex

movfwRCREG

movwfSerData

movwfTXREG

; Send it back out

movlw30h

subwfSerData, F

movlw10h

subwfSerData, W; F - W

btfscSTATUS, C; Positive means letter input

gotoLetter1

RtnLetter1:

swapfSerData, W

movwfOutput

RcvHexLoop:

btfssPIR1, RCIF

gotoRcvHexLoop

movfwRCREG

movwfSerData

movwfTXREG

; Send it back out

movlw30h

subwfSerData, F

movlw10h

subwfSerData, W; F - W

btfscSTATUS, C; Positive means letter input

gotoLetter2

RtnLetter2:

movfwSerData

iorwfOutput, F

callSSpace

return

Letter1:

movlw07h

subwfSerData, F

movlw10h

subwfSerData, W

btfscSTATUS, C; Positive means bad input

gotoLetter1E

gotoRtnLetter1

Letter1E:

movlwd'32'

subwfSerData, F

gotoRtnLetter1

Letter2:

movlw07h

subwfSerData, F

movlw10h

subwfSerData, W

btfscSTATUS, C; Positive means bad input

gotoLetter2E

gotoRtnLetter2

Letter2E:

movlwd'32'

subwfSerData, F

gotoRtnLetter2

;-----------------------------------------------------------------

; LongDelay, 15 cycles, 3ins/cycle 22.5uS for 8Mhz clock

long_delay:

movlwd'15'

movwfCounter

long_delay_L:

decfszCounter, F

gotolong_delay_L

return

;-----------------------------------------------------------------

; SendString, send the string out to serial port

; Input: String location in W

SendString:

movwfCounter

SendLoop:

btfssPIR1, TXIF;Wait till buffer is empty

gotoSendLoop

callStringStart

iorwfZero, W

btfscSTATUS, Z;Zero is the end of string

return

movwfTXREG

incfCounter, F

movfwCounter

gotoSendLoop

;-----------------------------------------------------------------

; NewLine, send s newline character into serial port

; Input: None

NewLine:

btfssPIR1, TXIF;Wait till buffer is empty

gotoNewLine

movlw0dh

movwfTXREG

movlw0ah

NewLineLoop:

btfssPIR1, TXIF;Wait till buffer is empty

gotoNewLineLoop

movwfTXREG

return

;-----------------------------------------------------------------

; Space, send a space character into serial port

; Input: None

SSpace:

btfssPIR1, TXIF;Wait till buffer is empty

gotoSSpace

movlw' '

movwfTXREG

return

;-----------------------------------------------------------------

; SendChar, send a character into serial port

; Input: W

SendChar:

btfssPIR1, TXIF;Wait till buffer is empty

gotoSendChar

movwfTXREG

return

;-----------------------------------------------------------------

; Beep, genertate a 0.5 sec beeper signal, 2KHz

; Using: Data0, 1, 2, 3

Beep:

clrfToggle

movlwd'200'

movwfData0

movlwd'100'

movwfData2

movlwd'10'

movwfData3

BeepLoop:

decfszData0, F

gotoBeepLoop

movlwd'200'

movwfData0

movlwb'00010000'

xorwfPORTB, F

clrwdt

decfszData2, F

gotoBeepLoop

movlwd'100'

movwfData2

decfszData3, F

gotoBeepLoop

bcf

_BEEP

return

;-----------------------------------------------------------------

; End of program

end