BiohazrD:
I am actually also building one of these, although I have had different problems (reading the incoming data fast enough). Would you mind posting all of your code somewhere? I'd like to see how you are doing things to give me some insight to my project.
Hey BiohazrD,
You posted in my thread, and mentioned you were working with a card reader too? Here is my code, I got it from this instructable: http://www.instructables.com/id/Arduino-magnetic-stripe-decoder/ and make tweaks to fit it on an ATMEGA168. There is definitely a better way to do the bit to decimal conversion as well. but it work very nicely with a Omron V3A-4K, but Im sure it would work fine with any 2-track one-way card reader with a clock/data/card_present pin. Here is my code, you don't need to have both interrupts and the bit operations could be reduced down but the following works well:
The bit conversion is based on the following:
[size=8pt]
** ANSI/ISO BCD Data format **
This is a 5-bit Binary Coded Decimal format. It uses a 16-character set, which
uses 4 of the 5 available bits. The 5th bit is an ODD parity bit, which means
there must be an odd number of 1's in the 5-bit character..the parity bit will
"force" the total to be odd. Also, the Least Significant Bits are read FIRST
on the strip. See Figure 6.
The sum of the 1's in each case is odd, thanks to the parity bit. If the read
system adds up the 5 bits and gets an EVEN number, it flags the read as ERROR,
and you got to scan the card again (I *know* a lot of you out there *already*
understand parity, but I got to cover all the bases...not everyone sleeps with
their modem and can recite the entire AT command set at will, you know). See
Figure 6 for details of ANSI/ISO BCD.
Figure 6: ANSI/ISO BCD Data Format
---------
* Remember that b1 (bit #1) is the LSB (least significant bit)!
* The LSB is read FIRST!
* Hexadecimal conversions of the Data Bits are given in parenthesis (xH).
--Data Bits-- Parity
b1 b2 b3 b4 b5 Character Function
0 0 0 0 1 0 (0H) Data
1 0 0 0 0 1 (1H) "
0 1 0 0 0 2 (2H) "
1 1 0 0 1 3 (3H) "
0 0 1 0 0 4 (4H) "
1 0 1 0 1 5 (5H) "
0 1 1 0 1 6 (6H) "
1 1 1 0 0 7 (7H) "
0 0 0 1 0 8 (8H) "
1 0 0 1 1 9 (9H) "
0 1 0 1 1 : (AH) Control
1 1 0 1 0 ; (BH) Start Sentinel
0 0 1 1 1 < (CH) Control
1 0 1 1 0 = (DH) Field Separator
0 1 1 1 0 > (EH) Control
1 1 1 1 1 ? (FH) End Sentinel
***** 16 Character 5-bit Set *****
10 Numeric Data Characters
3 Framing/Field Characters
3 Control Characters
The magstripe begins with a string of Zero bit-cells to permit the self-
clocking feature of biphase to "sync" and begin decoding. A "Start Sentinel"
character then tells the reformatting process where to start grouping the
decoded bitstream into groups of 5 bits each. At the end of the data, an "End
Sentinel" is encountered, which is followed by an "Longitudinal Redundancy
Check (LRC) character. The LRC is a parity check for the sums of all b1, b2,
b3, and b4 data bits of all preceding characters. The LRC character will catch
the remote error that could occur if an individual character had two
compensating errors in its bit pattern (which would fool the 5th-bit parity
check).
The START SENTINEL, END SENTINEL, and LRC are collectively called "Framing
Characters", and are discarded at the end of the reformatting process.
[/size]
For my project I am reading from Track #2:
[size=8pt] *** Track 2 Layout: ***
| SS | PAN | FS | Additional Data | ES | LRC |
SS=Start Sentinel ";"
PAN=Primary Acct. # (19 digits max)
FS=Field Separator "="
Additional Data=Expiration Date, offset, encrypted PIN, etc.
ES=End Sentinel "?"
LRC=Longitudinal Redundancy Check
[/size]
/*
* Magnetic Stripe Reader
* Original Code by Stephan King http://www.kingsdesign.com
* Minor Tweaks made to fit on ATMEGA168
* Reads a magnetic stripe.
*
*/
int cld1Pin = 5; // Card status pin
int rdtPin = 2; // Data pin
volatile int reading = 0; // Reading status
volatile int buffer[255]; // Buffer for data
volatile int i = 0; // Buffer counter
volatile int bit = 0; // global bit
volatile char cardData[40]; // holds card info
volatile int charCount = 0;
void setup() {
Serial.begin(9600);
// The interrupts are key to reliable
// reading of the clock and data feed
attachInterrupt(0, changeBit, CHANGE);
attachInterrupt(1, writeBit, FALLING);
}
// Flips the global bit
void changeBit(){
if (bit == 0) {
bit = 1;
} else {
bit = 0;
}
}
// Writes the bit to the buffer
void writeBit(){
buffer[i] = bit;
i++;
}
void loop(){
// Active when card present
while(digitalRead(cld1Pin) == LOW){
reading = 1;
}
// Active when read is complete
// Reset the buffer
if(reading == 1) {
sendData();
}
}
// prints the buffer
void sendData(){
decode();
reset();
}
void reset() {
reading = 0;
i = 0;
charCount = 0;
}
int getStartSentinal(){
int sentinal = 0;
for (int j = 0; j < i - 5; j++) {
if (buffer[j] == 1 && buffer[j + 1] == 1 &&
buffer[j + 2] == 0 && buffer[j + 3] == 1 &&
buffer[j + 4] == 0) {
sentinal = j;
break;
}
}
return sentinal;
}
void decode() {
int sentinal = getStartSentinal();
int j;
int i = 0;
int k = 0;
int thisByte[5];
for (j = sentinal; j < 255 - sentinal; j = j + 1) {
thisByte[i] = buffer[j];
i++;
if (i % 5 == 0) {
i = 0;
if (thisByte[0] == 0 & thisByte[1] == 0 & thisByte[2] == 0 & thisByte[3] == 0 & thisByte[4] == 0) {
break;
}
printMyByte(thisByte);
}
}
Serial.print("Stripe_Data:");
for (k = 0; k < charCount; k = k + 1) {
Serial.print(cardData[k]);
}
Serial.println("");
}
void printMyByte(int thisByte[]) {
cardData[charCount] = decodeByte(thisByte);
charCount++;
}
char decodeByte(int thisByte[]) {
if (thisByte[0] == 0 & thisByte[1] == 0 & thisByte[2] == 0 & thisByte[3] == 0 & thisByte[4] == 1){
return '0';
}
if (thisByte[0] == 1 & thisByte[1] == 0 & thisByte[2] == 0 & thisByte[3] == 0 & thisByte[4] == 0){
return '1';
}
if (thisByte[0] == 0 & thisByte[1] == 1 & thisByte[2] == 0 & thisByte[3] == 0 & thisByte[4] == 0){
return '2';
}
if (thisByte[0] == 1 & thisByte[1] == 1 & thisByte[2] == 0 & thisByte[3] == 0 & thisByte[4] == 1){
return '3';
}
if (thisByte[0] == 0 & thisByte[1] == 0 & thisByte[2] == 1 & thisByte[3] == 0 & thisByte[4] == 0){
return '4';
}
if (thisByte[0] == 1 & thisByte[1] == 0 & thisByte[2] == 1 & thisByte[3] == 0 & thisByte[4] == 1){
return '5';
}
if (thisByte[0] == 0 & thisByte[1] == 1 & thisByte[2] == 1 & thisByte[3] == 0 & thisByte[4] == 1){
return '6';
}
if (thisByte[0] == 1 & thisByte[1] == 1 & thisByte[2] == 1 & thisByte[3] == 0 & thisByte[4] == 0){
return '7';
}
if (thisByte[0] == 0 & thisByte[1] == 0 & thisByte[2] == 0 & thisByte[3] == 1 & thisByte[4] == 0){
return '8';
}
if (thisByte[0] == 1 & thisByte[1] == 0 & thisByte[2] == 0 & thisByte[3] == 1 & thisByte[4] == 1){
return '9';
}
if (thisByte[0] == 0 & thisByte[1] == 1 & thisByte[2] == 0 & thisByte[3] == 1 & thisByte[4] == 1){
return ':';
}
if (thisByte[0] == 1 & thisByte[1] == 1 & thisByte[2] == 0 & thisByte[3] == 1 & thisByte[4] == 0){
return ';';
}
if (thisByte[0] == 0 & thisByte[1] == 0 & thisByte[2] == 1 & thisByte[3] == 1 & thisByte[4] == 1){
return '<';
}
if (thisByte[0] == 1 & thisByte[1] == 0 & thisByte[2] == 1 & thisByte[3] == 1 & thisByte[4] == 0){
return '=';
}
if (thisByte[0] == 0 & thisByte[1] == 1 & thisByte[2] == 1 & thisByte[3] == 1 & thisByte[4] == 0){
return '>';
}
if (thisByte[0] == 1 & thisByte[1] == 1 & thisByte[2] == 1 & thisByte[3] == 1 & thisByte[4] == 1){
return '?';
}
}
This could potentially have nothing todo with what you're talking about though lol 