请选择 进入手机版 | 继续访问电脑版

你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【中秋活动】STM32F103RBT6+RC522 NFC读写S50复旦卡

胤幻1988 发布时间:2021-9-14 14:00
今天,我们抽空来弄下STM32F103RBT6通过SPI方式驱动RC522  NFC模块读写S50复旦卡~
一个简单的下例子,NFC的应用在生活中随处可见了。我们这里的假设应用场景是在不同杯子
底部粘上复旦卡,来辨别不同的杯子TYPE型号~这里仅对块地址17的第一个字节进行判断!
复旦卡就是常见的那种门禁卡钥匙扣形状的:
M2.jpg
主板用自制的STM32F103RBT6的一个小板:
M1.jpg
下载器用CMSIS DAP 带串口的: M3.jpg

好,下面开始接线:
M6.png
接好线的图:
M4.jpg
STM32F103RBT6 和RC522 及S50复旦卡就不多说了,网上大把资料。
上程序:
spi.h
  1. #ifndef __SPI_H
  2. #define __SPI_H
  3. #include "sys.h"


  4. //#define RC522_RST                   PCout(7)
  5. #define RC522_RST                   PCout(7)       //测试后恢复PCout(7)
  6. #define RC522_CS        PBout(9)
  7. #define SPIReadByte()          SPIWriteByte(0)
  8. // SPI总线速度设置
  9. #define SPI_SPEED_2                   0
  10. #define SPI_SPEED_4                   1
  11. #define SPI_SPEED_8                   2
  12. #define SPI_SPEED_16                  3
  13. #define SPI_SPEED_32                   4
  14. #define SPI_SPEED_64                   5
  15. #define SPI_SPEED_128                 6
  16. #define SPI_SPEED_256                 7
  17.                                                                                                                                                                         
  18. void SPI2_Init(void);                         //初始化SPI口
  19. void SPI2_SetSpeed(u8 SpeedSet); //设置SPI速度   
  20. u8 SPIWriteByte(u8 TxData);//SPI总线读写一个字节
  21.                  
  22. #endif

复制代码
spi.c
  1. #include "spi.h"

  2. //这里针是对SPI2的初始化
  3. void SPI2_Init(void)
  4. {         
  5.         RCC->APB2ENR|=1<<3;            //PORTB时钟使能
  6.         RCC->APB2ENR|=1<<4;            //PORTC时钟使能
  7.         RCC->APB1ENR|=1<<14;           //SPI2时钟使能
  8.         GPIOB->CRH&=0XFFFFFF0F;         
  9.         GPIOB->CRH|=0X00000030;//PB.9 推挽输出
  10.         GPIOC->CRL&=0X0FFFFFFF;         
  11.         GPIOC->CRL|=0X30000000;//PC. 7 推挽输出
  12.         //        GPIOB->CRH&=0XFFFFFFF0;         
  13.         //        GPIOB->CRH|=0X00000003;//PB. 8 推挽输出   此脚做测试用,测试完恢复PC7复位RFID功能
  14.         RC522_RST=1;             //RC522 复位脚置1
  15.         RC522_CS=1;


  16.         //这里只针对SPI口初始化
  17.         GPIOB->CRH&=0X000FFFFF;
  18.         GPIOB->CRH|=0XBBB00000;        //PB13/14/15复用            
  19.         GPIOB->ODR|=0X7<<13;           //PB13/14/15上拉
  20.         SPI2->CR1|=0<<10;                //全双工模式        
  21.         SPI2->CR1|=1<<9;                 //软件nss管理
  22.         SPI2->CR1|=1<<8;  

  23.         SPI2->CR1|=1<<2;                 //SPI主机
  24.         SPI2->CR1|=0<<11;                //8bit数据格式        
  25.         SPI2->CR1|=1<<1;                 //空闲模式下SCK为1 CPOL=1
  26.         SPI2->CR1|=1<<0;                 //数据采样从第二个时间边沿开始,CPHA=1  
  27.         //对SPI2属于APB1的外设.时钟频率最大为36M.
  28.         SPI2->CR1|=3<<3;                 //Fsck=Fpclk1/256
  29.         SPI2->CR1|=0<<7;                 //MSBfirst   
  30.         SPI2->CR1|=1<<6;                 //SPI设备使能
  31.         SPI2_SetSpeed(5);        
  32.         SPIWriteByte(0xff);//启动传输                 
  33. }   
  34. //SPI2速度设置函数
  35. //SpeedSet:0~7
  36. //SPI速度=fAPB2/2^(SpeedSet+1)
  37. //fAPB2时钟一般为90Mhz
  38. void SPI2_SetSpeed(u8 SpeedSet)
  39. {
  40.         SpeedSet&=0X07;                        //限制范围
  41.         SPI2->CR1&=0XFFC7;
  42.         SPI2->CR1|=SpeedSet<<3;        //设置SPI5速度  
  43.         SPI2->CR1|=1<<6;                 //SPI设备使能         
  44. }
  45. //SPI2 读写一个字节
  46. //TxData:要写入的字节
  47. //返回值:读取到的字节
  48. u8 SPIWriteByte(u8 TxData)
  49. {                                          
  50.         u16 retry=0;                                 
  51.         while((SPI2->SR&1<<1)==0)                //等待发送区空        
  52.         {
  53.                 retry++;
  54.                 if(retry>=0XFFFE)return 0;         //超时退出
  55.         }                          
  56.         SPI2->DR=TxData;                                   //发送一个byte
  57.         retry=0;
  58.         while((SPI2->SR&1<<0)==0)                 //等待接收完一个byte  
  59.         {
  60.                 retry++;
  61.                 if(retry>=0XFFFE)return 0;        //超时退出
  62.         }                                                              
  63.         return SPI2->DR;                          //返回收到的数据                           
  64. }



复制代码
rc522.h
  1. #ifndef _RC522_H_
  2. #define _RC522_H_

  3. #include <stm32f10x.h>
  4. #include "sys.h"
  5. #include "spi.h"


  6. extern u8 CupType;


  7. /////////////////////////////////////////////////////////////////////
  8. //MF522命令字
  9. /////////////////////////////////////////////////////////////////////
  10. #define PCD_IDLE              0x00               //取消当前命令
  11. #define PCD_AUTHENT           0x0E               //验证密钥
  12. #define PCD_RECEIVE           0x08               //接收数据
  13. #define PCD_TRANSMIT          0x04               //发送数据
  14. #define PCD_TRANSCEIVE        0x0C               //发送并接收数据
  15. #define PCD_RESETPHASE        0x0F               //复位
  16. #define PCD_CALCCRC           0x03               //CRC计算

  17. /////////////////////////////////////////////////////////////////////
  18. //Mifare_One卡片命令字
  19. /////////////////////////////////////////////////////////////////////
  20. #define PICC_REQIDL           0x26               //寻天线区内未进入休眠状态
  21. #define PICC_REQALL           0x52               //寻天线区内全部卡
  22. #define PICC_ANTICOLL1        0x93               //防冲撞
  23. #define PICC_ANTICOLL2        0x95               //防冲撞
  24. #define PICC_AUTHENT1A        0x60               //验证A密钥
  25. #define PICC_AUTHENT1B        0x61               //验证B密钥
  26. #define PICC_READ             0x30               //读块
  27. #define PICC_WRITE            0xA0               //写块
  28. #define PICC_DECREMENT        0xC0               //扣款
  29. #define PICC_INCREMENT        0xC1               //充值
  30. #define PICC_RESTORE          0xC2               //调块数据到缓冲区
  31. #define PICC_TRANSFER         0xB0               //保存缓冲区中数据
  32. #define PICC_HALT             0x50               //休眠

  33. /////////////////////////////////////////////////////////////////////
  34. //MF522 FIFO长度定义
  35. /////////////////////////////////////////////////////////////////////
  36. #define DEF_FIFO_LENGTH       64                 //FIFO size=64byte
  37. #define MAXRLEN  18

  38. /////////////////////////////////////////////////////////////////////
  39. //MF522寄存器定义
  40. /////////////////////////////////////////////////////////////////////
  41. // PAGE 0
  42. #define     RFU00                 0x00   
  43. #define     CommandReg            0x01   
  44. #define     ComIEnReg             0x02   
  45. #define     DivlEnReg             0x03   
  46. #define     ComIrqReg             0x04   
  47. #define     DivIrqReg             0x05
  48. #define     ErrorReg              0x06   
  49. #define     Status1Reg            0x07   
  50. #define     Status2Reg            0x08   
  51. #define     FIFODataReg           0x09
  52. #define     FIFOLevelReg          0x0A
  53. #define     WaterLevelReg         0x0B
  54. #define     ControlReg            0x0C
  55. #define     BitFramingReg         0x0D
  56. #define     CollReg               0x0E
  57. #define     RFU0F                 0x0F
  58. // PAGE 1     
  59. #define     RFU10                 0x10
  60. #define     ModeReg               0x11
  61. #define     TxModeReg             0x12
  62. #define     RxModeReg             0x13
  63. #define     TxControlReg          0x14
  64. #define     TxAutoReg             0x15
  65. #define     TxSelReg              0x16
  66. #define     RxSelReg              0x17
  67. #define     RxThresholdReg        0x18
  68. #define     DemodReg              0x19
  69. #define     RFU1A                 0x1A
  70. #define     RFU1B                 0x1B
  71. #define     MifareReg             0x1C
  72. #define     RFU1D                 0x1D
  73. #define     RFU1E                 0x1E
  74. #define     SerialSpeedReg        0x1F
  75. // PAGE 2   
  76. #define     RFU20                 0x20  
  77. #define     CRCResultRegM         0x21
  78. #define     CRCResultRegL         0x22
  79. #define     RFU23                 0x23
  80. #define     ModWidthReg           0x24
  81. #define     RFU25                 0x25
  82. #define     RFCfgReg              0x26
  83. #define     GsNReg                0x27
  84. #define     CWGsCfgReg            0x28
  85. #define     ModGsCfgReg           0x29
  86. #define     TModeReg              0x2A
  87. #define     TPrescalerReg         0x2B
  88. #define     TReloadRegH           0x2C
  89. #define     TReloadRegL           0x2D
  90. #define     TCounterValueRegH     0x2E
  91. #define     TCounterValueRegL     0x2F
  92. // PAGE 3      
  93. #define     RFU30                 0x30
  94. #define     TestSel1Reg           0x31
  95. #define     TestSel2Reg           0x32
  96. #define     TestPinEnReg          0x33
  97. #define     TestPinValueReg       0x34
  98. #define     TestBusReg            0x35
  99. #define     AutoTestReg           0x36
  100. #define     VersionReg            0x37
  101. #define     AnalogTestReg         0x38
  102. #define     TestDAC1Reg           0x39  
  103. #define     TestDAC2Reg           0x3A   
  104. #define     TestADCReg            0x3B   
  105. #define     RFU3C                 0x3C   
  106. #define     RFU3D                 0x3D   
  107. #define     RFU3E                 0x3E   
  108. #define     RFU3F                                          0x3F

  109. /////////////////////////////////////////////////////////////////////
  110. //和MF522通讯时返回的错误代码
  111. /////////////////////////////////////////////////////////////////////
  112. #define         MI_OK                 0
  113. #define         MI_NOTAGERR           1
  114. #define         MI_ERR                2

  115. #define        SHAQU1        0X01
  116. #define        KUAI4        0X04
  117. #define        KUAI7        0X07
  118. #define        REGCARD        0xa1
  119. #define        CONSUME        0xa2
  120. #define READCARD        0xa3
  121. #define ADDMONEY        0xa4

  122. //
  123. //#define  spi_cs 1;
  124. //sbit  spi_ck=P0^6;
  125. //sbit  spi_mosi=P0^7;
  126. //sbit  spi_miso=P4^1;
  127. //sbit  spi_rst=P2^7;
  128. #define SPIReadByte()        SPIWriteByte(0)
  129. //u8 SPIWriteByte(u8 byte);
  130. //void SPI2_Init(void);


  131. //#define MYRC522_CS   PAout(4)
  132. //#define MYRC522_RST  PAout(6)



  133. void InitRc522(void);
  134. void ClearBitMask(u8   reg,u8   mask);
  135. void WriteRawRC(u8   Address, u8   value);
  136. void SetBitMask(u8   reg,u8   mask);
  137. char PcdComMF522(u8   Command,
  138.                  u8 *pIn ,
  139.                  u8   InLenByte,
  140.                  u8 *pOut ,
  141.                  u8  *pOutLenBit);
  142. void CalulateCRC(u8 *pIn ,u8   len,u8 *pOut );
  143. u8 ReadRawRC(u8   Address);
  144. void PcdAntennaOn(void);

  145. char PcdReset(void);
  146. char PcdRequest(unsigned char req_code,unsigned char *pTagType);
  147. void PcdAntennaOn(void);
  148. void PcdAntennaOff(void);
  149. char M500PcdConfigISOType(unsigned char type);
  150. char PcdAnticoll(unsigned char *pSnr);
  151. char PcdSelect(unsigned char *pSnr);
  152. char PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr);
  153. char PcdWrite(unsigned char addr,unsigned char *pData);
  154. char PcdRead(unsigned char addr,unsigned char *pData);
  155. char PcdHalt(void);
  156. void Reset_RC522(void);
  157. u8 RfidTest(void);
  158. u8 ReadCupType(void);
  159. u8 WriteCupType1(void);
  160. u8 WriteCupType2(void);

  161. #endif
复制代码
rc522.c
  1. #include "sys.h"
  2. #include "delay.h"
  3. #include "rc522.h"
  4. #include  <stdio.h>
  5. #include  <string.h>
  6. #include  <ctype.h>
  7. #include  <stdlib.h>
  8. #include  <stdarg.h>
  9. #include  <math.h>

  10. u8 CupType;

  11. /*0扇区的第0块是不能写的,只能读,前4字节是卡片ID*/
  12. /*块3前6字节是A密钥,中间4字节是控制块,后6字节是B密钥*/
  13. /*扇区0:0-3块  扇区1:4-7块  扇区2:8-11块  扇区3:12-15块*/
  14. /*3、7、11、15块存储密钥*/
  15. void delay_ns(u32 ns)
  16. {
  17.   u32 i;
  18.   for(i=0;i<ns;i++)
  19.   {
  20.     __nop();
  21.     __nop();
  22.     __nop();
  23.     __nop();
  24.     __nop();               
  25.   }
  26. }


  27. void InitRc522(void)
  28. {
  29.   SPI2_Init();
  30.   PcdReset();
  31.   PcdAntennaOff();  
  32.   PcdAntennaOn();
  33.   M500PcdConfigISOType( 'A' );
  34. }

  35. void Reset_RC522(void)
  36. {
  37.         PcdReset();
  38.   PcdAntennaOff();  
  39.   PcdAntennaOn();
  40. }                        
  41. /////////////////////////////////////////////////////////////////////
  42. //功    能:寻卡
  43. //参数说明: req_code[IN]:寻卡方式
  44. //                0x52 = 寻感应区内所有符合14443A标准的卡
  45. //                0x26 = 寻未进入休眠状态的卡
  46. //          pTagType[OUT]:卡片类型代码
  47. //                0x4400 = Mifare_UltraLight
  48. //                0x0400 = Mifare_One(S50)
  49. //                0x0200 = Mifare_One(S70)
  50. //                0x0800 = Mifare_Pro(X)
  51. //                0x4403 = Mifare_DESFire
  52. //返    回: 成功返回MI_OK
  53. /////////////////////////////////////////////////////////////////////
  54. char PcdRequest(u8   req_code,u8 *pTagType)
  55. {
  56.         char   status;  
  57.         u8   unLen;
  58.         u8   ucComMF522Buf[MAXRLEN];

  59.         ClearBitMask(Status2Reg,0x08);
  60.         WriteRawRC(BitFramingReg,0x07);
  61.         SetBitMask(TxControlReg,0x03);

  62.         ucComMF522Buf[0] = req_code;

  63.         status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen);

  64.         if ((status == MI_OK) && (unLen == 0x10))
  65.         {   
  66.                 *pTagType     = ucComMF522Buf[0];
  67.                 *(pTagType+1) = ucComMF522Buf[1];
  68.         }
  69.         else
  70.         {   status = MI_ERR;   }
  71.    
  72.         return status;
  73. }

  74. /////////////////////////////////////////////////////////////////////
  75. //功    能:防冲撞
  76. //参数说明: pSnr[OUT]:卡片序列号,4字节
  77. //返    回: 成功返回MI_OK
  78. /////////////////////////////////////////////////////////////////////  
  79. char PcdAnticoll(u8 *pSnr)
  80. {
  81.     char   status;
  82.     u8   i,snr_check=0;
  83.     u8   unLen;
  84.     u8   ucComMF522Buf[MAXRLEN];
  85.    

  86.     ClearBitMask(Status2Reg,0x08);
  87.     WriteRawRC(BitFramingReg,0x00);
  88.     ClearBitMask(CollReg,0x80);

  89.     ucComMF522Buf[0] = PICC_ANTICOLL1;
  90.     ucComMF522Buf[1] = 0x20;

  91.     status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen);

  92.     if (status == MI_OK)
  93.     {
  94.              for (i=0; i<4; i++){   
  95.              *(pSnr+i)  = ucComMF522Buf[i];
  96.              snr_check ^= ucComMF522Buf[i];
  97.         }
  98.          if (snr_check != ucComMF522Buf[i]){   
  99.                                       status = MI_ERR;   
  100.                                  }
  101.     }
  102.    
  103.     SetBitMask(CollReg,0x80);
  104.     return status;
  105. }

  106. /////////////////////////////////////////////////////////////////////
  107. //功    能:选定卡片
  108. //参数说明: pSnr[IN]:卡片序列号,4字节
  109. //返    回: 成功返回MI_OK
  110. /////////////////////////////////////////////////////////////////////
  111. char PcdSelect(u8 *pSnr)
  112. {
  113.     char   status;
  114.     u8   i;
  115.     u8   unLen;
  116.     u8   ucComMF522Buf[MAXRLEN];
  117.    
  118.     ucComMF522Buf[0] = PICC_ANTICOLL1;
  119.     ucComMF522Buf[1] = 0x70;
  120.     ucComMF522Buf[6] = 0;
  121.     for (i=0; i<4; i++)
  122.     {
  123.             ucComMF522Buf[i+2] = *(pSnr+i);
  124.             ucComMF522Buf[6]  ^= *(pSnr+i);
  125.     }
  126.     CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]);
  127.   
  128.     ClearBitMask(Status2Reg,0x08);

  129.     status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);
  130.    
  131.     if ((status == MI_OK) && (unLen == 0x18))
  132.     {   status = MI_OK;  }
  133.     else
  134.     {   status = MI_ERR;    }

  135.     return status;
  136. }

  137. /////////////////////////////////////////////////////////////////////
  138. //功    能:验证卡片密码
  139. //参数说明: auth_mode[IN]: 密码验证模式
  140. //                 0x60 = 验证A密钥
  141. //                 0x61 = 验证B密钥
  142. //          addr[IN]:块地址
  143. //          pKey[IN]:密码
  144. //          pSnr[IN]:卡片序列号,4字节
  145. //返    回: 成功返回MI_OK
  146. /////////////////////////////////////////////////////////////////////               
  147. char PcdAuthState(u8   auth_mode,u8   addr,u8 *pKey,u8 *pSnr)
  148. {
  149.     char   status;
  150.     u8   unLen;
  151.     u8   ucComMF522Buf[MAXRLEN];

  152.     ucComMF522Buf[0] = auth_mode;
  153.     ucComMF522Buf[1] = addr;
  154.     memcpy(&ucComMF522Buf[2], pKey, 6);
  155.     memcpy(&ucComMF522Buf[8], pSnr, 4);
  156.    
  157.     status = PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen);
  158.     if ((status != MI_OK) || (!(ReadRawRC(Status2Reg) & 0x08)))
  159.     {   status = MI_ERR;   }
  160.    
  161.     return status;
  162. }

  163. /////////////////////////////////////////////////////////////////////
  164. //功    能:读取M1卡一块数据
  165. //参数说明: addr[IN]:块地址
  166. //          p [OUT]:读出的数据,16字节
  167. //返    回: 成功返回MI_OK
  168. /////////////////////////////////////////////////////////////////////
  169. char PcdRead(u8   addr,u8 *p )
  170. {
  171.     char   status;
  172.     u8   unLen;
  173.     u8   i,ucComMF522Buf[MAXRLEN];

  174.     ucComMF522Buf[0] = PICC_READ;
  175.     ucComMF522Buf[1] = addr;
  176.     CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
  177.    
  178.     status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
  179.           if ((status == MI_OK) && (unLen == 0x90))
  180.     {
  181.         for (i=0; i<16; i++)
  182.         {    *(p +i) = ucComMF522Buf[i];   }
  183.     }
  184.     else
  185.     {   status = MI_ERR;   }
  186.    
  187.     return status;
  188. }

  189. /////////////////////////////////////////////////////////////////////
  190. //功    能:写数据到M1卡一块
  191. //参数说明: addr[IN]:块地址
  192. //          p [IN]:写入的数据,16字节
  193. //返    回: 成功返回MI_OK       /*读01扇区数据,改密码只能写3、7、11、15扇区*/
  194. /////////////////////////////////////////////////////////////////////                  
  195. char PcdWrite(u8   addr,u8 *p )
  196. {
  197.     char   status;
  198.     u8   unLen;
  199.     u8   i,ucComMF522Buf[MAXRLEN];
  200.    
  201.     ucComMF522Buf[0] = PICC_WRITE;
  202.     ucComMF522Buf[1] = addr;
  203.     CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);

  204.     status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);

  205.     if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
  206.     {   status = MI_ERR;   }
  207.         
  208.     if (status == MI_OK)
  209.     {
  210.         //memcpy(ucComMF522Buf, p , 16);
  211.         for (i=0; i<16; i++)
  212.         {   
  213.                 ucComMF522Buf[i] = *(p +i);   
  214.         }
  215.         CalulateCRC(ucComMF522Buf,16,&ucComMF522Buf[16]);

  216.         status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,18,ucComMF522Buf,&unLen);
  217.         if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
  218.         {   status = MI_ERR;   }
  219.     }
  220.    
  221.     return status;
  222. }

  223. /////////////////////////////////////////////////////////////////////
  224. //功    能:命令卡片进入休眠状态
  225. //返    回: 成功返回MI_OK
  226. /////////////////////////////////////////////////////////////////////
  227. char PcdHalt(void)
  228. {
  229.     uint8_t   status;
  230.     uint8_t   unLen;
  231.     uint8_t   ucComMF522Buf[MAXRLEN];

  232.     ucComMF522Buf[0] = PICC_HALT;
  233.     ucComMF522Buf[1] = 0;
  234.     CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);

  235.     status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);

  236.     return status;
  237. }

  238. /////////////////////////////////////////////////////////////////////
  239. //用MF522计算CRC16函数
  240. /////////////////////////////////////////////////////////////////////
  241. void CalulateCRC(u8 *pIn ,u8   len,u8 *pOut )
  242. {
  243.     u8   i,n;
  244.     ClearBitMask(DivIrqReg,0x04);
  245.     WriteRawRC(CommandReg,PCD_IDLE);
  246.     SetBitMask(FIFOLevelReg,0x80);
  247.     for (i=0; i<len; i++)
  248.     {   WriteRawRC(FIFODataReg, *(pIn +i));   }
  249.     WriteRawRC(CommandReg, PCD_CALCCRC);
  250.     i = 0xFF;
  251.     do
  252.     {
  253.         n = ReadRawRC(DivIrqReg);
  254.         i--;
  255.     }
  256.     while ((i!=0) && !(n&0x04));
  257.     pOut [0] = ReadRawRC(CRCResultRegL);
  258.     pOut [1] = ReadRawRC(CRCResultRegM);
  259. }

  260. /////////////////////////////////////////////////////////////////////
  261. //功    能:复位RC522
  262. //返    回: 成功返回MI_OK
  263. /////////////////////////////////////////////////////////////////////
  264. char PcdReset(void)
  265. {
  266.          
  267.           RC522_RST=1;
  268.     delay_ns(1000);
  269.           RC522_RST=0;
  270.     delay_ns(1000);
  271.           RC522_RST=1;
  272.     delay_ns(1000);
  273.     WriteRawRC(CommandReg,PCD_RESETPHASE);
  274.     delay_ns(1000);
  275.    
  276.     WriteRawRC(ModeReg,0x3D);            //和Mifare卡通讯,CRC初始值0x6363
  277.     WriteRawRC(TReloadRegL,30);           
  278.     WriteRawRC(TReloadRegH,0);
  279.     WriteRawRC(TModeReg,0x8D);
  280.     WriteRawRC(TPrescalerReg,0x3E);
  281.         
  282.           WriteRawRC(TxAutoReg,0x40);       //
  283. //WriteRawRC(ComIEnReg,0x20);        
  284. //WriteRawRC(DivlEnReg,0x90);        
  285.    
  286.     return MI_OK;
  287. }
  288. //////////////////////////////////////////////////////////////////////
  289. //设置RC632的工作方式
  290. //////////////////////////////////////////////////////////////////////
  291. char M500PcdConfigISOType(u8   type)
  292. {
  293.    if (type == 'A')                     //ISO14443_A
  294.    {
  295.        ClearBitMask(Status2Reg,0x08);
  296.        WriteRawRC(ModeReg,0x3D);//3F
  297.        WriteRawRC(RxSelReg,0x86);//84
  298.        WriteRawRC(RFCfgReg,0x7F);   //4F
  299.               WriteRawRC(TReloadRegL,30);//tmoLength);// TReloadVal = 'h6a =tmoLength(dec)
  300.              WriteRawRC(TReloadRegH,0);
  301.        WriteRawRC(TModeReg,0x8D);
  302.              WriteRawRC(TPrescalerReg,0x3E);
  303.              delay_ns(1000);
  304.        PcdAntennaOn();
  305.    }
  306.    else{ return 1; }
  307.    
  308.    return MI_OK;
  309. }
  310. /////////////////////////////////////////////////////////////////////
  311. //功    能:读RC632寄存器
  312. //参数说明:Address[IN]:寄存器地址
  313. //返    回:读出的值
  314. /////////////////////////////////////////////////////////////////////
  315. u8 ReadRawRC(u8   Address)
  316. {
  317.     u8   ucAddr;
  318.     u8   ucResult=0;
  319.           RC522_CS=0;
  320.     ucAddr = ((Address<<1)&0x7E)|0x80;
  321.         
  322.          SPIWriteByte(ucAddr);
  323.          ucResult=SPIReadByte();
  324.          RC522_CS=1;
  325.    return ucResult;
  326. }

  327. /////////////////////////////////////////////////////////////////////
  328. //功    能:写RC632寄存器
  329. //参数说明:Address[IN]:寄存器地址
  330. //          value[IN]:写入的值
  331. /////////////////////////////////////////////////////////////////////
  332. void WriteRawRC(u8   Address, u8   value)
  333. {  
  334.     u8   ucAddr;

  335.           RC522_CS=0;
  336.     ucAddr = ((Address<<1)&0x7E);

  337.          SPIWriteByte(ucAddr);
  338.          SPIWriteByte(value);
  339.          RC522_CS=1;
  340. }
  341. /////////////////////////////////////////////////////////////////////
  342. //功    能:置RC522寄存器位
  343. //参数说明:reg[IN]:寄存器地址
  344. //          mask[IN]:置位值
  345. /////////////////////////////////////////////////////////////////////
  346. void SetBitMask(u8   reg,u8   mask)  
  347. {
  348.     char   tmp = 0x0;
  349.     tmp = ReadRawRC(reg);
  350.     WriteRawRC(reg,tmp | mask);  // set bit mask
  351. }

  352. /////////////////////////////////////////////////////////////////////
  353. //功    能:清RC522寄存器位
  354. //参数说明:reg[IN]:寄存器地址
  355. //          mask[IN]:清位值
  356. /////////////////////////////////////////////////////////////////////
  357. void ClearBitMask(u8   reg,u8   mask)  
  358. {
  359.     char   tmp = 0x0;
  360.     tmp = ReadRawRC(reg);
  361.     WriteRawRC(reg, tmp & ~mask);  // clear bit mask
  362. }

  363. /////////////////////////////////////////////////////////////////////
  364. //功    能:通过RC522和ISO14443卡通讯
  365. //参数说明:Command[IN]:RC522命令字
  366. //          pIn [IN]:通过RC522发送到卡片的数据
  367. //          InLenByte[IN]:发送数据的字节长度
  368. //          pOut [OUT]:接收到的卡片返回数据
  369. //          *pOutLenBit[OUT]:返回数据的位长度
  370. /////////////////////////////////////////////////////////////////////
  371. char PcdComMF522(u8   Command,
  372.                  u8 *pIn ,
  373.                  u8   InLenByte,
  374.                  u8 *pOut ,
  375.                  u8 *pOutLenBit)
  376. {
  377.     char   status = MI_ERR;
  378.     u8   irqEn   = 0x00;
  379.     u8   waitFor = 0x00;
  380.     u8   lastBits;
  381.     u8   n;
  382.     long   i;
  383.     switch (Command){
  384.     case PCD_AUTHENT:
  385.                            irqEn   = 0x12;
  386.                            waitFor = 0x10;
  387.                            break;
  388.                 case PCD_TRANSCEIVE:
  389.                           irqEn   = 0x77;
  390.                           waitFor = 0x30;
  391.                           break;
  392.                 default:
  393.                         break;
  394.     }
  395.    
  396.     WriteRawRC(ComIEnReg,irqEn|0x80);
  397.     ClearBitMask(ComIrqReg,0x80);        //清所有中断位
  398.     WriteRawRC(CommandReg,PCD_IDLE);
  399.     SetBitMask(FIFOLevelReg,0x80);                 //清FIFO缓存
  400.    
  401.     for (i=0; i<InLenByte; i++){   
  402.                 WriteRawRC(FIFODataReg, pIn [i]);   
  403.                 }
  404.     WriteRawRC(CommandReg, Command);         
  405.    
  406.     if (Command == PCD_TRANSCEIVE){   
  407.                     SetBitMask(BitFramingReg,0x80);
  408.                  }         //开始传送
  409.                                                                                     
  410.     //i = 600;//根据时钟频率调整,操作M1卡最大等待时间25ms
  411.           i = 100000;
  412.     do
  413.     {
  414.         n = ReadRawRC(ComIrqReg);
  415.         i--;
  416.     }while ((i!=0) && !(n&0x01) && !(n&waitFor));
  417.     ClearBitMask(BitFramingReg,0x80);

  418.     if (i!=0){   
  419.         if(!(ReadRawRC(ErrorReg)&0x1B)){
  420.             status = MI_OK;
  421.             if (n & irqEn & 0x01){   
  422.                                                     status = MI_NOTAGERR;
  423.                                                 }
  424.             if (Command == PCD_TRANSCEIVE){
  425.                        n = ReadRawRC(FIFOLevelReg);
  426.                       lastBits = ReadRawRC(ControlReg) & 0x07;
  427.                 if (lastBits){  
  428.                                                                    *pOutLenBit = (n-1)*8 + lastBits;  
  429.                                                                 }else{  
  430.                                                                    *pOutLenBit = n*8;   
  431.                                                                 }
  432.                 if (n == 0){   
  433.                                                                     n = 1;   
  434.                                                                 }
  435.                 if (n > MAXRLEN){  
  436.                                                          n = MAXRLEN;   
  437.                                                                  }
  438.                 for (i=0; i<n; i++){   
  439.                                                                     pOut [i] = ReadRawRC(FIFODataReg);  
  440.                                                                 }
  441.             }
  442.         }else{   
  443.                                      status = MI_ERR;  
  444.                                  }
  445.         
  446.     }
  447.     SetBitMask(ControlReg,0x80);           // stop timer now
  448.     WriteRawRC(CommandReg,PCD_IDLE);
  449.     return status;
  450. }

  451. /////////////////////////////////////////////////////////////////////
  452. //开启天线  
  453. //每次启动或关闭天险发射之间应至少有1ms的间隔
  454. /////////////////////////////////////////////////////////////////////
  455. void PcdAntennaOn(void)
  456. {
  457.     u8   i;
  458.     i = ReadRawRC(TxControlReg);
  459.     if (!(i & 0x03)){
  460.         SetBitMask(TxControlReg, 0x03);
  461.     }
  462. }


  463. /////////////////////////////////////////////////////////////////////
  464. //关闭天线
  465. /////////////////////////////////////////////////////////////////////
  466. void PcdAntennaOff(void)
  467. {
  468.         ClearBitMask(TxControlReg, 0x03);
  469. }
  470. extern unsigned char CT[2];//卡类型
  471. extern unsigned char SN[4]; //卡号
  472. extern unsigned char pptr[64];
  473. extern unsigned char KEY[6];


  474. u8 RfidTest(void)
  475. {
  476.         static u8 oncnt;
  477.         static u16 allcnt;
  478.         static u8 res=1;
  479.         u8 status;
  480.         allcnt++;                                                 /*未明确什么含义 RF卡扫描次数?*/
  481.         if(PcdRequest(PICC_REQALL,CT)==0)                         /*扫描卡*/
  482.         {
  483.                 status = PcdAnticoll(SN);                             /*防冲撞--获取卡号*/
  484.                 status = PcdSelect(SN);                               /*根据卡号选择卡*/
  485.                 //1个扇区4个块 每个块16个字节 密码长度6个字节
  486.                 //块地址=扇区编号×4+扇区内的块编号 17 代表4扇区 块1
  487.                 //将保存在块地址17内的6个字节的密码与秘钥B进行比较
  488.                 //调用该函数需要选择密码验证是KEYA还是KEYB,
  489.                 //然后输入你要操作的块地址(想要读写的)()
  490.                 //存放密码数组和存放卡片序列号的数组。(感觉仅用来计算扇区)
  491.                 //验证成功后就可以对该块所在的扇区内所有的块进行操作了
  492.                 //读、写、加值、减值、转移、恢复)
  493.                 //KEYA KEYB 默认密码都是0XFF
  494.                 status = PcdAuthState(PICC_AUTHENT1B,17,KEY,SN);      /*解密:验证B密钥,密码所在地址 3-7-11-15-19*/
  495.                 status = PcdRead(17,pptr);                            /*读4扇区01块数据 返回16个字节数据*/
  496.                 if(status == MI_OK)  //5次以上成功
  497.                 {
  498.                         oncnt++;
  499.                         CupType = pptr[0];//茶杯类型在0位置
  500.                 }
  501.         }
  502.         if(allcnt>13)//检测13次
  503.         {
  504.                 if(oncnt>5)//5次以上成功
  505.                 {
  506.                         res= 0;
  507.                 }
  508.                 else
  509.                 {
  510.                         res = 1;
  511.                         CupType=0xff;
  512.                 }
  513.                 allcnt=0;oncnt=0;
  514.         }
  515.         return res;
  516. }
  517. /////////////////////////////////////////////////////////////////////
  518. //功    能:读取杯子类型
  519. //
  520. //返    回: 失败  返回0xff   型号一返回01    型号二返回02   空白卡返回00
  521. /////////////////////////////////////////////////////////////////////

  522. extern u8 CheckRFTime;
  523. u8 AllCnt=0;

  524. u8 ReadCupType(void)
  525. {
  526.         u8 status;  

  527.     AllCnt++;
  528.         /*无卡次数,也就是非MI_OK的次数*/
  529.         status = PcdRequest(PICC_REQALL,CT);                    /*扫描卡  0 OK  2失败*/
  530.         if(status==MI_OK)
  531.                 printf("寻卡状态:成功\r\n");
  532.         else
  533.         {
  534.                 printf("寻卡状态:失败\r\n");
  535.                 return 0XDF;
  536.         }
  537.                
  538.         status = PcdAnticoll(SN);                               /*防冲撞*/
  539.         if(status==MI_OK)
  540.                 printf("防冲撞:成功\r\n");
  541.         else
  542.         {
  543.                 printf("防冲撞:失败\r\n");
  544.                 return 0XDF;
  545.         }
  546.                
  547.         status = PcdSelect(SN);                                 /*选卡*/
  548.         if(status==MI_OK)
  549.                 printf("选卡:成功\r\n");
  550.         else
  551.         {
  552.                 printf("选卡:失败\r\n");
  553.                 return 0XDF;
  554.         }
  555.                
  556.         //PS:块地址17之前被强制性写入了杯子的型号(用另一个程序)
  557.         status = PcdAuthState(PICC_AUTHENT1A,17,KEY,SN);        
  558.         if(status==MI_OK)
  559.                 printf("密码校验:成功\r\n");
  560.         else
  561.         {
  562.                 printf("密码校验:失败\r\n");
  563.                 return 0XDF;               
  564.         
  565.         }
  566.                
  567.         status = PcdRead(17,pptr);
  568.         
  569.         if(status == MI_OK)
  570.         {
  571.                 return pptr[0];
  572.                         
  573.         }
  574.         else
  575.         {
  576.           return 0XEF;
  577.         }


  578. }

  579. /*写杯子类型1*/
  580. u8 WriteCupType1(void)
  581. {

  582.         u8 status;  
  583.         u8 CUP1KEY[16]={0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF};

  584.     AllCnt++;
  585.         /*无卡次数,也就是非MI_OK的次数*/
  586.         status = PcdRequest(PICC_REQALL,CT);                    /*扫描卡  0 OK  2失败*/
  587.         printf("%d%s",PICC_REQALL,CT);
  588.         if(status==MI_OK)
  589.                 printf("寻卡状态:成功\r\n");
  590.         else
  591.         {
  592.                 printf("寻卡状态:失败\r\n");
  593.                 return 0XDF;
  594.         }
  595.                
  596.         status = PcdAnticoll(SN);                               /*防冲撞*/
  597.         if(status==MI_OK)
  598.                 printf("防冲撞:成功\r\n");
  599.         else
  600.         {
  601.                 printf("防冲撞:失败\r\n");
  602.                 return 0XDF;
  603.         }
  604.                
  605.         status = PcdSelect(SN);                                 /*选卡*/
  606.         if(status==MI_OK)
  607.                 printf("选卡:成功\r\n");
  608.         else
  609.         {
  610.                 printf("选卡:失败\r\n");
  611.                 return 0XDF;
  612.         }
  613.                
  614.         //PS:块地址17之前被强制性写入了杯子的型号(用另一个程序)
  615.         status = PcdAuthState(PICC_AUTHENT1A,17,KEY,SN);        
  616.         if(status==MI_OK)
  617.                 printf("密码校验:成功\r\n");
  618.         else
  619.         {
  620.                 printf("密码校验:失败\r\n");
  621.                 return 0XDF;               
  622.         
  623.         }
  624.                
  625.         status = PcdWrite(17,CUP1KEY);
  626.         printf("%S",CUP1KEY);
  627.         if(status == MI_OK)
  628.         {
  629.                 return MI_OK;
  630.                         
  631.         }
  632.         else
  633.         {
  634.           return 0XEF;
  635.         }
  636. }
  637. /*写杯子类型2*/
  638. u8 WriteCupType2(void)
  639. {

  640.         u8 status;  
  641.         u8 CUP2KEY[16]={0X02,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF};

  642.     AllCnt++;
  643.         /*无卡次数,也就是非MI_OK的次数*/
  644.         status = PcdRequest(PICC_REQALL,CT);                    /*扫描卡  0 OK  2失败*/
  645.         if(status==MI_OK)
  646.                 printf("寻卡状态:成功\r\n");
  647.         else
  648.         {
  649.                 printf("寻卡状态:失败\r\n");
  650.                 return 0XDF;
  651.         }
  652.                
  653.         status = PcdAnticoll(SN);                               /*防冲撞*/
  654.         if(status==MI_OK)
  655.                 printf("防冲撞:成功\r\n");
  656.         else
  657.         {
  658.                 printf("防冲撞:失败\r\n");
  659.                 return 0XDF;
  660.         }
  661.                
  662.         status = PcdSelect(SN);                                 /*选卡*/
  663.         if(status==MI_OK)
  664.                 printf("选卡:成功\r\n");
  665.         else
  666.         {
  667.                 printf("选卡:失败\r\n");
  668.                 return 0XDF;
  669.         }
  670.                
  671.         //PS:块地址17之前被强制性写入了杯子的型号(用另一个程序)
  672.         status = PcdAuthState(PICC_AUTHENT1A,17,KEY,SN);        
  673.         if(status==MI_OK)
  674.                 printf("密码校验:成功\r\n");
  675.         else
  676.         {
  677.                 printf("密码校验:失败\r\n");
  678.                 return 0XDF;               
  679.         
  680.         }
  681.                
  682.         status = PcdWrite(17,CUP2KEY);
  683.         
  684.         if(status == MI_OK)
  685.         {
  686.                 return MI_OK;
  687.                         
  688.         }
  689.         else
  690.         {
  691.           return 0XEF;
  692.         }
  693. }

  694. /////////////////////////////////////////////////////////////////////
  695. //功    能:扣款和充值
  696. //参数说明: dd_mode[IN]:命令字
  697. //               0xC0 = 扣款
  698. //               0xC1 = 充值
  699. //          addr[IN]:钱包地址
  700. //          pValue[IN]:4字节增(减)值,低位在前
  701. //返    回: 成功返回MI_OK
  702. /////////////////////////////////////////////////////////////////////                 
  703. /*char PcdValue(u8 dd_mode,u8 addr,u8 *pValue)
  704. {
  705.     char status;
  706.     u8  unLen;
  707.     u8 ucComMF522Buf[MAXRLEN];
  708.     //u8 i;
  709.         
  710.     ucComMF522Buf[0] = dd_mode;
  711.     ucComMF522Buf[1] = addr;
  712.     CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);

  713.     status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);

  714.     if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
  715.     {   status = MI_ERR;   }
  716.         
  717.     if (status == MI_OK)
  718.     {
  719.         memcpy(ucComMF522Buf, pValue, 4);
  720.         //for (i=0; i<16; i++)
  721.         //{    ucComMF522Buf[i] = *(pValue+i);   }
  722.         CalulateCRC(ucComMF522Buf,4,&ucComMF522Buf[4]);
  723.         unLen = 0;
  724.         status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,6,ucComMF522Buf,&unLen);
  725.                 if (status != MI_ERR)
  726.         {    status = MI_OK;    }
  727.     }
  728.    
  729.     if (status == MI_OK)
  730.     {
  731.         ucComMF522Buf[0] = PICC_TRANSFER;
  732.         ucComMF522Buf[1] = addr;
  733.         CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
  734.    
  735.         status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);

  736.         if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
  737.         {   status = MI_ERR;   }
  738.     }
  739.     return status;
  740. }*/

  741. /////////////////////////////////////////////////////////////////////
  742. //功    能:备份钱包
  743. //参数说明: sourceaddr[IN]:源地址
  744. //          goaladdr[IN]:目标地址
  745. //返    回: 成功返回MI_OK
  746. /////////////////////////////////////////////////////////////////////
  747. /*char PcdBakValue(u8 sourceaddr, u8 goaladdr)
  748. {
  749.     char status;
  750.     u8  unLen;
  751.     u8 ucComMF522Buf[MAXRLEN];

  752.     ucComMF522Buf[0] = PICC_RESTORE;
  753.     ucComMF522Buf[1] = sourceaddr;
  754.     CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);

  755.     status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);

  756.     if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
  757.     {   status = MI_ERR;   }
  758.    
  759.     if (status == MI_OK)
  760.     {
  761.         ucComMF522Buf[0] = 0;
  762.         ucComMF522Buf[1] = 0;
  763.         ucComMF522Buf[2] = 0;
  764.         ucComMF522Buf[3] = 0;
  765.         CalulateCRC(ucComMF522Buf,4,&ucComMF522Buf[4]);

  766.         status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,6,ucComMF522Buf,&unLen);
  767.                 if (status != MI_ERR)
  768.         {    status = MI_OK;    }
  769.     }
  770.    
  771.     if (status != MI_OK)
  772.     {    return MI_ERR;   }
  773.    
  774.     ucComMF522Buf[0] = PICC_TRANSFER;
  775.     ucComMF522Buf[1] = goaladdr;

  776.     CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);

  777.     status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);

  778.     if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
  779.     {   status = MI_ERR;   }

  780.     return status;
  781. }*/
复制代码
通过串口来读写RF卡(仅块地址17):
指令:SS11PP  //查询杯子RFID型号
指令:SS22PP  //强制写杯子RFID卡为型号1
指令:SS22PP  //强制写杯子RFID卡为型号2

编译下载,通过串口操作(S50卡放读写模块上):
M9.png
好了,简单的分析就到这了~大神勿喷~感谢观看~
代码:
STM32F103RBT6_RC522_NFC_DEMO.rar (511.74 KB, 下载次数: 1)
1 收藏 评论0 发布时间:2021-9-14 14:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版