Magnetic Stripe Card Reader!
December 21st, 2008 | By: jpBelow 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.h>; 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; } }


[...] Parts Code Diagrams [...]
Hey,
I’m using your GPL code for an article in a hacking magazine. Hope its okay!
Go right ahead! Just mention HackMiami in the magazine as well. Let me know when it is published.
Hello,
Thanks for this great tutorial!
I am interesting in making a personnal card-reader but I don’t find any MR read head. Does anybody know where I can buy it?
Thanks
I bought the magnetic card reader at allelectronics.com for $4 american. It’s the best price I’ve found.
I tried to modif the code for the Arduino Diecimila and using an Omron reader and all I get as a read are characters. here is the code below. Thanks for help
==============================================================================
/*
* 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 =3, CLOCK = 11, CARD_IN = 2;
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(1, 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(3, 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(3, 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 = 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;
}
}
============================================================================
I tried to tweak the code for Arduino Diecimila with no luck. Any help will be appreciated.
Sorry for the late reply. Which Omron reader are you using?
[...] sketch which takes web data and prints it on a thermal printer. I found a great tutorial for reading a magstripe reader with a Sanguino, so I’ll either adapt the code for Arudino use or just use a Sanguino. I haven’t [...]
Does the magnetic stripe card reader used in the project have a TTL interface?
Hello i need to make a card reader whit Arduino Duemilanove (2009) and a Omron V3B-4K is it possible to use your code or need’s to be mod and to what pins i connect the reader
TKS
There is some modification to be done in order to get it to work with that Arduino and card reader. But it is definitely possible.
I plan to revisit this project and make a non breadboard version of it.
Can you give-me some direction to start pls the idea that i have is like this:
have a LCD saying (Please Pass Card) (Invalid Card){When the card of a non authorized worker try to use the machine} (Machine ON) (Out of Service)
I thinking to use the card reader a LCD and a relay to start the machine.
My Arduino is going to arrive in 1 day to start the tests if you can point me in the right direction i will be very happy because I’m only starting to learn who to use this now. I have seen that the part of LCD and relay is not very difficult but card reader i think that is not so easy…
TKS
Jaime Branco
Any tips on getting custom card blanks and a writer? It can’t be _that_ hard can it?
the above program will not work for arduino decimila or duemilanove because the program uses 3 interrupts which both the arduino’s don’t have [they have only 2 interrupts]
hey can you please check if the connections in the diagram and the program’s pin connection are all correct.i have an ARDUINO MEGA and i tried connecting all the pins in the sanguino to the respective pins in the mega i am using a OMRON 3S4YR-SBR4N-50 manual half insert reader the connections i made are correct i checked it two three times
OMRON PIN DETAIL FROM DATASHEET
not connected — pin1
read data (output) — pin2
read clock (output) — pin3
card load (output) — pin4
card detection rear(output) — pin5
card detection rear(input) — pin6
card detection front(output) — pin7
card detection front(input) — pin8
vin — pin9
ground — pin10
ARDUINO MEGA PIN DETAIL
pin1 — connected to omron pin2
pin2 (interrupt 0)– connected to omron pin5
pin3 (interrupt 1)– connected to omron pin3
pin21(interrupt 2)– connected to omron pin4
i have not connected any lcd and have removed all the codings for the lcd..when i’ve hooked it up the pc and check for the data using serial monitor all i get is Raw: and 2-3 line of spaces when i insert and remove a card.please tell me what i’m doing wrong???
hey i have also changed the pin numbers in the program too