Magnetic Stripe Reader

 

Photograph of the prototype hardware:

 

 

Circuit diagram:

 

 

Controlling program:

 

(*$d 2313 - uses an AT90S2313*)

(*$c 4��� - 4MHz crystal in target*)

PROGRAM MagneticStripeReader (input, output);

(* Scan a magnetic card stripe for ISO 5-bit BCD format data (tracks 2,3),

�� convert to ASCII characters and send data to the serial port at 19200 baud*)

USES

UART; (* library modules imported *)

 

CONST

cardNotLoaded = 4;��� (* port D lines used for input *)

clockLine���� = 5;��� (* sample data on falling edge of clock *)

dataLine����� = 6;��� (* data on this line is inverted: lo=1, hi=0 *)

BOD���������� = ';';(* beginning of data sentinel *)

EOD���������� = '?';(* end of data sentinel *)

CR����������� = #$0d; (* carriage return *)

LF����������� = #$0a; (* line feed *)

 

TYPE

TerrCode = (noError, overRun, frameErr); (* error codes returned by UART RX *)

TBdRate = (B2400, B4800, B9600, B19200);

 

VAR

status : boolean;���� (* UART TX status *)

pinD�� : byte | sfr;(* card reader attached to port D *)

i����� : word;������� (* index used in GetChar: global for speed *)

ch���� : byte;������� (* char used in GetChar *)

parity : boolean;���� (* parity check *)

ascCh: char;������� (* ASCII char for sending via UART *)

first: boolean;���� (* flag for the first character read *)

 

(* Imported from UART *)

PROCEDURE InitUART(bdRate:TBdRate); LIBRARY;

FUNCTION GotRXbyte(VAR data:BYTE; VAR errCode:Terrcode):BOOLEAN; LIBRARY;

FUNCTION PutTxbyte(data:BYTE):BOOLEAN; LIBRARY;

 

PROCEDURE SendMessage(msg:string);

(* Send intro message to UART *)

VAR

��� i : word;

BEGIN

��� FOR i:= 1 TO Ord(msg[0]) DO

����� WHILE NOT PutTxbyte(msg[i]) DO;(* wait for char to be sent *)

END;

 

PROCEDURE SendCRLF;

(* Start a new line *)

BEGIN

��� REPEAT

��� UNTIL PutTxbyte(CR);

��� REPEAT

��� UNTIL PutTxbyte(LF);

END;

 

FUNCTION GetChar(VAR first: boolean):char;

(* get a character from reader *)

BEGIN

��� parity := FALSE;�������������� (* init. parity variable *)

��� ch:=#0;����������������������� (* ready to build character *)

��� i:=1;������������������������� (* index character bits *)

��� REPEAT

����� (* wait for clock to go low *)

����� WHILE Bit(pinD,clockLine)=#1 DO;

 

����� (* sample data line *)

����� IF Bit(pinD,dataLine)= #0 THEN (* data=1 [data inverted] *)

������� BEGIN

��������� ch:= ch + Chr(i);������� (* add a '1' bit to code *)

��������� parity := NOT parity;��� (* toggle parity *)

��������� first := FALSE;��������� (* we now have the first '1' in data stream *)

������� END;

����� i:=i Shl 1;����������������� (* index next bit position *)

����� IF first THEN i:=1;��������� (* reset index & wait for 1st '1' to arrive *)

 

����� (* wait for clock to go high again *)

����� WHILE Bit(pinD,clockLine)=#0 DO;

 

��� UNTIL i=%00100000;�� (* all 5 bits collected? *)

���

��� ch:=(ch & #$0f)+#$30;��������� (* mask parity bit & convert to ASCII char *)

 

��� IF parity THEN (* good read (odd-parity) *)

����� GetChar := ch

��� ELSE

�� ���GetChar := '*'; (* return a dummy char for bad read *)

END;

 

BEGIN

InitUART(B19200);���� (* initialize UART *)

SendMessage("Magnetic Stripe");

SendMessage(" Reader V1.1"); SendCRLF;

Wait(500); (* wait 0.5s for reader to power-up *)

REPEAT

�� (* wait for card to be loaded *)

��� WHILE Bit(pinD,cardNotLoaded)=#1 DO;

 

��� (* get and display other data *)

��� first := TRUE;(* flag first char to be read *)

��� REPEAT

����� ascCh := GetChar(first);������ (* get 1 character from reader *)

���� status := PutTXbyte(ascCh);��� (* send to UART *)

��� UNTIL (ascCh = EOD)OR(Bit(pinD,cardNotLoaded)=#1);

��� SendCRLF;

 

��� (* wait for card to be unloaded *)

��� WHILE Bit(pinD,cardNotLoaded)=#0 DO;

FOREVER;

END.

 

Back