//****************************************************************************
// Filename sim.c
// Description In this project, a SIM card has been used as the external
// EEPROM memory expansion of MCU.
//----------------------------------------------------------------------------
// Controller STC12LE5A60S2
// Clock 22.1184MHz
// Compiler Keil
//----------------------------------------------------------------------------
// Date 12/3/2010
//****************************************************************************
#include <8051.h>
#include <stdio.h>
__sfr __at (0x8E) AUXR ;
__sfr __at (0x8F) WAKE_CLKO ;
typedef unsigned char uchar;
#define SIM_VCC P3_5
#define SIM_CLK P1_0 // STC12C4052AD CLKOUT0
#define SIM_RST P1_1 //接SIM卡的RST引脚
#define SIM_IO P1_2 //接SIM卡的I/O引脚
uchar buf[30]={0}; //存放记录数据
uchar tmp[4]={0}; //存放命令临时数据
uchar i=0; //指向buf的起始
//****************************************************************************
//串口初始化函数
//****************************************************************************
void Uart_Init()
{
PCON |= 0x80; // double baud rate
AUXR |= 0xC0; // T1: 1T
WAKE_CLKO |=0x01; // Output T0
SCON = 0x50;
TMOD |= 0x22;
TL0=TH0=0xFE; // SIM card CLK: 3MHz, fosc=12MHz
TL1=TH1=0xF3; // Baud:57600, fosc=12MHz
TR0=1;
TR1=1;
TI=1;
RI=0;
}
//****************************************************************************
// 向串口1发送一个字符
//****************************************************************************
void putchar (char c)
{
while(!TI);
TI=0;
SBUF=c;
}
//****************************************************************************
// 延时1个ETU(基本时间单位)
// 如SIM卡时钟频率为3.579545MHz,则ETU为372/3.579545M=103.92us
//****************************************************************************
void delay_1_ETU() // 1 ETU = 372/3MHz = 124us
{
__asm
mov r6, #4
__d1: mov r7, #91
djnz r7, .
djnz r6, __d1
__endasm;
}
//****************************************************************************
// 延时半个ETU(103.92us/2=51.96us)
//****************************************************************************
void delay_half_ETU() // 0.5 ETU = 62us
{
__asm
mov r6, #16
__d2: mov r7, #10
djnz r7, .
djnz r6, __d2
__endasm;
}
//****************************************************************************
// 延时400个ETU:400*103.92us=41.568ms
// (16*(89*(3+2*160)+3)+3)*(12/22.1184)/6=41595us
//****************************************************************************
void delay_400_ETU() // 400 ETU = 49600us
{
__asm
mov r5, #9
__d4: mov r6, #107
__d3: mov r7, #153
djnz r7, .
djnz r6, __d3
djnz r5, __d4
__endasm;
}
//****************************************************************************
// 从SIM卡读取一个字节
//****************************************************************************
uchar read_SIM_byte()
{
uchar loop;
uchar recvdata = 0;
__bit Parity = 0; //奇偶校验位
while(SIM_IO); //等待起始位
delay_1_ETU(); //延时一个etu
delay_half_ETU(); //延时半个etu
for(loop=0;loop<8;loop++)
{
recvdata >>= 1;
if (SIM_IO)
{
recvdata |= 0x80;
}
Parity ^= SIM_IO;
delay_1_ETU(); //延时一个etu
}
Parity ^= SIM_IO;
delay_1_ETU(); //延时一个etu
if(!Parity) //此字节如通过奇偶校验则原样显示,通不过则显示0x99
{
return recvdata;
}
else
{
return 0x99;
}
}
//****************************************************************************
// 向SIM卡发送一个字节
//****************************************************************************
void write_SIM_byte(uchar dataToSend)
{
uchar loop;
__bit Parity = 0; //奇偶校验位
SIM_IO = 0; //发送起始位
delay_1_ETU(); //延时一个etu
for(loop=0;loop<8;loop++)
{
SIM_IO = dataToSend & 0x01;
Parity ^= dataToSend & 0x01;
dataToSend >>= 1;
delay_1_ETU(); //延时一个etu
}
SIM_IO = Parity; //如果前8位异或的结果是1,则校验位发1,如果结果是0,则发0
delay_1_ETU(); //延时一个etu
SIM_IO = 1; //将IO拉高
delay_1_ETU();
delay_1_ETU();
}
//****************************************************************************
// 向SIM卡发送命令,参考ISO7816-1/2/3/4协议或GSM11-11
//****************************************************************************
void command(uchar CLA,uchar INS,uchar P1,uchar P2,uchar P3,uchar contral)
{
delay_1_ETU();delay_1_ETU();//延时两个etu
write_SIM_byte(CLA); //CLA,INS,P1,P2,P3为协议中所规定的命令格式参数
write_SIM_byte(INS);
write_SIM_byte(P1);
write_SIM_byte(P2);
write_SIM_byte(P3);
switch(contral&0x0F) //contral自定义参数
{
case 0: //contral低4位为0,表示无其他命令参数发送,直接返回
break;
case 2: //contral低4位为2,表示tmp中2字节其他命令参数要发送
tmp[2]=read_SIM_byte(); //读取SIM卡返回参数INS
delay_1_ETU();delay_1_ETU();
write_SIM_byte(tmp[0]); //发送其他参数
write_SIM_byte(tmp[1]);
break;
default://contral低4位为其他值时,表示buf中P3字节数据参数要发送
tmp[2]=read_SIM_byte();
delay_1_ETU();delay_1_ETU();
for(i=0;i<P3;i++)
write_SIM_byte(buf[i]);
break;
}
switch((contral&0xF0)>>4) //contral自定义参数
{
case 0: //contral高4位为0,表示无其他命令参数读取,直接返回
break;
case 2: //contral高4位为2,表示2字节其他命令参数要接收,存储到tmp中
tmp[0]=read_SIM_byte();
tmp[1]=read_SIM_byte();
break;
default://contral高4位为其他值,表示P3字节数据参数要接收,存储到buf中
tmp[2]=read_SIM_byte();
for(i=0;i<P3;i++)
buf[i]=read_SIM_byte();
tmp[0]=read_SIM_byte();
tmp[1]=read_SIM_byte();
break;
}
}
//****************************************************************************
// 从SIM卡读取6F3A文件记录,参数为记录号,1-250
//****************************************************************************
void read_SIM_6F3A(uchar blocknum)
{
tmp[0]=0x7F;
tmp[1]=0x10;
command(0xA0,0xA4,0x00,0x00,0x02,0x22); //选择6F3A的上层文件7F10
tmp[0]=0x6F;
tmp[1]=0x3A;
command(0xA0,0xA4,0x00,0x00,0x02,0x22); //选择文件6F3A
command(0xA0,0xB2,blocknum,0x04,0x1C,0x10); //读取记录数据
}
//****************************************************************************
// 向SIM卡写入6F3A文件记录,参数为记录号,1-250
//****************************************************************************
void write_SIM_6F3A(uchar blocknum)
{
tmp[0]=0x7F;
tmp[1]=0x10;
command(0xA0,0xA4,0x00,0x00,0x02,0x22); //选择6F3A的上层文件7F10
tmp[0]=0x6F;
tmp[1]=0x3A;
command(0xA0,0xA4,0x00,0x00,0x02,0x22); //选择文件6F3A
command(0xA0,0xDC,blocknum,0x04,0x1C,0x21); //更新记录数据
}
//****************************************************************************
// SIM卡初始化
//****************************************************************************
void SIM_Init()
{
SIM_VCC = 0;
SIM_IO = 1; //将I/O端口置为接收方式
SIM_RST = 0; //RST复位信号需在提供CLK信号后400个时钟周期内保持低电平
delay_400_ETU();
SIM_RST = 1; //提供复位信号后400~40000个时钟周期内,I/O口有复位应答ATR
tmp[0]=read_SIM_byte(); //ATR信号不止3个字节,此处只接收了前3个,其他字节丢弃
tmp[1]=read_SIM_byte();
tmp[2]=read_SIM_byte();
delay_400_ETU();
//write_SIM_byte('\xFF'); //PTS
//write_SIM_byte('\x00');
//write_SIM_byte('\xFF');
//tmp[0]=read_SIM_byte();
//tmp[1]=read_SIM_byte();
//tmp[