单片机
返回首页

STM32F407使用MFRC522射频卡调试及程序移植成功

2020-05-22 来源:eefocus

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


1、操作环境

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

在这里插入图片描述

在这里插入图片描述

2、关于引脚的配置

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


链接:http://pan.baidu.com/s/1boMyMlx


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了

在这里插入图片描述

主函数里面程序


int main(void)

{

  /* USER CODE BEGIN 1 */

unsigned char status,i;

unsigned int temp;

  /* USER CODE END 1 */


  /* MCU Configuration--------------------------------------------------------*/


  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

  HAL_Init();


  /* USER CODE BEGIN Init */


  /* USER CODE END Init */


  /* Configure the system clock */

  SystemClock_Config();


  /* USER CODE BEGIN SysInit */


  /* USER CODE END SysInit */


  /* Initialize all configured peripherals */

  MX_GPIO_Init();

  MX_USART1_UART_Init();

  /* USER CODE BEGIN 2 */

  

  printf('The USART Is Ok!!!rn');

  

  //  下面进行的是初始化

  PcdReset();

  PcdAntennaOff(); //关闭天线

  PcdAntennaOn();  //开启天线

  M500PcdConfigISOType('A');  // 选择工作方式

  printf('开始寻卡... ...rn');

  /* USER CODE END 2 */


  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

    /* USER CODE END WHILE */


    /* USER CODE BEGIN 3 */

  

  status = PcdRequest(PICC_REQALL, g_ucTempbuf);//寻卡

  if (status == MI_ERR)     // 如果寻卡失败,则重新初始化 然后continue 继续寻卡

  {

  PcdReset();

  PcdAntennaOff(); //关闭天线

  PcdAntennaOn();  //开启天线

  M500PcdConfigISOType('A');

  continue;

  }  

  

  // 如果寻卡成功  则LED1闪烁   然后串口打印出来卡的类型

  HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);

  HAL_Delay(10);

  HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);

  HAL_Delay(10);

  HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);

  HAL_Delay(10);

  HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);

  HAL_Delay(10);

  printf('rn卡的类型:');

  for (i = 0; i < 2; i++)

  {

  temp = g_ucTempbuf[i];

  printf('%X', temp);

  }

  //PcdHalt();

  }

  /* USER CODE END 3 */

}


下面是我移植的底层驱动程序,应该也是大部分人想要的吧,不过最好还是自己好好看看那手册改一下


我只贴出有关SPI通讯的程序,其他部分跟我上面给出的网盘资料里面的C51例程是差不多的,通用


/*******************************************************************

 @func : ReadRawRC

 @brief : 读RC632寄存器

 @pram : Address[IN]:寄存器地址

 @retval : 读出的值

 @NOTE : MFRC522数据手册.pdf 10.2是关于SPI的详细说明   10.2.2 Read data

: unsigned char === uint8_t

 @Call : 内部调用

*******************************************************************/

unsigned char ReadRawRC(unsigned char Address) 

{

     unsigned char i, ucAddr;

     unsigned char ucResult=0;

   

HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_RESET);// MF522_NSS = 0;

HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);// MF522_SCK = 0;

 

 

// 地址左移一位是因为LSB是要保留 即RFU位(Reserved for Future Use)

// &0x7E 是把bit1~bit6 的地址(address)写入

// |0x80 是为了使最高位为1   1(Read) 0(Write) 即使能 '读'

     ucAddr = ((Address<<1)&0x7E)|0x80;

 

for(i=8;i>0;i--)

{

if((ucAddr&0x80)==0x80)

{

HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_SET);

}

else

{

HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_RESET);

}

HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);

ucAddr <<= 1;

HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);


}

 

for(i=8;i>0;i--)

{

HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);

ucResult <<= 1;

ucResult |= HAL_GPIO_ReadPin(MISO_GPIO_Port, MISO_Pin);

HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);

// 有人说对于STM32这里需要加一句延时,这个是没必要的  这个我经过测试是可以使用的,不用延时

}


      

     HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_SET);// MF522_NSS = 1;

HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);// MF522_SCK = 1; 

 

 

     return ucResult;

}




/*******************************************************************

 @func : WriteRawRC

 @brief : 写RC632寄存器

 @pram : Address[IN]:寄存器地址

: value[IN]:写入的值

 @retval : None

 @Call : 内部调用

*******************************************************************/

void WriteRawRC(unsigned char Address, unsigned char value)

{  

    unsigned char i, ucAddr;

HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);// MF522_SCK = 0;

HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_RESET);// MF522_NSS = 0;

ucAddr = ((Address << 1) & 0x7E);

for(i=8;i>0;i--)

{

if ((ucAddr&0x80)==0x80)

{

HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_SET);

}

else

{

HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_RESET);

}

HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);

ucAddr <<= 1;

HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);

}

    

for(i=8;i>0;i--)

{

// MF522_SI = ((value&0x80)==0x80);

if ((value&0x80)==0x80)

{

HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_SET);

}

else

{

HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_RESET);

}

HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);

value <<= 1;

HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);

}

    

 

HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_SET);// MF522_NSS = 1; 

HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);// MF522_SCK = 1;

}


复位函数


/*******************************************************************

 @func : PcdReset

 @brief : 复位RC522

 @pram : None

 @retval : 成功返回MI_OK

 @NOTE : 外部调用

*******************************************************************/

char PcdReset(void)

{

    /* MF522_RST=1; */

HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_SET);

    HAL_Delay(10);

    /* MF522_RST=0; */

HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_RESET);

    HAL_Delay(10);

    /* MF522_RST=1; */

HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_SET);

    HAL_Delay(10);

    WriteRawRC(CommandReg,PCD_RESETPHASE); // 复位

    HAL_Delay(10);

    

    WriteRawRC(ModeReg,0x3D);            // 和Mifare卡通讯,CRC初始值0x6363

WriteRawRC(TReloadRegL,30);      // 16位定时器低位

WriteRawRC(TReloadRegH,0); // 16位定时器高位

WriteRawRC(TModeReg,0x8D); // 定时器内部设置

WriteRawRC(TPrescalerReg,0x3E); // 定时器分频系数设置

WriteRawRC(TxAutoReg, 0x40); // 调制发送信号为100%ASK 调试的时候加上这一句试试

    return MI_OK;

}


其他的底层驱动函数就不需要改了,由于总的代码量比较长,我就只贴出关键的,其他不需要改的直接参考资料里面的例程即可


我自己移植过来完整的有很多程序的注注释,有兴趣的可以下载一下,不过自己花时间看看数据手册打个注释是最好的

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • PIC单片机控制的遥控防盗报警器电路

  • 红外线探测报警器

  • 短波AM发射器电路设计图

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 开关电源的基本组成及工作原理

  • 带有短路保护系统的5V直流稳压电源电路图

    相关电子头条文章