智能卡RC500读卡程序
- 格式:doc
- 大小:129.50 KB
- 文档页数:24
2002/01/10版本目录第一章RC500系统描述MIFARE 系统简介RC500系统结构及功能说明RC500系统安装用户系统开发步骤第二章RC500系统通信协议通信接口定义通信方式标准RS232通信协议TTL电平RS232通信协议LD自定义格式通信协议通信命令传输:两次握手协议第三章RC500系统操作命令模块操作命令卡片操作基础命令集卡片操作高级命令集第四章Advic32 函数动态链接库运行环境说明ADVIC32 动态库说明ADVIC32 常量定义ADVIC32 函数定义ADVIC32 函数详解附录一 RC500命令代码速查表附录二 RC500命令返回码表第一章RC500系统描述RC500系列MIFARE卡读写器/读写模块是本公司研制生产的智能卡读写器/读写模块系列产品之一。
它独立完成对MIFARE系列非接触卡的读写及控制操作,广泛应用于需以MIFARE卡作为存贮媒体的系统中。
它可以作为用户系统中的一部份,受控于主控制器,完成用户系统设定的对MIFARE卡片的所有操作。
用户应用本模块,能够简便地构成自己的智能卡应用产品。
1.1MIFARE系统简介近几年来,IC智能卡中的非接触式射频卡的安全保密、使用简便等特点使其在各领域的应用中异军突起,特别在民用系统(自动电表抄表系统、公交/地铁自动售票系统、企业“一卡通”、巡更保安系统等)中得到广泛的应用。
人们己愈来愈多开始接收和使用智能卡。
相信该领域的发展将越来越大。
MIFARE智能卡系统的核心是PHILIPS公司的MIFARE 1 S50系列晶片,该技术己被制定为国际标准:ISO/IEC 14443 TYPE A。
目前许多较大的IC卡卡片制造商的非接触卡制造均以MIFARE技术为标准。
MIFARE卡中包含一块ASIC微晶片和一个高频天线,其工作原理是:读写器中的MIFARE基站向MIFARE卡发一组固定频率()的电磁波,卡片内有一个LC串联谐振电路,其频率与基站发射的频率相同,在电磁波的激励下,LC谐振电路产生共振,从而使卡片内具有电荷,当所积累的电荷达到2V时,卡片中芯片将卡内数据发射出去或接收基站对卡片的操作。
【实例95】非接触IC卡读写MF RC500的命令集的程序定义代码如下。
#define M500Pcd_IDLE 0x00 //取消当前命令#define M500Pcd _WRITEE2 0x01 //写EEPROM#define M500Pcd _READE2 0x03 //读EEPROM#define M500Pcd _LOADCONFIG 0x07 //调EEPROM中保存的RC500设置#define M500Pcd _LOADKEYE2 0x0B //将EEPROM中保存的密钥调入缓存#define M500Pcd _AUTHENT1 0x0C //验证密钥第一步#define M500Pcd _AUTHENT2 0x14 //验证密钥第二步#define M500Pcd _RECEIVE 0x16 //接收数据#define M500Pcd _LOADKEY 0x19 //传送密钥#define M500Pcd _TRANSMIT 0x1A //发送数据#define M500Pcd _TRANSCEIVE 0x1E //发送并接收数据#define M500Pcd _Startup 0x3F //复位#define M500Pcd _CALCCRC 0x12 //CRC计算MF RC500的64个寄存器的程序定义代码如下。
// PAGE 0#define RegPage 0x00#define RegCommand 0x01#define RegFIFOData 0x02#define RegPrimaryStatus 0x03#define RegFIFOLength 0x04#define RegSecondaryStatus 0x05#define RegInterruptEn 0x06#define RegInterruptRq 0x07// PAGE 1#define RegPage 0x08#define RegControl 0x09#define RegErrorFlag 0x0A#define RegCollPos 0x0B#define RegTimerValue 0x0C#define RegCRCResultLSB 0x0D#define RegCRCResultMSB 0x0E#define RegBitFraming 0x0F// PAGE 2#define RegPage 0x10#define RegTxControl 0x11#define RegCwConductance 0x12#define RFU13 0x13#define RegCoderControl 0x14#define RegModWidth 0x15#define RFU16 0x16#define RFU17 0x17// PAGE 3#define RegPage 0x18 #define RegRxControl1 0x19 #define RegDecoderControl 0x1A #define RegBitPhase 0x1B #define RegRxThreshold 0x1C #define RFU1D 0x1D #define RegRxControl2 0x1E #define RegClockQControl 0x1F // PAGE 4#define RegPage 0x20 #define RegRxWait 0x21 #define RegChannelRedundancy 0x22 #define RegCRCPresetLSB 0x23 #define RegCRCPresetMSB 0x24 #define RFU25 0x25 #define RegMfOutSelect 0x26 #define RFU27 0x27 // PAGE 5#define RegPage 0x28 #define RegFIFOLevel 0x29 #define RegTimerClock 0x2A #define RegTimerControl 0x2B #define RegTimerReload 0x2C #define RegIRqPinConfig 0x2D #define RFU2E 0x2E #define RFU2F 0x2F // PAGE 6#define RegPage 0x30 #define RFU31 0x31 #define RFU32 0x32 #define RFU33 0x33 #define RFU34 0x34 #define RFU35 0x35 #define RFU36 0x36 #define RFU37 0x37 // PAGE 7#define RegPage 0x38#define RFU39 0x39 #define RegTestAnaSelect 0x3A #define RFU3B 0x3B #define RFU3C 0x3C #define RegTestDigiSelect 0x3D#define RFU3E 0x3E#define RegTestDigiAccess 0x3F主程序的代码如下:#define MI_OK 0#define uchar unsigned char#define uint unsigned int//操作子函数extern char M500PcdReset();//复位并初始化RC500extern char M500PcdRequest(uchar req_code); //寻卡extern char M500PcdAnticoll(uchar *snr); //防冲撞extern char M500PcdSelect(uchar *snr); //选定一张卡extern char M500ChangeCodeKey(uchar *uncoded,uchar *coded); //转换密钥格式extern char M500PcdAuthKey(uchar *coded); //传送密钥extern char M500PcdAuth(uchar auth_mode,uchar block,uchar *snr); //验证密钥extern char M500PcdRead(uchar addr,uchar *readdata); //读块extern char M500PcdWrite(uchar addr,uchar *writedata); //写块extern char M500PcdHalt(void); //卡休眠extern char M500PcdReadE2(uint startaddr,uchar length,uchar *readdata); //读RC500-EEPROM数据extern char M500PcdWriteE2(uint startaddr,uchar length,uchar *writedata); //写数据到RC500-EEPROMextern char M500PcdConfigRestore();//恢复RC500出厂设置//Mifarel卡命令字#define PICC_REQIDL 0x26 //寻天线区内未进入休眠状态的卡#define PICC_REQALL 0x52 //寻天线区内全部卡#define PICC_ANTICOLL1 0x93 //防冲撞#define PICC_AUTHENT1A 0x60 //验证A密钥#define PICC_AUTHENT1B 0x61 //验证B密钥#define PICC_READ 0x30 //读块#define PICC_WRITE 0xA0 //写块#define PICC_DECREMENT 0xC0 //减值#define PICC_INCREMENT 0xC1 //加值#define PICC_RESTORE 0xC2 //存储#define PICC_TRANSFER 0xB0 //传送#define PICC_HALT 0x50 //休眠void main (void){ int count;idata struct TranSciveBuffer{uchar MFCommand; uchar MFLength; uchar MFData[16];}MFComData;M500PcdReset() ; //初始化RC500M500PcdReadE2(startaddr, length, readdata); //读MF RC500的系列号并存贮它For (count = 0 ;count<100 ;count + + ){status = M500PcdRequest(req_code); //发送请求代码给卡,并等待应答if (status= =MI_OK)status= M500PcdAnticoll(serialno); //防冲撞if (status= =MI_OK)status= M500PcdSelect(serialno); //选择一个指定的卡if (status= =MI_OK)status = M500ChangeCodeKey(uncoded, coded); //转换密钥格式if (status= =MI_OK)status =M500PcdAuthKey(coded); //传送密钥if (status= =MI_OK)status = M500PcdAuth(auth_mode, block, serialno); //验证密钥,鉴定卡if (status= =MI_OK)status = M500PcdRead(addr, blockdata); //读卡for ( i=0;i<16;i + + )*(blockdata+i) = MFComData.MFData[i]; ;if (status==MI_OK)status= M500PcdWrite(addr, blockdata); //写卡}}。
基于MFRC500的RFID读写器方案发布: 2011-9-1 | 作者: —— | 来源:liaoziruo| 查看: 329次| 用户关注:0引言无线射频识别技术RFID(radiofrequencyidentifiestion)是20世纪90年代兴起的一种非接触的自动识别技术,利用其射频信号空间祸合的传输特性,可以实现对被识别物体的自动识别。
识别过程无须物理接触,无须光学可视,无须人工管理即可完成信息的录人和处理。
采用RFID技术,可以实现对运动目标、多目标的识别。
同时,电子标签可读写、能携带大量数据、保密性强,且具有不怕污渍、灰尘等较强的环境适应力。
正是由于这些其它识另一0 引言无线射频识别技术RF ID( r ad io frequency identifiestion) 是20世纪90年代兴起的一种非接触的自动识别技术,利用其射频信号空间祸合的传输特性,可以实现对被识别物体的自动识别。
识别过程无须物理接触,无须光学可视,无须人工管理即可完成信息的录人和处理。
采用RFID技术,可以实现对运动目标、多目标的识别。
同时,电子标签可读写、能携带大量数据、保密性强,且具有不怕污渍、灰尘等较强的环境适应力。
正是由于这些其它识另一方式无法比拟的优势,RFID技术在生产、物流、交通、运输、医疗、防伪等领域有着广泛的应用和巨大的发展前景。
在RFID系统中,射频读写器是识别标签后将采集信息送人后台信息处理系统的关键设备,对保证RFID系统的可靠工作具有重要作用。
本文将以Philips公司的MF RC500芯片为核心设计一种以AT-MEG A162MCU为控制器的RFID射频读写器。
它能完成对Mifare one卡所有读写及控制的操作,并且还可以方便地嵌人到其他系统(如门禁、收费)中,成为用户系统的一部分。
1 RFID 基本原理及系统组成RFID 系统一般由电子标签、读写器、后台计算机组成。
电子标签,又称为射频标签、应答器或数据载体;读写器又称为读头、通信器或读出装置(取决于电子标签是否可以无线改写数据)。
通讯格式:数据包长度L(1byte) 命令字C(1byte) 数据包D(L-1bytes)通讯方向:-> 下位机送给上位机<- 上位机送给下位机IC卡读写器所有命令一览表命令字功能(十六进制)01 终止卡02 寻卡,返回卡类型(2 bytes)+ 卡系列号(4 bytes)03 防冲突,防冲突读卡的系列号 MLastSelectedSnr04 选择卡05 校验卡密码(E2)(Key loading into the MF RC500's EEPROM )06 下载密码(E2)(Key loading into the MF RC500's EEPROM )07 直接校验密码(Authentication with direct key loading from the uC )08 读卡09 写卡0A 块值操作(加值、减值)0B 启动,测试蜂鸣器0C 参数设置0D 设置通讯波特率0F 选定新的扇区命令的具体说明1) 启动(其实就是测试蜂鸣器)<- 02 0B 0F (02为长度,0B为命令字,测试蜂鸣器,0F蜂鸣器响的时间)-> 01 00 (01为长度,00为测试成功)2) 寻卡<- 02 02 26 (02为命令字,26为RegMfOutSelect)-> 03 00 04 00 (00为命令成功代码,04表示Mifare One卡)<- 02 0B 0F-> 01 003) 防冲突<- 01 03 (03为命令字)-> 05 00 52 00 75 7A (52 00 75 7A为卡号CardSerialNo)<- 02 0B 0F-> 01 004) 选择<- 01 04 (04为命令字)-> 03 00 80 00<- 02 0B 0F-> 01 005) 终止<- 01 01 (01为命令字)-> 01 00<- 02 0B 0F-> 01 006) 参数设置<- 01 0C (0C为命令字)-> 01 007) 密码下载(扇区1密码为12个F)<- 09 06 60 01 FF FF FF FF FF FF (06为命令字,60为PICC_AUTHENT1A(61为PICC_AUTHENT1B),01为扇区号,12个F为密码)-> 01 00<- 02 0B 0F-> 01 008) 数据读(扇区1块0块1块2)<- 02 02 52 (02为命令字,52为PICC_REQALL)-> 03 00 04 00 (04为RegFIFOLength)<- 01 03 (03为命令字)-> 05 00 52 00 75 7A (52 00 75 7A为卡号)<- 01 04 (04为命令字)-> 03 00 08 00<- 04 05 60 01 04 (05为命令字,60为PICC_AUTHENT1A(61为PICC_AUTHENT1B),01为扇区1,04为RegFIFOLength)-> 01 00<- 02 08 04 (08为命令号,04为块号)-> 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (16个00为数据)<- 02 08 05 (08为命令号,05为块号)-> 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (16个00为数据)<- 02 08 06 (08为命令号,06为块号)-> 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (16个00为数据)<- 02 08 07 (08为命令号,07为块号)-> 11 00 00 00 00 00 00 00 ff 07 80 69 ff ff ff ff ff ff (第一个00为返回代码,后面6个00为密码A,ff 07 80 69为控制位,后面6个ff为密码B)<- 02 0B 0F-> 01 009) 数据写(扇区1块0块1块2)<- 12 09 04 12 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (09为命令字,04为块号,12开始的16个字节为要写的数据)-> 01 00<- 02 0B 0F-> 01 00<- 12 09 05 45 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (09为命令字,05为块号,45开始的16个字节为要写的数据)-> 01 00<- 02 0B 0F-> 01 00<- 12 09 06 78 90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (09为命令字,06为块号,78开始的16个字节为要写的数据)-> 01 00<- 02 0B 0F-> 01 00<- 12 09 07 11 11 11 11 11 11 ff 07 80 69 11 11 11 11 11 11 (09为命令字,07为块号,把密码A和密码B都修改成1)-> 01 00<- 02 0B 0F-> 01 0010) 块值操作(初始化)<- 12 09 04 11 11 11 11 EE EE EE EE 11 11 11 11 04 FB 04 FB (09为命令字,04为绝对块号,11开始的16个字节为要写的数据)-> 01 00<- 02 0B 0F-> 01 0011) 块值操作(读出)<- 02 08 04 (08为命令字,04为块号)-> 11 00 11 11 11 11 EE EE EE EE 11 11 11 11 04 FB 04 FB (11后面的16个自己是读出来的数据)<- 02 0B 0F-> 01 0012) 块值操作(加值)<- 08 0A C1 04 22 22 22 22 04 (0A为命令字,C1为PICC_INCREMENT,04为块号,4个字节的22是要加值的数据,04为块号)-> 01 00<- 02 0B 0F-> 01 0013) 块值操作(减值)<- 08 0A C0 04 11 11 11 11 04 (0A为命令字,C0为PICC_DECREMENT为块号,4个字节的11是要减值的数据,04为块号)-> 01 00<- 02 0B 0F-> 01 0014) 修改密码<- 02 02 26 (02为命令字,26为RegMfOutSelect)-> 03 00 04 00<- 01 03 (03为命令字)-> 05 00 52 00 75 7A (52 00 75 7A为卡号)<- 01 04 (04为命令字)-> 03 00 80 00<- 04 05 60 01 04 (05为命令字,60为PICC_AUTHENT1A(61为PICC_AUTHENT1B),01为扇区号,04为RegFIFOLength,04是由扇区号乘4得到的)-> 01 00<- 12 09 07 33 33 33 33 33 33 ff 07 80 69 33 33 33 33 33 33 (09为命令字,07为块号,33后面的12个字节为新密码)-> 01 00<- 02 0B 0F-> 01 0015) 测试蜂鸣器<- 02 0B XX (其中,02为命令的长度,表示在字节02后面还有两个字节的命令;0B为命令字,是自定义的读卡、写卡等命令;XX为蜂鸣器鸣叫的时间;整个命令的功能是让蜂鸣器连续鸣叫一定的时间,用于确定RC500模块是否已经进入正常工作状态。
程序采用标准C 语言编制,以PCW C Compiler IDE 编译器为开发环境,以下是部分程序源代码以及子函数说明。
该程序代码在PIC16F876 单片机上测试通过。
程序将RF 场适时的开启与关闭,大大降低了MCU 与RF 场的功耗,同时减少了在读卡过程中MF RC500 对MCU 的干扰。
unsigned char regread ( unsigned char reg adr ) :读取寄存器地址的值;void regwrite ( unsigned char reg adr , unsigned char reg value ) :向寄存器中写值;unsigned char Get PiccUid ( unsigned char uid[ ] ) :读取卡的卡号;void ReadMcuEeprom ( unsigned char volume[ ] , unsigned char eeprom adr , unsigned char num ) :读取MCU EEPROM 中eeprom adr 地址的前num 个数据,放入volume 数组中;void KeyEncryptArithmetic ( unsigned char key[ ] , unsigned char uid[ ] ) :加密算法;unsigned char LoadKey ( unsigned char uncoded[ ] , unsigned char coded[ ] ) :编码;void Picc authent ( unsigned char auth mode , unsigned char addr , unsigned char uid[ ] ) :认证操作; void ConfigurationCard ( unsigned char Config block ) :对配置卡的数据进行读值操作;void UserCard ( ) :对用户卡中的数据进行读写、加值、减值操作。
基于RC500的智能门禁控制系统研究来源:一卡通世界作者:袁万锦张革 2018-10-9 11:16:52 评论0 条摘要:介绍了基于RC500的智能门禁控制系统的设计与开发,门禁控制器主要由射频天线、读卡模块、单片机控制系统及RS485通信接口组成,由RS500接口与PC机组成通信网络系统,并给出了AT89C52与MF RC500的接口原理图,对读卡程序进行了说明,最后给出了主要程序设计的流程图。
关键词:射频识别;Mifare智能IC卡;门禁;MF RC500;RS485网络智能门禁系统是指采用现代电子与信息技术,在建筑物内外的出人口对人(或物>的进、出实施放行、拒绝、记录和报警等操作的一种电子自动化控制系统。
本系统的前端设备为基于MF RC500的Mifare非接触式IC卡读卡器,识读距离可达到1OCIB,具有抗恶劣环境、保密性强、准确性高、安全性高、识别号唯一无法伪造、可同时识别多个识别对象的优点。
本系统由若干台门禁控制器组成,由RS485网络相互连接,通过RS485/232转换器与计算机相连,并通过管理计算机对各门进行控制。
只有经过本系统授权的非接触式IC卡在被授权的有效时段内,控制器才向电控门锁发出开锁指令,允许持卡人进门。
无效卡或没有经过授权的卡,以及授权卡在非有效时段内,控制系统则不会向电控门锁发出开锁指令,不允许进门。
根据需要,管理者可以随时增加、修改或取消授权卡的通行时段。
每次读卡的信息,无论是否向电控门锁发出开锁指令,系统都自动记录下来,管理者通过调阅出入口的读卡记录,可以方便地查询持卡人进门的情况,通过管理计算机上的软件还可以提取出考勤信息,作为考勤机使用。
1 系统组成由图1可以看出,系统主要由AT89C52单片机为核心,辅以射频卡读卡模块、存储器、键盘、LCD显示器、实时时钟、I/O接口、RS485通信模块、看门狗外围电路而构成智能门禁控制器。
MCU(微控制器>采用AT89C52(其开发简单,运行稳定>;存储器采用AT24C512(用于存储系统参数及数据,AT24C512是基于I C总线的串口操作方式,是性价比较高的存储芯片>;液晶屏采用TC1602A;时钟芯片采用PHILIPS公司的PCF8563(也是基于I C总线的串口操作方式,可以很方便地记录时间>;键盘采用4×4矩阵键盘;防止系统死机采用MAX813L(作为看门狗>。
ZLG500A读卡模块使用指南版本1.412005年8月20日目 录§1 概述 (3)1.1 照片 (3)1.1.1 独立模块 (3)1.1.2 天线一体化模块 (3)1.2 特征 (4)1.3 电气特性 (4)§2 硬件描述 (5)2.1 引脚描述 (5)2.2 串行接口...............................................................................................................................6 §3 ZLG500三线三线串行读串行读串行读卡模块接口规范卡模块接口规范.. (7)3.1 接口原理 (7)3.2 时序图 (7)3.3 写数据MCU ZLG500 (8)§4 ZLG500读卡模块数据传输协议 (9)4.1 介绍 (9)4.2 协议 (9)4.2.1协议描述 (9)4.2.2 数据块格式 (9)4.3 ZLG500和MCU 命令C51函数(版本号1.4) (11)4.3.1 底层函数和高级函数 (11)4.3.2 状态值列表 (12)4.3.2版本说明 (13)4.4 函数描述 (13)4.4.1 请求Request (14)4.4.2 防碰撞Anticoll (15)4.4.3 选择Select (16)4.4.4 证实Authentication (17)4.4.5 暂停Halt (18)4.4.6 读Read (19)4.4.7 写Write (20)4.4.8 加Increment (21)4.4.9 减Decrement (22)4.4.10 恢复Restore (23)4.4.11 传送Transfer (24)4.4.12 装载密钥Load Key (25)4.4.13 复位Reset (26)4.4.14 获取信息Get Info (27)4.4.15 置位控制位Set Control Bit (28)4.4.16 清除控制位Clr Control Bit (29)4.4.17 配置Config (30)4.4.18检查写—Check Write (31)4.4.19输出蜂鸣器信号Buzzer (32)4.4.20读EEPROM (33)4.4.21写EEPROM (34)4.4.22关闭RC500—Close (35)4.4.23值操作 (36)4.4.24防碰撞2—Anticoll2 (37)4.4.25 证实2—Authentication2 (38)4.4.26 直接密码证实AuthKey (39)4.4.27多层防碰撞CascAnticoll (40)4.4.28多层选择Select (41)4.4.29写UltraLight—ULWrite (42)4.4.30带内部自动传送的值操作 (43)4.4.31写寄存器 (44)4.4.32读寄存器 (45)4.5 利用SPI_INIT()初始化SPI接口 (46)4.6 全局变量 (46)4.7 SPI看门狗定时器 (46)4.8 应用程序举例 (47)1 概述1.1 照片1.1.1独立模块需外加天线才可使用实际尺寸41.5mm25.3mm1.1.2天线一体化模块实际尺寸58mm×34.5mm1.2 特征!"四层电路板设计双面表贴EMC性能优良!"采用最新PHILIPS高集成ISO14443A读卡芯片MF RC500!"三线SPI接口能与任何MCU接口!"控制线输出口!"无源蜂鸣器信号输出口能用软件控制输出频率及持续时间!"能读写RC500内EEPROM!"发光二极管指示模块当前状态!"可提供C51函数库1.3 电气特性符号参数最小典型最大单位T STR环境或存储温度范围 -40 +150 O CO C+85+25T OP工作温度范围 -25V5.5V CC工作电压范围 4.55I CC1电流消耗config成功后75 MAI CC2电流消耗close成功后7 MA2 硬件描述2.1 引脚描述如照片所示J1为与天线的接口J2为与MCU的接口如下二表所示管脚符号描述J1-1 GND 地J1-2 TX1 天线发送1J1-3 GND 地J1-4 TX2 天线发送2J1-5 GND 地J1-6 RX 天线接收管脚符号类型描述J2-1 SCLK 输入三线SPI接口时钟线总是由外部MCU产生J2-2 SDA TA 双向数据线可双向传输J2-3 SS 双向传输启动线接MCU外部中断J2-4 VCC PWR 电源正端J2-5 RST 复位模块复位端若模块名后缀不带G如zlg500A T则高电平有效若模块名后缀带G如zlg500A TG则低电平有效或该端悬空J2-6 GND PWR 电源负端J2-7 CTRL 输出控制线输出J2-8 BZ 输出蜂鸣器信号输出2.2 串行接口ZLG500模块可方便地与任何MCU 进行接口如下图所示与MCS51单片机的典型接口三线分别为片选SS 时钟线SCLK 和数据线SDATA 主控制器的MCU 和读卡模块内的MCU 通过此三线相连三根线上的实际电平是双方口线状态逻辑线与的结果3 ZLG500三线三线串行读卡模块接口规范串行读卡模块接口规范3.1 接口原理接口空闲时主机SS=1SCLK=0SDATA=0从机SS=1SCLK=1SDATA=0其中SS和DATA是双向的而时钟线SCLK是单向的即时钟只能由主控制器产生该信号必须严格遵守时序规范否则将出现通信错误读卡模块必须释放该线SS 为数据发送使能若一方有数据要发送给另一方则该方控制SS线为低并在发送结束后将该线置高接收数据方不得控制该线双方必须遵守通信协议不得同时控制该线SDATA 为数据线由数据发送端控制数据接收端必须释放该线该线在一次传输开始时还同时作为数据接收端的响应信号以下几个概念必须搞清楚数据发送器在一次传输中控制SS信号和写数据的一方数据接收器在一次传输中响应SS信号和读数据的一方MCU 外部控制器在一次数据传输中可以是数据接收器或发送器但必须产生SCLK信号ZLG500本模块在一次数据传输中可以是数据接收器或发送器但必须接收SCLK信号3.2 时序图如图所示无论数据传输的方向如何SPI线上信号的波形总是如下由图中可以看出在SS为低的情况时钟和数据线上的信号才有效且在SCLK为低时SDATA变化在SCLK为高时SDATA应保持稳定以上传输中从数据发送器请求开始至数据接收器响应的时间是不确定的取决接收器内的MCU是否忙有必要设置一个看门狗定时器对数据接收器的响应进行监视一旦接收器响应则MCU必须根数据传输的方向严格控制以下几个时间以确保数据传输无误t1—数据接收器响应至MCU产生第一个SCLK上升沿的时间t2—两个字节传输之间SCLK低电平的持续时间t3—传输最后一个字节的最后一位的SCLK信号的上升沿至SS上升沿的时间tH—SCLK信号的高电平持续时间tL—SCLK信号的低电平持续时间在数据传输的不同方向时对时间t1— t3tH 和tL 都有各自不同的要求3.3 写数据MCU ZLG500除响应信号外三根线上的信号全由MCU 产生MCU 在SS 线上产生一个下降沿发出请求数据传输的信号等待ZLG500响应后本次数据传输开始ZLG500将在SCLK 为高时读取SDATA 线上的数据传输完毕后MCU 应在SS 线上产生一个上升沿结束本次传输见下表动作序号 动作发出者动作 动作接收者 动作说明1 MCU 置SDATA为输入SCLK=0SS= ZLG500 本次数据传输开始请求 2 ZLG500 SDATA = MCU 本次数据传输响应 3 MCU 置SDATA 为输出且输出串行数据 ZLG500 数据传输4 MCU SCLK=延时 ZLG500 MCU 产生时钟脉冲高电平时ZLG500读数据 5 MCU 重复动作34传送N 8位 ZLG500 数据传输N 字节 6 MCU SS=SDATA=0SCLK =0 ZLG500 本次数据传输结束传输过程中必须严格遵守以下时间要求 t1>7s t2>14s tH>7s tL>9s t3=任意3.4读数据MCU ZLG500响应信号SCLK 信号由MCU 产生SS 信号和SDATA 信号由ZLG500产生ZLG500会在SS 线上产生一个下降沿发出请求数据传输的信号等待MCU 响应后本次数据传输开始MCU 将在SCLK 为高时读取SDATA 线上的数据传输完毕后ZLG500将会在SS 线上产生一个上升沿结束本次传输见下表动作序号 动作发出者动作动作接收者 动作说明1 ZLG500 SDATA =1SS= MCU 本次数据传输开始请求2 MCU 置SDATA 为输入 ZLG500 本次数据传输响应3 ZLG500 SDATA =串行数据 MCU 数据传输4 MCU SCLK=延时 ZLG500 MCU 产生时钟且读取数据 5 双方 重复动作34传送N 8位 双方 数据传输N 字节 6 ZLG500 SS =SDATA =0 MCU 本次数据传输结束传输过程中必须严格遵守以下时间要求t1>14s t2>16s tH>6s tL>6s t3>9s4 ZLG500读卡模块数据传输协议4.1 介绍本文档描述了MIFARE串行读卡模块ZLG500与主机微处理器之间的串行通信软件的通信协议和命令ZLG500是一个简单的串行读写模块它可以读写MIFARE无线智能卡在这个器件中包括了一个PCB天线提供了一个三线通信接口CMOS电平SPI可受控于主机微处理器4.2 协议4.2.1协议描述通信必须先由MCU发送命令和数据给ZLG500ZLG500执行命令完毕后将命令执行的状态和响应数据发回MCU开始通信前收发双方必须处于空闲状态ZLG500的RST有两种接法一是接硬件复位电路如阻容复位等这样系统上电后必须要等待ZLG500复位结束二是接外部MCU的一个I/O口由MCU控制复位推荐使用第二种方法这样在ZLG500出现异常时可由MCU控制复位首先MCU发出SS下降沿信号然后等待ZLG500在SDATA线上的响应若在50ms内未检测到此响应则退出本次传输将错误代码返回给主程序由主程序进行错误处理若ZLG500正确响应则MCU可将命令和数据发送出去然后MCU等待ZLG500发回的状态和响应数据也即等待SS线上的下降沿的产生此时的MCU可用软件查询也可用外部中断若在500ms内未检测到此信号则退出本次传输且向主程序报告错误代码若正确检测到SS信号则可接收状态和数据4.2.2 数据块格式4.2.2.1 MCU ZLG500命令模式SeqNr Command Len Data[0N] BCC INFO[0] . . . . . . INFO[n]SeqNr 1 Byte 数据交换包的序号Command 1 Byte 命令字符Len 1 Byte 数据的长度Data[]Len Byte 数据字节BCC1Byte的BCC校验4.2.2.2 ZLG500MCU响应模式SeqNr status Len Data[0N] BCC INFO[0] . . . . . . INFO[n]SeqNr 1 Byte 数据交换包的序号status 1 Byte 状态字符Len 1 Byte 数据的长度Data[]Len Byte 数据字节BCC1Byte的BCC校验4.2.2.3 数据块格式描述!"每个字节命令或数据传输时高位在先!"数据交换包的序号由MCU发送数据块时产生在经过一次正确的数据交换后主机在发送下一个命令时将数据包的序号加1ZLG500返回最近接收的包序号通常主机应用程序最好检查命令/响应包交换时的数据包的序号!"不管在执行命令时出现了任何错误响应包中的数据长度为0Len = 0!"BCC校验码计算数据块中所有的INFO字节然后将结果传送到数据块的最后一个字节如下式所示INFO[n] = BCC = ~INFO[0] ⊕ INFO[1] ⊕ ... ⊕ INFO[n-1](⊕ ... XOR~…NOT)4.3 ZLG500和MCU 命令C51函数(版本号1.4) 4.3.1 底层函数和高级函数命令 参数名称数值发送接收说明Request 0x41 _Mode _TagType 发出询问命令检查在有效范围内是否有卡存在Anticoll 0x42 _Bcnt _SNR 开始防冲突操作返回卡的序号Anticoll2 0x71 _Encoll,_Bcnt _SNR 可禁止或允许多张卡进入 CascAnticoll* 0x74 _Bcnt,_Select_Code _SNR 可实现三层防碰撞协议 Select 0x43 _SNR _Size 选择卡返回卡的存贮容量 CascSelect* 0x75_Select_Code, _SNR _Sak可实现三层选择Authentication 0x44 _Mode,_SecNr -- 开始验证操作 Authentication2 0x72 _Mode,_SecNr,_KeyNr 可选择密匙区验证 AuthKey 0x73 _Mode,_SecNr,_Key(6) -- 直接密码验证 Halt 0x45 -- -- 将卡置于挂起模式 Read 0x46 _Adr _Data 从卡中相应地址中读出一个16字节的块Write 0x47 _Adr,_Data -- 向卡中相应地址写入一16字节的数据块ULWrite* 0x76_Adr,_Data -- 向mifare UltraLight 卡中相应地址页写入4字节数据 Increment 0x48 _Adr,_Value -- 增加访问单元块的字节数并将结果保存在卡的内部寄存器Decrement 0x49 _Adr,_Value -- 减少访问单元块的字节数并将结果保存在卡的内部寄存器 Resore 0x4A _Adr -- 将所访问单元块的字节数保存在卡的内部寄存器中 Transfer 0x4B_Adr --将卡内部寄存器的内容转输到访问快的字节数Value 0x70_Mode,_Adr,_Value,_Trans_Adr 包含加减恢复函数并带自动传送ValueDebit* 0x77_Mode,_Adr,_Value -- 带内部自动传送的值操作支持Mifare Light LoadKey 0x4C _Mode,_SecNr,,_Nkey -- 改变存贮在EEPROM 中的密钥Reset 0x4E _Msec -- 关闭天线输出数ms 使卡复位 Get Info 0x4F -- _Info 读取固件信息RC500序列号 Set Control Bit0x50----将控制位置为高电平Clr Control Bit 0x51 -- -- 将控制位置为低电平 Config 0x52 -- -- 复位且配置RC500Write_Reg 0x3D_Reg,_Value写RC500内寄存器Read_Reg 0x3E _Reg *_Value 读RC500内寄存器Close 0x3F -- -- 关闭RC500 Check Write0x53_SNR,_Authmode,_Adr,_Data--将所传送的数据和上一次所写的数据进行比较Buzzer 0x60 _Freguence,_10ms -- 输出驱动无源蜂鸣器信号 Read E2 0x61 _Adr,_Length _Data 读RC500内EEPROM 的内容 Write E20x62_Adr,_Length,_Data-- 写数据到RC500内EEPROM Init_spi初始化spi 接口不与ZLG500通信4.3.2 状态值列表名称值 描述MI_OK, SPI_OK函数调用成功MI_NOTAGERR 1 在有效区域内没有卡MI_CRCERR 2 从卡中接收到了错误的CRC 校验和 MI_EMPTY 3 值溢出 MI_AUTHERR 4 不能验证MI_PARITYERR 5 从卡中接收到了错误的校验位 MI_CODEERR 6 通信错误MI_SENDRERR 8 在防冲突时读到了错误的串行码 MI_NOTAUTHERR 10 卡没有验证MI_BITCOUNTERR 11 从卡中接收到了错误数量的位 MI_BYTECOUNTERR 12 从卡中接收了错误数量的字节 MI_TRANSERR 14 调用Transfer 函数出错 MI_WRITEERR 15 调用Write 函数出错 MI_INCRERR 16 调用Increment 函数出错 MI_DECRERR 17 调用Decrment 函数出错 MI_READERR 18 调用Read 函数出错 MI_COLLERR 24 冲突错MI_QUIT 30 上一次了送命令时被打断 MIS_CHK_OK 0 Check Write 正确 MIS_CHK_FAILED 1 Check Write 出错 MIS_CHK_COMPERR 2 Check Write:写出错比较出错SPI_ERR 255 串行通信错误4.3.2版本说明一版本1.1对应于1.0增加了两个函数!"防碰撞Anticoll2可允许或禁止多张卡同时进入开线区!"证实Authentication2可选择不同的密匙区对一个扇区进行密码验证二版本1.2对应于1.1增加了一个函数!"直接密码证实AuthKey证实时6字节密码直接由主控制器MCU传入模块三版本1.3对应于1.2增加了四个函数!"多层防碰撞CascAnticoll支持多字节序列号!"多层选择CascSelect支持多字节序列号!"UL写函数ULWrite支持Mifare Ultralight四字节写!"自动传送值操作ValueDebit支持Mifare Light和pro四版本1.4相对于1.3增加了二个函数2004年8月10日升级!"写寄存器Write_Reg可直接控制RC500内的寄存器!"读寄存器Read_Reg可读出RC500内的寄存器4.4 函数描述下面是C51函数声明包含在头文件ZLG500.h中写应用程序时将其包含在应用函数中即可4.4.1 请求Request声明uchar mifs_request(uchar _Mode,uchar idata *_TagType);MCU ⇒ZLG500命令符0x41 长度 1Data[0]:_ModeZLG500 ⇒ MCU状态值MI_OK MI_NOTAGERRMI_BITCOUNTERR SPI_ERR长度2Data[0]: tagtype (低字节)Data[1]: tagtype (高字节)参数 _ModeALL=0请求天线范围内IDLE 状态的卡HALT 状态的除外ALL =1请求天线范围内的所有卡_tagtype 当发生错误时不返回任何内容Len=0描述此函数发送Request 命令检查在有效范围内是否有卡存在这个函数在选择一个新的卡是必须调用的ALL4.4.2防碰撞Anticoll声明uchar mifs_anticoll(uchar _Bcnt,uchar idata *_SNR);MCU ⇒ ZLG500命令符0x42长度 1Data[0]_BcntZLG500⇒ MCU状态值MI_OK MI_NOTAGERR MI_BITCOUNTERR SPI_RERR长度 4Data[0]snr(LL)Data[1]snr(LH)Data[2]snr(HL)Data[3]snr(HH)参数_Bcnt为预选卡所分配的位的个数通常Bcnt=0_SNR卡的序列号存贮在一个无符号的四字节数组中低字节放在地址处描述此函数开始防冲突操作必须在调用了Request命令后立即调用当知道了所要选择卡的序列号后就没有必要调用AntiColl此时调用了Request后直接调用Select函数即可4.4.3选择Select声明uchar mifs_select(uchar idata *_SNR,uchar idata *_Size);MCU ⇒ ZLG500命令符0x43长度 4Data[0]snr(LL)Data[1]snr(LH)Data[2]snr(HL)Data[3]snr(HH)ZLG500⇒ MCU状态值 MI_OK MI_QUIT MI_NOTAGERR MI_CRCERR MI_PAROTUERRMI_BITCOUNTERR SPI_ERR长度 1Data[0]_Size参数_SNR卡的序号存贮在一个无符号4字节字符数组中低字节放在代地址处_Size当Select命令返回值为MI_OK时A TS (answer to select)将返回主机描述这个函数选择某一个序列号的卡返回A TS字节给主机4.4.4 证实Authentication声明uchar mifs_authentication(uchar _Mode,uchar _SecNr);MCU ⇒ZLG500命令符 0x44 长度 2Data[0] _ModeData[1]_SecNrZLG500 ⇒ MCU状态值MI_OKMI_QUITMI_NOTAGERRMI_PAROTUERRMI_BITCOUNTERRSPI_ERR长度参数 _ModeAB = 0 利用密钥A 进行验证AB = 1利用密钥B 进行验证_SecNr所访问卡的扇区号描述 在对卡进行读写加减等操作前必须对卡进行验证若卡中的密钥与RC500中存储的密码相匹配则证实成功函数将返回MI_OKAB4.44.5暂停Halt4.声明uchar mifs_halt(void);MCU ⇒ ZLG500命令符0x45长度0ZLG500⇒ MCU状态值 MI_OK MI_QUIT MI_CODE SPI_ERR长度0参数无描述此函数将所选择卡置为挂起状态如果要进行重新选择则应用ALL模式调用Request命令或将卡复位如将卡离开天线操作区再进入或执行复位函数mifs_reset();4.4.6读Read描述uchar mifs_read(uchar _Adr,uchar idata *_Data);MCU ⇒ ZLG500命令符0x46长度 1Data[0]_AdrZLG500⇒ MCU状态值 MI_OK MI_QUIT MI_NOTAGERR MI_CRCERR MI_NOTAUTHERRMI_PAROTUERR MI_BITCOUNTERR SPI_ERR长度 16Data[0]所访问块的第一个字节Data[15]所访问块的最后一个字节参数_Adr所读数据地址描述此函数在所选的卡通过验证后读取一个16字节的块4.4.7写Write描述uchar mifs_write(uchar _Adr, uchar idata *_Data);MCU ⇒ ZLG500命令符0x47长度17Data[0]addressData[1]所访问块的第一个字节Data[16]所访问块的最后一个字节ZLG500⇒ MCU状态值 MI_OK MI_QUIT MI_NOTAGERR MI_NOTAUTHERR MI_WRITEERRMI_BITCOUNTERR SPI_ERR长度 0参数_Adr所写数据块地址063_Data16字节数据指针描述此函数在所选的卡通过验证后写入一个16字节的块4.4.8加Increment声明uchar mifs_increment(uchar _Adr,ulong idata *_Value);MCU ⇒ ZLG500命令符0x48长度 5Data[0]_AdrData[1]_Value(LL)Data[2]_Value(LH)Data[3]_Value(HL)Data[4]_Value(HH)ZLG500⇒ MCU状态值 MI_OK MI_QUIT MI_NOTAGERR MI_NOTAUTHERR MI_INCRERRMI_BITCOUNTERR SPI_ERR MI_INCRERR长度0参数_Adr所加数据块的地址_Value增加值贮在一个无符号的长整型变量4Byte中低地址存放高字节描述该函数读被访问的值块检查数据的结构用传输的值减值块的值并将结果贮存在卡的内部寄存器中值块有标准的格式不能自动进行对卡中EEPROM的写操作4.44.9减Decrement4.声明uchar mifs_decrement(uchar _Adr,ulong idata *_Value);MCU ⇒ ZLG500命令符0x49长度 5Data[0]_AdrData[1]_Value(LL)Data[2]_Value(LH)Data[3]_Value(HL)Data[4]_Value(HH)MSR⇒ 主机状态值 MI_OK MI_QUIT MI_NOTAGERR MI_NOTAUTHERR MI_DECRERRMI_BITCOUNTERR SPI_ERR长度0参数_Adr所减数据块的地址_Value减少值贮在一个无符号的长整型变量4Byte中低地址存放高字节描述该函数读被访问的值块检查数据的结构用传输的值减值块的值并将结果贮存在卡的内部寄存器中值块有标准的格式不能自动进行对卡中EEPROM的写操作4.4.44.1.100 恢复Restore 声明uchar mifs_restore(uchar _Adr);MCU ⇒Z LG500命令符0x4A长度1 Data[0] _AdrZLG500⇒M CU 状态值MI_OK, MI_QUIT, MI_NOTAGERR, MI_NOTAUTHERR, MI_DECRERR, MI_BITCOUNTERR, SPI_ERR, MIS_EMPTY长度 0 参数 _Adr所读块的地址描述该函数读被访问的值块且检查数据的结构并将结果贮存在卡的内部寄存器中不能自动进行对卡中EEPROM 的写操作4.4.44.1.111 传送Transfer 声明uchar mifs_transfer(uchar _Adr);MCU ⇒Z LG500命令符0x4B长度1 Data[0] _AdrZLG500⇒ MCU 状态值MI_OK, MI_QUIT, MI_NOTAGERR, MI_CODE, MI_BITCOUNTERR, MI_TRANSERR,MI_CODEERR, SPI_RERR长度 0 参数 _Adr卡中欲传输的块地址描述此函数将卡的内部寄存器内容转送给所选块地址在此操作前必须通过验证这个函数只能在Increment,Decrement,或Restore 操作后4.4.44.1.122 装载密钥Load Key 声明uchar mifs_load_key(uchar _Mode,uchar _SecNr,uchar *_Nkey);MCU ⇒ZLG500命令符0x4C长度 8Data[0] _ModeData[1] _SecNrData[2] _Nkey[0]: :Data[7]_Nkey[5]MSR ⇒主机 状态值 MI_OK MI_QUIT MI_AUTHERR SPI_ERR长度 0 参数 _ModeAB = 0 利用密钥A 进行验证AB = 1 利用密钥B 进行验证_SecNr: 密钥扇区号_Nkey: 6字节密钥首址描述这个函数将一个新的密钥写入到RC500的只写EEPROM 存贮器中AB4.4.44.1.133 复位Reset 声明uchar mifs_reset(uchar _Msec);MCU ⇒Z LG500命令符0x4E长度1 Data[0] _MsecZLG500⇒M CU 状态值 MI_OK MI_QUIT SPI_ERR长度 0 参数 _Msec射频电路关闭时间以毫秒为单位 描述该函数使射频电路关闭所规定的时间若_Msec=0射频电路部分将一直处于关闭状态一直到下一个Request 命令到来关闭射频能使天线内的所有卡复位举例_Msec = 0⇒ 射频电路关闭_Msec = 0x01⇒ 1 ms 射频电路关闭1ms _Msec= 0xFF⇒ 255 ms射频电路关闭255ms4.4.44.1.144 获取信息Get Info 声明uchar mifs_get_info(uchar idata *_Info);MCU ⇒Z LG500命令符 0x4F长度 0ZLG500⇒M CU 状态值 MI_OK MI_QUIT SPI_ERR 长度10 Data[0]产品类型标识0: : Data[4]产品类型标识4Data[5]RC500序列号0: : Data[8]RC500序列号3Data[9]软件版本号参数 _Info_Info[0]—_Info[4]为RC500的产品类型标识依次为0x30,0x88,0xf8,0x00,0xXX _Info[5]—_Info[8]为RC500的序列号 描述此函数返回一个包含有RC500的产品类型标识序列号和软件版本信息的数组4.4.44.1.155 置位控制位Set Control Bit 声明uchar mifs_set_control_bit();MCU ⇒Z LG500命令符 0x50长度 0ZLG500⇒M CU 状态值 MI_OK MI_QUIT SPI_ERR长度 0 描述此函数设置MIFARE 读卡器中的控制位为高电平4.4.44.1.166 清除控制位Clr Control Bit 声明uchar mifs_clr_control_bit();MCU ⇒Z LG500命令符 0x51长度 0ZLG500⇒M CU 状态值 MI_OK MI_QUIT SPI_ERR长度 0 描述此函数清除MIFARE 读卡器中的控制位4.44.17配置Config4.声明mifs_config(void);ucharMCU ⇒Z LG500命令符0x52长度0ZLG500⇒M CU状态值 MI_OK MI_QUIT SPI_ERR长度0参数说明模块每次上电复位之后都必须首先调用此函数对模块进行初始化才能进行进一步的操作4.4.18检查写Check Write声明uchar mifs_check_write(uchar idata *_SNR, uchar _Authmode, uchar _Adr, uchar idata *_Data);MCU ⇒Z LG500命令符0x53长度22Data[0]_SNR(LL)Data[1]_SNR(LH)Data[2]_SNR(HL)Data[3]_SNR(HH)Data[4]_AuthmodeData[5]_AdrData[6]块的第一个字节::Data[21]块的最后一个字节ZLG500⇒M CU状态值 MI_QUIT MIS_CHK_OK MIS_CHK_FAILED MIS_CHK_COMPERR SPI_ERR 长度0参数_SNR所要检查的卡的序号_Authmode上一次写命令时的验证模式_Adr所要检查的数据块的地址_Data所检查的数据描述此函数在数据写入卡的数据进行检查将重新进行Request/Select/Authenticated操作此函数进行将所给出的数据与相应地址的数据进行比较如果正确则返回MIS_CHK_OK信息如果两者间数据不相符则返回MIS_CHK_COMPERR信息发生其它任何错误时返回MIS_CHK_FAILED信息4.44.19输出蜂鸣器信号Buzzer4.声明mifs_buzzer(uchar _Frquence, uchar _10ms);MCU ⇒Z LG500命令符0x60长度 2Data[0]_FrequenceData[1]: _10msZLG500⇒M CU状态值 MI_OK SPI_ERR长度0参数_Frequence: 输出方波频率取值0255对应频率0.73—4K取值198对应2K_10ms: 方波输出持续时间取值025510ms的分辨率描述此函数输出一方波可驱动无源蜂鸣器频率和持续时间可调4.4.44.2.200 读EEPROM声明uchar mifs_read_E2(uchar _Adr,uchar _Length,uchar idata *_Data);MCU ⇒Z LG500命令符0x61长度2 Data[0]_AdrData[1]_LengthZLG500⇒M CU 状态值 MI_OK MI_QUIT MI_CRCERR MI_BITCOUNTERR SPI_ERR 长度_LengthData[0] byte… Data[_Length]byte参数 _Adr被读RC500内EEPROM 首址必须小于0x80_Length被读数据长度_Data读出数据缓冲区首址 描述此函数将RC500内EEPROM 的数据读出4.4.44.2.211 写EEPROM声明uchar mifs_write_E2(uchar _Adr,uchar _Length,uchar idata *_Data);MCU ⇒Z LG500命令符0x62长度_Length+2 Data[0]_AdrData[1]_LengthData[2]_Data[0]… Data[_Length+1]_Data[_Length-1]ZLG500⇒M CU 状态值 MI_OK MI_QUIT MI_CRCERR MI_BITCOUNTERR SPI_ERR长度 0参数 _Adr RC500内EEPROM 的写入首址取值范围0x300x7F_Length被写数据长度_Data写入数据缓冲区首址 描述此函数将数据写入RC500内EEPROM 中RC500内EEPROM 的0x00—0x0F 为只读产品信息区0x10—0x2F 为启动寄存器初始化文件区最好不要改写0x80—0x1FF 为只读密钥区可用LoadKey 写入4.4.44.2.222 关闭RC500Close 声明uchar mifs_close(void);MCU ⇒Z LG500命令符 0x3F长度 0ZLG500⇒M CU 状态值 MI_OK SPI_ERR长度 0参数描述此函数将RC500的复位管脚置为高电平关闭RC500使之电流最小若要重新启动则需调用Config()4.4.44.2.233 值操作声明uchar mifs_value(uchar _Mode, uchar _Adr, ulong idata *_Value, uchar _Trans _Adr);MCU ⇒Z LG500命令符0x70长度7 Data[0]_ModeData[1]_AdrData[2]_Value(LL)Data[3]_Value(LH)Data[4]_Value(HL)Data[5]_Value(HH)Data[6]_Trans_AdrZLG500⇒M CU 状态值MI_OK, MI_QUIT, MI_NOTAGERR, MI_CODE, MI_BITCOUNTERR, MI_TRANSERR, MI_CODEERR, SPI_RERR长度 0 参数_Mode: 0xC0—减0xC1—加0xC2恢复 _Adr 卡内块地址对该块进行值操作取值范围063_Value 当进行加或减操作时为加数或减数当进行恢复操作时该值为空值 _Trans_Adr传输块地址取值范围063描述此函数对卡内的某一块进行加减或数据备份该块必须为值块格式并支持自动传送4.4.24防碰撞2Anticoll2声明uchar mifs_anticoll2(uchar _Encoll, uchar _Bcnt,uchar idata *_SNR);MCU ⇒ ZLG500命令符0x71长度 2Data[0]_EncollData[1]_BcntZLG500⇒ MCU状态值MI_OK MI_NOTAGERR MI_BITCOUNTERR MI_COLLERR SPI_RERR长度 4Data[0]snr(LL)Data[1]snr(LH)Data[2]snr(HL)Data[3]snr(HH)参数_Encoll: 若为1则使能多张卡进入天线区若为0则不多张卡进入此时返回错误MI_COLLERR._Bcnt为预选卡所分配的位的个数通常Bcnt=0_SNR卡的序列号存贮在一个无符号的四字节数组中低字节放在地址处描述此函数开始防冲突操作必须在调用了Request命令后立即调用当知道了所要选择卡的序列号后就没有必要调用AntiColl此时调用了Request后直接调用Select函数即可4.4.25 证实2Authentication2 声明uchar mifs_authentication2(uchar _Mode, uchar _SecNr, uchar _KeyNr);MCU ⇒ZLG500命令符0x72 长度3Data[0]_ModeData[1]_SecNrData[2]_KeyNrZLG500 ⇒ MCU状态值MI_OKMI_QUITMI_NOTAGERRMI_PAROTUERRMI_BITCOUNTERR SPI_ERR长度 0 参数 _ModeAB = 0 利用密钥A 进行验证AB = 1 利用密钥B 进行验证_SecNr所访问卡的扇区号_KeyNr用于证实的密匙区号 描述在对卡进行读写加减等操作前必须对卡进行验证若卡中的密钥与RC500中所选择的密码相匹配则证实成功函数将返回MI_OKAB4.4.26 直接密码证实AuthKey 声明uchar mifs_authentication2(uchar _Mode, uchar _SecNr, uchar *_Key);主机 ⇒ 读卡器命令符0x73 长度8Data[0]_ModeData[1]_SecNrData[2]_Key[0] …Data[7]_Key[5]读卡器 ⇒ 主机状态值MI_OKMI_QUITMI_NOTAGERRMI_PAROTUERRMI_BITCOUNTERR COMM_ERR长度 0 参数 _ModeAB = 0 利用密钥A 进行验证AB = 1 利用密钥B 进行验证_SecNr所访问卡的扇区号 _Key用于证实的密码首址描述在对卡进行读写加减等操作前必须对卡进行验证若卡中的密钥与所传输的密码相匹配则证实成功函数将返回MI_OKAB4.4.27多层防碰撞CascAnticoll声明uchar mifs_Cascanticoll(uchar _Select_Code,uchar _Bcnt,uchar *_SNR);主机⇒ 读卡器命令符0x74长度 2Data[0]_Select_CodeData[1]_Bcnt读卡器⇒ 主机状态值MI_OK MI_QUIT MI_NOTAGERR MI_BITCOUNTERR COMM_ERR长度 4Data[0]snr(LL)Data[1]snr(LH)Data[2]snr(HL)Data[3]snr(HH)参数_Select_Code防碰撞层级编码一层0x93二层0x95三层0x97_Bcnt为预选卡所分配的位的个数通常Bcnt=0_SNR卡的序列号存贮在一个无符号的四字节数组中低字节放在地址处描述此函数开始防冲突操作必须在调用了Request命令后立即调用当知道了所要选择卡的序列号后就没有必要调用AntiColl此时调用了Request后直接调用Select函数即可4.4.28多层选择Select声明uchar mifs_CascSelect(uchar _Select_Code, uchar *_SNR,uchar *_Sak);主机⇒ 读卡器命令符0x75长度 5Data[0]_Select_CodeData[1]snr(LL)Data[2]snr(LH)Data[3]snr(HL)Data[4]snr(HH)读卡器⇒ 主机状态值MI_OK, MI_QUIT, MI_NOTAGERR, MI_CRCERR, MI_PARITYERR,MI_BITCOUNTERR,COMM_ERR长度 1Data[0]_Sak参数_Select_Code防碰撞层级编码一层0x93二层0x95三层0x97_SNR卡的序号存贮在一个无符号4字节字符数组中低字节放在代地址处_Sak当Select命令返回值为MI_OK时Sak将返回主机若_Sak.2为1则表示还有序列号的一部分未读出应进行下一层的选择否则选择结束描述这个函数选择某一个序列号的卡返回A TS字节给主机4.4..4.229写UltraLight ULWrite描述uchar mifs_ULWrite(uchar _Adr, uchar *_Data);主机⇒ 读卡器命令符0x76长度 5Data[0]页地址Data[1]所访问块的第一个字节Data[4]所访问块的最后一个字节读卡器⇒ 主机状态值 MI_OK MI_QUIT MI_NOTAGERR MI_NOTAUTHERR MI_WRITEERRMI_BITCOUNTERR COMM_ERR长度 0参数_Adr所写数据块地址015_Data4字节数据指针描述写入一个4字节的数据4.44.30带内部自动传送的值操作4.声明uchar mifs_ValueDebit(uchar _Mode, uchar _Adr, ulong *_Value);主机⇒读卡器命令符0x77长度 6Data[0]_ModeData[1]_AdrData[2]_Value(LL)Data[3]_Value(LH)Data[4]_Value(HL)Data[5]_Value(HH)读卡器⇒主机状态值MI_OK, MI_QUIT, MI_NOTAGERR, MI_CODE, MI_BITCOUNTERR, MI_TRANSERR, MI_CODEERR, COMM_RERR长度 0参数_Mode: 0xC0—减Mifare Light只支持减0xC1—加0xC2恢复_Adr卡内块地址对该块进行值操作取值范围063_Value当进行加或减操作时为加数或减数当进行恢复操作时该值为空值描述此函数对卡内的某一块进行加减或数据备份该块必须为值块格式并支持内部自动传送支持Mifare Light4.4.31写寄存器声明uchar mifs_write_reg(uchar _Reg,uchar _Value);主机⇒读卡器命令符0x3d长度 2Data[0]_RegData[1]_Value读卡器⇒主机状态值MI_OK , COMM_RERR长度 0参数_Reg寄存器地址_Value寄存器值描述此函数可对RC500内的寄存器直接进行控制在某些应用中是比较方便的例如1向地址0x11写入值0x59或0x5a可关闭一个发送管脚从而节省功耗2向地址0x12写入0x01至0x3f之间的一个值可以控制天线发送管脚的电导率值越大电导率越高功耗越大读卡距离越远反之功耗越低读卡距离越近4.4.32读寄存器声明uchar mifs_read_reg(uchar _Reg,uchar *_Value);主机⇒读卡器命令符0x3e长度 1Data[0]_Reg读卡器⇒主机状态值MI_OK , COMM_RERR长度 1Data[0]寄存器值参数_Reg寄存器地址*_Value寄存器值地址描述此函数可读RC500内的寄存器的值4.5 利用spi_init()初始化SPI接口声明spi_ini (void);void描述此函数将SPI接口初始化成空闲状态接SS线的外部中断1为下降沿触发且将定时器1配置成SPI接口的看门狗定时器4.6 全局变量在ZLG500.C中使用了二个全局变量一是通信数据缓冲区spi_buffer[26]所有的要通过SPI接口发送和接收的数据都放在这里包括序号命令/状态长度和BCC等为了方便地访问这些变量定义了如索引常量#defineSEQNR#define COMMAND 11STA TUS#define#define LENGTH 23MODE#defineBCNT3#defineADR 3#define3#defineSERNRSIZE 3#defineTIME 3#define#define TAGTYPE 3INFO 3#define#define4SECNR#define DA TABYTES 4V ALUE4#defineNKEY5#define#define AUTHMODE 7#define ADRCHKWR 8#define DA TACHKWR 9二是标志位newdata当外部中断1中断接收到新数据时该位置位4.7 SPI看门狗定时器定时器0或1作为SPI接口看门狗定时器该定时器被设置成50ms溢出发送时开定时器中断若中断之前通信未能完成ZLG500在SDA TA线上未返回响应信号而造成该定时器产生中断则取消本次传输发送子程序返回SPI_ERR接收时关中断用软件判断溢出次数若在500ms内未收到ZLG500返回的数据SS线上未产生下降沿则退出本次命令的执行命令返回SPI_ERR广州周立功单片机发展有限公司 Tel: (020)38730976 38730977 Fax: 38730925 4.8 应用程序举例例子读出RC500和MIFARE 卡的序列号然后选择一个卡将该卡的20块初始化成值块且备份到21块中最后使该卡进入HALT 状态且驱动2KHz 蜂鸣器响200毫秒 将ZLG500.c mface_3.asm 及主程序文件main.c 放于同一项目中然后在主程序中输入以下代码#include "zlg500.h" #include “string.h” sbit zlg500_RST=P1^2; //假若ZLG500的复位接到MCU 的P1.2口uchar idata card_snr[4]; uchar idata RC500_snr[4];uchar code Nkey_a[6] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5}; uchar code Nkey_b[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; main() { uchar idata tt[2]; uchar idata size; uchar idata bankdata[16]; ulong idata value=1; uchar i,j;zlg500_RST =1; //使ZLG500复位 for(i =255;i>0;i--) for(j =255;j>0;j--); zlg500_RST =0; for(i =255;i>0;i--)for(j =255;j>0;j--); spi_init(); EA =1;i =mifs_config(); //ZLG500配置 i =mifs_get_info(bankdata); //读信息memcpy(RC500_snr,&bankdata[8],4); //存RC500序列号 mifs_load_key(KEYA,5,Nkey_b); //装载密钥 while(1) {while(mifs_request(IDLE,tt)!=0); //请求 if(mifs_anticoll(0,card_snr)!=0) continue; //防碰撞 if(mifs_select(card_snr,&size)!=0) continue; //选择 if(mifs_authentication(KEYA,5)!=0) continue; //证实 bankdata[0]=0x10; bankdata[4]=~0x10;广州周立功单片机发展有限公司 Tel: (020)38730976 38730977 Fax: 38730925 bankdata[8]=0x10;for(i=1;i<4;i++){bankdata[i]=0x00;bankdata[4+i]=0xff;bankdata[8+i]=0x00;}bankdata[12]=0x14;bankdata[13]=~0x14;bankdata[14]=0x14;bankdata[15]=~0x14;if(mifs_write(20,bankdata)!=0) continue;//写一个值块if(mifs_check_write(card_snr,KEYA,20,bankdata)!=0) continue;//检查写if(mifs_restore(20)!=0) continue;//恢复20块的数据if(mifs_transfer(21)!=0) continue;//传送到21块if(mifs_read(21,bankdata)!=0) continue;//读出mifs_halt(); //使卡进入HALT状态mifs_buzzer(198,20);//蜂鸣器口输出2KHz 方波持续200毫秒 }}。
#include "MyDefine.c"#include "MfErrNo.h"#include "MfRc500R.h"#include "MfRcuC.h"#include "ExternVariableDef.c"#define D_dataextern void Delay_10us(uchar );//unsigned char idata MLastSelectedSnr[5] ;unsigned char idata MRcvBuffer[16] ;unsigned char idata MSndBuffer[18];static MfCmdInfo idata MInfo ;extern void Delay_ms(unsigned int);bit haveset;/****************************************************************************** ********\*名称:s_data **功能:发送1字节HEX **参数:******************************************************************************** ********/unsigned char Mf500PcdConfig(void){unsigned char D_data status = MI_RESETERR;unsigned int D_data ii=5000;unsigned char D_data st_data;do{RST_RC500=1; // reset RC500Delay_10us(200); // waitRST_RC500=0; // clear reset pinDelay_10us(200); // waitst_data=ReadRC(RegPage);if (st_data==0x80) break;}while(--ii);ii=5000;do{WriteRC(RegPage,0x00); // Dummy access in order to determine the busst_data= ReadRC(RegCommand);if (!st_data) break;}while(--ii); // configuration// necessary read access// after first write access, the returned value// should be zero ==> interface recognizedif (st_data)status = MI_INTERFACEERR;elsestatus = 0;if(!status){XBYTE[RegClockQControl]=0x0;XBYTE[RegClockQControl]=0x40;Delay_10us(5);ClearBitMask(RegClockQControl,0x40); // clear bit ClkQCalib forXBYTE[RegBitPhase]=0xAd;XBYTE[RegRxThreshold]=0xFF;XBYTE[RegRxControl2]=01;XBYTE[RegFIFOLevel]=0x1A; // initialize to 26dXBYTE[RegTimerControl]=0x02; // TStopRxEnd=0,TStopRxBeg=0,XBYTE[RegIRqPinConfig]=0x3; // interrupt active low enablestatus=PcdRfReset(1); // Rf - reset and enable output driver }return status;}unsigned char Mf500PiccRequest(unsigned char req_code, unsigned char *atq){unsigned char D_data status = MI_OK;PcdSetTmo(2);WriteRC(RegChannelRedundancy,0x03); // RxCRC and TxCRC disable, parity enable ClearBitMask(RegControl,0x08); // disable crypto 1 unitWriteRC(RegBitFraming,0x07); // set TxLastBits to 7ResetInfo();MSndBuffer[0] = req_code;MInfo.nBytesToSend = 1;status = PcdSingleResponseCmd(PCD_TRANSCEIVE);if (status) // error occuredatq[0] = 0;else{if (MInfo.nBitsReceived != 16) // 2 bytes expected{atq[0] = 0;status = MI_BITCOUNTERR;}else{status = MI_OK;memcpy(atq,MRcvBuffer,2);}}return status;}unsigned char Mf500PiccCascSelect(unsigned char select_code,unsigned char *snr, unsigned char *sak){unsigned char D_data status = MI_OK;// if (CardSortChar==102)//1102卡不需要// return 0;PcdSetTmo(2);WriteRC(RegChannelRedundancy,0x0F); // RxCRC,TxCRC, Parity enableClearBitMask(RegControl,0x08); // disable crypto 1 unitResetInfo();MSndBuffer[0] = select_code;MSndBuffer[1] = 0x70; // number of bytes sendmemcpy(MSndBuffer+2,snr,4);MSndBuffer[6] = MSndBuffer[2] ^ MSndBuffer[3] ^ MSndBuffer[4] ^ MSndBuffer[5];MInfo.nBytesToSend = 7;status = PcdSingleResponseCmd(PCD_TRANSCEIVE);sak[0] = 0;if (status == MI_OK) // no timeout occured{if (MInfo.nBitsReceived != 8) // last byte is not completestatus = MI_BITCOUNTERR;else{sak[0] = MRcvBuffer[0];// memcpy(MLastSelectedSnr,snr,4);}}return status;}unsigned char Mf500PiccAnticoll (unsigned char bcnt, u nsigned char *snr){return Mf500PiccCascAnticoll(0x93,bcnt,snr); // first cascade level}unsigned char Mf500PiccCascAnticoll (unsigned char select_code,unsigned char bcnt,unsigned char *snr){unsigned char D_data s tatus = MI_OK;unsigned char D_data snr_in[4]; // copy of the input parameter snrunsigned char D_data nbytes = 0; // how many bytes receivedunsigned char D_data nbits = 0; // how many bits receivedunsigned char D_data complete = 0; // complete snr recivedunsigned char D_data i = 0;unsigned char D_data byteOffset = 0;unsigned char D_data snr_crc; // check byte calculationunsigned char D_data snr_check;unsigned char D_data dummyShift1; // dummy byte for snr shiftunsigned char D_data dummyShift2; // dummy byte for snr shift// if (CardSortChar==102)//1102卡不需要// return 0;PcdSetTmo(2);memcpy(snr_in,snr,4);WriteRC(RegDecoderControl,0x28); // ZeroAfterColl aktivierenClearBitMask(RegControl,0x08); // disable crypto 1 unitcomplete=0;while (!complete && (status == MI_OK) ){ResetInfo();WriteRC(RegChannelRedundancy,0x03); // RxCRC and TxCRC disable, parity enablenbits = bcnt % 8;if (nbits){WriteRC(RegBitFraming,nbits << 4 | nbits); // TxLastBits/RxAlign auf nb_bi nbytes = bcnt / 8 + 1;if (nbits == 7 ){MInfo.cmd = PICC_ANTICOLL1; // pass command flag to ISRWriteRC(RegBitFraming,nbits); // reset RxAlign to zero}}elsenbytes = bcnt / 8;MSndBuffer[0] = select_code;MSndBuffer[1] = 0x20 + ((bcnt/8) << 4) + nbits; //number of bytes sendmemcpy (MSndBuffer+2,snr_in,nbytes);MInfo.nBytesToSend = 2 + nbytes;status = PcdSingleResponseCmd(PCD_TRANSCEIVE);// in order to solve an inconsistancy in the anticollision sequence// (will be solved soon), the case of 7 bits has to be treated in a// separate wayif (nbits == 7){// reorder received bitsdummyShift1 = 0x00;for (i = 0; i < MInfo.nBytesReceived; i++){dummyShift2 = MRcvBuffer[i];MRcvBuffer[i] = (dummyShift1 >> (i+1)) | (MRcvBuffer[i] << (7-i));dummyShift1 = dummyShift2;}MInfo.nBitsReceived -= MInfo.nBytesReceived; // subtract received parity bits // recalculation of collision positionif ( MInfo.collPos ) MInfo.collPos += 7 - (MInfo.collPos + 6) / 9;}if ( status == MI_OK || status == MI_COLLERR) // no other occured{// R e s p o n s e P r o c e s s i n gif ( MInfo.nBitsReceived != 40) // not 5 bytes answeredstatus = MI_BITCOUNTERR;else{byteOffset = 0;if ( nbits != 0 ) // last byte was not complete{snr_in[nbytes - 1] = snr_in[nbytes - 1] | MRcvBuffer[0];byteOffset = 1;}for ( i =0; i < (4 - nbytes); i++)snr_in[nbytes + i] = MRcvBuffer[i + byteOffset];if (status != MI_COLLERR ) // no error and no collision{// SerCh checksnr_crc = snr_in[0] ^ snr_in[1] ^ snr_in[2] ^ snr_in[3];snr_check = MRcvBuffer[4];if (snr_crc != snr_check)status = MI_SERNRERR;elsecomplete = 1;}else // collision occured{bcnt = bcnt + MInfo.collPos - nbits;status = MI_OK;}}}}if (status == MI_OK)memcpy(snr,MRcvBuffer,4);ClearBitMask(RegDecoderControl,0x20); // ZeroAfterColl disablereturn status;}void SetBitMask(unsigned int reg,unsigned char mask){XBYTE[reg] |= mask;} // clear bit maskvoid ClearBitMask(unsigned int reg,unsigned char mask){XBYTE[reg] &= ~mask;} // clear bit maskvoid FlushFIFO(void){SetBitMask(RegControl,0x01);}void WriteRC(unsigned int Address, unsigned char value){XBYTE[Address]=value;} // write value at the specifiedunsigned char ReadRC(unsigned int Address){return XBYTE[Address];}// read value at the specifiedunsigned char PcdRfReset(unsigned int nms){unsigned char D_data status = MI_OK;ClearBitMask(RegTxControl,0x03); // Tx2RF-En, Tx1RF-En disablenif (nms > 0){nms=1000*nms;Delay_10us(nms);SetBitMask(RegTxControl,0x03);}return status;}void PcdSetTmo(unsigned char tmoLength){switch(tmoLength){ // timer clock frequency 13,56 MHzcase 1: // short timeout (1,0 ms)WriteRC(RegTimerClock,0x07); // TAutoRestart=0,TPrescale=128WriteRC(RegTimerReload,0x6a);// TReloadVal = 'h6a =106(dec)break;case 2: // medium timeout (1,5 ms)WriteRC(RegTimerClock,0x07); // TAutoRestart=0,TPrescale=128WriteRC(RegTimerReload,0xa0);// TReloadVal = 'ha0 =160(dec)break;case 3: // long timeout (6 ms)WriteRC(RegTimerClock,0x09); // TAutoRestart=0,TPrescale=4*128WriteRC(RegTimerReload,0xa0);// TReloadVal = 'ha0 =160(dec)break;case 4: // long timeout (19.2 ms)WriteRC(RegTimerClock,0x0a); // TAutoRestart=0,TPrescale=4*128WriteRC(RegTimerReload,0xff);// TReloadVal = 'ff =255(dec)break;case 5: // long timeout (38.4 ms)WriteRC(RegTimerClock,0x0b); // TAutoRestart=0,TPrescale=4*4*128WriteRC(RegTimerReload,0xff);// TReloadV al = 'ff =255(dec)break;case 6: // long timeout (76.8 ms)WriteRC(RegTimerClock,0x0c); // TAutoRestart=0,TPrescale=2*4*4*128WriteRC(RegTimerReload,0xff);// TReloadV al = 'ff =255(dec)break;case 7: // long timeout (153.6 ms)WriteRC(RegTimerClock,0x0d); // TAutoRestart=0,TPrescale=2*2*4*4*128WriteRC(RegTimerReload,0xff);// TReloadV al = 'ff =255(dec)break;default: // short timeout (1,0 ms)WriteRC(RegTimerClock,0x07); // TAutoRestart=0,TPrescale=128WriteRC(RegTimerReload,tmoLength);// TReloadVal = tmoLengthbreak;}}void ResetInfo(void){MInfo.cmd = 0;MInfo.status = MI_OK;MInfo.irqSource = 0;MInfo.nBytesSent = 0;MInfo.nBytesToSend = 0;MInfo.nBytesReceived = 0;MInfo.nBitsReceived = 0;MInfo.collPos = 0;}unsigned char PcdSingleResponseCmd(unsigned char cmd){unsigned char D_data status = MI_OK;unsigned char D_data tmpStatus ;unsigned char D_data lastBits;unsigned char D_data irqEn = 0x00;unsigned char D_data waitFor = 0x00;unsigned char D_data timerCtl = 0x00;unsigned int D_data ii=50000;WriteRC(RegInterruptEn,0x7F); // disable all interruptsWriteRC(RegInterruptRq,0x7F); // reset interrupt requestsWriteRC(RegCommand,PCD_IDLE); // terminate probably running commandFlushFIFO(); // flush FIFO bufferhaveset=1;// initialising the ISR-Function pointer for mifare// protocol - do this after initialising the MpXXXX variablesMInfo.irqSource = 0x0; // reset interrupt flags// depending on the command code, appropriate interrupts are enabled (irqEn) // and the commit interrupt is choosen (waitFor).switch(cmd){case PCD_IDLE: // nothing else required irqEn = 0x00;waitFor = 0x00;break;case PCD_WRITEE2: // LoAlert and TxIRq irqEn = 0x11;waitFor = 0x10;break;case PCD_READE2: // HiAlert, LoAlert and IdleIRq irqEn = 0x07;waitFor = 0x04;break;case PCD_LOADCONFIG: // IdleIRq and LoAlertcase PCD_LOADKEYE2: // IdleIRq and LoAlertcase PCD_AUTHENT1: // IdleIRq and LoAlert irqEn = 0x05;waitFor = 0x04;break;case PCD_CALCCRC: // LoAlert and TxIRq irqEn = 0x11;waitFor = 0x10;break;case PCD_AUTHENT2: // IdleIRqirqEn = 0x04;waitFor = 0x04;break;case PCD_RECEIVE: // HiAlert and IdleIRq MInfo.nBitsReceived = -(ReadRC(RegBitFraming) >> 4);irqEn = 0x06;waitFor = 0x04;break;case PCD_LOADKEY: // IdleIRqirqEn = 0x05;waitFor = 0x04;break;case PCD_TRANSMIT: // LoAlert and IdleIRqirqEn = 0x05;waitFor = 0x04;break;case PCD_TRANSCEIVE: // TxIrq, RxIrq, IdleIRq and LoAlert MInfo.nBitsReceived = -(ReadRC(RegBitFraming) >> 4);irqEn = 0x3D;waitFor = 0x04;break;default:status = MI_UNKNOWN_COMMAND;}if (status == MI_OK){// Initialize uC Timer for global Timeout managementirqEn |= 0x20; // always enable timout irqwaitFor |= 0x20; // always wait for timeout// processing time counter// 6.4 us resolution - max 420 msWriteRC(RegInterruptEn,irqEn | 0x80); //necessary interrupts are enabled // count up from 1WriteRC(RegCommand,cmd); //start commandtmpStatus=ReadRC(RegFIFOLength);Delay_10us(1);do{if (MInfo.irqSource & waitFor) break;}while (--ii);WriteRC(RegInterruptEn,0x7F); // disable all interruptsWriteRC(RegInterruptRq,0x7F); // clear all interrupt requestsSetBitMask(RegControl,0x04); // stop timer nowWriteRC(RegCommand,PCD_IDLE); // reset command registerif (!(MInfo.irqSource & waitFor)) // reader has not terminated // timer 3 expiredstatus = MI_ACCESSTIMEOUT;elsestatus = MInfo.status; // set statusif (status == MI_OK) // no timeout error occured{if ((tmpStatus = (ReadRC(RegErrorFlag) & 0x17))) // error occured{if (tmpStatus & 0x01) // collision detected{MInfo.collPos = ReadRC(RegCollPos); // read collision positionstatus = MI_COLLERR;}else{MInfo.collPos = 0;if (tmpStatus & 0x02) // parity errorstatus = MI_PARITYERR;}if (tmpStatus & 0x04) // framing errorstatus = MI_FRAMINGERR;if (tmpStatus & 0x10) // FIFO overflow{FlushFIFO();status = MI_OVFLERR;}if (tmpStatus & 0x08) // CRC errorstatus = MI_CRCERR;if (status == MI_OK)status = MI_NY_IMPLEMENTED;// key error occures always, because of// missing crypto 1 keys loaded}// if the last command was TRANSCEIVE, the number of// received bits must be calculated - even if an error occuredif (cmd == PCD_TRANSCEIVE || cmd == PCD_RECEIVE){// number of bits in the last bytelastBits = ReadRC(RegSecondaryStatus) & 0x07;if (lastBits)MInfo.nBitsReceived += (MInfo.nBytesReceived-1)*8 + lastBits;elseMInfo.nBitsReceived=(MInfo.nBytesReceived)*8+MInfo.nBitsReceived;}}elseMInfo.collPos = 0x00;}// reset interface variables for ISRhaveset=0;return status;}///////////////////////////////////////////////////////////////////////// C O D E K E Y S///////////////////////////////////////////////////////////////////////unsigned char Mf500HostCodeKey( unsigned char * uncoded, unsigned char * coded){unsigned char D_data status = MI_OK;unsigned char D_data cnt = 0;unsigned char D_data ln = 0; // low nibbleunsigned char D_data hn = 0; // high nibblefor (cnt = 0; cnt < 6; cnt++){ln = uncoded[cnt] & 0x0F;hn = uncoded[cnt] >> 4;coded[cnt * 2 + 1] = (~ln << 4) | ln;coded[cnt * 2 ] = (~hn << 4) | hn;}return MI_OK;}///////////////////////////////////////////////////////////////////////// A U T H E N T I C A T I O N// W I T H P R O V I D E D K E Y S///////////////////////////////////////////////////////////////////////unsigned char Mf500PiccAuthKey( unsigned char auth_mode, unsigned char *snr, unsigned char *keys, unsigned char block){unsigned char D_data status= MI_OK;PcdSetTmo(2);FlushFIFO(); // empty FIFOResetInfo();memcpy (MSndBuffer,keys,12) ;MInfo.nBytesToSend =12;status=PcdSingleResponseCmd(PCD_LOADKEY);if (status == MI_OK)status = Mf500PiccAuthState(auth_mode,snr,block);return status;}/*unsigned char Mf500PiccAuthKey_SHC1102( unsigned char *keys){unsigned char D_data status= MI_OK;PcdSetTmo(2);WriteRC(RegChannelRedundancy,0x0F); // RxCRC,TxCRC, Parity enableClearBitMask(RegControl,0x08); // disable crypto 1 unitResetInfo();MSndBuffer[0] = 0x80;MSndBuffer[1] = 8;memcpy(MSndBuffer+2,keys,4);MInfo.nBytesToSend = 6;status = PcdSingleResponseCmd(PCD_TRANSCEIVE);if (status) // error occuredreturn status;else{if (MInfo.nBitsReceived != 4) // 2 bytes expected{MRcvBuffer[0] = 0;status = MI_BITCOUNTERR;}else{if ((MRcvBuffer[0]&0x0f)==0x0a)status = MI_OK;elsestatus = MI_BITCOUNTERR;}}}*////////////////////////////////////////////////////////////////////////// A U T H E N T I C A T I O N S T A T E S///////////////////////////////////////////////////////////////////////unsigned char Mf500PiccAuthState( unsigned char auth_mode, unsigned char *snr, unsigned char block){unsigned char D_data status = MI_OK;unsigned char D_data i = 0;status = ReadRC(RegErrorFlag); // read error flags of the previous// key loadif (status != MI_OK){if (status & 0x40) // key error flag setstatus = MI_KEYERR;elsestatus = MI_AUTHERR; // generic authentication error }else{PcdSetTmo(2);MSndBuffer[0] = auth_mode; // write authentication commandMSndBuffer[1] = block; // write block number for authentication// memcpy(MSndBuffer + 2,snr,4); // write 4 bytes card serial numbermemcpy(MSndBuffer+2,snr,4);ResetInfo();MInfo.nBytesToSend = 6;status = PcdSingleResponseCmd(PCD_AUTHENT1);if (status == MI_OK){if (ReadRC(RegSecondaryStatus) & 0x07) // RxLastBits mu?leer seinstatus = MI_BITCOUNTERR;else{ResetInfo();MInfo.nBytesToSend = 0;if ((status = PcdSingleResponseCmd(PCD_AUTHENT2)) == MI_OK){if ( ReadRC(RegControl) & 0x08 ) // Crypto1 activatedstatus = MI_OK;elsestatus = MI_AUTHERR;}}}}return status;}///////////////////////////////////////////////////////////////////////// M I F A R E R E A D///////////////////////////////////////////////////////////////////////unsigned char Mf500PiccRead( unsigned char addr, unsigned char * mdata){unsigned char D_data status = MI_OK;unsigned char D_data tmp = 0;unsigned char D_data ReLen;status=ReadRC(RegControl);FlushFIFO(); // empty FIFOPcdSetTmo(4); // long timeout_nop_();WriteRC(RegChannelRedundancy,0x0F); // RxCRC, TxCRC, Parity enable_nop_();ResetInfo();MSndBuffer[0] = PICC_READ; // read command codeMSndBuffer[1] = addr;MInfo.nBytesToSend = 2;status = PcdSingleResponseCmd(PCD_TRANSCEIVE);if (status != MI_OK){if (status != MI_NOTAGERR ) // no timeout occured{if (MInfo.nBitsReceived == 4) // NACK{MRcvBuffer[0] &= 0x0f; // mask out upper nibbleif ((MRcvBuffer[0] & 0x0a) == 0)status = MI_NOTAUTHERR;elsestatus = MI_CODEERR;}}memset(mdata,0,16); // in case of an error initialise // data}else // Response Processing{// if (CardSortChar==102)// ReLen=4;// elseReLen=16;if (MInfo.nBytesReceived != ReLen){status = MI_BYTECOUNTERR;memset(mdata,0,ReLen);}elsememcpy(mdata,MRcvBuffer,ReLen);}PcdSetTmo(2); // short timeoutreturn status;}///////////////////////////////////////////////////////////////////////// M I F A R E W R I T E///////////////////////////////////////////////////////////////////////unsigned char Mf500PiccWrite( unsigned char addr, unsigned char *mdata){unsigned char D_data status = MI_OK;unsigned char D_data WrLen;status=ReadRC(RegControl);PcdSetTmo(4); // long timeoutif (!bitReadCardMode)WriteRC(RegChannelRedundancy,0x0F); // RxCRC, TxCRC, Parity enable elseWriteRC(RegChannelRedundancy,0x07); // TxCRC, Parity enable ResetInfo();MSndBuffer[0] = PICC_WRITE; // Write command codeMSndBuffer[1] = addr;_nop_();MInfo.nBytesToSend = 2;_nop_();status = PcdSingleResponseCmd(PCD_TRANSCEIVE);if (status != MI_NOTAGERR) // no timeout error{if (MInfo.nBitsReceived != 4) // 4 bits are necessarystatus = MI_BITCOUNTERR;else // 4 bit received{MRcvBuffer[0] &= 0x0f; // mask out upper nibbleswitch(MRcvBuffer[0]){case 0x00:status = MI_NOTAUTHERR;break;case 0x0a:status = MI_OK;break;default:status = MI_CODEERR;break;}}}if ( status == MI_OK){PcdSetTmo(4); // long timeoutResetInfo();// if (CardSortChar==102)// WrLen=4;//1102卡// elseWrLen=16;memcpy(MSndBuffer,mdata,WrLen);MInfo.nBytesToSend = WrLen;status = PcdSingleResponseCmd(PCD_TRANSCEIVE);if (status != MI_NOTAGERR) // no timeout occured{if (MInfo.nBitsReceived != 4) // 4 bits are necessarystatus = MI_BITCOUNTERR;else // 4 bit received{MRcvBuffer[0] &= 0x0f; // mask out upper nibbleswitch(MRcvBuffer[0]){case 0x00:status = MI_WRITEERR;break;case 0x0a:status = MI_OK;break;default:status = MI_CODEERR;break;}}}PcdSetTmo(2); // short timeout}WriteRC(RegChannelRedundancy,0x0F); // RxCRC, TxCRC, Parity enablereturn status;}void int2() interrupt 2 using 1{static unsigned char D_data irqBits;static unsigned char D_data irqMask;// static unsigned char oldPageSelect;static unsigned char D_data nbytes;static unsigned char D_data cnt;if (haveset)//MpIsrInfo && MpIsrOut && MpIsrIn) // transfer pointers have to be set// correctly{//oldPageSelect = ReadRC(RegPage); // save old page select// Attention: ReadRC cannnot be// used because of the internal// write sequence to the page// reg//WriteRC(RegPage,0x80); // select page 0 for ISRwhile( (ReadRC(RegPrimaryStatus) & 0x08)) // loop while IRQ pending{irqMask = ReadRC(RegInterruptEn); // read enabled interrupts// read pending interruptsirqBits = ReadRC(RegInterruptRq) & irqMask;MInfo.irqSource |= irqBits; // save pending interrupts//LoAlertIRQif (irqBits & 0x01) // LoAlert{nbytes = 0x40 - ReadRC(RegFIFOLength);// less bytes to send, than space in FIFOif ((MInfo.nBytesToSend - MInfo.nBytesSent) <= nbytes){nbytes = MInfo.nBytesToSend - MInfo.nBytesSent;WriteRC(RegInterruptEn,0x01); // disable LoAlert IRQ}// write remaining data to the FIFOfor ( cnt = 0;cnt < nbytes;cnt++){WriteRC(RegFIFOData,MSndBuffer[MInfo.nBytesSent]);MInfo.nBytesSent++;}cnt=ReadRC(RegFIFOLength);WriteRC(RegInterruptRq,0x01); // reset IRQ bit}// TxIRQ Handlingif (irqBits & 0x10) // TxIRQ{WriteRC(RegInterruptRq,0x10); // reset IRQ bitWriteRC(RegInterruptEn,0x82); // enable HiAlert Irq for// responseif (MInfo.cmd == PICC_ANTICOLL1) // if cmd is anticollision{ // switch off parity generationWriteRC(RegChannelRedundancy,0x02); // RxCRC and TxCRC disable, parity disableWriteRC(RegPage,0x00); // reset page address}}if (irqBits & 0x0E) // HiAlert, Idle or RxIRQ{// read some bytes ( length of FIFO queue)// into the receive buffernbytes = ReadRC(RegFIFOLength);// read date from the FIFO and store them in the receive bufferfor ( cnt = 0; cnt < nbytes; cnt++){MInfo.nBytesReceived++;MRcvBuffer[cnt]=ReadRC(RegFIFOData);}WriteRC(RegInterruptRq,0x0A & irqBits);// reset IRQ bit - idle irq will// be deleted in a seperate section }if (irqBits & 0x04) // Idle IRQ{WriteRC(RegInterruptEn,0x20); // disable Timer IRQWriteRC(RegInterruptRq,0x20); // disable Timer IRQ requestirqBits &= ~0x20; // clear Timer IRQ in local varMInfo.irqSource &= ~0x20; // clear Timer IRQ in info var// when idle received, then cancel// timeoutWriteRC(RegInterruptRq,0x04); // reset IRQ bit// status should still be MI_OK// no error - only used for wake up}if (irqBits & 0x20) // timer IRQ{WriteRC(RegInterruptRq,0x20); // reset IRQ bitMInfo.status = MI_NOTAGERR; // timeout error// otherwise ignore the interrupt }}}}///////////////////////////////////////////////////////////////////////// V A L U E M A N I P U L A T I O N////////////////////////////////////////////////////////////////////////*unsigned char Mf500PiccValue(unsigned char dd_mode,unsigned char addr,unsigned char *value,unsigned char trans_addr){unsigned char D_data status = MI_OK;PcdSetTmo(2);ResetInfo();MSndBuffer[0] = dd_mode; // Inc,Dec command code MSndBuffer[1] = addr;MInfo.nBytesToSend = 2;status = PcdSingleResponseCmd(PCD_TRANSCEIVE);if (status != MI_NOTAGERR) // no timeout error{if (MInfo.nBitsReceived != 4) // 4 bits are necessary{status = MI_BITCOUNTERR;}else // 4 bit received{MRcvBuffer[0] &= 0x0f; // mask out upper nibbleswitch(MRcvBuffer[0]){case 0x00:status = MI_NOTAUTHERR;break;case 0x0a:status = MI_OK;break;case 0x01:status = MI_V ALERR;break;default:status = MI_CODEERR;break;}}}if ( status == MI_OK){PcdSetTmo(4); // long timeoutResetInfo();memcpy(MSndBuffer,value,4);MInfo.nBytesToSend = 4;status = PcdSingleResponseCmd(PCD_TRANSCEIVE);if (status == MI_OK) // no timeout occured{if (MInfo.nBitsReceived != 4) // 4 bits are necessarystatus = MI_BITCOUNTERR;else // 4 bit received{MRcvBuffer[0] &= 0x0f; // mask out upper nibbleswitch(MRcvBuffer[0]){case 0x00:status = MI_NOTAUTHERR;break;case 0x01:status = MI_V ALERR;break;default:status = MI_CODEERR;break;}}}elseif (status == MI_NOTAGERR )status = MI_OK; // no response after 4 byte value -// transfer command has to follow}if ( status == MI_OK){ResetInfo();MSndBuffer[0] = PICC_TRANSFER; // transfer command code MSndBuffer[1] = trans_addr;MInfo.nBytesToSend = 2;status = PcdSingleResponseCmd(PCD_TRANSCEIVE);if (status != MI_NOTAGERR) // timeout occured{if (MInfo.nBitsReceived != 4) // 4 bits are necessarystatus = MI_BITCOUNTERR;else // 4 bit received{MRcvBuffer[0] &= 0x0f; // mask out upper nibbleswitch(MRcvBuffer[0]){case 0x00:status = MI_NOTAUTHERR;break;case 0x0a:status = MI_OK;break;case 0x01:status = MI_V ALERR;break;default:status = MI_CODEERR;break;}}}}return status;}*//*unsigned char PcdWriteE2( unsigned int startaddr,unsigned char length,unsigned char *mdata){unsigned char D_data status = MI_OK;unsigned char D_data i;ResetInfo();MSndBuffer[0] = startaddr & 0xFF;MSndBuffer[1] = (startaddr >> 8) & 0xFF;memcpy(MSndBuffer + 2,mdata,length);MInfo.nBytesToSend = length + 2;status = PcdSingleResponseCmd(PCD_WRITEE2); // write e2i=100;do{Delay_ms(1);if (ReadRC(RegSecondaryStatus) & 0x40) break;}while (--i);WriteRC(RegCommand,PCD_IDLE);return status;}*/unsigned char PcdReadE2(unsigned int startaddr,unsigned char length,unsigned char * mdata) {unsigned char D_data status = MI_OK;PcdSetTmo(6);ResetInfo();MSndBuffer[0] = startaddr & 0xFF;MSndBuffer[1] = (startaddr >> 8) & 0xFF;MSndBuffer[2] = length;MInfo.nBytesToSend = 3;status = PcdSingleResponseCmd(PCD_READE2);if (status == MI_OK){if (MInfo.nBytesReceived >= length){memcpy(mdata,MRcvBuffer,length);}else{memcpy(mdata,MRcvBuffer,MInfo.nBytesReceived);}}return status;}/*unsigned char Mf500PiccHalt(void){unsigned char D_data status = MI_CODEERR;PcdSetTmo(2);ResetInfo();MSndBuffer[0] = PICC_HALT ; // Halt command codeMSndBuffer[1] = 0x00; // dummy addressMInfo.nBytesToSend = 2;status = PcdSingleResponseCmd(PCD_TRANSCEIVE);if (status){// timeout error ==> no NAK received ==> OKif (status == MI_NOTAGERR || status == MI_ACCESSTIMEOUT) status = MI_OK;}//reset command register - no response from tagWriteRC(RegCommand,PCD_IDLE);return status;}*/。