Reading serial data from magnetic card

I recently purchased a magnetic card reader for use with the Arduino. For data out of the reader it has a clock line and a data line. Clock is active high, data active low. Warning: I'm a noob with this stuff, but I was under the impression that I could wait for the clock line to go high, read the data line, wait for the clock line to go low... repeat. This however produces rather random output. I thought that timing could have something to do with it, so I attached a RISING interrupt to the clock line and read the data line in the interrupt function. This produces less random data (all HIGHs), but not correct as far as I can tell.

Is the Arduino just not fast enough to pull in data from a magnetic card reader? Will I need some kind of synchronous serial buffering IC between the reader and the Arduino? Any advice/suggestions appreciated.

Need more info. Do you have a datasheet for the reader?

I'm guessing that it normally connects to something like a PC or a cash register. What kind of connection does it use? Serial port? USB? Does it sit between the computer and the keyboard?

As far as the arduino being fast enough, unless the device is sending >100kbps it should be plenty fast enough.

Its a TTL device with an 7 pin ribbon cable output and "datasheet" consisting of (may be out of order)

1 - 5v 2 - Ground 3 - Card present (active low) 4 - Head 1 clock (active high) 5 - Head 1 data (active low) 6 - Head 2 clock (active high) 7 - Head 2 data (active low)

I'm fairly certain that its not designed to plug into a computer thru any standard userlevel ports. I think its just two F2F decoders in a plastic package. That makes me feel a lot better that the Arduino isn't too slow though. I was dumping debug data out the serial port to see what it was getting back. Could that slow it down enough to matter?

Link to the actual device I purchased:

The data isn't necessarily in ASCII, which could explain the garbage you see. I don't know that you're reading it correctly, but check the standards for track 1 and track 2 (which are different) and see what the binary format on the card is.

I cheated when I had a card reader project - I just got one with an rs232 interface. :|


Right, I hadn't gotten to the decoding bit yet (and really I don't think I'll need to), I was just looking for consistent results. All 1's is consistent I suppose, but certainly not correct. I'm only reading track 2 if it helps. I'm using this for authentication, so I don't necessarily care about what the data works out to in ASCII, just what it works out to in bits as a key. Once I get that part down, I may do something more elaborate with decoding the data or getting a shim to read track 1 info.

int ledPin = 13;                
int cardPin = 7;
int dataPin = 6;
int cardPresent;

volatile int data = 0;
volatile int flag = 0;

void setup() {
  pinMode(ledPin, OUTPUT);   
  pinMode(cardPin, INPUT);


  attachInterrupt(0, cardin, RISING);

void loop(){
  cardPresent = digitalRead(cardPin);  
  if (cardPresent == HIGH) {            
    digitalWrite(ledPin, LOW);  
  } else {
    digitalWrite(ledPin, HIGH);     
  if (flag == 1) { Serial.print(data); flag=0; }

void cardin() {
  data = digitalRead(dataPin);
  flag = 1;

Theres my code. Hopefully one of you guys will find the blaring error in it, or enlighten me in some other useful way.

Code looks OK at a glance.

Does the datasheet have a timing diagram? You may need to wait after the clock edge before reading, or read on the falling edge (instead of rising as you are now), or something...

I don't think it's a speed issue; IIRC, the data comes off the read head pretty slowly.


waitaminute, where's the clock line? If you're reading on the rising edge of the data line and using the data line as the interrupt, then sure you're going to read 1 every time. Think about it a bit.

You want to attach the clock line to the interrupt, and read the data line on the clock edge (not sure if it's falling or rising, check the datasheet).

The card present is probably used as a wakeup signal for the system, or a flag to make sure you aren't trying to read when the card isn't in the slot (e.g., a partially inserted card swipe generating garbage).


The track 2 data is 5 bits per character. There are the digits 0-9, a start and end sentenel, and a separator character (which is used to mark the end of the pan).

Personally I use ps/2 or usb hid card readers, though.

The difference is price - a raw output reader like the one he's working with can be had for cheap (I've seen surplus for US$10 or so, a little more new), but one with an interface (rs232, ps/2, USB HID) is on the order of US$100. I think my last USB model was $80 from CDW.


kg4wsv: I'll experiment with a little delay after the clock goes high to see if that helps out. As far as the clock line is concerned its hooked up to pin2 for interrupt 0. No need to define it in a variable since int0 has to be on pin 2. The "datasheet" I received for this unit was (other than I don't remember the order off the top of my head) the pinout I mentioned above. Thats it.

Cardin is useless other than as you can see in the code I light an LED when it goes low. Nice feature since I'm only using one out of two heads and can immediately see if I have the card in backwards.

I've put resistors on all the lines between the reader and the Arduino in case the pcb in the reader doesn't already do that. Is there any easy way to test that, or does anyone know that "all F2F decoder ICs have built in current limiting resistors on their outputs" or something?

Got it sorted out. Seems the pinout that came with the reader was wrong. The clock line was active low, so all I needed to do was put the interrupt on FALLING rather than RISING. Pulled data from all my cards no problem.