分享免费的编程资源和教程

网站首页 > 技术教程 正文

STM32——NFC门禁模块(RC522)(含代码)

goqiw 2024-11-07 11:06:29 技术教程 28 ℃ 0 评论

大家好,今天给大家介绍,文章末尾附有本毕业设计的论文和源码的获取方式,也可现在直接进群免费领取。

点击这里找小助理0元领取:扫码进群领资料

1. 前言(包括一些个人理解)

(2021/11/1编辑)
在项目需要做一个NFC门禁功能的时候,突然发现有个RC522丢在我的桌面,甚至不知道它上面的引脚什么意思(还不会SPI通讯),搜索关键词“RC522”去看博客搜索资料,发现了很多都在说扇区,块,S50(M1)卡,然后就给代码,一开始我还以为S50是内嵌在这个模块里面的一个存储器,然后越看越怪,后面去淘宝搜索S50,才发现S50其实是我们的门禁卡,RC522是用来感应和判断的。


  • PCD是接近式卡。PICC是接近式耦合设备。
  • 在通信过程中实际上是使用PCD命令控制RC522发出PICC命令与卡进行交互。

2. RC522门禁工作过程


  • 过程:寻卡->防冲突->选卡->操作卡
  • PCD命令
/*MFRC522命令集,中文手册P59*/
#define MFRC_IDLE              		0x00	//取消当前命令的执行
#define MFRC_TRANSMIT          		0x04    //发送FIFO缓冲区内容
#define MFRC_RECEIVE           		0x08    //激活接收器接收数据
#define MFRC_TRANSCEIVE        		0x0C    //发送并接收数据
#define MFRC_AUTHENT           		0x0E    //执行Mifare认证(验证密钥)
#define MFRC_RESETPHASE        		0x0F    //复位MFRC522
#define MFRC_CALCCRC           		0x03    //激活CRC计算
#define MFRC_NOCMDCHANGE            0x07	//无命令改变
  • PICC命令
/*Mifare1卡片命令字*/
#define PICC_REQIDL           	0x26        //寻天线区内未进入休眠状态的卡
#define PICC_REQALL           	0x52        //寻天线区内全部卡
#define PICC_ANTICOLL1        	0x93        //防冲撞
#define PICC_ANTICOLL2        	0x95        //防冲撞
#define PICC_AUTHENT1A        	0x60        //验证A密钥
#define PICC_AUTHENT1B        	0x61        //验证B密钥
#define PICC_READ             	0x30        //读块
#define PICC_WRITE            	0xA0        //写块
#define PICC_DECREMENT        	0xC0        //减值(扣除)
#define PICC_INCREMENT        	0xC1        //增值(充值)
#define PICC_TRANSFER         	0xB0        //转存(传送)
#define PICC_RESTORE          	0xC2        //恢复(重储)
#define PICC_HALT             	0x50        //休眠

3. CubeMx配置

3.1 SPI通讯的配置

打开SPI模式设置为:Full-Duplex Master(全双工主机模式)

  • 分频设置为8~256都行,这样随之波特率也会改变,波特率越小通信速度越快
  • Clock Phase (CPHA) 设置为第一个上升沿这里一定要1Edge
  • 不开启CRC检测

3.2 SDA和REST引脚的配置


随后再定义两个普通的OUTPUT输出的引脚作为复位和使能引脚

4. 外设代码函数编写

4.1 主函数能调用的接口函数

  • 初始化
/***************************************************************************************
* 函数名称:PCD_Init
* 功能描述:读写器初始化
* 入口参数:无
* 出口参数:无
* 返 回 值:无
* 说    明:无
***************************************************************************************/
void PCD_Init(void)
{
    MFRC_Init();      //MFRC管脚配置
    PCD_Reset();      //PCD复位  并初始化配置
    PCD_AntennaOff(); //关闭天线
    PCD_AntennaOn();   //开启天线
    PCD_Reset();
}
  • 寻卡
/***************************************************************************************
* 函数名称:PCD_Request
* 功能描述:寻卡
* 入口参数: -RequestMode:寻卡方式
*                 PICC_REQIDL:寻天线区内未进入休眠状态
*                 PICC_REQALL:寻天线区内全部卡
*             -pCardType:用于保存卡片类型
* 出口参数:-pCardType:卡片类型
*                       0x4400:Mifare_UltraLight
*                       0x0400:Mifare_One(S50)
*                       0x0200:Mifare_One(S70)
*                       0x0800:Mifare_Pro(X)
*                       0x4403:Mifare_DESFire
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:无
***************************************************************************************/
char PCD_Request(uint8_t RequestMode, uint8_t *pCardType)
{
    int status;
    uint16_t unLen;
    uint8_t CmdFrameBuf[MFRC_MAXRLEN];

    MFRC_ClrBitMask(MFRC_Status2Reg, 0x08);//关内部温度传感器
    MFRC_WriteReg(MFRC_BitFramingReg, 0x07); //存储模式,发送模式,是否启动发送等
    MFRC_SetBitMask(MFRC_TxControlReg, 0x03);//配置调制信号13.56MHZ

    CmdFrameBuf[0] = RequestMode;

    status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 1, CmdFrameBuf, &unLen);

    if((status == PCD_OK) && (unLen == 0x10))
    {
        *pCardType = CmdFrameBuf[0];
        *(pCardType + 1) = CmdFrameBuf[1];
    }

    return status;
}
  • 防冲撞

4.2 二级内部调用函数

  • 宏定义
  • MFRC管脚配置
  • PCD复位 并初始化配置
  • 关闭天线
  • 开启天线
  • RC与M1卡通讯帧函数

4.3 第三级最底层函数

  • 读一个寄存器
  • 设置寄存器的位
  • 清除寄存器的位

4.4 头文件

5. 使用教程

//先用CubeMx初始化
PCD_Init();//RC522初始化
/*
* 函数功能:验证刷卡人,以及发送上位机刷卡人身份
* 参    数:无
* 返 回 值:无
* 注    意:无
* 作    者:苏释州
*/
void NFC(void)
{
	//寻卡
	if (PCD_Request(PICC_REQALL, RxBuffer)!=0)//返回值为0,代表寻卡成功;并把卡类型存入RxBuffer中)
	{
		/*果然这里要清空一下不然就会乱,会有一些RxBuffer没用的在那里占位*/
		memset(RxBuffer, 0, sizeof(RxBuffer));//清空字符串
		return;//如果不加这个判断的话,则会无论寻卡是否成功都会有值000
	}
	//防冲撞
	if (PCD_Anticoll(RxBuffer)!=0)//防冲撞,完成这部就可以简单地 读取卡号
	{
		memset(RxBuffer, 0, sizeof(RxBuffer));//清空字符串
		return;//如果不加这个判断的话,则会无论寻卡是否成功都会扰乱卡号
	}
	//处理卡号数据
	sprintf(Card_ID,"%x%x%x%x",RxBuffer[0],RxBuffer[1],RxBuffer[2],RxBuffer[3]);
	//对卡号进行权限的判断
	if(strcmp(Card_ID,"b59dfcaa")==0)//卖家配的卡
    {
		DoorControl(1);//开门
		HAL_TIM_Base_Start_IT(&htim5);//开门的时候开启定时器5的中断,进入关门计时
		memset(RxBuffer, 0, sizeof(RxBuffer));//清空字符串,这里要清除RxBuffer才行,否则Card_ID又会被组起来
    }
	else if(strcmp(Card_ID,"e1eff3cc")==0)//刘骏帆手机本科生证
	{
		DoorControl(1);//开门
		HAL_TIM_Base_Start_IT(&htim5);//开启定时器5的中断
		memset(RxBuffer, 0, sizeof(RxBuffer));//清空字符串,这里要清除RxBuffer才行,否则Card_ID又会被组起来
	}
    else
    {
		DoorControl(1);//开门
		HAL_TIM_Base_Start_IT(&htim5);//开启定时器5的中断
		memset(RxBuffer, 0, sizeof(RxBuffer));//清空字符串
    }
    HAL_Delay(100);
	return;
}

完整代码可进群免费领取!!!

嵌入式物联网的学习之路非常漫长,不少人因为学习路线不对或者学习内容不够专业而错失高薪offer。不过别担心,我为大家整理了一份150多G的学习资源,基本上涵盖了嵌入式物联网学习的所有内容。点击下方链接,0元领取学习资源,让你的学习之路更加顺畅!记得点赞、关注、收藏、转发哦!

点击这里找小助理0元领取:扫码进群领资料


本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表