Serial I2C Smart Card Reader/Writter

Introduction
This project demonstrates how to operate the 'I2C card
reader (ST14C02)' using a serial interface.
The target device is a PIC16F84 running at 4Mhz.
Operation
See application code below. When a 256-byte I2C memory
card such as the ST Microelectronics ST14C02 is inserted
in to the card socket the string "/E01" is
transmitted out of the serial port, when the card is
removed the string "/E00" is transmitted.
The card reader/writer responds to the following commands.
All commands are appended with a carriage return.
READ
"/Raa" Read 4-bytes of data from hexadecimal
address aa.
Example: Read 4-bytes of data from address 80hex.
Command: "/R80"
Response: "/Rdddddddd" where dd is hexadecimal
data
WRITE
"/Waadddddddd" Write 4-bytes of data to hexadecimal
address aa.
Example: Write 4-bytes of data (1,2,3,4) to address
00hex
Command: "/W0001020304"
Response: "/W"
QUERY
"/Q" Query card status.
Example: Get card status
Command: "/Q"
Response: "/Qdd" where dd=00 card absent,
dd=01 card present
Remember to put the carriage return at the end of each
command.
Application code
Below is the application code for this project. To use
it, select and copy (ctr-insert) the code below, paste
it into a text editor and save as a 'C' file in your
working directory. You may also need to change the build
output path using 'Project | Options'
///////////////////////////////////////////////////////////////////////
//// AI2CCARD.C ////
//// ////
//// Demonstrates the 'I2C card reader (ST14C02)' sub-circuit. ////
//// When an ST140 is inserted into the card socket the ////
//// string "/E01" is sent and "/E00" when the card is removed. ////
//// "/Waadddddddd" writes data to the card where aa is the ////
//// address in hex and DD are four data bytes to write. ////
//// "/Raa" reads four bytes of data from address aa. ////
//// All commands and responses are appended with a carriage ////
//// return. ////
//// ////
//// This program is an example of how your application code is ////
//// is organised. Note the #include "i2ccard.inc", this include ////
//// file was generated by QuickBuilder and contains all ////
//// dirver code. ////
//// ////
//// This demo is intended for a PIC16F84 ////
//// Compile using CCS 'C' visit www.quickbuilder.co.uk/qb/ccs ////
///////////////////////////////////////////////////////////////////////
#include <16f84.H>
#fuses XT,NOPROTECT,NOWDT
#case
#include "i2ccard.inc"
// Comms vars
int RxCmd = 0;
int RxData[8];
int RxIP=0;
int RxState = 0;
void BlinkLED(void) {
LED_1OFF();
delay_ms(100);
LED_1ON();
}
int HexToNibble( char c ) {
if ( (c >= '0') && (c <= '9') )
return c-'0';
else if ( (c >= 'A') && (c <= 'F') )
return c-('A'-0x0a);
else
return 0;
}
int GetCommand( void ) {
int c,d,n;
if ( RS232_1INCOMING()==0 ) // incomming char
return 0;
c = RS232_1IN();
if (c=='/')
RxState = 0;
switch ( RxState ) {
case 0 : // command start
RxIP = 0;
n = 0;
RxCmd = RS232_1IN(); // get command char
RxState = 1;
break;
case 1 : // get data
if (c==0x0d) { // end of commad hex data
RxState = 0;
return 1;
} else { // get data
c = HexToNibble( c);
if ( !bit_test(n,0) ) { // high nibble
RxData[ RxIP ] = c<<4;
n++;
} else { // low nibble
RxData[ RxIP] |= c;
RxIP++; // inc index and wrap
RxIP &=0x7;
n++;
}
}
break;
default: // illegal state
RxState = 0;
}
return 0;
}
void DoCommand( void ) {
int addr,i,d;
BlinkLED();
switch (RxCmd) {
case 'R' : // read 4-bytes from card
printf(RS232_1OUT,"/R");
for (i=0 ; i<4; i++) {
d = ST1402_1READ( RxData[0]++ );
printf(RS232_1OUT,"%02X", d);
}
printf(RS232_1OUT,"\n");
break;
case 'W' : // write 4-bytes to card
for (i=1 ; i<5; i++) {
ST1402_1WRITE( RxData[0]++,RxData[i] );
}
printf(RS232_1OUT,"/W\n");
break;
case 'Q' : // query card status
if ( ST1402_1PRESENT() ) // card present
printf(RS232_1OUT,"/Q01\n");
else // card not present
printf(RS232_1OUT,"/Q00\n");
break;
default: // unknown command
printf(RS232_1OUT,"/?\n");
}
RxCmd = 0;
}
void DoCard( void ) {
static int1 CardPresent=0;
if (ST1402_1PRESENT() ) {
if (!CardPresent) {
BlinkLED();
printf(RS232_1OUT,"/E01\n");
}
CardPresent = 1;
} else {
if (CardPresent) {
BlinkLED();
printf(RS232_1OUT,"/E00\n");
}
CardPresent = 0;
}
}
main() {
INIT_SUB_CIRCUITS();
BlinkLED();
while(1) {
if ( GetCommand() )
DoCommand();
DoCard();
}
}
|