STM32
直播中

陈利妮

7年用户 1029经验值
私信 关注
[问答]

如何去使用基于STM32的MFRC522射频卡模块呢

如何对MFRC522射频卡模块进行调试呢?
如何去使用基于STM32的MFRC522射频卡模块呢?

回帖(1)

李高胜

2021-10-22 11:23:57
  基于STM32的MFRC522射频卡模块使用
  本学期感测技术选修课需要做一个作品出来,用到了MFRC522射频卡模块,经历一个星期的调试,终于可以正常使用并寻卡成功了了。 成功的把C51的程序移植到了STM32上面。 现在分享一下调试过程
  1、操作环境
  我所使用的是STM32F407的开发板,使用STM32CubeMX配置初始代码。 MFRC522使用软件模拟SPI通信
  2、 关于引脚的配置
  1、SPI通信引脚
  NSS(SDA) ---------》》 片选信号 SCK ---------》》 时钟信号 MOSI ---------》》 信号输出端(即单片机引脚设置为输入,MFRC522该引脚输出) MISO ---------》》 信号输入端
  
  (上图截图于数据手册,移植别人的程序最好看一下所使用的芯片的数据手册,很有用,方便自己理解程序)
  这里说明一下,在 MFRC522数据手册里面说了, MFRC522需要工作在从机模式下。 所以MFRC522这个模块就是从机(Slave),而所使用的单片机就是主机(Master) 这就是为什么上面的MOSI对应的单片机引脚要设置为输出,(Master Output Slave Input)
  MISO信号输入端是指的输入给单片机了
  2、 通信时序
  
  这是数据手册里面的,一定要注意时序的正确性
  片选信号在数据写入期间一定要保持低电平,而无数据时(即空闲状态)必须保持高电平
  强调:时序很重要
  时序出错,一切都白扯
  3、 程序流程
  
  下面我把我用STM32CubeMX的配置贴出来
  
  一定要注意按照这样配置,因为数据手册里面的时序要求是NSS(SDA)引脚默认状态必须是高电平,即1,所以IO口设置必须为High, 且上拉,其他引脚同理,只是不需要上拉了
  3、 下面先贴一下寻卡结果
  
  S50的卡是0x04000, 所以打印的就是40了
  主函数里面程序
  1 int main(void)
  2 {
  3 /* USER CODE BEGIN 1 */
  4 unsigned char status,i;
  5 unsigned int temp;
  6
  7 /* USER CODE END 1 */
  8
  9 /* MCU Configuration--------------------------------------------------------*/
  10
  11 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  12 HAL_Init();
  13
  14 /* USER CODE BEGIN Init */
  15
  16 /* USER CODE END Init */
  17
  18 /* Configure the system clock */
  19 SystemClock_Config();
  20
  21 /* USER CODE BEGIN SysInit */
  22
  23 /* USER CODE END SysInit */
  24
  25 /* Initialize all configured peripherals */
  26 MX_GPIO_Init();
  27 MX_USART1_UART_Init();
  28 /* USER CODE BEGIN 2 */
  29
  30 printf(“The USART Is Ok!!!rn”);
  31
  32 // 下面进行的是初始化
  33 PcdReset();
  34 PcdAntennaOff(); //关闭天线
  35 PcdAntennaOn(); //开启天线
  36 M500PcdConfigISOType(‘A’); // 选择工作方式
  37
  38 printf(“开始寻卡。.. 。..rn”);
  39 /* USER CODE END 2 */
  40
  41 /* Infinite loop */
  42 /* USER CODE BEGIN WHILE */
  43 while (1)
  44 {
  45 /* USER CODE END WHILE */
  46
  47 /* USER CODE BEGIN 3 */
  48
  49 status = PcdRequest(PICC_REQALL, g_ucTempbuf);//寻卡
  50 if (status == MI_ERR) // 如果寻卡失败,则重新初始化 然后continue 继续寻卡
  51 {
  52 PcdReset();
  53 PcdAntennaOff(); //关闭天线
  54 PcdAntennaOn(); //开启天线
  55 M500PcdConfigISOType(‘A’);
  56 continue;
  57 }
  58
  59 // 如果寻卡成功 则LED1闪烁 然后串口打印出来卡的类型
  60 HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
  61 HAL_Delay(10);
  62 HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);
  63 HAL_Delay(10);
  64 HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
  65 HAL_Delay(10);
  66 HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);
  67 HAL_Delay(10);
  68 printf(“rn卡的类型:”);
  69 for (i = 0; i 《 2; i++)
  70 {
  71 temp = g_ucTempbuf[i];
  72 printf(“%X”, temp);
  73 }
  74 //PcdHalt();
  75 }
  76 /* USER CODE END 3 */
  77 }
  下面是我移植的底层驱动程序,应该也是大部分人想要的吧,不过最好还是自己好好看看那手册改一下
  我只贴出有关SPI通讯的程序,其他部分跟我上面给出的网盘资料里面的C51例程是差不多的,通用
  1 /*******************************************************************
  2 @func : ReadRawRC
  3 @brief : 读RC632寄存器
  4 @pram : Address[IN]:寄存器地址
  5 @retval : 读出的值
  6 @NOTE : MFRC522数据手册.pdf 10.2是关于SPI的详细说明 10.2.2 Read data
  7 : unsigned char === uint8_t
  8 @Call : 内部调用
  9 *******************************************************************/
  10 unsigned char ReadRawRC(unsigned char Address)
  11 {
  12 unsigned char i, ucAddr;
  13 unsigned char ucResult=0;
  14
  15 HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_RESET);// MF522_NSS = 0;
  16 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);// MF522_SCK = 0;
  17
  18
  19 // 地址左移一位是因为LSB是要保留 即RFU位(Reserved for Future Use)
  20 // &0x7E 是把bit1~bit6 的地址(address)写入
  21 // |0x80 是为了使最高位为1 1(Read) 0(Write) 即使能 ‘读’
  22 ucAddr = ((Address《《1)&0x7E)|0x80;
  23
  24 for(i=8;i》0;i--)
  25 {
  26 if((ucAddr&0x80)==0x80)
  27 {
  28 HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_SET);
  29 }
  30 else
  31 {
  32 HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_RESET);
  33 }
  34 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);
  35 ucAddr 《《= 1;
  36 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);
  37
  38 }
  39
  40 for(i=8;i》0;i--)
  41 {
  42 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);
  43 ucResult 《《= 1;
  44 ucResult |= HAL_GPIO_ReadPin(MISO_GPIO_Port, MISO_Pin);
  45 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);
  46 // 有人说对于STM32这里需要加一句延时,这个是没必要的 这个我经过测试是可以使用的,不用延时
  47 }
  48
  49
  50 HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_SET);// MF522_NSS = 1;
  51 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);// MF522_SCK = 1;
  52
  53
  54 return ucResult;
  55 }
  56
  57
  58
  59 /*******************************************************************
  60 @func : WriteRawRC
  61 @brief : 写RC632寄存器
  62 @pram : Address[IN]:寄存器地址
  63 : value[IN]:写入的值
  64 @retval : None
  65 @Call : 内部调用
  66 *******************************************************************/
  67 void WriteRawRC(unsigned char Address, unsigned char value)
  68 {
  69 unsigned char i, ucAddr;
  70
  71 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);// MF522_SCK = 0;
  72 HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_RESET);// MF522_NSS = 0;
  73
  74 ucAddr = ((Address 《《 1) & 0x7E);
  75
  76 for(i=8;i》0;i--)
  77 {
  78 if ((ucAddr&0x80)==0x80)
  79 {
  80 HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_SET);
  81 }
  82 else
  83 {
  84 HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_RESET);
  85 }
  86 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);
  87 ucAddr 《《= 1;
  88 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);
  89 }
  90
  91
  92 for(i=8;i》0;i--)
  93 {
  94 // MF522_SI = ((value&0x80)==0x80);
  95 if ((value&0x80)==0x80)
  96 {
  97 HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_SET);
  98 }
  99 else
  100 {
  101 HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_RESET);
  102 }
  103 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);
  104 value 《《= 1;
  105 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);
  106 }
  107
  108
  109
  110
  111 HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_SET);// MF522_NSS = 1;
  112 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);// MF522_SCK = 1;
  113
  114 }
  复位函数
  1 /*******************************************************************
  2 @func : PcdReset
  3 @brief : 复位RC522
  4 @pram : None
  5 @retval : 成功返回MI_OK
  6 @NOTE : 外部调用
  7 *******************************************************************/
  8 char PcdReset(void)
  9 {
  10 /* MF522_RST=1; */
  11 HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_SET);
  12 HAL_Delay(10);
  13 /* MF522_RST=0; */
  14 HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_RESET);
  15 HAL_Delay(10);
  16 /* MF522_RST=1; */
  17 HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_SET);
  18 HAL_Delay(10);
  19 WriteRawRC(CommandReg,PCD_RESETPHASE); // 复位
  20 HAL_Delay(10);
  21
  22 WriteRawRC(ModeReg,0x3D); // 和Mifare卡通讯,CRC初始值0x6363
  23 WriteRawRC(TReloadRegL,30); // 16位定时器低位
  24 WriteRawRC(TReloadRegH,0); // 16位定时器高位
  25 WriteRawRC(TModeReg,0x8D); // 定时器内部设置
  26 WriteRawRC(TPrescalerReg,0x3E); // 定时器分频系数设置
  27 WriteRawRC(TxAutoReg, 0x40); // 调制发送信号为100%ASK 调试的时候加上这一句试试
  28 return MI_OK;
  29 }
  其他的底层驱动函数就不需要改了,由于总的代码量比较长,我就只贴出关键的,其他不需要改的直接参考资料里面的例程即可
  我自己移植过来完整的有很多程序的注注释,有兴趣的可以下载一下,不过自己花时间看看数据手册打个注释是最好的
  任何你的不足,在你成功地那一刻,都会被别人说成特色!! 加油吧
举报

更多回帖

发帖
×
20
完善资料,
赚取积分