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


[...] 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
im in miami were can i find this equipment locally what all do i need and a estimate of the price list
where is a legitimate person or site i can buy this equipment from.
Nitroboozter do you have success now with arduino mega ?
i really loved this one i just need to know does this can be used to collect data from cards and then to be downloaded by using the program
if it dont is there any other way to do it