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

2020-05-22来源: eefocus关键字:STM32F407  MFRC522  射频卡  程序移植

本学期感测技术选修课需要做一个作品出来,用到了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;

}


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


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

关键字:STM32F407  MFRC522  射频卡  程序移植 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic497983.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:STM32f407---oled屏幕配套取字模软件使用
下一篇:STM32之寄存器开发

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

CubeMX Stm32F407 生成一定周期的占空比不同的方波 DMA + 定时器
先上图如图 是我生成的一个波形  这个波形的占空比在连续的四个周期内分别是10%,20%,30%,40%, 并且按照这个顺序循环这里大致介绍一下实现的方式。使用的软件是Cubemx(库函肯定也可以实现)第一步是器件选型  这一部分不做介绍  用的是Stm32F407第二是时钟配置接下来是定时器配置 第三步就是生成代码了这里 需要在生成的代码里面加上一行开始的代码。
发表于 2020-04-14
CubeMX Stm32F407 生成一定周期的占空比不同的方波 DMA + 定时器
基于Stm32F407的任意波形发生器
今天跟大家分享一个DAC转换的例子:先来效果图示波器使用的是Loto示波器OSC802三角波20KHz示例三角波20KHz示例正弦波20KHz示例测试使用的是Loto虚拟示波器   以上两张图的波形每一个周期都是300个DAC点组成,DAC转换速度是3MHz具体的实现代码如下:主要是最下面的三个函数  一个是DAC的初始化函数,另一个是定时器4的初始化函数 最后一个是波形发生函数。这是DAC+DMA的初始化函数  这要是设置DAC和DMA的基本参数 DAC触发选择的是定时器4的触发引脚, 也可以换成以上的其他定时器接下来是定时器的初始化定时器初始化部分很简单,不需要配置IO 
发表于 2020-04-14
基于Stm32F407的任意波形发生器
基于STM32F407的 中景园0.96寸OLED(IIC)的程序升级
前天学习了韦东山老师的嵌入式linux教学的一期视频中关于LCD的刷新显示章节,对于显示的机制有了一些略微的理解,回想起来之前一直在用的OLED不禁想要去看看有没有人做过相应的程序,结果没有找到!于是自己做了一个底层的代码。还是老规矩先来展示效果图图片展示的是OLED 的显示数字和字符串,OLED屏幕的刷新频率达到了惊人的40Hz,而且几乎不占用 CPU时间(数据全部走DMA) 我的程序是基于其他大佬的硬件IIC和DMA程序改编的,程序的整体框架如下在编写用户程序之前 我需要先实现 单片机内存到 OLED内存的这个工作,这一部分我选择使用的是STM32F407的硬件IIC 集合DMA来实现的,虽然网上对STM32F407的硬件
发表于 2020-04-14
基于STM32F407的 中景园0.96寸OLED(IIC)的程序升级
基于Stm32F407的步进电机的速度控制方案------初步
这里跟大家分享一下我的步进电机的速度控制思路(最终初步解决了问题)这里我选择的是 Stm32F407 作为主控芯片,我的大致速度控制思路就是通过调整PSC 和ARR的值来实现对速度的控制。对应于我的代码的定时器框图如下(我用的是TIM14)为了实现修改定时器的频率我们需要修改对应的PSC和ARR的值、  这里的定时器模式我选择是PWM模式对应的定时器部分的初始化代码如下以上代码完成了定时器的IO复用和对应的时钟的初始化,这里我们不在赘述!  我们接下来就是需要通过修改 定时器对应的PSC和ARR值来实现对定时器输出的脉冲的频率进行调整所以我考虑的是 我们写一个数组,将不同的转速下对应的PSC和ARR值都分别写入
发表于 2020-04-14
基于Stm32F407的步进电机的速度控制方案------初步
基于Stm32F407的多路(6路)步进电机速度控制函数
应学弟们的要求特意将步进电机的速度控制函数完善。重点:这里只是速度控制函数, 没有加减速曲线! 没有记录步数!  只是简单的把步进电机当成直流电机用! 很初级的一个程序!程序的下载链接在这里 开发平台Keil5 单片机 Stm32F407接下来 我就程序的实现过程给大家进行分享   第一部分是实现的机制介绍  详细链接 在这里!主要就是通过修改 PSC和ARR寄存器的值,我们可以修改 定时器的溢出频率!而我们的定时器模式设置成 PWM输出模式, CCR寄存器 我们设置一个较小的值*(我们要控制脉冲的频率 ,所以单个脉冲的宽度是我们不关心的!)   修改了 PSC 和ARR
发表于 2020-04-14
基于Stm32F407的多路(6路)步进电机速度控制函数
Stm32F407控制直流减速编码电机--使用增量式速度PI
的是500线的光电编码器,控制相对于 12线磁编码器要简单很多,当然价格 贵不少。。。控制电机的速度,我们第一步肯定是要使用 PWM波,先使用Stm32F407 生成一个我们需要的 占空比可调的  频率 符合要求的方波信号。(此处注意,方波信号的频率不宜过高或者过低,过高容易导致电机驱动的晶闸管经常处于开关状态--发热巨大;过低则容易产生噪音,对电机也低频的冲击) 直接上代码!第一部分是产生 可控方波的代码程序大概就是这样的,这一部分很简单,只是简单的定时器的 输出配置第二部分是配置 一路编码器接口,我们的 Stm32F407的定时器 1 2 3 4 5 8 支持编码器的解码功能,本次比赛中我们的 定时器
发表于 2020-04-14
Stm32F407控制直流减速编码电机--使用增量式速度PI
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved