飞道的博客

STM32+MFRC522完成IC卡号读取、密码修改、数据读写

219人阅读  评论(0)

一、环境介绍

MCU:  STM32F103ZET6

开发软件: Keil5

非接触式读写卡模块: MFRC522

完整工程源码下载: https://download.csdn.net/download/xiaolong1126626497/18905806

二、功能介绍

使用MFRC522模块完成对IC卡卡号读取、卡类型区分、IC卡扇区密码修改、扇区数据读写等功能;底层采用SPI模拟时序,可以很方便的移植到其他设备,完成项目开发。  现在很多嵌入式方向的毕业设计经常使用到该模块,比如: 校园一卡通设计、水卡充值消费设计、公交卡充值消费设计等。

三、MFR522介绍

MF RC522 是应用于13.56MHz 非接触式通信中高集成度读写卡系列芯片中的一员。是NXP 公司针对“三表”应用推出的一款低电压、低成本、体积小的非接触式读写卡芯片,是智能仪表和便携式手持设备研发的较好选择。

MF RC522 利用了先进的调制和解调概念,完全集成了在13.56MHz 下所有类型的被动非接触式通信方式和协议。支持 ISO14443A 的多层应用。其内部发送器部分可驱动读写器天线与ISO 14443A/MIFARE卡和应答机的通信,无需其它的电路。接收器部分提供一个坚固而有效的解调和解码电路,用于处理ISO14443A 兼容的应答器信号。数字部分处理ISO14443A 帧和错误检测(奇偶 &CRC)。此外,它还支持快速CRYPTO1 加密算法,用于验证MIFARE 系列产品。MFRC522 支持MIFARE?更高速的非接触式通信,双向数据传输速率高达424kbit/s。

作为13.56MHz 高集成度读写卡系列芯片家族的新成员,MF RC522 与MF RC500和 MF RC530 有不少相似之处,同时也具备诸多特点和差异。它与主机间的通信采用连线较少的串行通信,且可根据不同的用户需求,选取SPI、I2C 或串行UART(类似RS232)模式之一,有利于减少连线,缩小PCB 板体积,降低成本。

四、IC卡介绍

非接触式IC卡又称射频卡,由IC芯片、感应天线组成,封装在一个标准的PVC卡片内,芯片及天线无任何外露部分。是世界上最近几年发展起来的一项新技术,它成功的将射频识别技术和IC卡技术结合起来,结束了无源(卡中无电源)和免接触这一难题,是电子器件领域的一大突破。卡片在一定距离范围(通常为5—10cm)靠近读写器表面,通过无线电波的传递来完成数据的读写操作。

射频读写器向IC卡发一组固定频率的电磁波,卡片内有一个LC串联谐振电路,其频率与读写器发射的频率相同,这样在电磁波激励下,LC谐振电路产生共振,从而使电容内有了电荷;在这个电荷的另一端,接有一个单向导通的电子泵,将电容内的电荷送到另一个电容内存储,当所积累的电荷达到2V时,此电容可作为电源为其它电路提供工作电压,将卡内数据发射出去或接受读写器的数据。

非接触性IC卡与读卡器之间通过无线电波来完成读写操作。二者之间的通讯频率为13.56MHZ。非接触性IC卡本身是无源卡,当读写器对卡进行读写操作时,读写器发出的信号由两部分叠加组成:一部分是电源信号,该信号由卡接收后,与本身的L/C产生一个瞬间能量来供给芯片工作。另一部分则是指令和数据信号,指挥芯片完成数据的读取、修改、储存等,并返回信号给读写器,完成一次读写操作。读写器则一般由单片机,专用智能模块和天线组成,并配有与PC的通讯接口,打印口,I/O口等,以便应用于不同的领域。

M1卡详细指标

M1卡是指M1芯片,是指菲利浦下属子公司恩智浦出品的芯片缩写,全称为NXP Mifare1系列,常用的有S50及S70两种型号。

M1(S50)卡详细规格:

  1. 芯片类型:PhilipsMifare1ICS50
  2. 存储容量:8Kbit,16个分区,每分区两组密码;
  3. 工作频率:13.56?MHz;
  4. 通讯速率:106KBoud;
  5. 读写距离:2.5~10cm;
  6. 读写时间:1~2ms;
  7. 工作温度:-20℃~55℃;
  8. 擦写寿命:>100,000次;
  9. 数据保存:>10年;
  10. 外形尺寸:ISO标准卡85.6x54x0.82;
  11. 封装材料:PVC、PET、PETG、0.13mm铜线;

Mifare S50和Mifare S70又常被称为Mifare Standard、Mifare Classic、MF1,是遵守ISO14443A标准的卡片中应用最为广、影响力最大的的一员。而Mifare S70的容量是S50的4倍,S50的容量是1K字节,S70的容量为4K字节。

读写器对卡片的操作时序和操作命令,二者完全一致。    Mifare S50和Mifare S70的每张卡片都有一个4字节的全球唯一序列号,卡上数据保存期为10年,可改写10万次,读无限次。一般的应用中,不用考虑卡片是否会被读坏写坏的问题,

当然暴力硬损坏除外。 Mifare S50和Mifare S70的区别主要有两个方面。一是读写器对卡片发出请求命令,二者应答返回的卡类型(ATQA)字节不同。Mifare S50的卡类型(ATQA)是0004H,Mifare S70的卡类型(ATQA)是0002H。另一个区别就是二者的容量和内存结构不同。

M1卡分为16个扇区,每个扇区由4块(0、1、2、3)组成。实际操作时,将16个扇区分为64个块,按绝对地址编号为0-63。

结构如下:

 

  1. 第0个扇区用于存放厂商代码,意见固话,不可更改。
  2. 每个扇区的块0、块1、块2为数据块,可以用于存储数据。数据块可以进行读写操作。
  3. 每个扇区的块3为控制块,包括了密码A、存储控制、密码B。具体结构如下:

  4. 每个扇区的密码和控制位都是独立的,可以根据实际需求设定各自的密码及存取控制。存取控制为4个字节,共32位,扇区中的每个块(包括数据和控制块)存取条件是由密码和存取控制共同决定的,在存取控制中每个块都有一个相应的三个控制位。定义如下:

 Mifare 1 S50 白卡读写时一般步骤: 寻卡-->下载块密码--> 读写块数据。控制块也是一样。

 

     数据块的访问权限设置表格:(根据自己需要的权限,完成上图字节6、7、8的填充即可)

   控制块的读写权限设置:(包含了对密码A、控制权限、密码的读写权限)

 

 

 

           7  6  5  4  3  2  1  0

字节6 1  1  1  1  1  1  1  1

字节7 0  0  0  0  1  1  1  1

字节8 0  0  0  0  0  0  0  0

字节9

设置的控制权限如下:0xFF 0x0F 0x00 0x00

代表数据块的权限: 验证密码A或者密码B都可以对数据块进行读写操作或者加值键值操作。

2. 代表控制块的权限

(1) 验证A密码之后可以写A/B密码,不能读密码。

                     可以读控制字节(4个),无法写控制字节

                      可以读写B密码       

(2) 验证B密码之后,可以读写A/B密码,也可读控制字节,但无法写控制字节。   

 

五、核心代码

5.1  rc522.c


  
  1. #include "sys.h"
  2. #include "RFID_RC522.h"
  3. #include "delay.h"
  4. #include "string.h"
  5. #include "usart.h"
  6. /*
  7. 函数功能:移植接口--SPI时序读写一个字节
  8. 函数参数:data:要写入的数据
  9. 返 回 值:读到的数据
  10. */
  11. u8 RC522_SPI_ReadWriteOneByte(u8 tx_data)
  12. {
  13. u8 rx_data= 0;
  14. u8 i;
  15. for(i= 0;i< 8;i++)
  16. {
  17. RC522_SCLK= 0;
  18. if(tx_data& 0x80){RC522_OUTPUT= 1;}
  19. else {RC522_OUTPUT= 0;}
  20. tx_data<<= 1;
  21. RC522_SCLK= 1;
  22. rx_data<<= 1;
  23. if(RC522_INPUT)rx_data|= 0x01;
  24. }
  25. return rx_data;
  26. }
  27. /*
  28. 函数功能:初始化RC522的IO口
  29. */
  30. void RC522_IO_Init(void)
  31. {
  32. RCC->APB2ENR|= 1<< 2; //PA时钟使能
  33. RCC->APB2ENR|= 1<< 7; //PF时钟使能
  34. //PA5 时钟 RC522_SCLK
  35. //PA6 输入 RC522_INPUT
  36. //PA7 输出 RC522_OUTPUT
  37. GPIOA->CRL&= 0x000FFFFF;
  38. GPIOA->CRL|= 0x38300000;
  39. GPIOA->ODR|= 0x3<< 5;
  40. //RC522_RST <----->PF1--复位脚
  41. //RC522_SDA <----->PF0--片选脚
  42. GPIOF->CRL&= 0xFFFFFF00;
  43. GPIOF->CRL|= 0x00000033;
  44. GPIOF->ODR|= 0x3<< 0;
  45. }
  46. /*
  47. 功能描述:选卡读取卡存储器容量
  48. 输入参数:serNum 传入卡序列号
  49. 返 回 值:成功返回卡容量
  50. */
  51. u8 RC522_MFRC522_SelectTag(u8 *serNum) //读取卡存储器容量
  52. {
  53. u8 i;
  54. u8 status;
  55. u8 size;
  56. u8 recvBits;
  57. u8 buffer[ 9];
  58. buffer[ 0]=PICC_ANTICOLL1; //防撞码1
  59. buffer[ 1]= 0x70;
  60. buffer[ 6]= 0x00;
  61. for(i= 0;i< 4;i++)
  62. {
  63. buffer[i+ 2]=*(serNum+i); //buffer[2]-buffer[5]为卡序列号
  64. buffer[ 6]^=*(serNum+i); //卡校验码
  65. }
  66. RC522_CalulateCRC(buffer, 7,&buffer[ 7]); //buffer[7]-buffer[8]为RCR校验码
  67. RC522_ClearBitMask(Status2Reg, 0x08);
  68. status=RC522_PcdComMF522(PCD_TRANSCEIVE,buffer, 9,buffer,&recvBits);
  69. if((status==MI_OK)&&(recvBits== 0x18))
  70. size=buffer[ 0];
  71. else
  72. size= 0;
  73. return size;
  74. }
  75. /*
  76. 延时函数,纳秒级
  77. */
  78. void RC522_Delay(u32 ns)
  79. {
  80. u32 i;
  81. for(i= 0;i<ns;i++)
  82. {
  83. __nop();
  84. __nop();
  85. __nop();
  86. }
  87. }
  88. /*
  89. 函数功能:RC522芯片初始化
  90. */
  91. void RC522_Init(void)
  92. {
  93. RC522_IO_Init(); //RC522初始化
  94. RC522_PcdReset(); //复位RC522
  95. RC522_PcdAntennaOff(); //关闭天线
  96. DelayMs( 2); //延时2毫秒
  97. RC522_PcdAntennaOn(); //开启天线
  98. M500PcdConfigISOType( 'A'); //设置RC632的工作方式
  99. }
  100. /*
  101. 函数功能:复位RC522
  102. */
  103. void RC522_Reset(void)
  104. {
  105. RC522_PcdReset(); //复位RC522
  106. RC522_PcdAntennaOff(); //关闭天线
  107. DelayMs( 2); //延时2毫秒
  108. RC522_PcdAntennaOn(); //开启天线
  109. }
  110. /*
  111. 功 能: 寻卡
  112. 参数说明: req_code[IN]:寻卡方式
  113. 0x52 = 寻感应区内所有符合14443A标准的卡
  114. 0x26 = 寻未进入休眠状态的卡
  115. pTagType[OUT]:卡片类型代码
  116. 0x4400 = Mifare_UltraLight
  117. 0x0400 = Mifare_One(S50)
  118. 0x0200 = Mifare_One(S70)
  119. 0x0800 = Mifare_Pro(X)
  120. 0x4403 = Mifare_DESFire
  121. 返 回 值: 成功返回MI_OK
  122. */
  123. char RC522_PcdRequest(u8 req_code,u8 *pTagType)
  124. {
  125. char status;
  126. u8 unLen;
  127. u8 ucComMF522Buf[MAXRLEN]; // MAXRLEN 18
  128. RC522_ClearBitMask(Status2Reg, 0x08); //清RC522寄存器位,/接收数据命令
  129. RC522_WriteRawRC(BitFramingReg, 0x07); //写RC632寄存器
  130. RC522_SetBitMask(TxControlReg, 0x03); //置RC522寄存器位
  131. ucComMF522Buf[ 0]=req_code; //寻卡方式
  132. status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf, 1,ucComMF522Buf,&unLen); //通过RC522和ISO14443卡通讯
  133. if((status==MI_OK)&&(unLen== 0x10))
  134. {
  135. *pTagType=ucComMF522Buf[ 0];
  136. *(pTagType+ 1)=ucComMF522Buf[ 1];
  137. }
  138. else
  139. {
  140. status = MI_ERR;
  141. }
  142. return status;
  143. }
  144. /*
  145. 功 能: 防冲撞
  146. 参数说明: pSnr[OUT]:卡片序列号,4字节
  147. 返 回: 成功返回MI_OK
  148. */
  149. char RC522_PcdAnticoll(u8 *pSnr)
  150. {
  151. char status;
  152. u8 i,snr_check= 0;
  153. u8 unLen;
  154. u8 ucComMF522Buf[MAXRLEN];
  155. RC522_ClearBitMask(Status2Reg, 0x08); //清RC522寄存器位
  156. RC522_WriteRawRC(BitFramingReg, 0x00); //写
  157. RC522_ClearBitMask(CollReg, 0x80); //清
  158. ucComMF522Buf[ 0]=PICC_ANTICOLL1; //PICC_ANTICOLL1 = 0x93
  159. ucComMF522Buf[ 1]= 0x20;
  160. status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf, 2,ucComMF522Buf,&unLen); //0x0c,通过RC522和ISO14443卡通讯
  161. //PCD_TRANSCEIVE =发送并接收数据
  162. //2:写入卡里的数据字节长度
  163. //ucComMF522Buf:存放数据的地址
  164. //unLen:从卡里读出的数据长度
  165. if(status==MI_OK)
  166. {
  167. for(i= 0;i< 4;i++)
  168. {
  169. *(pSnr+i)=ucComMF522Buf[i]; //把读到的卡号赋值给pSnr
  170. snr_check^=ucComMF522Buf[i];
  171. }
  172. if(snr_check!=ucComMF522Buf[i])
  173. {
  174. status = MI_ERR;
  175. }
  176. }
  177. RC522_SetBitMask(CollReg, 0x80);
  178. return status;
  179. }
  180. /*
  181. 功 能:选定卡片
  182. 参数说明:pSnr[IN]:卡片序列号,4字节
  183. 返 回:成功返回MI_OK
  184. */
  185. char RC522_PcdSelect(u8 *pSnr)
  186. {
  187. char status;
  188. u8 i;
  189. u8 unLen;
  190. u8 ucComMF522Buf[MAXRLEN];
  191. ucComMF522Buf[ 0]=PICC_ANTICOLL1;
  192. ucComMF522Buf[ 1]= 0x70;
  193. ucComMF522Buf[ 6]= 0;
  194. for(i= 0;i< 4;i++)
  195. {
  196. ucComMF522Buf[i+ 2]=*(pSnr+i);
  197. ucComMF522Buf[ 6]^=*(pSnr+i);
  198. }
  199. RC522_CalulateCRC(ucComMF522Buf, 7,&ucComMF522Buf[ 7]); //用MF522计算CRC16函数,校验数据
  200. RC522_ClearBitMask(Status2Reg, 0x08); //清RC522寄存器位
  201. status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf, 9,ucComMF522Buf,&unLen);
  202. if((status==MI_OK)&&(unLen== 0x18))status=MI_OK;
  203. else status=MI_ERR;
  204. return status;
  205. }
  206. /*
  207. 功 能:验证卡片密码
  208. 参数说明:auth_mode[IN]: 密码验证模式
  209. 0x60 = 验证A密钥
  210. 0x61 = 验证B密钥
  211. addr[IN]:块地址
  212. pKey[IN]:扇区密码
  213. pSnr[IN]:卡片序列号,4字节
  214. 返 回:成功返回MI_OK
  215. */
  216. char RC522_PcdAuthState(u8 auth_mode,u8 addr,u8 *pKey,u8 *pSnr)
  217. {
  218. char status;
  219. u8 unLen;
  220. u8 ucComMF522Buf[MAXRLEN]; //MAXRLEN 18(数组的大小)
  221. //验证模式+块地址+扇区密码+卡序列号
  222. ucComMF522Buf[ 0]=auth_mode;
  223. ucComMF522Buf[ 1]=addr;
  224. memcpy(&ucComMF522Buf[ 2],pKey, 6); //拷贝,复制
  225. memcpy(&ucComMF522Buf[ 8],pSnr, 4);
  226. status=RC522_PcdComMF522(PCD_AUTHENT,ucComMF522Buf, 12,ucComMF522Buf,&unLen);
  227. if((status!= MI_OK)||(!(RC522_ReadRawRC(Status2Reg)& 0x08)))status = MI_ERR;
  228. return status;
  229. }
  230. /*
  231. 功 能:读取M1卡一块数据
  232. 参数说明:
  233. addr:块地址
  234. p :读出的块数据,16字节
  235. 返 回:成功返回MI_OK
  236. */
  237. char RC522_PcdRead(u8 addr,u8 *p)
  238. {
  239. char status;
  240. u8 unLen;
  241. u8 i,ucComMF522Buf[MAXRLEN]; //18
  242. ucComMF522Buf[ 0]=PICC_READ;
  243. ucComMF522Buf[ 1]=addr;
  244. RC522_CalulateCRC(ucComMF522Buf, 2,&ucComMF522Buf[ 2]);
  245. status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf, 4,ucComMF522Buf,&unLen); //通过RC522和ISO14443卡通讯
  246. if((status==MI_OK&&(unLen== 0x90)))
  247. {
  248. for(i= 0;i< 16;i++)
  249. {
  250. *(p +i)=ucComMF522Buf[i];
  251. }
  252. }
  253. else
  254. {
  255. status=MI_ERR;
  256. }
  257. return status;
  258. }
  259. /*
  260. 功 能:写数据到M1卡指定块
  261. 参数说明:addr:块地址
  262. p :向块写入的数据,16字节
  263. 返 回:成功返回MI_OK
  264. */
  265. char RC522_PcdWrite(u8 addr,u8 *p)
  266. {
  267. char status;
  268. u8 unLen;
  269. u8 i,ucComMF522Buf[MAXRLEN];
  270. ucComMF522Buf[ 0]=PICC_WRITE; // 0xA0 //写块
  271. ucComMF522Buf[ 1]=addr; //块地址
  272. RC522_CalulateCRC(ucComMF522Buf, 2,&ucComMF522Buf[ 2]);
  273. status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf, 4,ucComMF522Buf,&unLen);
  274. if((status!= MI_OK)||(unLen != 4)||((ucComMF522Buf[ 0]& 0x0F)!= 0x0A))
  275. {
  276. status = MI_ERR;
  277. }
  278. if(status==MI_OK)
  279. {
  280. for(i= 0;i< 16;i++) //向FIFO写16Byte数据
  281. {
  282. ucComMF522Buf[i]=*(p +i);
  283. }
  284. RC522_CalulateCRC(ucComMF522Buf, 16,&ucComMF522Buf[ 16]);
  285. status = RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf, 18,ucComMF522Buf,&unLen);
  286. if((status != MI_OK)||(unLen != 4)||((ucComMF522Buf[ 0]& 0x0F)!= 0x0A))
  287. {
  288. status = MI_ERR;
  289. }
  290. }
  291. return status;
  292. }
  293. /*
  294. 功 能:命令卡片进入休眠状态
  295. 返 回:成功返回MI_OK
  296. */
  297. char RC522_PcdHalt(void)
  298. {
  299. u8 status;
  300. u8 unLen;
  301. u8 ucComMF522Buf[MAXRLEN]; //MAXRLEN==18
  302. status=status;
  303. ucComMF522Buf[ 0]=PICC_HALT;
  304. ucComMF522Buf[ 1]= 0;
  305. RC522_CalulateCRC(ucComMF522Buf, 2,&ucComMF522Buf[ 2]);
  306. status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf, 4,ucComMF522Buf,&unLen);
  307. return MI_OK;
  308. }
  309. /*
  310. 功 能:用MF522计算CRC16函数
  311. 参 数:
  312. *pIn :要读数CRC的数据
  313. len:-数据长度
  314. *pOut:计算的CRC结果
  315. */
  316. void RC522_CalulateCRC(u8 *pIn ,u8 len,u8 *pOut )
  317. {
  318. u8 i,n;
  319. RC522_ClearBitMask(DivIrqReg, 0x04); //CRCIrq = 0
  320. RC522_WriteRawRC(CommandReg,PCD_IDLE);
  321. RC522_SetBitMask(FIFOLevelReg, 0x80); //清FIFO指针
  322. //向FIFO中写入数据
  323. for(i= 0;i<len;i++)
  324. {
  325. RC522_WriteRawRC(FIFODataReg,*(pIn +i)); //开始RCR计算
  326. }
  327. RC522_WriteRawRC(CommandReg,PCD_CALCCRC); //等待CRC计算完成
  328. i= 0xFF;
  329. do
  330. {
  331. n=RC522_ReadRawRC(DivIrqReg);
  332. i--;
  333. }
  334. while((i!= 0)&&!(n& 0x04)); //CRCIrq = 1
  335. //读取CRC计算结果
  336. pOut[ 0]=RC522_ReadRawRC(CRCResultRegL);
  337. pOut[ 1]=RC522_ReadRawRC(CRCResultRegM);
  338. }
  339. /*
  340. 功 能:复位RC522
  341. 返 回:成功返回MI_OK
  342. */
  343. char RC522_PcdReset(void)
  344. {
  345. RC522_RST= 1; //PF1写1
  346. RC522_Delay( 10);
  347. RC522_RST= 0; //PF1清0
  348. RC522_Delay( 10);
  349. RC522_RST= 1; //PF1写1
  350. RC522_Delay( 10);
  351. RC522_WriteRawRC(CommandReg,PCD_RESETPHASE); //写RC632寄存器,复位
  352. RC522_WriteRawRC(CommandReg,PCD_RESETPHASE); //写RC632寄存器,复位
  353. RC522_Delay( 10);
  354. RC522_WriteRawRC(ModeReg, 0x3D); //和Mifare卡通讯,CRC初始值0x6363
  355. RC522_WriteRawRC(TReloadRegL, 30); //写RC632寄存器
  356. RC522_WriteRawRC(TReloadRegH, 0);
  357. RC522_WriteRawRC(TModeReg, 0x8D);
  358. RC522_WriteRawRC(TPrescalerReg, 0x3E);
  359. RC522_WriteRawRC(TxAutoReg, 0x40); //必须要
  360. return MI_OK;
  361. }
  362. /*
  363. 函数功能:设置RC632的工作方式
  364. */
  365. char M500PcdConfigISOType(u8 type)
  366. {
  367. if(type== 'A') //ISO14443_A
  368. {
  369. RC522_ClearBitMask(Status2Reg, 0x08); //清RC522寄存器位
  370. RC522_WriteRawRC(ModeReg, 0x3D); //3F//CRC初始值0x6363
  371. RC522_WriteRawRC(RxSelReg, 0x86); //84
  372. RC522_WriteRawRC(RFCfgReg, 0x7F); //4F //调整卡的感应距离//RxGain = 48dB调节卡感应距离
  373. RC522_WriteRawRC(TReloadRegL, 30); //tmoLength);// TReloadVal = 'h6a =tmoLength(dec)
  374. RC522_WriteRawRC(TReloadRegH, 0);
  375. RC522_WriteRawRC(TModeReg, 0x8D);
  376. RC522_WriteRawRC(TPrescalerReg, 0x3E);
  377. RC522_Delay( 1000);
  378. RC522_PcdAntennaOn(); //开启天线
  379. }
  380. else return 1; //失败,返回1
  381. return MI_OK; //成功返回0
  382. }
  383. /*
  384. 功 能:读RC632寄存器
  385. 参数说明:Address[IN]:寄存器地址
  386. 返 回:读出的值
  387. */
  388. u8 RC522_ReadRawRC(u8 Address)
  389. {
  390. u8 ucAddr;
  391. u8 ucResult= 0;
  392. RC522_CS= 0; //片选选中RC522
  393. ucAddr=((Address<< 1)& 0x7E)| 0x80;
  394. RC522_SPI_ReadWriteOneByte(ucAddr); //发送命令
  395. ucResult=RC522_SPI_ReadWriteOneByte( 0); //读取RC522返回的数据
  396. RC522_CS= 1; //释放片选线(PF0)
  397. return ucResult; //返回读到的数据
  398. }
  399. /*
  400. 功 能:写RC632寄存器
  401. 参数说明:Address[IN]:寄存器地址
  402. value[IN] :写入的值
  403. */
  404. void RC522_WriteRawRC(u8 Address,u8 value)
  405. {
  406. u8 ucAddr;
  407. RC522_CS= 0; //PF0写 0 (SDA)(SPI1片选线,低电平有效)
  408. ucAddr=((Address<< 1)& 0x7E);
  409. RC522_SPI_ReadWriteOneByte(ucAddr); //SPI1发送一个字节
  410. RC522_SPI_ReadWriteOneByte(value); //SPI1发送一个字节
  411. RC522_CS= 1; //PF1写1(SDA)(SPI1片选线)
  412. }
  413. /*
  414. 功 能:置RC522寄存器位
  415. 参数说明:reg[IN]:寄存器地址
  416. mask[IN]:置位值
  417. */
  418. void RC522_SetBitMask(u8 reg,u8 mask)
  419. {
  420. char tmp= 0x0;
  421. tmp=RC522_ReadRawRC(reg); //读RC632寄存器
  422. RC522_WriteRawRC(reg,tmp|mask); //写RC632寄存器
  423. }
  424. /*
  425. 功 能:清RC522寄存器位
  426. 参数说明:reg[IN]:寄存器地址
  427. mask[IN]:清位值
  428. */
  429. void RC522_ClearBitMask(u8 reg,u8 mask)
  430. {
  431. char tmp= 0x0;
  432. tmp=RC522_ReadRawRC(reg); //读RC632寄存器
  433. RC522_WriteRawRC(reg,tmp&~mask); // clear bit mask
  434. }
  435. /*
  436. 功 能:通过RC522和ISO14443卡通讯
  437. 参数说明:Command[IN]:RC522命令字
  438. pIn [IN]:通过RC522发送到卡片的数据
  439. InLenByte[IN]:发送数据的字节长度
  440. pOut [OUT]:接收到的卡片返回数据
  441. *pOutLenBit[OUT]:返回数据的位长度
  442. */
  443. char RC522_PcdComMF522(u8 Command,u8 *pIn,u8 InLenByte,u8 *pOut,u8 *pOutLenBit)
  444. {
  445. char status=MI_ERR;
  446. u8 irqEn= 0x00;
  447. u8 waitFor= 0x00;
  448. u8 lastBits;
  449. u8 n;
  450. u16 i;
  451. switch(Command)
  452. {
  453. case PCD_AUTHENT: //验证密钥
  454. irqEn= 0x12;
  455. waitFor= 0x10;
  456. break;
  457. case PCD_TRANSCEIVE: //发送并接收数据
  458. irqEn= 0x77;
  459. waitFor= 0x30;
  460. break;
  461. default:
  462. break;
  463. }
  464. RC522_WriteRawRC(ComIEnReg,irqEn| 0x80);
  465. RC522_ClearBitMask(ComIrqReg, 0x80); //清所有中断位
  466. RC522_WriteRawRC(CommandReg,PCD_IDLE);
  467. RC522_SetBitMask(FIFOLevelReg, 0x80); //清FIFO缓存
  468. for(i= 0;i<InLenByte;i++)
  469. {
  470. RC522_WriteRawRC(FIFODataReg,pIn[i]);
  471. }
  472. RC522_WriteRawRC(CommandReg,Command);
  473. if(Command==PCD_TRANSCEIVE)
  474. {
  475. RC522_SetBitMask(BitFramingReg, 0x80); //开始传送
  476. }
  477. //有问题,下面的循环
  478. //i = 600;//根据时钟频率调整,操作M1卡最大等待时间25ms
  479. i= 2000;
  480. do
  481. {
  482. n=RC522_ReadRawRC(ComIrqReg);
  483. i--;
  484. }
  485. while((i!= 0)&&!(n& 0x01)&&!(n&waitFor));
  486. RC522_ClearBitMask(BitFramingReg, 0x80);
  487. if(i!= 0)
  488. {
  489. if(!(RC522_ReadRawRC(ErrorReg)& 0x1B))
  490. {
  491. status=MI_OK;
  492. if(n&irqEn& 0x01)
  493. {
  494. status=MI_NOTAGERR;
  495. }
  496. if(Command==PCD_TRANSCEIVE)
  497. {
  498. n=RC522_ReadRawRC(FIFOLevelReg);
  499. lastBits=RC522_ReadRawRC(ControlReg)& 0x07;
  500. if(lastBits)
  501. {
  502. *pOutLenBit=(n -1)* 8+lastBits;
  503. }
  504. else
  505. {
  506. *pOutLenBit=n* 8;
  507. }
  508. if(n== 0)n= 1;
  509. if(n>MAXRLEN)n=MAXRLEN;
  510. for(i= 0; i<n; i++)
  511. {
  512. pOut[i]=RC522_ReadRawRC(FIFODataReg);
  513. }
  514. }
  515. }
  516. else
  517. {
  518. status=MI_ERR;
  519. }
  520. }
  521. RC522_SetBitMask(ControlReg, 0x80); // stop timer now
  522. RC522_WriteRawRC(CommandReg,PCD_IDLE);
  523. return status;
  524. }
  525. /*
  526. 函数功能:开启天线
  527. 参 数:每次启动或关闭天险发射之间应至少有1ms的间隔
  528. */
  529. void RC522_PcdAntennaOn(void)
  530. {
  531. u8 i;
  532. i=RC522_ReadRawRC(TxControlReg);
  533. if(!(i& 0x03))
  534. {
  535. RC522_SetBitMask(TxControlReg, 0x03);
  536. }
  537. }
  538. /*
  539. 函数功能:关闭天线
  540. 参 数:每次启动或关闭天险发射之间应至少有1ms的间隔
  541. */
  542. void RC522_PcdAntennaOff(void)
  543. {
  544. RC522_ClearBitMask(TxControlReg, 0x03); //清RC522寄存器位
  545. }

5.2 rc522.h


  
  1. #ifndef RFID_RC522_H
  2. #define RFID_RC522_H
  3. #include "sys.h"
  4. /*
  5. RC522射频模块外部的接口:
  6. *1--SDA <----->PF0--片选脚
  7. *2--SCK <----->PA5--时钟线
  8. *3--MOSI<----->PA7--输出
  9. *4--MISO<----->PA6--输入
  10. *5--悬空
  11. *6--GND <----->GND
  12. *7--RST <----->PF1--复位脚
  13. *8--VCC <----->VCC
  14. */
  15. #define RC522_OUTPUT PAout(7)
  16. #define RC522_INPUT PAin(6)
  17. #define RC522_SCLK PAout(5)
  18. #define RC522_CS PFout(0)
  19. #define RC522_RST PFout(1)
  20. //MF522命令字
  21. #define PCD_IDLE 0x00 //取消当前命令
  22. #define PCD_AUTHENT 0x0E //验证密钥
  23. #define PCD_RECEIVE 0x08 //接收数据
  24. #define PCD_TRANSMIT 0x04 //发送数据
  25. #define PCD_TRANSCEIVE 0x0C //发送并接收数据
  26. #define PCD_RESETPHASE 0x0F //复位
  27. #define PCD_CALCCRC 0x03 //CRC计算
  28. //Mifare_One卡片命令字
  29. #define PICC_REQIDL 0x26 //寻天线区内未进入休眠状态,返回的是卡的类型
  30. #define PICC_REQALL 0x52 //寻天线区内全部卡,返回的是卡的类型
  31. #define PICC_ANTICOLL1 0x93 //防冲撞
  32. #define PICC_ANTICOLL2 0x95 //防冲撞
  33. #define PICC_AUTHENT1A 0x60 //验证A密钥
  34. #define PICC_AUTHENT1B 0x61 //验证B密钥 命令认证代码
  35. #define PICC_READ 0x30 //读块
  36. #define PICC_WRITE 0xA0 //写块
  37. #define PICC_DECREMENT 0xC0 //扣款
  38. #define PICC_INCREMENT 0xC1 //充值
  39. #define PICC_RESTORE 0xC2 //调块数据到缓冲区
  40. #define PICC_TRANSFER 0xB0 //保存缓冲区中数据
  41. #define PICC_HALT 0x50 //休眠
  42. //MF522 FIFO长度定义
  43. #define DEF_FIFO_LENGTH 64 //FIFO size=64byte
  44. #define MAXRLEN 18
  45. //MF522寄存器定义
  46. // PAGE 0
  47. #define RFU00 0x00
  48. #define CommandReg 0x01
  49. #define ComIEnReg 0x02
  50. #define DivlEnReg 0x03
  51. #define ComIrqReg 0x04
  52. #define DivIrqReg 0x05
  53. #define ErrorReg 0x06
  54. #define Status1Reg 0x07
  55. #define Status2Reg 0x08
  56. #define FIFODataReg 0x09
  57. #define FIFOLevelReg 0x0A
  58. #define WaterLevelReg 0x0B
  59. #define ControlReg 0x0C
  60. #define BitFramingReg 0x0D
  61. #define CollReg 0x0E
  62. #define RFU0F 0x0F
  63. // PAGE 1
  64. #define RFU10 0x10
  65. #define ModeReg 0x11
  66. #define TxModeReg 0x12
  67. #define RxModeReg 0x13
  68. #define TxControlReg 0x14
  69. #define TxAutoReg 0x15
  70. #define TxSelReg 0x16
  71. #define RxSelReg 0x17
  72. #define RxThresholdReg 0x18
  73. #define DemodReg 0x19
  74. #define RFU1A 0x1A
  75. #define RFU1B 0x1B
  76. #define MifareReg 0x1C
  77. #define RFU1D 0x1D
  78. #define RFU1E 0x1E
  79. #define SerialSpeedReg 0x1F
  80. // PAGE 2
  81. #define RFU20 0x20
  82. #define CRCResultRegM 0x21
  83. #define CRCResultRegL 0x22
  84. #define RFU23 0x23
  85. #define ModWidthReg 0x24
  86. #define RFU25 0x25
  87. #define RFCfgReg 0x26
  88. #define GsNReg 0x27
  89. #define CWGsCfgReg 0x28
  90. #define ModGsCfgReg 0x29
  91. #define TModeReg 0x2A
  92. #define TPrescalerReg 0x2B
  93. #define TReloadRegH 0x2C
  94. #define TReloadRegL 0x2D
  95. #define TCounterValueRegH 0x2E
  96. #define TCounterValueRegL 0x2F
  97. // PAGE 3
  98. #define RFU30 0x30
  99. #define TestSel1Reg 0x31
  100. #define TestSel2Reg 0x32
  101. #define TestPinEnReg 0x33
  102. #define TestPinValueReg 0x34
  103. #define TestBusReg 0x35
  104. #define AutoTestReg 0x36
  105. #define VersionReg 0x37
  106. #define AnalogTestReg 0x38
  107. #define TestDAC1Reg 0x39
  108. #define TestDAC2Reg 0x3A
  109. #define TestADCReg 0x3B
  110. #define RFU3C 0x3C
  111. #define RFU3D 0x3D
  112. #define RFU3E 0x3E
  113. #define RFU3F 0x3F
  114. //和MF522通讯时返回的错误代码
  115. #define MI_OK 0
  116. #define MI_NOTAGERR 1
  117. #define MI_ERR 2
  118. #define SHAQU1 0X01
  119. #define KUAI4 0X04
  120. #define KUAI7 0X07
  121. #define REGCARD 0xa1
  122. #define CONSUME 0xa2
  123. #define READCARD 0xa3
  124. #define ADDMONEY 0xa4
  125. /*
  126. RC522各种驱动函数
  127. */
  128. u8 RC522_SPI_ReadWriteOneByte(u8 tx_data);
  129. void RC522_IO_Init(void);
  130. u8 RC522_MFRC522_SelectTag(u8 *serNum);
  131. void RC522_Delay(u32 ns);
  132. void RC522_Init(void);
  133. void RC522_Reset(void);
  134. char RC522_PcdRequest(u8 req_code,u8 *pTagType);
  135. char RC522_PcdAnticoll(u8 *pSnr);
  136. char RC522_PcdSelect(u8 *pSnr);
  137. char RC522_PcdAuthState(u8 auth_mode,u8 addr,u8 *pKey,u8 *pSnr);
  138. char RC522_PcdRead(u8 addr,u8 *p);
  139. char RC522_PcdWrite(u8 addr,u8 *p);
  140. char RC522_PcdHalt(void);
  141. void RC522_CalulateCRC(u8 *pIn ,u8 len,u8 *pOut );
  142. char RC522_PcdReset(void);
  143. char M500PcdConfigISOType(u8 type);
  144. char M500PcdConfigISOType(u8 type);
  145. u8 RC522_ReadRawRC(u8 Address);
  146. void RC522_WriteRawRC(u8 Address,u8 value);
  147. void RC522_SetBitMask(u8 reg,u8 mask) ;
  148. void RC522_ClearBitMask(u8 reg,u8 mask);
  149. char RC522_PcdComMF522(u8 Command,u8 *pIn,u8 InLenByte,u8 *pOut,u8 *pOutLenBit);
  150. void RC522_PcdAntennaOn(void);
  151. void RC522_PcdAntennaOff(void);
  152. #endif

 


转载:https://blog.csdn.net/xiaolong1126626497/article/details/117075834
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场