Introduction: Turn Your Arduino Into a Magnetic Card Reader!

Picture of Turn Your Arduino Into a Magnetic Card Reader!

Everyone has used a magnetic card reader, I believe. I mean, who carries cash these days? They're not difficult to get your hands on, either, and during a trip to my favorite local electronics shop, I found a bin full of these guys. So....of course, I picked one up and brought it home to see what sort of stuff I could do with it and an AVR.

This instructable will show you how to connect a Magtek magnetic card reader to an AVR or Arduino/clone and read data from the first track of card. Buckle your seats; magnetic card readers have a high bit rate!

Step 1: The Equipment List

Picture of The Equipment List
Here are a few things you'll need to get started.
  • Magnetic card reader (Mine is a Magetk 90mm dual-head reader. $5.00)
  • AVR, Arduino, or clone (ATmega328p ~ $4.30 from Mouser.com
  • solderless breadboard
  • some wire
  • maybe a header if you like that sorta thing.
  • something to read your serial port. I use AVR Terminal from BattleDroids.net

That's all you should need to get started. Depending on the magcard reader you end up getting, you may have to modify these instructions, and most assuredly the code, to work with your specific reader. However, the code I've written should get you pretty far, I hope.

Step 2: Self-clocking Magnetic Card Readers

Picture of Self-clocking Magnetic Card Readers

Magnetic card readers are "self-clocking," meaning that they provide a clock called a strobe, against which the connected microcontroller can sync. This is a boon. It means you don't have to worry about looking for a clocking signal and timing the signal to center directly on the clock pulse, and no bothersome oscillating into the sweet spot of the clock signal. This make sense when you think about card swipes: everyone swipes at a different pace, some slower, some faster than others. Self-clocking allows even my sweet grandma the ability to use her card without breaking her wrist. Reminds me of having to change the setting for her that determines how much time is valid between clicks to register a double-click....

This card reader's data is valid 1.0 us before the strobe is put onto the line, so there's no worry about delaying to get yourself into the "bit time." For a dual head reader such as the one I'm using, there are two data tracks available to read. In this 'ible, I'm going to show reading from the primary first track to get you started.

There are five connections you will need to make (four if you don't mind giving up more fine tuned control for fewer I/O ports being used). Check out the picture below. The red wire goes to +5V while the black wire goes to ground. The green wire is /CARD_PRESENT; the yellow wire is /STROBE, and the white wire is /DATA1. The forward slash ( / ) means that the data is inverted. A low signal (ie 0) is read as a one, or high. The other connectors are brown for /STROBE2 and orange for /DATA2. We won't be using these.

If you want, you can forget about /CARD_PRESENT. This data line goes low after about 17 head flux rotations to indicate that a card is present (instead of, say, random noise causing your reader to send bogus data) and is used to validate that the data you're getting is card data and not junk. You can skip this connection if you check for the start sentinel on the data stream. More on that later.

As you can see below, I used a right angle male header connected to a bread board and connected my reader to that. I connected /STROBE to PIND2 (digital pin 2 on an Arduino), /CARD_PRESENT to PIND3 (for illustration purposes), and /DATA1 to PIND4. Make sure you enable pullups on these pins so your pins don't float. I also traded out my Arduino for a Bare Bones AVR because I like the way it fits into the breadboard.

Step 3: Magnetic Card Basics

Picture of Magnetic Card Basics
The primary functions that you'll need to do to read a magnetic card are:
1. Detect when the card has been swiped
2. Read the stream of data
3. Detect when the card has gone
4. Process the data
5. Display the data

First, I'll introduce you to some magnetic card basics that you'll need to know when you start writing your own code.

Magnetic Card Standards

Magnetic cards are standardized by the ISO in the following documents:

7810 Physical characteristics of credit card size document
7811-1 Embossing
7811-2 Magnetic stripe - low coercivity
7811-3 Location of embossed characters
7811-4 Location of tracks 1 & 2
7811-5 Location of track 3
7811-6 Magnetic stripe - high coercivity
7813 Financial transaction cards

As you can see, financial cards are specified in a separate document and often have different formats than, say, your grocery card or international calling card. You will have to program for these differences. I just had a credit card and insurance card handy, so I programmed for these types (which both happen to be format B).

Card Formats

There are several different formats for magnetic cards. Format A and B are common, with B being the most common I've seen, and which is supported in this code. Formats C through M are reserved by the ISO, I believe, while N through ?? are reserved for institutional custom use.

Track 1
For financial cards, the first track is recorded at 210 bits per inch and is the first 0.110" of the card from the top. The data is encoded as "card data" as 7-bits per character. That's 6-bits for the character and a bit for parity. There are ~ 79 alphanumeric characters on track 1.
The physical ordering is backwards. That is, data is  but it's written backwards on the card (and hence, will be read by your firmware) as . The parity is odd.

The card data format looks like this:
[SS] [FC] [Primary Account #] [FS] [Name] [FS] [Additional data] [FS][ES][LRC]where:
SS Start sentinel
FC Format code
FS Field separator
ES End sentinel
LRC Longitudinal Redundancy Check character

Track one SS = '%', FC = one of the formats (going to be B a lot of times), FS is often '', ES is '?' and the LRC character is commonly '<' although it's not specified in the standards. Besides being written on the card backward, the data has an odd parity bit and is 0x20 from ASCII. We'll handle this when we process the data.

Track 2 
Track two is 0.110" wide and starts 0.110 from the top of the card. It's recording density is 75 bits per inch. The data is 5-bits per character and consists of around 40 numeric symbols only. You shouldn't encounter any letters on this track.

The card data format should follow this structure:
[SS] [primary account #] [FS] [additional data | discretionary data] [ES] [LRC]
The SS for track two is the semicolon: ';' and the FS is '='

With this holy knowledge under your belt, continue on to the next steps to see code implementing the procedure outlined above.

Step 4: Detect When a Card Is Swiped

Picture of Detect When a Card Is Swiped
1. Detect when a card has been swiped
Formally, one would check the /CARD_PRESENT pin to see if it's dropped low. Fortunately, this isn't really necessary. We'll check for valid card later. Alternately, you could read your strobe pin to see when strobes have been put onto the pin, however, this will net you lots of clocking zero's. The reader will send about 60-70 leading zero's to let you know that data is about to be presented. However, we're going to use the nature of binary data to determine when to start recording bits.

The start sentinel (SS) for track one is the percentage sign (%). It's binary value is 0010 0101 which means it will be stored (and read) as 1010 001 (it's 7-bits so the 8th bit isn't transmitted). Now, the astute reader will notice that even though the data is backwards it doesn't match the binary ASCII value. That's because it's 0x20 off of hex. The % symbol is 0x25 and 0100 0101 is 0x05. Card data has 0x20 subtracted from the value. That one hanging out there in the high nibble is the odd parity bit. It's put there so that there are an odd number of "1"s in the value.

So because we know that a valid card will always start with this start sentinel, and because the parity bit is a 1, then when we detect the first HIGH to LOW transition on the data pin, then we know we have just started to receive the start sentinel from a card. Now, this isn't always going to be true, and a foolproof plan would be to check the /CARD_PRESENT card to see if it's gone LOW in addition.

The simplest way to detect the start of the SS, is to create an external interrupt triggered on the falling edge of the /STROBE. The data is valid 1.0 us before the falling edge, so when you've sampled the falling edge, then you know you can read the /DATA1 pin and get a valid value. Here's the code to create your external interrupt triggered on a falling edge.

voidInitInterrupt(void){    // Setup interrupt    BSET(EIMSK,INT0);     // external interrupt mask    BSET(EICRA,ISC01);    // falling edge    BCLR(EICRA,ISC00);    // falling edge    BSET(SREG,7);         // I-bit in SREG}

In my common.h that I include in all my programs, the definitions of BSET and BCLR can be found. Refer to that file should you have any questions about how to set bits. Now, when the interrupt is triggered, we want to sample the /DATA1 (in my code defined as CARD_DATA) and set a bit in a general purpose IO register. If we're on the 7th bit, save off the register as a character in our global buffer. I use a GPIOR0 register because it's spiffy fast access. The pseudo code is something like this:

Stop 16-bit timer    Clear timer    If DATA is LOW        Set BIT=1 in REGISTER        Decrement BIT        Set flag so we don't skip any more 0's    else DATA is HIGH        Set BIT=0 in REGISTER         Decrement BIT    If BIT is 0        Add byte to buffer        Increment index        Reset BIT

If you are asking yourself why decrement instead of increment, remember that the data is backwards, so instead of recording the bits as we get them from LSB to MSB, we save them from MSB to LSB so we don't have to reverse the bits later when processing the data. If you really wanted, you could also add 0x20 hex here, but since it's about 5us on these strobes, I'm keeping the processing in this interrupt service routine to a minimum.

ISR(INT0_vect){	StopTimer();	ClearTimer();	if ( !BCHK(PIND,CARD_DATA1) )	// inverse low = 1	{		BSET(GPIOR0,bit);		--bit;		bDataPresent = 1;	} else if (bDataPresent) {		BCLR(GPIOR0,bit);		--bit;	}	if (bit < 0) {		buff[idx] = (char)GPIOR0;		++idx;		bit = 6;	}			StartTimer();}

If you're wondering what the timing business is about, that's covered in the step in determining when the card has left the reader.

Step 5: Read the Stream of Data

Read the stream of data


Well, I've already shown you how to read the data, as it's part of the Interrupt Service Routine for our falling edge external interrupt. An alternative method would be to set a flag in the ISR, and in the main loop poll the flag and read the data that way, but I believe the way I've presented it is cleaner. Be your own judge and write yours however your MCU will allow it.

That being said, let's move on to finding out how to detect when the card pulls an Elvis and has left the building.

Step 6: Detect the Card Leaving the Reader

Picture of Detect the Card Leaving the Reader

Detect when a card has gone


Formally, one would sample the /CARD_PRESENT pin to see if it's gone HIGH again, but we don't need no steenkin' /CARD_PRESENT taking up another I/O port. This is where those timers come in.

Every time the interrupt is called because we've detected a falling edge on /STROBE, we stop a timer, clear the timer value and start reading. When we've finished reading we start the timer again. Repeat ad nauseum, or until the timer reaches a certain value. That means that the last interrupt has been called and no more data has come in, so we assume that's it and start processing the data we've collected.

For timers, we use TIMER1, ie the 16-bit timer. I'm using a 16 Mhz resonator externally to my AVR. If you're using an arduino, then you probably are, too. So, I've chosen a prescaler value of 1024 which means every (16,000,000 / 1024) times the timer will increment. That is to say, it will 'tick' 15,625 times a second. The /CARD_PRESENT will go HIGH indicating the card has left the reader about 150ms after the last data bit. Knowing this, I just decided to check about every 1/4 of a second. That would look something like this:
    ( ((F_CPU) / PRESCALER) / 4 )
which turns out to be around 3900. So, when the timer counter TCNT1 reaches 3900, then I know it's been about 300ms and I can pretty safely conclude that the card has left the reader. Easy.

#define PRESCALER	     1024#define CHECK_TIME     ( (F_CPU / PRESCALER) / 4 )		// 250 ms#define StartTimer()     BSET(TCCR1B,CS10), BSET(TCCR1B,CS12)	// 1024 prescaler#define StopTimer()      BCLR(TCCR1B,CS10), BCLR(TCCR1B,CS12)#define ClearTimer()     (TCNT1 = 0)

You've seen in the ISR where the timer is started, stopped, and cleared on each interrupt. Now, in the main loop we just check to see if the timer counter has reached our target value, and if so, start the data processing.

for (;;){	if( TCNT1 >= CHECK_TIME)	{			
StopTimer();		
ClearTimer();		
ProcessData();		
ReadData();					
idx = 0;		
bit = 6;		
bDataPresent = 0;		
memset(&buff,0,MAX_BUFF_SZ1);	
}	
}

Now it's safe to process the data.

Step 7: Process the Data

Picture of Process the Data

Process the data


The processing phase consists of:
  • checking for a valid SS
  • checking parity
  • converting to ASCII
  • checking for a valid ES
  • checking LRC

Here, I don't bother with checking parity, as I just set that bit to zero. I also don't calculate the LRC for this little tutorial. That would be something that a more fully realized firmware might want to do.

Here's the code to process the data doing the above steps (sans the previously mentioned). Find it in the image below. It's commented and pretty self-explanatory. A special note on parity and ASCII:
I simply clear the parity bit (7th bit...ie a 1 with 6 zeros behind it) and to convert from "card data" you must add 0x20 to the value. That's about it.

Step 8: Display the Data

Picture of Display the Data

Display the data

The display goes to a terminal program I wrote specifically for connecting to an AVR via RS232 or USB. The program is called AVR Terminal. The ReadData() method is pretty ugly and you're encouraged to find a cleaner solution than the one I came up with.

There's also an output of the function in AVR Terminal. The output is first of a health insurance card, and the second is of a VISA card. Click the [i] in the upper left corner of the picture and choose original or large image to see it better.

Step 9: Code Download and Wrapup

In this instructable I've discussed some basics of magnetic card readers and shown you some code to get you started in the right direction in reading data from magnetic cards. There's plenty more work that could be done, such as reading and decoding the 2nd track, calculating the LRC and calculating the odd parity on each byte.

The full source code is available for download below. It was written in AVR Studio 4.17.

I hope you enjoyed this instructable and, as always, I look forward to any comments or suggestions that you may have.

Happy coding and AVR'ing!

Comments

Build_it_Bob (author)2010-11-14

Awesome work on this. You explained all the steps in a way that takes something that is compli cated and kept it interresting all the way through. I didn't know much about what was on a stripe and now I have at least a basic idea . Thanks for the education!
Build_it_Bob

nevdull (author)Build_it_Bob2010-11-14

Thanks for the kind words! I'm glad you were able to learn something from it and I appreciate your comments!
Cheers!
-gian

asher_smith343 (author)2016-12-06

Hey, how can i upload this code to arduino?

I am not so familiar with C/C++ .Can you please help me out?

ElectricNerd15 (author)2016-06-05

Hello. I was just wondering if you could use the data taken from the code and use it to perform another process on the computer, like logging into something or opening a folder/program. If anyone sees this and can answer it, please reply with your answer and how to do it. Thanks!

-ElectricNerd15

Also, does anyone know where I can find an inexpensive magnetic stripe writer?

eduke (author)2014-02-14

Hi,

Where is the link to the code? I do not see it anywhere ...

abrp (author)2016-02-11

Hi nevdull!!

I've found this proyect very interesting!! I would like to make it but I can't find any suitable link to buy the Magtek 90mm dual-head magnetic card reader (the same that you showed in the image). I found this link but I think you can't buy it here..

http://www.epsys.no/readers/magstripe/magtek

Could you share a valid link where we can buy the same model with which you made the project?

Thanks a lot and congratulations! good post!!

:)

EricP58 (author)2015-11-05

So how does the AVR terminal work? You said "The display goes to a terminal program I wrote specifically for connecting to an AVR via RS232 or USB." Can you elaborate on that please?

nevdull (author)EricP582015-11-24

Hi EricP58,

The AVR terminal acts simply as a dumb terminal, with some added control codes for for transparently manipulating the AVR from the PC. It also has no special telnet control sequences that would interfere with a serial port connection and has ANSI support. It easily allowed converting values between hex, binary, and decimal, as well.

The hardware part is either through a MAX232 to a DB9 serial port using RS232 signaling protocol or through USB via an FTDI USB-to-RS232 IC. There are several new dumb serial terminals available now, so any of those would also be a good choice.

petru.simion.56 (author)2015-01-30

Hi,

What is the format of the data you get off the card reader? I mean, do you the information about the former cardholder (name for example) or you get in another format?

Thank you in advance.

arun.pillai.3726 (author)2014-10-26

I am doing penetrating for ATM machines. I wonder if any one of you have experience creating smart card reader to encryption , or data between EPP readers and ATM PCs, smart card readers to read tr1, tr2 and tr3 data.

I am newbie in hardware hacking. kindly guide me

carlosd3 (author)2014-09-03

I'm building a vending machine using all the electronics arduino, the machine has a bill acceptor and coin acceptor my interest is to add a device to receive pto also with credit / debit card. I just do not know where to start can help me?

KellyCx1 (author)2014-02-19

Since the Arduino pictured above has a USB port, could I be able to use a USB card reader as opposed to a serial one?

gep30 (author)2013-11-27

how could i go about finding what type of format a student id at a college will fall under.

mic_mic_mic (author)2012-12-14

thanks for the prompt response. I hoping to get my head into a queuing system project and part of it involves simulating a bank ATM card reader to get user data and relay it to a server. I'm still looking around for the perfect magnetic reader. Price is a major factor due to budget constraints on school projects.

The data should essentially identify the unique ATM card/debit card holder on swapping.

Any tips on what i should focus on to get it up and running?

I tried replying but there seems to be a problem with where the captcha is

nevdull (author)mic_mic_mic2012-12-14

heya. I would focus on reading card format B on a single track. You could use an option like this one at ebay but you'd need an AVR that understood USB (ATmega32U4, AT90USB*, etc). There's another one at ebay ($9) using RS232 so you could interface it with the arduino's USART either through a DB9 or stripping the serial cable from the reader and running the pins directly into the arduino's headers.

Also, I re-edited page 3 and 4 (4 is still a little FUBAR with formatting) as I just found out that MAJOR important mag card format information wasn't being formatted and displayed. That should be fixed now and you should have more card format information and how to read it.

Good luck!

mic_mic_mic (author)2012-12-14

Very helpful. One question, are you sure it was 5$? I've scoured the net and cant seem to find it for that price. he cheapest i've seen is around 50$. Could you post a link where you got it for the friendly price?

nevdull (author)mic_mic_mic2012-12-14

Well I wish I could share the price with you out on the intertubes but I picked up a handful of these gems at my local electronic hobby shop. And sure enough, they were $5. However, I was back there just last weekend and noticed they still had a small box full of them but they were now priced at $10. But you're right, these devices do tend to be a little pricey. The USB type more so than the straight serial versions.

Good luck!

wherewillwhy (author)2012-09-18

GJ W00T You certainly dont "fake the funk " brother

nevdull (author)wherewillwhy2012-09-28

Would faking the funk be committing a funkadelic felony?

Hope you enjoyed this or my other instructables! Thanks! Always glad to get your comments.

Cheers!
Gian

Krayzi99 (author)2012-06-10

Where the heck did you get $5.00 as the price? It's more like $5(0).00!

nevdull (author)Krayzi992012-06-10

I got my magnetic card reader from a local electronics shop where they were all in a bin for $5/ea. Where you find yours will obviously dictate the ultimate price of your project, but I have seen them on ebay from a few dollars and up (though you may pay more in shipping unless its free). I would try ebay first. You might get lucky with a good deal here and there on these items. Of course, if you're buying everything from scratch, including the arduino, it'll cost more, but this 'ible was targeted more toward current arduino/avr owners who just wanted to play around with a free/cheap mag card reader they could get their hands on.

Try your luck on ebay looking for a mag card reader in a price range that's workable for you. It could be there.

Good luck!

SpiralEdge (author)2010-10-03

I'm new to electronics and got lost at the part where the coding begins. How did you connect the card reader to the computer in order to read data from it?

nevdull (author)SpiralEdge2010-10-04

I connected the arduino through wires connecting the serial interface of the magnetic card.

pdrocb (author)nevdull2012-02-14

Hello! Thanks fo your post!

I have an Arduino... but normally you have a .pde extension in the .zip i dont see any. Can you please help me, how can I use your code into Arduino.

Thank you!

Another question did you use a Magtek MiniWedge Stripe with RS232 or usb or keyboard?

nevdull (author)pdrocb2012-02-15

This code isn't from the Arduino IDE nor does it compile into an arduino PDE file. This is normal code written in C that can run on a wide range of ATmega devices, including the Arduino. However, my guess is, you will require a programmer to download it into flash just like with the other atmegas. Sorry for any confusion there.

Re: your other question. My magcard uses a serial protocol that I describe in this instructable. It's pretty standard but doesn't use USB. I had the Arduiono redirect output to a windows terminal via RS232.

Good luck!

CoolKoon (author)2010-10-01

Could you by any chance get one with a similar price that could write these cards as well? :P I could really make use of one :P

Spaceman Spiff (author)CoolKoon2010-10-02

Identity Theft anyone? Just kidding, ha ha ha.

CoolKoon (author)Spaceman Spiff2010-10-02

Nah, I hate magnetic cards and would love to develop a way to introduce some false information on them (in a BOFH way) :D

nevdull (author)CoolKoon2010-10-04

Well I agree, in that it would be kinda geeky fun to have mag cards that were written with the info you wanted (and or encrypted) for testing on home egress, maybe a small sub-zoned area inside your house protected by mag card

hintss (author)nevdull2011-04-10

I like iButtons for that.

CoolKoon (author)nevdull2010-10-05

Yeah, but I'd need a writer for that as well. I suppose yours can't do that, can it?

nevdull (author)CoolKoon2010-10-05

No, my mag card device is a reader-only. Check ebay for some reader/writer combos, although for raw bang-for-your-buck, 125khz RFID reader/writers are only dollars (for the chip, you'd have to build the circuit). Tough decision to make if you're really settled on magnetic cards.

CoolKoon (author)nevdull2010-10-05

I'm not really settled on mag cards, but haven't seen RFID writers either. I could make use of one too :P

nevdull (author)CoolKoon2010-10-05

You'll find RFID writers on ebay again, and at futurlec.com, i believe.  But why buy one when you can build one with the Atmel U2270B RFID basestation in a chip for a coupla bucks.  Yum yum.


CoolKoon (author)nevdull2010-10-09

Thanks for the idea! I even managed to find such chip at a local supplier. I'll see whether I can make it into something useful ;)

nevdull (author)CoolKoon2010-10-11

awesome! Good going, let me know how it turns out!

ducktape3618 (author)2011-02-26

awesome to hack my dad his new credit card!

jcouch1227 (author)2011-01-12

Anyone know what that red thing is called, a header? the thing in the second picture above. thanks

nevdull (author)jcouch12272011-01-13

It's a right-angle 7-pin male header, to be precise. :)
Cheers!
-gian

nevdull (author)2009-08-20

I have in my head a difference between electromagnetic door lock and an electronic mechanical door lock. I think (and tell me if I'm off base here), that TheSodaJerk is talking about an electromagnetic door lock (the locking mechanism is provided by electromagnets.no bolting), and what you're talking about (a moving deadbolt-type-of-thing that is moved electronically). Either one would be pretty spiffy.

nevdull (author)WillTheRescue2009-08-23

Haha nintendo! That's pretty cool :)

TheBestJohn (author)nevdull2009-10-17

Electromagnets and magnetic cards are not an overall good paring.

xarlock667 (author)TheBestJohn2010-09-19

So, there you are, all set to go inside your house, and your card is demagnetized. Or the power is out. (With a magnetic lock, your house could be unsecured.) Electro mechanical is the way to go, but it is still useless. All that security is for nothing if I can get in your window, go through your garage, pop the face off the lock plate and bypass your circuit, or in the case of a electromagnetic lock over power the magnet with another magnet. Mechanical locks are cheaper, last longer, and do not demagnetize. Further they do not tell thieves you have anything worth protecting.

mutput7 (author)xarlock6672010-11-19

You sound pretty pro at this sort of thing...

xarlock667 (author)mutput72010-11-19

If I wanted in your home, there is almost nothing you could do to stop me. EVER. If I wanted your things, I could take them and again you could not do anything to stop me. This is because I have had a LOT of training in many fields you cannot find, and would have no use for. The best protection for you against someone that wants your things is a BFD, or a BFG.

For your home not much beats a Big F-ing Dog. Even hardened military hate clearing houses with dogs in them. They are territorial, strike at the damnedest times, and can seriously hurt you, or tip others that you are where you should not be, doing things you should not do.

For your person, get a Big F-ing Gun. Ever heard the sound of someone racking the slide on a .12ga shotgun? You cannot carry it on your person, but for home defense, nothing comes close. Load it with 2" bird shot, or bb shot and you will not kill the neighbors. None of that 3.5" buck, or slugs! A bullet flies till something stops it! Make sure that it is the wall of your house and not granny down the street!

swilus (author)xarlock6672010-12-07

My trailer is so secure you would die before you EVER found a way in!

mutput7 (author)xarlock6672010-11-20

Laser duckie. Whatcha gotta say to THAT?!
...

Exactly.

About This Instructable

244,280views

395favorites

License:

Bio: Gian is a computational biologist and is the Managing Director at Open Design Strategies, LLC. He holds a BA in Molecular/Cellular Biology and an ... More »
More by nevdull:Create A Custom Medieval-/Fantasy-Style Calligraphy QuillPractical DACsUsing Enumerated Types as Bitflags
Add instructable to: