📄 ic_c.c
字号:
/******************************************
; 程序名称:SLE4442 逻辑加密存储卡读写程序
;
; 程序功能:首先对IC卡20~2Fh应用数据区16个
; 单元写数据,再将其读到片外数据
; 区2000h为起始地址的单元。
; 运行结果:2000 = 80,81,82...8F
******************************************/
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
uchar LedBuf[8]; /*显示缓冲区*/
uchar xdata *CS8255 = 0xffff;
uchar xdata *OUTSEG = 0xfffc; /*字形控制口*/
uchar xdata *OUTBIT = 0xfffd; /*字位控制口*/
uchar code Led_ICError[8] = {0xf9,0xc6,0xff,0x86,0xaf,0xaf,0xa3,0xaf};
uchar code Led_ICGood[8] = {0xff,0xf9,0xc6,0xff,0xc2,0xa3,0xa3,0xa1};
uchar code Led_NoIC[8] = {0xc8,0xc0,0xff,0xf9,0xc6,0xff,0xf9,0xc8};
/* 延时5us宏定义 */
#define Delay5us() _nop_();_nop_();_nop_();_nop_();_nop_()
/* 延时10us宏定义 */
#define Delay10us() _nop_();_nop_();_nop_();_nop_();_nop_();\
_nop_();_nop_();_nop_();_nop_();_nop_()
/* IC卡常数 */
/*---------------------------------------------
此处为IC卡保护区00~03单元的值,用于识别卡,这四个
字节是SLE4442的标识,如果IC卡保护区00~03单元的值
不是这四个字节,表明该卡不是SLE4442卡或卡已损坏
---------------------------------------------*/
#define IDENTIFY1 0xA2
#define IDENTIFY2 0x13
#define IDENTIFY3 0x10
#define IDENTIFY4 0x91
/* IC卡引脚位定义 */
sbit IO = P1^0; /*数据*/
sbit CLK = P1^1; /*脉冲*/
sbit RST = P1^2; /*复位*/
/* IC卡状态指示 */
sbit IC_INS = P1^3; /*插入正确*/
sbit IC_WRS = P1^4; /*写操作*/
sbit IC_RDS = P1^5; /*读操作*/
uchar bdata ibase; /*定义位寻址单元,用于发送与接收一个字节*/
sbit mybit0 = ibase^0;
sbit mybit1 = ibase^1;
sbit mybit2 = ibase^2;
sbit mybit3 = ibase^3;
sbit mybit4 = ibase^4;
sbit mybit5 = ibase^5;
sbit mybit6 = ibase^6;
sbit mybit7 = ibase^7;
/************************************************
函数名称:Readchar()
功 能:读一个字节
输 入: 无
输 出:所得的字节的值
************************************************/
uchar Readchar(void)
{
CLK=0; Delay5us(); mybit0=IO; CLK=1; Delay5us(); /*一个脉冲接收1 bit*/
CLK=0; Delay5us(); mybit1=IO; CLK=1; Delay5us(); /*一个脉冲接收1 bit*/
CLK=0; Delay5us(); mybit2=IO; CLK=1; Delay5us(); /*一个脉冲接收1 bit*/
CLK=0; Delay5us(); mybit3=IO; CLK=1; Delay5us(); /*一个脉冲接收1 bit*/
CLK=0; Delay5us(); mybit4=IO; CLK=1; Delay5us(); /*一个脉冲接收1 bit*/
CLK=0; Delay5us(); mybit5=IO; CLK=1; Delay5us(); /*一个脉冲接收1 bit*/
CLK=0; Delay5us(); mybit6=IO; CLK=1; Delay5us(); /*一个脉冲接收1 bit*/
CLK=0; Delay5us(); mybit7=IO; CLK=1; Delay5us(); /*一个脉冲接收1 bit*/
return(ibase); /*返回读得的一个字节*/
}
/************************************************
函数名称:SendByte()
功 能:把一个字节的数据由低到高位依次发送出去
输 入:uchar sendchar -- 要发送的字节
输 出;无
************************************************/
void SendByte(uchar sendchar)
{
uchar i;
ibase = sendchar;
for(i=8; i>0; i--) /*8个比特发送8次*/
{
CLK = 0;
Delay5us();
IO = mybit0; /*一个脉冲发送一个比特mybit0*/
CLK = 1;
Delay5us();
ibase >>= 1; /*将下次要发送的比特位移到mybit0*/
}
}
/************************************************
函数名称:RstCard()
功 能:使IC卡SLE4442复位
输 入:无
输 出:0 -- 复位成功
1 -- 复位失败,卡为无效卡或卡已损坏
************************************************/
uchar RstCard(void)
{
uchar i;
uchar ReadBuf[4];
IO = 1; /*IO引脚置高电平*/
RST = 0; /*RST引脚置低电平*/
CLK = 0; /*CLK 引脚置低电平*/
/*下面在一个RST脉冲期间产生一个CLK脉冲*/
Delay10us(); RST = 1;
Delay5us(); CLK = 1;
Delay5us(); CLK = 0;
Delay5us(); RST = 0;
for(i=0; i<4; i++) ReadBuf[i] = Readchar(); /*接收复位响应值*/
CLK = 1;
Delay5us();
CLK = 0;
IO = 1; /*置CLK和IO为复位时序图复位完成时的状态*/
if((ReadBuf[0]==IDENTIFY1) && (ReadBuf[1]==IDENTIFY2)&&
(ReadBuf[2]==IDENTIFY3) && (ReadBuf[3]==IDENTIFY4))
{
return 0; /*复位值正确,返回复位成功*/
}
else
{
return 1; /*复位值错误,返回复位失败*/
}
}
/************************************************
函数名:SendCommand()
功 能:根据不同的参数把命令字发给IC卡
参 数:uchar command -- 命令字;
uchar Address -- 地址;
uchar senddata -- 数据
返回值:无
************************************************/
void SendCommand(uchar command,uchar Address,uchar senddata)
{
IO = 1; /*产生开始状态*/
CLK = 0; Delay5us();
CLK = 1; Delay10us();
IO = 0; Delay10us();
CLK = 0;
SendByte(command); /*发送命令*/
SendByte(Address);
SendByte(senddata);
CLK = 0; /*产生停止状态*/
IO = 0; Delay5us();
CLK = 1; Delay5us();
IO = 1; Delay5us();
}
/************************************************
函数名称:SendClock()
功 能:发送处理脉冲
输 入:无
输 出:无
************************************************/
void SendClock(void)
{
CLK = 0; Delay10us(); /*产生一个脉冲,做为处理的工始*/
CLK = 1; Delay10us();
/*不断产生处理脉冲,驱动IC卡内部处理,直到IC卡将IO口拉为高电平*/
do
{
CLK = 0; Delay10us();
CLK = 1; Delay10us();
} while(IO == 0);
}
/************************************************
函数名称:ReadCm()
功 能:从主存储器中读出数据块并存入ReadBuf中
输 入:uchar StarAddr -- 开始地址(0-255)
uchar ByteNum -- 要读出的字节数(1-256)
uchar *RecBuf -- 接收数据缓冲区
输 出: 0 -- 读成功
1 -- 表示无效卡或者卡损坏
************************************************/
uchar ReadCm(uchar StarAddr,uchar ByteNum,uchar *RecBuf)
{
uchar i;
if(RstCard() == 1) /*使卡复位*/
return 1; /*如果复位失败返回1*/
SendCommand(0x30,StarAddr,0x00); /*发送读主存命令*/
for(i=0; i<ByteNum; i++)
{
*RecBuf = Readchar(); /*从主存中读出ByteNum个字节并存入RecBuf中*/
RecBuf++;
}
return 0;
}
/************************************************
函数名称: WriteCm()
功 能: 把存在WriteBuf中的ByteNum个字节的数据存入主存储器中
输 入: uchar StarAdr -- 开始地址(0-255)
uchar ByteNum -- 要写入的字节数(1-256)
uchar *WriteBuf -- 写入数据缓冲区
输 出: 0 -- 写成功
1 -- 表示无效卡或者卡损坏
注 意:要校验密钥正确,才能对卡的主存储器写入数据
************************************************/
uchar WriteCm(uchar StarAdr,uchar ByteNum,uchar *WriteBuf)
{
uchar i;
if(RstCard() == 1) /*使卡复位*/
return 1; /*如果复位失败返回1*/
for(i=0; i<ByteNum; i++)
{
SendCommand(0x38,StarAdr,*WriteBuf); /*发送写主存储区命令*/
SendClock(); /*发送处理脉冲*/
StarAdr++; /*写入字节地址加1*/
WriteBuf++; /*写入缓冲区指针加1*/
}
return 0;
}
/************************************************
函数名称:ReadPm()
功 能:读保护存储器,并把保护存储器的4字节的内容存在RecBuf中
输 入:uchar *RecBuf -- 接收数据缓冲区,长度为4个字节
输 出:0 -- 读成功
1 -- 表示无效卡或者卡损坏
************************************************/
uchar ReadPm(uchar *RecBuf)
{
uchar i;
if(RstCard() == 1) /*使卡复位*/
return 1; /*如果复位失败返回1*/
SendCommand(0x34,0x00,0x00); /*读保护存储器命令*/
IO = 1; /*置IO口为输入状态*/
Delay10us(); /*延时10us*/
for(i=0; i<4; i++) /*读保护存储器4个字节*/
{
*RecBuf=Readchar();
RecBuf++; /*接收缓冲区指针加1*/
}
SendClock(); /*发送处理脉冲*/
return 0;
}
/************************************************
函数名称:WritePm()
功 能:写保护数据存储器
输 入:uchar StartAdr -- 起始地址(0-31)
uchar ByteNum -- 写入的字节数(1-32)
uchar *WriteBuf -- 写入数据缓冲区
输 出:0 -- 写成功
1 -- 表示无效卡或者卡损坏
注 意: 首先校验密钥正确,才能对卡的护存储器写
入数据,其次写入的数据必须与卡中对应的
数据相等才能写入
************************************************/
uchar WritePm(uchar StartAdr,uchar ByteNum,uchar *WriteBuf)
{
uchar i;
if(RstCard() == 1) /*使卡复位*/
return 1; /*如果复位失败返回1*/
for(i=0; i<ByteNum; i++)
{
SendCommand(0x3c,StartAdr,*WriteBuf); /*写入一个字节*/
SendClock(); /*发送写命令处理脉冲*/
StartAdr++; /*写入字节地址加1*/
WriteBuf++; /*写入缓冲区指针加1*/
}
return 0;
}
/************************************************
函数名称:ReadPsw()
功 能:读加密存储器
输 入:uchar *Psw --- 用于装读到的加密存储器内容,长度为4个字节
Psw第一字节:错误计数器值
Psw第二字节到第四字节:卡的密码值
输 出:0 -- 读成功
1 -- 表示无效卡或者卡损坏
注 意: 必须校验密码正确才能读到正确的密钥值,否则读到的密码值为00 00 00
************************************************/
uchar ReadPsw(uchar *Psw)
{
uchar i;
if(RstCard() == 1) /*使卡复位*/
return 1; /*如果复位失败返回1*/
SendCommand(0x31,0,0);/*读加密存储器命令*/
for(i=0; i<4; i++) /*读加密存储器的四个字节*/
{
*Psw = Readchar();
Psw++;
}
return 0;
}
/************************************************
函数名称:CheckPsw()
功 能:校验密码,把Psw中1,2,3字节的内容分别与加密存储器的1,2,3字节比较
输 入:uchar *Psw -- 待校验的密码值,长度为3个字节
输 出: 3 -- 核对密码成功
0 -- 卡已报废
1 -- 只剩一次校验机会,校验密码失败
2 -- 只剩二次校验机会,校验密码失败
4 -- 卡为无效卡或已损坏
************************************************/
uchar CheckPsw(uchar *Psw)
{
uchar ReadBuf[4], i;
if(ReadPsw(ReadBuf)==1) /*读加密存储器*/
return 4;
if(ReadBuf[0]==0x07)
{
SendCommand(0x39,0,0x03); /*将EC写为0x03*/
SendClock(); /*发送处理脉冲*/
}
else if(ReadBuf[0]==0x06 || ReadBuf[0]==0x05 || ReadBuf[0]==0x03)
{
SendCommand(0x39,0,0x01); /*将EC写为0x01*/
SendClock(); /*发送处理脉冲*/
}
else if(ReadBuf[0]==0x01 || ReadBuf[0]==0x02 || ReadBuf[0]==0x04)
{
SendCommand(0x39,0,0x00); /*将EC写为0x00*/
SendClock(); /*发送处理脉冲*/
}
SendCommand(0x33,1,Psw[0]); SendClock(); /*校验密码的第一个字节*/
SendCommand(0x33,2,Psw[1]); SendClock(); /*校验密码的第二个字节*/
SendCommand(0x33,3,Psw[2]); SendClock(); /*校验密码的第三个字节*/
SendCommand(0x39,0,0x07); SendClock(); /*擦除错误计数器*/
SendCommand(0x31,0,0);/*读加密存储器命令*/
for(i=0;i<4;i++) ReadBuf[i]=Readchar(); /*读加密存储器的四个字节*/
if(ReadBuf[0]==0x07) return 3; /*剩下3次校验机会,校验密码成功*/
else if(ReadBuf[0]==6 || ReadBuf[0]==5 || ReadBuf[0]==3) return 2;
/*剩下2次校验机会,校验密码失败*/
else if(ReadBuf[0]==4 || ReadBuf[0]==2 || ReadBuf[0]==1) return 1;
/*剩下1次校验机会,校验密码失败*/
else return 0; /*无校验机会,卡报废*/
}
/************************************************
函数名称:SetPsw()
功 能:修改加密存储器中的密码
输 入:NewPsw -- 新密码缓冲区,长度为3个字节
输 出:0 -- 读成功
1 -- 表示无效卡或者卡损坏
注 意: 必须校验密码成功后才能修改密码,否则密码写不进卡中
************************************************/
uchar SetPsw(uchar *NewPsw)
{
uchar i;
if(RstCard() == 1) /*使卡复位*/
return 1; /*如果复位失败返回1*/
for(i=0; i<3; i++)
{
SendCommand(0x39,i+1,*NewPsw); /*发送新的密码值*/
SendClock(); /*发送处理脉冲*/
NewPsw++; /*密码值缓冲区指针加1*/
}
return 0;
}
/* 程序延时 */
void Delay(uint count)
{
uchar i;
while(count-- != 0) for(i=0;i<120;i++);
}
/* LED显示函数 */
void DispLed(uchar LedPtr[8])
{
uchar i, pos=0x80;
for(i=0; i<8; i++)
{
*OUTSEG = LedPtr[i];
*OUTBIT = pos;
Delay(2);
pos>>=1;
}
}
main()
{
uchar ReadBuf[16]; /*读数据缓冲区*/
uchar WriteBuf[16]; /*写数据缓冲区*/
uchar i;
uchar retw, retr;
uchar psw[3] = {0xff,0xff,0xff}; /*IC卡初始密码: FF FF FF*/
uchar xdata *PTR = 0x0080 ;0x2000 ;片内地址; /*片外RAM地址指针*/
*CS8255 = 0x88;
while(IC_INS) DispLed(Led_NoIC);
*OUTBIT = 0;
Delay(500);
if(ReadCm(0x00,8,ReadBuf)==0) /*读卡状态*/
{ /*读IC卡状态正确*/
if(CheckPsw(psw)==3)
{ /*密码校验成功*/
for(i=0;i<16;i++) WriteBuf[i]=i+0x80;
retw = WriteCm(0x20,16,WriteBuf); /*写IC卡*/
IC_WRS = 0; Delay(600); IC_WRS = 1;
retr = ReadCm(0x20,16,ReadBuf); /*读IC*/
IC_RDS = 0; Delay(600); IC_RDS = 1;
if(retw==0 && retr==0) /*读写正确*/
{
for(i=0; i<16; i++) *PTR++ = ReadBuf[i]; /*将IC卡数据写入片外RAM*/
while(1) DispLed(Led_ICGood);
}
else while(1) DispLed(Led_ICError);
}
else while(1) DispLed(Led_ICError);
}
else while(1) DispLed(Led_ICError);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -