[PIC] Wiegand decoding and reading

185 views
Skip to first unread message

Mauricio Jancic

unread,
Jan 23, 2008, 5:56:07 AM1/23/08
to Microcontroller discussion list - Public.
Hello,

This mail is longer than I expected. I'm sorry for that. The basic
issue is about the IOC feature, specifically trying to read a wiegand
package.

I'm trying to read a card number using a wiegand output reader.

I'm using a PIC16F88x so I'm using the full portb interrupt on
change. The IOC is properly set on by setting ICB<1:0> bits, since I'm using
RB0 and RB1.

On the interrupt, when IOC is detected I have the following code:

if( RBIF && RBIE )
{
RX_TEMP = PORTB; // Read PORTB
RX_TEMP &= 0x03; // Leave only the necesary bits

if( (RX_TEMP != 0x03) && RX_TEMP ) // Both bits can't
be 1 or 0 at the same time *ERROR CONDITION*
{
if( RX_TEMP & 0x01 ) // If RB0 is 1
{
getCardData( 1 );
}
else
{
getCardData( 0 );
}
wait = 2; // Wait for
500 uS
RBIE = 0; // Disable
IOC for the above time
timeout = 200; // Timeout end of
card (50 ms)
}

RBIF=0; //Clear IOC bit
}


Well, that's the basic code. It's working mostly, except that every
once in a while, an interrupt generates but the code reads a bit
incorrectly.
The "wait" is used to avoid the IOC to interrupt when the wiegand
signals return to high level. Since the wiegand LOW pulse is aprox. 40-50 uS
and the space between bits is 2mS, the 500uS should be fine.

Once the 500uS have finished the IOC interrupt is enabled:

RX_TEMP = PORTB;
RBIF = 0;
RBIE = 1;

This procedure is to ensure that any interrupt is clear before
re-enabling the IOC.


Problems:
Once a read is finished, the firmware outputs a stream of data
trough the serial port (see attached file). The correct number of the card
should be FC 081 and Card No. 00695. As you can see, the number is read ok
most of the time, but the parity is not.

Page 2 here explains how the parity should be.
http://www.hidcorp.com/documents/understandCardDataFormats_wp_en.pdf

In the beginning I was using the internal oscillator, but that lead to
aprox. 4 to 6 *ERROR CONDITIONS* detected, when I change the oscillator to
20 MHz external, that count went down to 0 to 1. That makes me wonder if
there should be something I'm missing about the whole IOC feature.

Regards,

Mauricio

output.txt

Bill van Dijk

unread,
Jan 23, 2008, 6:41:34 PM1/23/08
to Microcontroller discussion list - Public.
I just finished a project exactly like yours, although I did my code in
assembler. I did not use the interrupt since there are two data lines to
check. I used polling of the two ports.
A data pulse is about 40us, with a 2ms spacing. A read can be considered
completed after 100ms. I built a trap to catch cards with more than 26 bits,
in which case my code does not try to process the data (which makes no sense
anyway since the format is unknown), but simply displays the number of bits
read. Most reader outputs are open collector outputs capable of sinking
about 16mA.

If you use the interrupt on change feature, make sure you disable the
interrupt as soon as one occurs, and reset only once the data line has
returned to high before resetting the interrupt again (or it may result in
an incorrect interrupt as the line returns back to its high state). Your
method of waiting is risky. The timing of the reader is too "loose".

> if( (RX_TEMP != 0x03) && RX_TEMP ) // Both bits can't
> be 1 or 0 at the same time *ERROR CONDITION*

I'm not a C guy, but both output bits of the reader WILL be 1 in the normal
rest state. They can never be both 0 though. Testing for this condition is
redundant IMHO though.

Your attachment reads:
The parity is calculated as follow:
Even parity: using bits 1 to 12
Odd parity: using bits 12 to 25

That is not exactly correct, the leading parity bit (0), includes itself, 0
- 12. The trailing parity bit (26) includes bits 13 - 26 inclusive. Checking
the parity is actually surprisingly simple. In the even parity, count all
the 1's (of the proper bits), and check the LSB of the register containing
the count to be 0. For the odd parity it should be 1.

I run mine of the internal RC oscillator, no problem at all. I also decode
and do parity check, and drive an LCD all off that one PIC (16F628A)

I hope this helps,

Bill van Dijk


--
http://www.piclist.com PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist

Mauricio Jancic

unread,
Jan 24, 2008, 7:05:04 AM1/24/08
to Microcontroller discussion list - Public.
Thanks. The problem was solved yesterday. It was quite stupid actually.
There was some additional code on the interrupt that on a given condition
took more than 50uS to execute. If, a pulse was received while on this
particular condition, the pulse will be lost and I'll miss a bit of
information.

Regarding the IF that you mentioned. It's to provide additional security
when reading the card. It's just some way to make sure you are not reading
garbage.

Regards,

Reply all
Reply to author
Forward
0 new messages