9 Steps

## Step 4: 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.

Remove these ads by Signing Up