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 *)
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.