前段时间需要编写SLE4442的操作程序,想找一个参考一下(公司里有PIC的,但是感觉有点乱,倒是也能参考,并且帮了不少忙),上网上查了一下,只在一个网站上发现有,但是需要缴费注册或者上传10篇高质量的源代码换积分,没办法,只有靠自己了,现在测试通过了,特共享一下,希望用到的少走弯路。
先写一下中间的经历(有表达不清的地方请见谅):
1.写了程序,开始连读都不正确,结果发现读是正确的,只是读的区域不同,所以读到的正确数据与期望的数据不一致,这一点很快解决了
2.接下来是密码校验,弄了两天时间才调好,一直以为是时序问题,昨天才发现是多谢了一行复位代码造成的,是这样的:写数据都先复位,问题就出在在这里,密码校验十一个不能被打断的序列,必须严格按照序列操作,具体看datasheet。
3.最后一步是修改数据,因为修改数据必须在密码校验通过以后才行,这个弄好的快点,因为密码校验过程就有数据修改的部分,既然那个能过,说明程序没有大问题,最后发现,先复位一下就行了。
4.总结一下:每次操作(不论是读、写、修改数据)都要记的复位(使用复位操作)一下,一直到本次操作结束,中间不要复位,尤其是密码校验,其他的没什么难的,只要按照datasheet上的时序就能操作。
5.说一点俺程序的亮点:就是processing mode,datasheet和参考程序都是发送固定个时钟脉冲的,俺改了一下,就是判断是不是仍在processing mode,是的话就一直发时钟脉冲,不是就退出,代码少了,执行的也快
啰嗦了这么多,下面把最重要的部分拿出:
/*------------------------------------------------------------------- ic卡操作时钟频率必须在7-50kHz,即时钟脉冲宽度在10-71us之间 操作 命令 地址 数据 执行结果(凡是数据修改或者写入须通过密码验证) 读主存储区: 0x30 0-ff 无效 从输入的地址开始连续读出数据 读保护区: 0x34 无效 无效 连续读出4个字节 读安全区: 0x31 0 无效 连续读出4个字节,第一个为错误计数 修改主存贮区: 0x38 0-ff 有效 将数据写入到输入的地址 写改保护区: 0x3c 0-1f 有效 将数据与输入的地址数据对比,一致后将对应保护位清零 修改安全区: 0x39 0-3 有效 将数据写入到输入的地址,其中错误计数只能从1改为0 比较校验数据: 0x33 1-3 有效 将数据与输入地址的数据对比,全部一致后将错误计数擦除 -------------------------------------------------------------------*/ void ic_clk_delay(void) { unsigned char i=70; //使用STC12C5052AD时的值 //unsigned char i=6; //使用AT89C2051时的值 for(;i!=0;i--) ; }
/*------------------------------------------------------------------- IC卡操作启动函数 Ic_clk=1时,Ic_data电平由高向低跳变 -------------------------------------------------------------------*/ void ic_star(void) { Ic_data=1; Data_led=Ic_data; //映射IC卡数据,驱动发光二极管 ic_clk_delay(); Ic_clk=1; ic_clk_delay(); Ic_data=0; ic_clk_delay(); Ic_clk=0; }
/*------------------------------------------------------------------- IC卡操作结束函数 Ic_clk=1时,Ic_data电平由低向高跳变 -------------------------------------------------------------------*/ void ic_stop(void) { Ic_data=0; ic_clk_delay(); Ic_clk=1; ic_clk_delay(); Ic_data=1; Data_led=0; }
/*------------------------------------------------------------------ IC卡数据写函数 ------------------------------------------------------------------*/ void ic_write(unsigned char in_data) { unsigned char i; for(i=8;i!=0;i--) //将数据串行输出,低位在前 { Ic_data=(bit)(in_data&0x01); in_data>>=1; ic_clk_delay(); Ic_clk=1; ic_clk_delay(); Ic_clk=0; } }
/*------------------------------------------------------------------- IC数据读函数 -------------------------------------------------------------------*/ unsigned char ic_reads(void) { unsigned char i,out_data; Ic_clk=0; ic_clk_delay(); for(i=8;i!=0;i--) //循环接收IC卡数据 { Ic_clk=1; ic_clk_delay(); out_data>>=1; if(Ic_data) out_data|=0x80; //先接收低位数据 Ic_clk=0; ic_clk_delay(); } return(out_data); //返回接收数据 }
/*------------------------------------------------------------------- IC卡复位及复位应答 -------------------------------------------------------------------*/ void ic_rest (void) { Data_led=1; Ic_clk=0; ic_clk_delay(); Ic_rest=1; ic_clk_delay(); Ic_clk=1; ic_clk_delay(); Ic_clk=0; ic_clk_delay(); Ic_rest=0; ic_clk_delay(); ic_reads(); ic_reads(); ic_reads(); ic_reads(); Data_led=0; }
/*------------------------------------------------------------------- 发送IC卡操作命令函数 -------------------------------------------------------------------*/ void ic_command(unsigned char command,unsigned char address,unsigned char ic_in_data) { ic_star(); ic_write(command); //发送命令 ic_write(address); //发送地址 ic_write(ic_in_data); //发送数据 ic_stop(); //操作命令结束 }
/*------------------------------------------------------------------- IC卡读函数 -------------------------------------------------------------------*/ void ic_bytes_read(unsigned char command,unsigned char address,unsigned char number) { ic_rest(); ic_command(command,address,0); p=parameter_last_time; for(;number!=0;number--) { *p=ic_reads(); p++; } p--; Ic_clk=1; ic_clk_delay(); Ic_clk=0; ic_clk_delay(); Data_led=0; }
/*------------------------------------------------------------------- IC卡字节修改 -------------------------------------------------------------------*/ void ic_byte_write(unsigned char command,unsigned char address,unsigned char ic_data) { if(command!=0x39&&command!=0x33) ic_rest(); ic_command(command,address,ic_data); Ic_clk=0; //从这一行开始的8行是processing mode ic_clk_delay(); Data_led=1; while(!Ic_data) { Ic_clk=!Ic_clk; ic_clk_delay(); } Data_led=0; }
/*------------------------------------------------------------------- IC卡核对密码: -------------------------------------------------------------------*/ void ic_password_compare(void) { unsigned char i,data_temp; //EA=0; ic_bytes_read(0x31,0,4); //读安全区数据 data_temp=parameter_last_time[0]; if(data_temp) //判断错误计数器是否为零 { switch(data_temp) { case 1: data_temp=0;break; case 3: data_temp=1;break; case 7: data_temp=3;break; default: data_temp=7;break; } ic_byte_write(0x39,0,data_temp); //将错位计数器的一位清零 for(i=3;i!=0;i--) ic_byte_write(0x33,(4-i),ic_password[3-i]); //核对密码 ic_byte_write(0x39,0,0xff); //擦除错误计数器 } ic_bytes_read(0x31,0,4); //读安全区数据 if(parameter_last_time[0]==7) Ic_password_ok=1; //EA=1; }
|