最近用了两个星期的时间,学习了 AT88SC102 加密 IC 卡的读写和密码验证。我
觉得 102 卡数据手册中的时序图对于我们这些新手来说很难看懂,没有 AT24C02
等的一步一步看得直观。刚开始简直无法入手,不得不在网上找了个例程参考通
讯时序。
读卡程序完成得较顺利,核对密码程序编写时反复看了 n 遍时
序图,擦除程序运行中总是擦不对位置,最终发现指令之间延时太少,12M 晶振
用了 3 个 nop 还不够,最后试验发现用 5 个 nop 就比较稳定了,看来还是要先计
算指令执行时间并核对时序要求时间。有时急于求成,不踏实呀。
/********************************************************
* 短延
时
********************************************************/
void DelayNop(void)
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
/********************************************************
* 长延
时
********************************************************/
void Delay(uchar ms)
{
uchar i;
while(ms--)
{
for(i = 0; i < 123; i++);
}
}
/********************************************************
* 初始
化
********************************************************/
void Card_Init(void)
*
*
*
{
card_power = 1;
card_clk = 0;
card_pgm = 0;
card_rst = 0;
card_io = 1;
DelayNop();
card_power = 0;
Delay(10);
}
//关 card_power
//开 card_power
/********************************************************
* 复
位
*
********************************************************/
void Card_Reset(void)
{
card_rst = 1;
card_clk = 1;
DelayNop();
card_clk = 0;
DelayNop();
card_rst = 0;
card_pgm = 0;
card_io = 1;
DelayNop();
}
/********************************************************
* 结
束
*
********************************************************/
void Card_End(void)
{
card_io = 1;
card_power = 1; //关电源
card_clk = 0;
card_pgm = 0;
card_rst = 0;
card_io = 0;
}
/********************************************************
* 选择地
址
********************************************************/
void Card_SetAddress(uint startaddress)
{
Card_Reset();
while(startaddress--)
{
*
card_clk = 1;
DelayNop();
card_clk = 0;
DelayNop();
}
}
/********************************************************
* 读
卡
*
********************************************************/
void Card_Read(uchar *pointer_cardbuf, uint startaddress, uchar bytes)
{
uchar j,i,readbyte;
Card_SetAddress(startaddress);
card_io = 1;
for(j = 0; j < bytes; j++)
{
readbyte = 0;
for(i = 0; i < 8; i++) //循环 8 位读一个字节;
{
card_clk = 1;
DelayNop();
readbyte = readbyte <<1;
readbyte = readbyte | card_io;
card_clk = 0;
DelayNop();
}
*pointer_cardbuf = readbyte;
pointer_cardbuf++;
}
card_io = 1; //有必要吗?
}
成功返回 1,失败返回
/********************************************************
* 核对密码
0
********************************************************/
bit Card_CheckPassword(uchar *password)
Card_End()
{
uchar j,i,temp;
*
//对返回值进行判断,执行
Card_SetAddress(80);
//80 - 95 Security Code (SC)
for(i = 0; i < 2; i++)
{
temp=*password;
for(j = 0;j < 8;j++)
{
card_io = (bit)(temp & 0x80);
DelayNop();
card_clk = 1;
DelayNop();
card_clk = 0;
DelayNop();
temp = temp << 1;
}
password++;
}
card_io = 1;
for(i = 0;i < 3;i++)
{
if(card_io)
{
Card_EraseScac(0);
if(card_io)
return(0);
else
{
Card_EraseScac(1);
card_io = 1;
DelayNop();
card_clk = 1;
DelayNop();
card_io = 1;
return(card_io);
}
}
card_clk = 1;
DelayNop();
card_clk = 0;
DelayNop();
}
return(0);
}
/********************************************************
* 校验密码成功后擦除
SCAC
********************************************************/
void Card_EraseScac(uchar value)
{
card_pgm = 1;
DelayNop();
if(value)
*
else
card_io = 1;
card_io = 0;
DelayNop();
card_clk = 1;
DelayNop();
card_pgm = 0;
Delay(5);
card_clk = 0;
card_io = 1;
DelayNop();
}
/********************************************************
* 写卡
********************************************************/
void Card_Write(uchar *pointer_cardbuf,uint startaddress,uchar bytes)
{
*
uchar i,j;
uchar doublebytes,wrbyte;
card_io = 1;
Card_SetAddress(startaddress);
doublebytes = bytes;
doublebytes = (doublebytes + 1) >> 1;
doublebytes--;
//单字节数转为双字节数
if(doublebytes)
{
for(i = 0; i < doublebytes; i++)
{
Card_WriteBit(1);
for(j = 0; j < 16; j++)
{
DelayNop();
card_clk = 1;
DelayNop();
card_clk = 0;
DelayNop();
}
}
Card_WriteBit(1);
Card_WriteBit(1);
}else
{
}
Card_SetAddress(startaddress);
for(i = 0; i < bytes; i++)
{
wrbyte = *pointer_cardbuf;
for(j = 0; j < 8; j++)
{
if(wrbyte & 0x80)
{
card_clk = 1;
DelayNop();
card_clk = 0;
DelayNop();
}else
{
Card_WriteBit(0);
}
wrbyte = wrbyte << 1;
}
pointer_cardbuf++;
}
}
*
/********************************************************
* 写 bit
********************************************************/
void Card_WriteBit(uchar bitt) //擦除为写 1
{
card_pgm = 1;
DelayNop();
card_io = bitt;
DelayNop();
card_clk = 1;
DelayNop();
card_pgm = 0;
Delay(5);
card_clk = 0;
DelayNop();
//小于 3 时写不正确
card_io = 1;
DelayNop();
card_clk = 1;
DelayNop();
card_clk = 0;
DelayNop();
}
IC 卡 WINDOWS 驱动程序手册一 、IC 卡驱动程序是一 32 位 Windows 应用程序调用的动
态链接库,文件名为 IC32.DLL。
二、 IC32.DLL 提供的函数:
注意:以下函数名的大小写必须严格区分,否则无法调用
返回读写器状态
1.IC_Status()
<1>、通用函数:
2.IC_ErrMsg()
3.IC_InitComm()
4.IC_ExitComm()
5.IC_InitType ()
6.IC_Read ()
7.IC_Write ()
8.IC_Erase ()
将错误码转换为错误信息
打开串口
关闭串口
设置要读卡的类型
读 IC 卡的内容
写内容到 IC 卡
对 IC 卡擦除操作(写 FF)
9.IC_Read_Float() 读 IC 卡存储的浮点数
10.IC_Write_Float() 写浮点数到 IC 卡
<2>、西门子 4432/4442 卡专用函数:
1.IC_ReadProtection () 读 S4432/S4442 卡的保护位
2.IC_WriteProtection () 写 S4432/S4442 卡的保护位
3.IC_ReadCount_SLE4442 () 读 S4442 卡的错误计数器
4.IC_CheckPass_SLE4442 () 效验 S4442 卡的密码
5.IC_ChangePass_SLE4442 () 改变 S4442 卡的密码
<3>、西门子 4418/4428 卡专用函数:
1.IC_ReadWithProtection () 带保护位读 S4418/S4428 卡
2.IC_WriteWithProtection () 带保护位写 S4418/S4428 卡
3.IC_ReadCount_SLE4428 () 读 S4428 卡的错误计数器
4.IC_CheckPass_SLE4428 () 效验 S4428 卡的密码
5.IC_ChangePass_SLE4428 () 改变 S4428 卡的密码
<4>、ATMEL AT88SC101/102/103 卡专用函数:
1. IC_CheckPass_102()
效验 ATMEL101/102/103 卡的系统密码
改变 ATMEL101/102/103 卡的密码
读 ATMEL101/102/103 卡的错误计数器
对 ATMEL101/102/103 卡的擦除操作
效验 ATMEL102 卡的应用区密码
改变 ATMEL102 卡的应用区密码
烧断 ATMEL102 卡的熔丝
2. IC_ChangePass_102()
3. IC_ReadCount_102 ()
4. IC_Erase_102()
5. IC_CheckAZPass_102()
6. IC_ChangeAZPass_102()
7. IC_Fuse_102 ()
<5>、西门子 4406 卡(电话卡)专用函数:
1. IC_RValue ()
2. IC_DEValue ()
<6>、ATMEL AT88SC1604 卡专用函数:
1. IC_CheckPass_1604()
2. IC_ChangePass_1604()
3. IC_ReadCount_1604 ()
4. IC_Fuse_1604 ()
读 S4406 卡的值
减 S4406 卡的值
效验 AT88SC1604 卡的系统密码
改变 AT88SC1604 卡的密码
读 AT88SC1604 卡的错误计数器
烧断 AT88SC1604 卡的熔丝
IC_Write24()
<7>、ATMEL AT24C 系列卡(非加密卡)专用函数:
1.
2. 写 AT24C 卡(用法见 IC_Write()函数)三 函数说明
<1>、通用函数:
1.
IC_Status(HANDLE ICDev)
__int16
ICDev
=0 正确*
----
InitComm 返回的设备 描述符
举例:IC_Status(ICDev)
说明:返回当前状态*
调用:HANDLE
返回:<0 错误,见错 误码
2.
__int16
IC_ErrMsg (__int16 ErrNo, unsigned char* ErrMsg)
调 用 : __int16 ErrNo
息 内 容
unsigned char * ErrMsg
号
0XEE 表示的错误信息存入 errmsg 指定的数据缓冲区。
>=0 ErrMsg 的有效长度
---- 错误信息内容
----
说明:获取错误信
IC 卡 操 作 函 数 返 回 的 错 误 号
返回:<0 错误。其绝对值为错误
将
举例:IC_ErrMsg(0xee,errmsg)
3.
__int16
InitComm(__int16 Port)
说明:打开通讯设备
---- 通讯口号,整数 0,1,2,3
返回:<0 错误
调用:__int16 Port
>=0 通讯设备标识符