zoukankan      html  css  js  c++  java
  • STM32F407使用MFRC522射频卡调试及程序移植成功

     版权声明:转载请注明出处,谢谢 https://blog.csdn.net/Kevin_8_Lee/article/details/88865556

     或               https://www.cnblogs.com/kevin-nancy/p/10621205.html

     这两个平台都是我的个人博客

    基于STM32的MFRC522射频卡模块使用

    本学期感测技术选修课需要做一个作品出来,用到了MFRC522射频卡模块,经历一个星期的调试,终于可以正常使用并寻卡成功了了。  成功的把C51的程序移植到了STM32上面。  现在分享一下调试过程

    1、操作环境

    我所使用的是STM32F407的开发板,使用STM32CubeMX配置初始代码。    MFRC522使用软件模拟SPI通信

    2、 关于引脚的配置

    淘宝买来的模块,店家都会送资料 ,也可以点下面连接保存至网盘

    链接 :    https://pan.baidu.com/s/1JlNNIjtvHuRbVMSRZocHLA

    提取码:z119 

    1、SPI通信引脚

    1         NSS(SDA)       --------->> 片选信号
    2         SCK            --------->> 时钟信号
    3         MOSI           --------->> 信号输出端(即单片机引脚设置为输入,MFRC522该引脚输出)
    4         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!!!
    ");
    31   
    32   //  下面进行的是初始化
    33   PcdReset();
    34   PcdAntennaOff(); //关闭天线
    35   PcdAntennaOn();  //开启天线
    36   M500PcdConfigISOType('A');  // 选择工作方式
    37     
    38   printf("开始寻卡... ...
    ");
    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("
    卡的类型:");
    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 }

    其他的底层驱动函数就不需要改了,由于总的代码量比较长,我就只贴出关键的,其他不需要改的直接参考资料里面的例程即可
    我自己移植过来完整的有很多程序的注注释,有兴趣的可以下载一下,不过自己花时间看看数据手册打个注释是最好的

    点击这里下载完整移植驱动程序

    任何你的不足,在你成功地那一刻,都会被别人说成特色!!     加油吧

  • 相关阅读:
    【成本管理】成本核算
    CW23:Work Log
    SQLSERVER数据库连接
    Oracle 创建用户 修改用户密码 授权命令
    CW24:WORK LOG
    ORA12560: TNS: 协议适配器错误的解决方法
    需求工程概述
    日语学习1:送气音和不送气音
    junit测试框架简单应用
    Java之Socket编程
  • 原文地址:https://www.cnblogs.com/kevin-nancy/p/10621205.html
Copyright © 2011-2022 走看看