【STM32外设系列】RFID模块

🎀 文章作者:二土电子

🌸 关注公众号获取完整程序工程!

🐸 期待大家一起学习交流!


一、RFID是什么

首先我们先来简单了解一下什么是RFID,射频识别技术(Radio Frequency Identification, RFID)是一种利用无线电波实现非接触式自动识别的技术。RFID系统通过无线电波与电子标签(Tag)进行通信,从而完成对目标对象的识别和数据交换。一个完整的RFID系统由三部分组成,分别是标签(ID卡)、读写器、天线。像我们生活中常见的校饭卡水卡这种都是RFID技术的实际应用。

插播一段笔者的小理解,学生时代,我们偶尔会听说某某某同学自己能充饭卡水卡,首先这肯定是可以的,但是了解了ID卡之后可能或更加清楚为什么,因为ID卡通常有三个分区,每一个分区都会有对应的密码,密码对了才可以对某一个分区进行读写,密码肯定是有手段可以破解的,所以可以做到自己充饭卡水卡,但是一般这种用到RFID技术做支付使用的场景时会有专人进行资金核对,还是建议大家不要做这种事情。

关于其他RFID的更加细节的内容大家可以自行搜索一下,这不是本文重点,这里就只是有一个简单的认识和理解,就不再做赘述了。

二、MF RC522模块

我们这里使用MF RC522模块来做读写器,搭配IC卡来组成一个RFID系统,学习一下RFID的使用方法。

MF RC522是高度集成的非接触式(13.56MHz)读写卡芯片。此发送模块利用调制和解调的原理,并将它们完全集成到各种非接触式通信方法和协议中(13.56MHz)。MF RC522支持SPI通信和IIC通信模式。

MF RC522模块

MF RC522的操作由可执行一系列命令的内部状态机来决定。通过向命令寄存器写入相应的命令代码来启动命令。关于MF RC522模块更多细节可以到MFRC522资料手册中查看,有需要的小伙伴可以私信获取。

三、程序设计

3.1 SPI程序设计

首先要实现和模块的通信,SPI通信必备的一些函数基本都是一样的,只要注意模块SPI模式即可,关于SPI四种模式的内容可以移步STM32速成笔记专栏查看,里面有对SPI的详细介绍。

我们这里使用的是软件模拟SPI,引脚分别是

SPI引脚对应IO
CSPA4
SCKPA5
MOSIPA7
MISOPA6

3.1.1 SPI读/写字节

RC522的SPI空闲状态下时钟线是低电平。

/*
 *==============================================================================
 *函数名称:Med_Rc522_WriteByte
 *函数功能:RC522写入数据
 *输入参数:data:写入的数据
 *返回值:无
 *备  注:无
 *==============================================================================
*/
void Med_Rc522_WriteByte (u8 data)
{
	u8 tempVar = 0;
	
	for (tempVar = 0;tempVar < 8;tempVar ++)
	{
		if (data & 0x80)
			RC522_MOSI = 1;
		else
			RC522_MOSI = 0;
		delay_us(200);
		RC522_SCLK = 0;
		delay_us(200);
		RC522_SCLK = 1;
		delay_us(200);
		
		data <<= 1;
	}
}
/*
 *==============================================================================
 *函数名称:Med_Rc522_ReadByte
 *函数功能:RC522读取数据
 *输入参数:data:写入的数据
 *返回值:读取到的数据
 *备  注:无
 *==============================================================================
*/
u8 Med_Rc522_ReadByte (void)
{
	u8 tempVar = 0;
	u8 data = 0;
	
	for (tempVar = 0;tempVar < 8;tempVar ++)
	{
		data <<= 1;
		RC522_SCLK = 0;
		delay_us(200);
		if (RC522_MISO == 1)
			data |= 0x01;
		delay_us(200);
		RC522_SCLK = 1;
		delay_us(200);
	}
	return data;
}

3.1.2 SPI读/写寄存器

/*
 *==============================================================================
 *函数名称:Med_Rc522_Write_Reg
 *函数功能:RC522写入寄存器
 *输入参数:addr:寄存器地址;data:数据
 *返回值:无
 *备  注:无
 *==============================================================================
*/
void Med_Rc522_Write_Reg (u8 addr,u8 data)
{
	addr = ( addr << 1 ) & 0x7E;
	RC522_CS = 0;   // 使能片选
	Med_Rc522_WriteByte(addr);   // 发送地址
	Med_Rc522_WriteByte(data);   // 发送数据
	RC522_CS = 1;   // 取消片选
}
/*
 *==============================================================================
 *函数名称:Med_Rc522_Read_Reg
 *函数功能:RC522读取寄存器
 *输入参数:addr:寄存器地址;
 *返回值:读取到的数据
 *备  注:无
 *==============================================================================
*/
u8 Med_Rc522_Read_Reg (u8 addr)
{
	u8 data = 0;
	
	addr = ((addr << 1) & 0x7E) | 0x80;
	RC522_CS = 0;   // 使能片选
	Med_Rc522_WriteByte(addr);   // 发送地址
	data = Med_Rc522_ReadByte();   // 读取数据
	RC522_CS = 1;   // 取消片选
	return data;
}

3.2 RC522功能函数

下面是一些RC522的功能函数实现

3.2.1 RC522开启天线

void Med_Rc522_OpenAntenna (void)
{
	u8 tempVar = 0;
	
	tempVar = Med_Rc522_Read_Reg(TxControlReg);
	if (!(tempVar & 0x30))
		Med_Rc522_SetBit(TxControlReg,0x30);
}

3.2.2 RC522工作类型设置

/*
 *==============================================================================
 *函数名称:Med_Rc522_WorkType
 *函数功能:RC522工作类型设置
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
*/
void Med_Rc522_WorkType (u8 type)
{
	if (type == 'A')
	{
		Med_Rc522_ClearBit(Status2Reg,0x80);
		Med_Rc522_Write_Reg(ModeReg,0x3D);
		Med_Rc522_Write_Reg(RxSelReg,0x86);
		Med_Rc522_Write_Reg(RFCfgReg,0x7F);
		Med_Rc522_Write_Reg(TReloadRegL,0x1E);
		Med_Rc522_Write_Reg(TReloadRegH,0x00);
		Med_Rc522_Write_Reg(TModeReg,0x8D);
		Med_Rc522_Write_Reg(TPrescalerReg,0x3E);
		delay_us(2);
		Med_Rc522_OpenAntenna();
	}
}

3.2.3 RC522寻卡

/*
 *==============================================================================
 *函数名称:Med_Rc522_FindCards
 *函数功能:RC522寻卡
 *输入参数:method:寻卡方式;cardType:卡片类型
 *返回值:MI_OK,成功
 *备  注:无
 *==============================================================================
*/
u8 Med_Rc522_FindCards (u8 method,u8 *cardType)
{
	char cStatus;
	u8 ucComMF522Buf [ MAXRLEN ]; 
	u32 ulLen;
	
	Med_Rc522_ClearBit(Status2Reg,0x08);
	Med_Rc522_Write_Reg(BitFramingReg,0x07);
	Med_Rc522_SetBit(TxControlReg,0x03);
	
	ucComMF522Buf[0] = method;   // 存入卡片命令字
	// 寻卡
	cStatus = Med_Rc522_CommWithCard(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,& ulLen );

	if ( (cStatus == MI_OK) && (ulLen == 0x10))	//寻卡成功返回卡类型 
   {
		 *cardType = ucComMF522Buf [0];
		 *(cardType + 1) = ucComMF522Buf[1];
   }
   else
     cStatus = MI_ERR;
   
   return cStatus;
}

3.2.4 RC522防冲撞

/*
 *==============================================================================
 *函数名称:Med_Rc522_Anticoll
 *函数功能:RC522防冲撞
 *输入参数:*pSnr:四字节卡片序列号
 *返回值:MI_OK,成功
 *备  注:无
 *==============================================================================
*/
u8 Med_Rc522_Anticoll (u8 *pSnr)
{
	char cStatus;
	u8 uc, ucSnr_check = 0;
	u8 ucComMF522Buf [MAXRLEN]; 
	u32 ulLen;

	Med_Rc522_ClearBit(Status2Reg,0x08);    // 清MFCryptol On位 只有成功执行MFAuthent命令后,该位才能置位
	Med_Rc522_Write_Reg(BitFramingReg,0x00);   // 清理寄存器 停止收发
	Med_Rc522_ClearBit(CollReg,0x80);       // 清ValuesAfterColl所有接收的位在冲突后被清除
 
	ucComMF522Buf[0] = 0x93;          // 卡片防冲突命令
	ucComMF522Buf[1] = 0x20;
	// 与卡片通信
	cStatus = Med_Rc522_CommWithCard(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&ulLen);

	if (cStatus == MI_OK)   // 通信成功
	{
		for (uc = 0;uc < 4;uc ++)
		{
			 *(pSnr + uc)  = ucComMF522Buf[uc];   // 读出UID
			 ucSnr_check  ^= ucComMF522Buf[uc];
		}
		
		if (ucSnr_check != ucComMF522Buf[uc])
			cStatus = MI_ERR;     
	}
	Med_Rc522_SetBit (CollReg, 0x80);
	
	return cStatus;
}

3.3 获取卡片ID并通过串口输出

最后我们编写一个业务函数用于在主函数的轮询中运行,寻卡成功后会输出卡片ID。

/*
 *==============================================================================
 *函数名称:App_Rc522_GetId
 *函数功能:RC522获取卡片ID并通过串口输出
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
*/
void App_Rc522_GetId (void)
{
	char cStr [ 30 ];
  u8 ucArray_ID [ 4 ];   // 先后存放IC卡的类型和UID(IC卡序列号)
	u8 ucStatusReturn;   // 返回状态
  static u8 ucLineCount = 0;
	
	// 寻卡
	if ((ucStatusReturn = Med_Rc522_FindCards(PICC_REQALL,ucArray_ID)) != MI_OK)
	{
		// 失败再次寻卡
		ucStatusReturn = Med_Rc522_FindCards(PICC_REQALL,ucArray_ID);
	}
	if (ucStatusReturn == MI_OK)
	{
		// 防冲撞(当有多张卡进入读写器操作范围时,防冲突机制会从其中选择一张进行操作)
		if (Med_Rc522_Anticoll(ucArray_ID) == MI_OK)
		{
			sprintf(cStr,"The Card ID is: %02X%02X%02X%02X",ucArray_ID[0],ucArray_ID[1],ucArray_ID[2],ucArray_ID[3]);
			printf("%s\r\n",cStr);
			
			if(ucLineCount == 0)
				ucLineCount ++;
				
				if(ucLineCount == 17)
					ucLineCount = 0;
		}
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二土电子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值