Magnetic Stripe Card Reader!
Below we have a magnetic card reader made at the HACKMIAMI labs. It reads track 2 found on most magnetic striped cards (i.e. credit cards, drivers licenses, and student ids). Something interesting to point out, while testing the equipment with an old student ID card from a local university we found out it holds the person’s social security number on the card. The SSN use to be the student ID number. I wouldn’t be surprised if other universities did the same. The magnetic card reader was made using a Sanguino (a beefy Arduino clone), an LCD found on SparkFun, and magnetic card reader from All Electronics.
Things to Keep in Mind
The +5V and ground is provided by the sanguino. The LEDs are just for DEBUGGING and are not necessary. The LCD4Bit.h file used is modified so ports 18 – 23 on the sanguino are used for the LCD. You can download the LCD4bit here. An arduino or most other clones can be used for this project.
Schematic

Code
/*
* MAGNETIC STRIPE CARD READER with LCD ver. 0.2
* BY JP! ... email: jp @ hackmiami [dot] org
* web: http://www.hackmiami.org/
*
* 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 3 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, see .
*
*/
#include ;
LCD4Bit lcd = LCD4Bit(2);
int incomingByte = 0;
int charMax = 16;
int charCount = 0;
char ch[] = " ";
boolean printToLCD = false;
int DATA = 1, CLOCK = 11, CARD_IN = 2, ENDSTOP = 10;
volatile int state = LOW;
int buf[255];
char actual_buf[255];
int i = 0;
void setup() {
Serial.begin(9600);
lcd.init(); //initialize the LCD
// SET PINS AS INPUT
pinMode(CARD_IN, INPUT);
pinMode(CLOCK, INPUT);
pinMode(DATA, INPUT);
pinMode(ENDSTOP, INPUT);
// SET PINS AS OUTPUT
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(0, OUTPUT);
attachInterrupt(2, stateToHigh, FALLING); // Wait for card to start being pulled out, interupt 0 is digital pin 10
attachInterrupt(0, stateToLow, FALLING); // Wait for card to be completely out, interupt 2 is digital pin 2
Serial.println("Ready... ");
lcd.printIn("Ready...");
}
void loop() {
digitalWrite(7, digitalRead(ENDSTOP)); // ENDSTOP LED for debugging
digitalWrite(6, digitalRead(CARD_IN)); // CARD_IN LED for debugging
// IF YOU HAVE SOMETHING TO PRINT TO LCD, PRINT IT
if (printToLCD) {
lcd.clear();
int j = 1;
while(actual_buf[j] != '=' && j <= 16) {
lcd.print(actual_buf[j]);
j++;
}
lcd.commandWrite(0xC0);
lcd.printIn("HACKMIAMI.ORG");
printToLCD = false;
}
}
// MAKE STATE GO HIGH AND START COLLECTING DATA
void stateToHigh() {
digitalWrite(0, HIGH);
state = HIGH;
Serial.print("STATE: HIGH\n");
// The data is synced to a clock. So everytime the clock rises there is data to be collected.
attachInterrupt(1, getData, RISING); // interupt 1 is digital pin 11
}
// SET STATE TO LOW, no longer need to collect data so detach interrupt
void stateToLow() {
detachInterrupt(1);
Serial.print("\nSTATE: LOW\n");
state = LOW;
digitalWrite(0, LOW);
Serial.print("\n");
complement();
// reverse();
readBuf();
Serial.print("\n");
i = 0;
}
// DECODE WHAT IS WRITTEN ON THE CARD
void readBuf() {
char values[] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', ':', ';', '<', '=', '>', '?'};
int index = 0, val, k = 0, binbuf = 0, parity = 0, parity_error = false;
Serial.print("RAW: ");
for (int j = 0; j < i; j++) {
Serial.print(buf[j]);
}
Serial.print("\n\n");
// FIND START SENTINEL
for (int j = 0; j < i - 5; j++) {
if (buf[j] == 1 && buf[j + 1] == 1 && buf[j + 2] == 0 && buf[j + 3] == 1 && buf[j + 4] == 0) {
k = j;
break;
}
}
int p = 0;
for (int j = k; j < i; j++) {
if ((j - k) % 5 == 4) {
actual_buf[p] = values[binbuf];
binbuf = 0;
if ((parity % 2) == buf[j]) {
parity_error = true;
}
parity = 0;
p++;
}
else {
binbuf += buf[j] * (int) ceil(pow(2, (j - k) % 5));
parity += buf[j];
}
}
for (int j = 0; j < p; j++) {
Serial.print(actual_buf[j]);
}
Serial.print("\n");
printToLCD = true;
if (parity_error) {
Serial.print("\nPARITY ERROR!");
}
}
// GET DATA AND ADD TO BUFFER
void getData() {
buf[i] = digitalRead(DATA);
i++;
}
// FLIP THE ORDER IN WHICH THE DATA WAS READ
void reverse() {
int buff[255];
int c = 0;
for (int j = i - 1; j >= 0; j--) {
buff[c] = buf[j];
c++;
}
for (int j = 0; j < i; j++) {
buf[j] = buff[j];
}
}
// INVERT THE 1's TO 0's AND VICE VERSA
void complement() {
for (int j = 0; j < i; j++) {
(buf[j] == 1) ? buf[j] = 0 : buf[j] = 1;
}
}

