本文介绍如何使用STM32控制RFID低频读卡器实现读卡操作,其中包含功能配置、数据解析功能。


目录

前言

一、前置准备

二、使用步骤

1.读卡器介绍

(1)前言

(2)数值帧指令分析

2.准备步骤

(1)修改读卡器地址

(2)测试读卡器功能

3、准备接线

三、代码编写:

1、功能布局

2、编写代码

 3、成果展示

四、资源链接(百度云)

总结




前言

        RFID是一种非接触式的自动识别技术,它通过射频信号自动识别目标对象并获取相关数据,识别工作无须人工干预,可工作于各种恶劣环境。RFID技术可识别高速运动物体并可同时识别多个标签,操作快捷方便。
        RFID按应用频率的不同分为低频(LF)、高频(HF)、超高频(UHF)、微波(MW),相对应的代表性频率分别为:低频135KHz以下、高频13.56MHz、超高频860M~960MHz、微波2.4GHz。低频频率相对于其他频率的优势在于防干扰能力强、适用于近距离应用、抗干扰性强、成本相对较低和适用于动物识别(这点存疑,因为目前淘宝我搜不到相关应用于动物领域的低频读卡器,因为低频读卡器普遍读卡距离近,所以适用于动物识别只是因为它穿透力强)。

        如果你要做的项目需要近距离识别的话本文可以满足你的需求,如果你需要远距离读卡识别的话本人的另外一篇博客可能会帮助你。本文的低频读卡器适合用于某物品的位置定位、ID识别等功能。


一、前置准备

两个读卡器模块的天线距离要20cm以上,否则会冲突导致读卡不稳定。最后组装好如图2所示。代码资料会稍后放在后面。

此卡未检测到vbios支持 未检测到卡片,若已贴卡_此卡未检测到vbios支持

图1 ID低频读卡器

此卡未检测到vbios支持 未检测到卡片,若已贴卡_嵌入式硬件_02

图2 组装

二、使用步骤

1.读卡器介绍

(1)前言

        首先畅科读卡器在出厂的时候内置了一些功能,比如我购买的是带有蜂鸣器的RS485协议的读卡器,我放卡上去会听到“滴”的一声,并且芯片上的LED灯会常亮,于此同时读卡器会发送一帧数据返回若干信息。卡片离开时LED灯会灭,并且会发送一帧数据显示已离开读卡器。我们可以配置相关功能比如检测到卡片时是否会“滴”的一声,检测到卡片时要不要主动返回数据给上位机,以及卡片离开时是否发送数据提示卡片已离开,还能设置波特率。顺便说一下通讯指令用到的都是十六进制位,数据类型用的是unsigned char。如果用多个读卡器的话,多个读卡器接到RS485转TTL芯片,STM32用一个串口跟这芯片相连,那么我们怎么区分哪个读卡器读到卡呢?这就要用到读卡器的地址了,我们还要修改读卡器的地址,比如出厂的读卡器模块地址都是0x00,我们要把多余的读卡器地址设置为0x01、0x02等等,反正不与0x00相同就行。

(2)数值帧指令分析

        我们来看读卡器的功能配置指令(如图3),以上我说的相关功能都可以在这里配置。

此卡未检测到vbios支持 未检测到卡片,若已贴卡_此卡未检测到vbios支持_03

图3 功能配置指令

        由上图可知,一帧数据指令是由以上若干格式组成的。我们要更改相关功能只需要修改对应的值即可,以下贴出读卡器使用说明中各个位指令的作用(如图5)。

此卡未检测到vbios支持 未检测到卡片,若已贴卡_单片机_04

图4 各个位的作用

        这里要注意的是校验和,上面可能说得不太清楚,根据我的理解是先把BCC校验(异或校验)算出来,然后把得出来的二进制位全部取反,取反后得到的就是校验和。写个例子,比如根据上面的功能配置指令,我写出来了一帧配置指令:

20 00 2C 04 00 00 96 00 校验和

配置指令的意思是开启主动输出卡号,主动输出卡片离开数据,9600的波特率,开启蜂鸣器提醒。我现在开始要算校验和,根据指示我得出来00 2C 04 00 00 96 00。

        然后计算BBC校验码,如图5。

此卡未检测到vbios支持 未检测到卡片,若已贴卡_嵌入式硬件_05

图5 BBC校验码计算

        得出二进制位是1011 1110,按位取反获得0100 0001。

        转换为十六进制为:41

        所以我们的校验和是41,填入后完整的数据指令是:

20 00 2C 04 00 00 96 00 41

         需要注意的是,数据指令的第二个位是读卡器的地址,你要改哪个读卡器的话就用地址定位你要改的读卡器。

2.准备步骤

(1)修改读卡器地址

如果你打算只使用一个读卡器完成测试的话,那就可以跳过这一步,否则的话请按照此步骤将读卡器的地址设置为不同的值。两个以上读卡器的话要修改读卡器地址,因为指令发送是发送给单个读卡器的,你需要读卡器的唯一地址才能确定这指令发给谁,否则后面发送指令时一样的地址会导致冲突。其中一个读卡器默认地址就为0x00就行了(如果你不想要0x00的话改成其他也行),其他的改成其他值(0xFF以内)。首先我们先把要改地址的读卡器接好线,电源线接3.3V,A、B线接到RS485转TTL芯片的A、B线,然后RS485转TTL芯片的串口线接到我们的USB转串口芯片上,j接好后插电脑。打开串口调试助手,按如图3所示配置:

此卡未检测到vbios支持 未检测到卡片,若已贴卡_此卡未检测到vbios支持_06

图6 串口调试助手的相关配置

        接下来我们查看修改模块地址指令(如图7)。

此卡未检测到vbios支持 未检测到卡片,若已贴卡_stm32_07

图7 修改模块地址指令

        我们可以看到,我们要修改的有两个值,一个是原地址,一个是新地址,分别位于第2和第5个字节。由于读卡器出厂都是默认地址为0x00,原地址就填0x00。新地址的话填你想要的值,我填的是0x01,发送成功后会接受到反馈指令,如图8。

此卡未检测到vbios支持 未检测到卡片,若已贴卡_嵌入式硬件_08

图8 修改读卡器地址

(2)测试读卡器功能

        如果我们用默认功能配置的话,是开启主动输出卡号,主动输出卡片离开数据,9600的波特率,开启蜂鸣器提醒。所以我们先测试的时候是把卡片放到天线上去,可以听到蜂鸣器响一声,并且串口调试助手接受到数据(如图9)。卡片拿走后返回卡片离开数据(如图10)。(这里我使用的是地址为0x01的读卡器,所以数据帧第二个字节是01)

此卡未检测到vbios支持 未检测到卡片,若已贴卡_嵌入式硬件_09

图9 检测到卡片时返回的数据

此卡未检测到vbios支持 未检测到卡片,若已贴卡_物联网_10

 图10 卡片已离开

        我们不仅要它读到卡号返回数据,还要随时能够确定读卡器天线上有没有卡片,接下来测试读卡指令,先看读卡指令的通讯格式(如图11)。

此卡未检测到vbios支持 未检测到卡片,若已贴卡_单片机_11

图11 寻卡指令格式

        我们根据地址寻卡,比如地址为0x01的读卡器,我们就把第2字节的地址位改成0x01,然后计算校验值得到D9,指令是20 01 27 00 D9 03。如图12所示。

此卡未检测到vbios支持 未检测到卡片,若已贴卡_物联网_12

图12 有卡与无卡数据帧返回情况

        测试完毕,开始写代码了。

3、准备接线

        整个实验我使用了STM32的串口1和串口2,串口1连接电脑打印调试信息,串口2接RS485转TTl芯片,RS485转TTl芯片再接读卡器模块。

STM32 -> RS485转TTl芯片

PA2 -> TXD

PA3 -> RXD

RS485转TTl芯片 -> 读卡器模块

A -> A

B -> B

        其他的比如接电源和串口1接电脑这些不再赘述了,如果读卡器没数据传回来可能是因为你的RS485转TTl芯片跟我的不太一样,有电平转换功能啥的,反接一下试试。

三、代码编写:

1、功能布局

        首先我们使用串口2来发送接收数据,数据处理后通过串口1显示读卡信息。

2、编写代码

        我们要配置串口2的中断服务函数。每接收完一帧数据帧,都会进行数据解析(RFID_LF_GetData())。(复制代码时建议复制下面完整版)

/*
函数名称:	NVIC_Configuration
函数参数:	void
函数返回值:static void
函数功能:	中断结构体配置
*/
static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 嵌套向量中断控制器组选择 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置USART为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = RFID_LF_USART_IRQ;
  /* 抢断优先级*/
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 子优先级 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置NVIC */
  NVIC_Init(&NVIC_InitStructure);
}

/*
函数名称:	USART_Config
函数参数:	void
函数返回值:void
函数功能:	PA2--TX		PA3--RX		串口2初始化
*/
void RFID_USART_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	// 打开串口GPIO的时钟
	RFID_LF_USART_GPIO_APBxClkCmd(RFID_LF_USART_GPIO_CLK, ENABLE);
	
	// 打开串口外设的时钟
	RFID_LF_USART_APBxClkCmd(RFID_LF_USART_CLK, ENABLE);

	// 将USART Tx的GPIO配置为推挽复用模式
	GPIO_InitStructure.GPIO_Pin = RFID_LF_USART_TX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(RFID_LF_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  // 将USART Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Pin = RFID_LF_USART_RX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(RFID_LF_USART_RX_GPIO_PORT, &GPIO_InitStructure);
	
	// 配置串口的工作参数
	// 配置波特率
	USART_InitStructure.USART_BaudRate = RFID_LF_USART_BAUDRATE;
	// 配置 针数据字长
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	// 配置停止位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	// 配置校验位
	USART_InitStructure.USART_Parity = USART_Parity_No ;
	// 配置硬件流控制
	USART_InitStructure.USART_HardwareFlowControl = 
	USART_HardwareFlowControl_None;
	// 配置工作模式,收发一起
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	// 完成串口的初始化配置
	USART_Init(RFID_LF_USARTx, &USART_InitStructure);
	
	// 串口中断优先级配置
	NVIC_Configuration();
	
	// 使能串口接收中断
	USART_ITConfig(RFID_LF_USARTx, USART_IT_RXNE, ENABLE);
	USART_ITConfig ( RFID_LF_USARTx, USART_IT_IDLE, ENABLE ); //使能串口总线空闲中断 	
	
	// 使能串口
	USART_Cmd(RFID_LF_USARTx, ENABLE);	    
}

/*
函数名称:	RFID_LF_USART_IRQHandler
函数参数:	void
函数返回值:void
函数功能:	接收一帧数据并且进行解析
*/

unsigned char RFID_LF_buff[512];
int RFID_LF_cnt = 0;
void RFID_LF_USART_IRQHandler(void)
{
	static u8 i = 0;
	//判断是接收中断触发
	if(USART_GetITStatus(RFID_LF_USARTx,USART_IT_RXNE))
	{
		//清除中断标志位
		USART_ClearITPendingBit(RFID_LF_USARTx,USART_IT_RXNE);
		//紧急事件
		RFID_LF_buff[i++] = USART_ReceiveData(RFID_LF_USARTx);	
		RFID_LF_cnt++;
	}
	
	//判断是空闲中断触发
	if(USART_GetITStatus(RFID_LF_USARTx,USART_IT_IDLE))
	{
		//清除中断标志位
		RFID_LF_USARTx->SR;
		RFID_LF_USARTx->DR;
		//紧急事件
		RFID_LF_buff[i] = '\0';
		i = 0;
		RFID_LF_GetData();
	}
}

        返回的数据进行数据解析,并且根据数据打印相对应的信息和卡号。

struct RFID_status
{
	int read_ok_flag;		//表示是否读到卡
	int R_read;				//表示读到的是哪个编号
	int R_no_read;
	int R_hadRead;			//表示哪个读卡器已经读到过卡了
}status;

/*
函数名称:	RFID_LF_GetData
函数参数:	void
函数返回值:void
函数功能:	分析数据
*/
void RFID_LF_GetData(void)
{
	int i = 0,j = 0;
	if(RFID_LF_cnt == ID_cnt)		//读到的数据位数为卡号时
	{
		status.read_ok_flag = 1;		//读卡成功标志位置1
		if(RFID_LF_buff[1] == 0x00 && RFID_LF_buff[2] == 0x27)		//当读到的数据确实是卡号时,并且读卡器是0
		{
			memcpy(R0_ID,RFID_LF_buff+4,5*sizeof(unsigned char));
			status.R_read = 1;
			status.R_hadRead = 1;
		}
		else if(RFID_LF_buff[1] == 0x01 && RFID_LF_buff[2] == 0x27)	//当读到的数据确实是卡号时,并且读卡器是1
		{
			memcpy(R1_ID,RFID_LF_buff+4,5*sizeof(unsigned char));
			status.R_read = 2;
			status.R_hadRead = 2;
		}
	}
	if(RFID_LF_cnt == fail_LF_cnt)		//读到的数据为卡号不存在时
	{
		if(RFID_LF_buff[1] == 0x00)		//读写器是0
		{
			status.R_no_read = 1;
		}
		else if(RFID_LF_buff[1] == 0x01)	//读写器是1
		{
			status.R_no_read = 1;
		}
	}
	
	RFID_display();		//显示卡号
	RFID_LF_cnt = 0;
	memset(RFID_LF_buff, 0, sizeof(RFID_LF_buff));//将内存的指针指到首地址----清空缓存
}

/*
函数名称:	RFID_display
函数参数:	void
函数返回值:void
函数功能:	显示卡号
*/
void RFID_display(void)
{
	int i = 0;
	if(status.read_ok_flag == 1)
	{
		if(status.R_read == 1)
		{
			printf("读写器0检测到卡片,卡号:");
			for(i = 0;i < card_ID_cnt;i++)
			{
				printf("%X ",R0_ID[i]);
			}
			printf("\n");
		}
		if(status.R_read == 2)
		{
			printf("读写器1检测到卡片,卡号:");
			for(i = 0;i < card_ID_cnt;i++)
			{
				printf("%X ",R1_ID[i]);
			}
			printf("\n");
		}
	}
	else
	{
		if(status.R_no_read == 1)
		{
			printf("读写器0未检测到卡片\n");
			printf("\n");
		}
		if(status.R_no_read == 2)
		{
			printf("读写器1未检测到卡片\n");
			printf("\n");
		}
	}
	
	status.read_ok_flag = 0;
	status.R_read = 0;
	status.R_no_read = 0;
	memset(R0_ID, 0, sizeof(R0_ID));//将内存的指针指到首地址----清空缓存
	memset(R1_ID, 0, sizeof(R1_ID));//将内存的指针指到首地址----清空缓存
}

        最后再写个寻卡命令

/*
函数名称:	RDID_SendCmd
函数参数:	USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num
函数返回值:void
函数功能:	给RFID模块发送指令
*/
void RFID_SendCmd( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
{
	uint8_t i;

	for(i=0; i<num; i++)
	{
		/* 发送一个字节数据到USART */
		Usart_SendByte(pUSARTx,array[i]);	
	}
	/* 等待发送完成 */
	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}

/*
函数名称:	Find_LF_Card
函数参数:	u8 reader
函数返回值:u8
函数功能:	低频指定读卡器寻卡函数,参数指定哪个读卡器(只有编号0或1)读卡,返回值为1表示读到卡了
*/
u8 Find_LF_Card(u8 reader)
{
	if(reader == 0)
	{
		//读写器0的单次寻卡
		RFID_SendCmd(RFID_LF_USARTx,find_R0_cmd,find_LF_cmd_cnt);				//单次寻卡
		while(USART_GetFlagStatus(RFID_LF_USARTx,USART_FLAG_TC)!=SET);
		if(status.R_hadRead == 1)		//说明读到卡了
		{
			printf("寻卡成功\n");
			status.R_hadRead = 0;
			return 1;
		}
		else
		{
			printf("寻卡失败\n");
			return 0;
		}
		
	}
	else if(reader == 1)
	{
		//读写器1的单次寻卡
		RFID_SendCmd(RFID_LF_USARTx,find_R1_cmd,find_LF_cmd_cnt);				//单次寻卡
		while(USART_GetFlagStatus(RFID_LF_USARTx,USART_FLAG_TC)!=SET);
		if(status.R_hadRead == 2)		//说明读到卡了
		{
			status.R_hadRead = 0;
			return 1;
		}
		else
			return 0;
	}
	return 0;
}

        最后是那些头文件的宏定义。

#define ID_cnt 11					//读到ID卡返回的数据数
#define fail_LF_cnt 7				//无卡时返回的数据数
#define find_LF_cmd_cnt 6			//读卡指令的字节数
#define card_ID_cnt 5				//卡号的数据数

//RFID_LF相关命令
//单次询问读写器0指令
unsigned char find_R0_cmd[find_LF_cmd_cnt] = {0x20,0x00,0x27,0x00,0xD8,0x03};
//单次询问读写器1指令
unsigned char find_R1_cmd[find_LF_cmd_cnt] = {0x20,0x01,0x27,0x00,0xD9,0x03};
//用来存放读写器0读出的卡号
unsigned char R0_ID[20];
//用来存放读写器1读出的卡号
unsigned char R1_ID[20];

        我最后做成完整的RFID_LF.c和RFID_LF.h文件,整个工程和资料可以在下面下载。

RFID_LF.c

#include "RFID_LF.h"

//RFID_LF相关命令
//单次询问读写器0指令
unsigned char find_R0_cmd[find_LF_cmd_cnt] = {0x20,0x00,0x27,0x00,0xD8,0x03};
//单次询问读写器1指令
unsigned char find_R1_cmd[find_LF_cmd_cnt] = {0x20,0x01,0x27,0x00,0xD9,0x03};
//用来存放读写器0读出的卡号
unsigned char R0_ID[20];
//用来存放读写器1读出的卡号
unsigned char R1_ID[20];

//内部函数声明
void RFID_SendCmd( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num);
void RFID_LF_GetData(void);
void RFID_display(void);

struct RFID_status
{
	int read_ok_flag;		//表示是否读到卡
	int R_read;				//表示读到的是哪个编号
	int R_no_read;
	int R_hadRead;			//表示哪个读卡器已经读到过卡了
}status;

/*
函数名称:	NVIC_Configuration
函数参数:	void
函数返回值:static void
函数功能:	中断结构体配置
*/
static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 嵌套向量中断控制器组选择 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置USART为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = RFID_LF_USART_IRQ;
  /* 抢断优先级*/
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 子优先级 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置NVIC */
  NVIC_Init(&NVIC_InitStructure);
}

/*
函数名称:	USART_Config
函数参数:	void
函数返回值:void
函数功能:	PA2--TX		PA3--RX		串口2初始化
*/
void RFID_USART_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	// 打开串口GPIO的时钟
	RFID_LF_USART_GPIO_APBxClkCmd(RFID_LF_USART_GPIO_CLK, ENABLE);
	
	// 打开串口外设的时钟
	RFID_LF_USART_APBxClkCmd(RFID_LF_USART_CLK, ENABLE);

	// 将USART Tx的GPIO配置为推挽复用模式
	GPIO_InitStructure.GPIO_Pin = RFID_LF_USART_TX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(RFID_LF_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  // 将USART Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Pin = RFID_LF_USART_RX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(RFID_LF_USART_RX_GPIO_PORT, &GPIO_InitStructure);
	
	// 配置串口的工作参数
	// 配置波特率
	USART_InitStructure.USART_BaudRate = RFID_LF_USART_BAUDRATE;
	// 配置 针数据字长
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	// 配置停止位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	// 配置校验位
	USART_InitStructure.USART_Parity = USART_Parity_No ;
	// 配置硬件流控制
	USART_InitStructure.USART_HardwareFlowControl = 
	USART_HardwareFlowControl_None;
	// 配置工作模式,收发一起
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	// 完成串口的初始化配置
	USART_Init(RFID_LF_USARTx, &USART_InitStructure);
	
	// 串口中断优先级配置
	NVIC_Configuration();
	
	// 使能串口接收中断
	USART_ITConfig(RFID_LF_USARTx, USART_IT_RXNE, ENABLE);
	USART_ITConfig ( RFID_LF_USARTx, USART_IT_IDLE, ENABLE ); //使能串口总线空闲中断 	
	
	// 使能串口
	USART_Cmd(RFID_LF_USARTx, ENABLE);	    
}

/*
函数名称:	RFID_LF_USART_IRQHandler
函数参数:	void
函数返回值:void
函数功能:	接收一帧数据并且进行解析
*/

unsigned char RFID_LF_buff[512];
int RFID_LF_cnt = 0;
void RFID_LF_USART_IRQHandler(void)
{
	static u8 i = 0;
	//判断是接收中断触发
	if(USART_GetITStatus(RFID_LF_USARTx,USART_IT_RXNE))
	{
		//清除中断标志位
		USART_ClearITPendingBit(RFID_LF_USARTx,USART_IT_RXNE);
		//紧急事件
		RFID_LF_buff[i++] = USART_ReceiveData(RFID_LF_USARTx);	
		RFID_LF_cnt++;
	}
	
	//判断是空闲中断触发
	if(USART_GetITStatus(RFID_LF_USARTx,USART_IT_IDLE))
	{
		//清除中断标志位
		RFID_LF_USARTx->SR;
		RFID_LF_USARTx->DR;
		//紧急事件
		RFID_LF_buff[i] = '\0';
		i = 0;
		RFID_LF_GetData();
	}
}

/*
函数名称:	RFID_Init
函数参数:	void
函数返回值:void
函数功能:	启用RFID模块
*/
void RFID_LF_Init(void)
{
	RFID_USART_Config();
	status.read_ok_flag = 0;
	status.R_read = 0;
	status.R_no_read = 0;
	printf("\t\n天线初始化成功\t\n");
}

/*
函数名称:	RFID_display
函数参数:	void
函数返回值:void
函数功能:	显示卡号
*/
void RFID_display(void)
{
	int i = 0;
	if(status.read_ok_flag == 1)
	{
		if(status.R_read == 1)
		{
			printf("读写器0检测到卡片,卡号:");
			for(i = 0;i < card_ID_cnt;i++)
			{
				printf("%X ",R0_ID[i]);
			}
			printf("\n");
		}
		if(status.R_read == 2)
		{
			printf("读写器1检测到卡片,卡号:");
			for(i = 0;i < card_ID_cnt;i++)
			{
				printf("%X ",R1_ID[i]);
			}
			printf("\n");
		}
	}
	else
	{
		if(status.R_no_read == 1)
		{
			printf("读写器0未检测到卡片\n");
			printf("\n");
		}
		if(status.R_no_read == 2)
		{
			printf("读写器1未检测到卡片\n");
			printf("\n");
		}
	}
	
	status.read_ok_flag = 0;
	status.R_read = 0;
	status.R_no_read = 0;
	memset(R0_ID, 0, sizeof(R0_ID));//将内存的指针指到首地址----清空缓存
	memset(R1_ID, 0, sizeof(R1_ID));//将内存的指针指到首地址----清空缓存
}


/*
函数名称:	RFID_LF_GetData
函数参数:	void
函数返回值:void
函数功能:	分析数据
*/
void RFID_LF_GetData(void)
{
	int i = 0,j = 0;
	if(RFID_LF_cnt == ID_cnt)		//读到的数据位数为卡号时
	{
		status.read_ok_flag = 1;		//读卡成功标志位置1
		if(RFID_LF_buff[1] == 0x00 && RFID_LF_buff[2] == 0x27)		//当读到的数据确实是卡号时,并且读卡器是0
		{
			memcpy(R0_ID,RFID_LF_buff+4,5*sizeof(unsigned char));
			status.R_read = 1;
			status.R_hadRead = 1;
		}
		else if(RFID_LF_buff[1] == 0x01 && RFID_LF_buff[2] == 0x27)	//当读到的数据确实是卡号时,并且读卡器是1
		{
			memcpy(R1_ID,RFID_LF_buff+4,5*sizeof(unsigned char));
			status.R_read = 2;
			status.R_hadRead = 2;
		}
	}
	if(RFID_LF_cnt == fail_LF_cnt)		//读到的数据为卡号不存在时
	{
		if(RFID_LF_buff[1] == 0x00)		//读写器是0
		{
			status.R_no_read = 1;
		}
		else if(RFID_LF_buff[1] == 0x01)	//读写器是1
		{
			status.R_no_read = 1;
		}
	}
	
	RFID_display();		//显示卡号
	RFID_LF_cnt = 0;
	memset(RFID_LF_buff, 0, sizeof(RFID_LF_buff));//将内存的指针指到首地址----清空缓存
}

void RFID_SendCmd( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
{
	uint8_t i;

	for(i=0; i<num; i++)
	{
		/* 发送一个字节数据到USART */
		Usart_SendByte(pUSARTx,array[i]);	
	}
	/* 等待发送完成 */
	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}

/*
函数名称:	Find_LF_Card
函数参数:	u8 reader
函数返回值:u8
函数功能:	低频指定读卡器寻卡函数,参数指定哪个读卡器(只有编号0或1)读卡,返回值为1表示读到卡了
*/
u8 Find_LF_Card(u8 reader)
{
	if(reader == 0)
	{
		//读写器0的单次寻卡
		RFID_SendCmd(RFID_LF_USARTx,find_R0_cmd,find_LF_cmd_cnt);				//单次寻卡
		while(USART_GetFlagStatus(RFID_LF_USARTx,USART_FLAG_TC)!=SET);
		if(status.R_hadRead == 1)		//说明读到卡了
		{
			printf("寻卡成功\n");
			status.R_hadRead = 0;
			return 1;
		}
		else
		{
			printf("寻卡失败\n");
			return 0;
		}
		
	}
	else if(reader == 1)
	{
		//读写器1的单次寻卡
		RFID_SendCmd(RFID_LF_USARTx,find_R1_cmd,find_LF_cmd_cnt);				//单次寻卡
		while(USART_GetFlagStatus(RFID_LF_USARTx,USART_FLAG_TC)!=SET);
		if(status.R_hadRead == 2)		//说明读到卡了
		{
			status.R_hadRead = 0;
			return 1;
		}
		else
			return 0;
	}
	return 0;
}

        RFID_LF.h

#ifndef __RFID_LF_H__
#define __RFID_LF_H__

#include "stm32f10x.h"
#include "ESP8266.h"
#include "string.h"
#include "delay.h"

//RFID模块用到串口2
//要改用其他串口就在这里改
// 串口2-USART2
#define  RFID_LF_USARTx                   USART2
#define  RFID_LF_USART_CLK                RCC_APB1Periph_USART2
#define  RFID_LF_USART_APBxClkCmd         RCC_APB1PeriphClockCmd
#define  RFID_LF_USART_BAUDRATE           9600

// USART GPIO 引脚宏定义
#define  RFID_LF_USART_GPIO_CLK           (RCC_APB2Periph_GPIOA)
#define  RFID_LF_USART_GPIO_APBxClkCmd    RCC_APB2PeriphClockCmd
    
#define  RFID_LF_USART_TX_GPIO_PORT       GPIOA   
#define  RFID_LF_USART_TX_GPIO_PIN        GPIO_Pin_2
#define  RFID_LF_USART_RX_GPIO_PORT       GPIOA
#define  RFID_LF_USART_RX_GPIO_PIN        GPIO_Pin_3

#define  RFID_LF_USART_IRQ                USART2_IRQn
#define  RFID_LF_USART_IRQHandler         USART2_IRQHandler

//陈皮项目RFID读卡可能用到的参数
#define ID_cnt 11					//读到ID卡返回的数据数
#define fail_LF_cnt 7				//无卡时返回的数据数
#define find_LF_cmd_cnt 6			//读卡指令的字节数
#define card_ID_cnt 5				//卡号的数据数

//宏定义读卡器编号
#define R0 0
#define R1 1

void RFID_LF_Init(void);
u8 Find_LF_Card(u8 reader);

#endif		//__RFID_LF_H__

        main.c(注意,我把usart.c.h改名成了ESP8266.c.h,这里用你的串口文件就行)

#include "stm32f10x.h"
#include "delay.h"
#include "RFID_LF.h"
#include "ESP8266.h"

int main(void)
{
	
	//模块初始化
	ESP8266_Usart_Init();
	RFID_LF_Init();
	Delay_Init();
	
	printf("程序开始\n");
	while(1)
	{
		delay_ms(500);
		Find_LF_Card(0);
		delay_ms(500);
		Find_LF_Card(1);
	}
}

 3、成果展示

        没读到卡时:

此卡未检测到vbios支持 未检测到卡片,若已贴卡_物联网_13

        读卡器0读到卡时:

此卡未检测到vbios支持 未检测到卡片,若已贴卡_嵌入式硬件_14

        读卡器1读到卡时:

此卡未检测到vbios支持 未检测到卡片,若已贴卡_物联网_15

四、资源链接(百度云)

资源在这里,注意我为了项目需求将usart.c.h文件改名成了ESP8266.c.h,你就正常用就可以了。我用的是STM32C6T6,代码都是一样的。

百度网盘下载

有问题的话评论区拍我就行。


总结

整个实验还是挺简单的,就是简单做数据的处理和收发而已。下篇博客我会做超高频13.56MHz的RFID读卡器的使用教程,这个相对于低频读卡器来说,它没有主动读卡和卡片离开信息提醒,我们必须要不断读卡来更新它的状态,整个数据处理起来还是比较麻烦的。