Ubeeto物联网开发板通过外接恩智浦半导体公司的RC522 IC卡读卡模块来实现对工作频率为13.56MHz的IC卡的各种操作。RC522支持对Mifare One类型的IC卡操作,例如M1-S20,M1-S50,M1-S70卡等,20,50,70系列的区别主要在存储容量大小,其他的操作基本完全一样。
本篇章主要涉及对IC卡某个扇区(Sector)密码的下载操作,以及对IC卡某个扇区(Sector)中的某个块(Block)进行数据的写入和读出操作。
目前市面上用的最多的IC卡是Mifare One S50 卡,所以Ubeeto开发板提供的驱动库完全是按照S50的规格来设计的,但是也兼容S20,S70等卡的读写操作,只是在操作时需注意其容量的差别:
1、S20卡共有5个扇区(Sector0~Sector4),每个扇区4个块(Block0~Block3),每个块16字节。
2、S50卡共有16个扇区(Sector0~Sector15),每个扇区4个块(Block0~Block3),每个块16字节。
3、S70卡共有16个扇区(Sector0~Sector15),每个扇区4个块(Block0~Block3),每个块16字节。注意:为了和S50保持兼容性,这里只提及了S70的前16个扇区,后面24个扇区不考虑。
S50卡的存储结构如下图:
每个扇区的块0~块2用来读取和写入您自定义的16字节数据。
每个扇区的块3用来存储该扇区的6字节密码A、4字节的存取控制字节、6字节密码B。一般我们只用密码A作为验证密钥即可。至于块3中的存取控制字节一般保持IC卡出厂默认值0xFF,0x07,0x80,0x69即可,至于块3中的密码B我们需填入一个自定义的6字节数据即可。如果对密码B以及存储控制字节详细内容感兴趣的可以参考此处,这里提供了S50卡的详细资料。
如果要读写操作每个扇区中的块0~块2中的某一块,必须先用密码A认证该扇区。
实际应用中我们可能只会用到某个扇区中的某一块作为安全认证用,至于剩下的几十个块我们也可以发挥想象来丰富我们的安全认证以及个性化数据存储功能。
本例中指定用来读写数据的块是位于扇区Sector4中的Block1块。当然您也可以从Sector0~Sector15,Block0~Block2中任意选择构成(Sector_X, Block_Y)组合。数据块的实际地址Addr = Sector_X*4 + Block_Y, 该Addr开发者无需关心,
名称 | 推荐购买链接(或者你可以自己制作) | 模块/芯片硬件资料下载 |
---|---|---|
RC522读卡模块 | RC522模块购买链接 | 下载地址(提取码:mf6v) |
声明:这里推荐的购买链接仅供参考,您完全可以去其他商家或渠道购买,只要功能相似即可,如果需要更低的成本建议自己开发硬件模块或定制。
提示:KEYA一旦下载至某个扇区后,今后对该扇区的块数据的读写前都需要先用这个KEYA验证,如果忘记了KEYA,这张IC卡的这个扇区就无法再次读写了。
--KEYA=0xA0,0xA1,0xA2,0xA3,0xA4,0xA5 KEYB=0xB0,0xB1,0xB2,0xB3,0xB4,0xB5 --KEYA是在本例中我们主要用的密钥,KEYB虽然用不到,但也不能填太容易破解的内容 --0xFF,0x07,0x80,0x69这4个存取控制字节的详细描述文章中已提供参考,如果您有更高开发要求可以前往了解下 DownloadKey = {0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xFF,0x07,0x80,0x69,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5} KeyA = {0xA0,0xA1,0xA2,0xA3,0xA4,0xA5} KeyFactory = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} --S50,S70卡等,新出厂时默认的密钥(A或B)全是0xFF, --需要写入Block(块)中的16字节数据 WriteData = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f} --配置USB以CDC虚拟串口模式工作 LIB_UsbConfig("CDC") --配置D8为普通输出,控制Core电路板上的LED1 LIB_GpioOutputConfig("D8","STANDARD") LIB_GpioWrite("D8",1) --LED1灭 --设置Core电路板上的按键1(占用D10口)以低电平有效的方式检测按键动作 LIB_ButtonConfig("BTN1","D10","L") --设置Core电路板上的按键2(占用D11口)以低电平有效的方式检测按键动作 LIB_ButtonConfig("BTN2","D11","L") --初始化RC522读卡模块并开始在后台一直寻找有效IC卡的出现 LIB_RC522Config() --开始大循环 while(GC(1) == true) do --如果发现IC卡,就输出其卡类型字符串以及卡的32位UID号 CardFoundFlag,Type,UID = LIB_RC522CardFind() btn1_value = LIB_ButtonQuery("BTN1") btn2_value = LIB_ButtonQuery("BTN2") if CardFoundFlag == 1 then --如果按键1短按,开始下载密码 if btn1_value == 1 then --用KeyFactory认证来判断是不是新卡 if LIB_RC522CardAuth("KEYA","Sector4",KeyFactory,UID) == 1 then --新卡 --向Sector4扇区的Block3块中写入16字节的密码及控制数据 --注意:密码必须写入每个扇区的Block3块中才行,这是IC卡厂家已经固定的 if LIB_RC522CardWrite("Sector4", "Block3", DownloadKey) == 1 then --写密码成功 print("KEY download success\r\n") else--写操作失败 print("KEY download fail\r\n") end else print("You can not download key to an used card\r\n") end --如果按键2短按,开始写操作并回读刚才写的内容 elseif btn2_value == 1 then --开始写操作 --用KeyA认证来判断是不是有效的卡 if LIB_RC522CardAuth("KEYA","Sector4",KeyA,UID) == 1 then --新卡 --向Sector4扇区的Block1数据块中写入16字节的数据 WriteData[1] = WriteData[1] + 1 --每次写入时第1个字节加1 if LIB_RC522CardWrite("Sector4", "Block1", WriteData) == 1 then --写密码成功 print("Write success\r\n") else--写操作失败 print("Write fail\r\n") end else print("You can not write to an invalid card\r\n") end --开始回读操作 --用KeyA认证来判断是不是有效的卡 if LIB_RC522CardAuth("KEYA","Sector4",KeyA,UID) == 1 then --新卡 --读取刚刚写操作所涉及的Sector4扇区的Block1块 result,rd = LIB_RC522CardRead("Sector4", "Block1") if result == 1 then --读操作成功 print("Sector4 Block1 Content:\r\n") --这里只打印了前2个字节和最后2个字节 print(string.format("%02x%02x...%02x%02x",rd[1],rd[2],rd[15],rd[16])) else print("Read fail\r\n") end else print("You can not read an invalid card\r\n") end --如果没有按键动作,就只打印出卡的类型和32位UID else --LED1闪烁一下 LIB_GpioWrite("D8",0) LIB_DelayMs(200) LIB_GpioWrite("D8",1) end end end
如果感兴趣,上面代码中出现的LIB开头的库函数可以在API文档中通过Ctrl+F查询。
在电脑端运行的调试助手上,我们可以看到如下打印输出信息:
简单、快捷、高效、强大的物联网开发板
© 2022. All Rights Reserved. 粤ICP备2021058065号