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