版权声明:转载请注明出处,谢谢 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通信引脚

         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!!!\r\n"); // 下面进行的是初始化
PcdReset();
PcdAntennaOff(); //关闭天线
PcdAntennaOn(); //开启天线
M500PcdConfigISOType('A'); // 选择工作方式 printf("开始寻卡... ...\r\n");
/* USER CODE END 2 */ /* Infinite loop */
/* USER CODE BEGIN WHILE */
while ()
{
/* 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();
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);
HAL_Delay();
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
HAL_Delay();
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);
HAL_Delay();
printf("\r\n卡的类型:");
for (i = ; i < ; 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=; 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<<)&0x7E)|0x80; for(i=;i>;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 <<= ;
HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET); } for(i=;i>;i--)
{
HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);
ucResult <<= ;
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 << ) & 0x7E); for(i=;i>;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 <<= ;
HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);
} for(i=;i>;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 <<= ;
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();
/* MF522_RST=0; */
HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_RESET);
HAL_Delay();
/* MF522_RST=1; */
HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_SET);
HAL_Delay();
WriteRawRC(CommandReg,PCD_RESETPHASE); // 复位
HAL_Delay(); WriteRawRC(ModeReg,0x3D); // 和Mifare卡通讯,CRC初始值0x6363
WriteRawRC(TReloadRegL,); // 16位定时器低位
WriteRawRC(TReloadRegH,); // 16位定时器高位
WriteRawRC(TModeReg,0x8D); // 定时器内部设置
WriteRawRC(TPrescalerReg,0x3E); // 定时器分频系数设置
WriteRawRC(TxAutoReg, 0x40); // 调制发送信号为100%ASK 调试的时候加上这一句试试
return MI_OK;
}

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

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

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

STM32F407使用MFRC522射频卡调试及程序移植成功的更多相关文章

  1. 015_STM32程序移植之_NRF24L01模块

    STM32程序移植之NRF24L01模块 引脚接线图如下所示 STM32引脚 NRF24L01引脚 功能 GND GND 3.3V 3.3V PB8 CE PB9 CSN PB13 SCK PB15 ...

  2. 射频识别技术漫谈(28)——基于MF1射频卡的酒店门锁设计

    电子门锁是现代星级酒店管理电子化.智能化的重要电子设备.相较于传统的机械锁,基于RFID技术的电子门锁使用方便,易于管理,安全性高,可实现对开锁用户的分优先级自动管理,对房间入住信息实现自动统计与报表 ...

  3. 动手实操丨RC522射频卡模块与IC卡完成充值消费查询的技术实现思路

    摘要:一文手把手教你利用RC522射频卡模块与IC卡完成充值消费查询的技术实现思路. 本文分享自华为云社区<​​​​​​​​​​​​​​RC522射频卡模块与IC卡完成充值消费查询的技术实现思路 ...

  4. 使用VS+VisualGDB编译调试Linux程序

    Linux程序开发变得越来越多,越来越多的程序.产品需要跨平台,甚至有些开源项目只支持Linux平台,所以掌握Linux开发变得越来越重要. 但是对于习惯了Windows下的开发,使用了VS这个宇宙第 ...

  5. 使用未付费的账号真机调试 iOS 程序,过几天后程序一打开就会闪退

    使用未付费的苹果开发者账号真机调试 iOS 程序,过几天后程序一打开就会闪退.   解决办法: 删除 Provisioning Profile,重新配置一次. 终极解决办法:花钱购买苹果开发者账号. ...

  6. Gdb调试多进程程序

    Gdb调试多进程程序 程序经常使用fork/exec创建多进程程序.多进程程序有自己独立的地址空间,这是多进程调试首要注意的地方.Gdb功能强大,对调试多线程提供很多支持. 方法1:调试多进程最土的办 ...

  7. 利用 PhpStorm、Idea 等 IDE 如何 运行/调试 Go 程序 ?

    以自己常用的 PhpStorm 为例 第一步:下载安装 Go插件 File -> Settings -> Plugins -> 输入关键字:Go 第二步:新建 Go项目 File - ...

  8. PDB调试Python程序

    pdb是python内置的调试工具, 它可以在终端中调试Python程序, 这允许pdb在很多无法安装IDE的服务器上使用. 虽然远程调试使用广泛, 但在必要的时候(比如难以在本地搭建运行环境)pdb ...

  9. VS2010 win7 QT4.8.0,实现VS2010编译调试Qt程序,QtCreator静态发布程序

    下载源代码,注意一定是源码压缩包如qt-everywhere-opensource-src-4.8.0.zip, 不是Qt发布的已编译的不同版本的标准库如qt-win-opensource-4.8.0 ...

随机推荐

  1. Android sutdio单元测试 简单使用步骤

    1.简介 单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证.比如一个函数,一个方法等 2.添加依赖 dependencies { testCompile 'junit: ...

  2. sql server 简单语句整合

    1.去重distinct , group by select distinct userid,username from 表名 select userid,username from 表名 group ...

  3. [转] MySQL索引原理

    MySQL索引原理 B+树索引是B+树在数据库中的一种实现,是最常见也是数据库中使用最为频繁的一种索引.B+树中的B代表平衡(balance),而不是二叉(binary),因为B+树是从最早的平衡二叉 ...

  4. linux chmod对文件权限的操作

    在Unix和Linux的各种操作系统下,每个文件(文件夹也被看作是文件)都按读.写.运行设定权限. 例如我用ls -l命令列文件表时,得到如下输出: -rw-r--r-- 1 apple users ...

  5. C# 接口(3)

    这么半天说了如何使用,实现接口.相信也都发现了接口和抽象类很多相似的地方. 但是! 这两个根本就是不一样的. 抽象类 :                                         ...

  6. iOS系统各个版本的占比查询

    目的:为了向大多数看齐,我们要实时了解应用系统的使用占比 1.苹果官网查询各个系统的占比: Apple 2.各种设备各种系统的占比 第三方

  7. npm更换为镜像

    背景:npm在安装的过程中需用从国外的网站获取代码,速度非常慢,因此更换为淘宝镜像,提升速度. 1.永久起作用: npm config set registry https://registry.ta ...

  8. 洛谷P3122 [USACO15FEB]圈住牛Fencing the Herd(计算几何+CDQ分治)

    题面 传送门 题解 题目转化一下就是所有点都在直线\(Ax+By-C=0\)的同一侧,也就可以看做所有点代入\(Ax+By-C\)之后的值符号相同,我们只要维护每一个点代入直线之后的最大值和最小值,看 ...

  9. Error creating bean with name 'dateSource' defined in file 错误信息

    问题的原因: 在web项目中搭建SSM框架,启动Tomcat时出现错误信息 有配置文件:applicationContext-mybatis.xml (Spring配置) spring-servlet ...

  10. SDUT OJ 数据结构实验之二叉树四:(先序中序)还原二叉树

    数据结构实验之二叉树四:(先序中序)还原二叉树 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Discuss Problem ...