本文介绍如何使用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所示。代码资料会稍后放在后面。
图1 ID低频读卡器
图2 组装
二、使用步骤
1.读卡器介绍
(1)前言
首先畅科读卡器在出厂的时候内置了一些功能,比如我购买的是带有蜂鸣器的RS485协议的读卡器,我放卡上去会听到“滴”的一声,并且芯片上的LED灯会常亮,于此同时读卡器会发送一帧数据返回若干信息。卡片离开时LED灯会灭,并且会发送一帧数据显示已离开读卡器。我们可以配置相关功能比如检测到卡片时是否会“滴”的一声,检测到卡片时要不要主动返回数据给上位机,以及卡片离开时是否发送数据提示卡片已离开,还能设置波特率。顺便说一下通讯指令用到的都是十六进制位,数据类型用的是unsigned char。如果用多个读卡器的话,多个读卡器接到RS485转TTL芯片,STM32用一个串口跟这芯片相连,那么我们怎么区分哪个读卡器读到卡呢?这就要用到读卡器的地址了,我们还要修改读卡器的地址,比如出厂的读卡器模块地址都是0x00,我们要把多余的读卡器地址设置为0x01、0x02等等,反正不与0x00相同就行。
(2)数值帧指令分析
我们来看读卡器的功能配置指令(如图3),以上我说的相关功能都可以在这里配置。
图3 功能配置指令
由上图可知,一帧数据指令是由以上若干格式组成的。我们要更改相关功能只需要修改对应的值即可,以下贴出读卡器使用说明中各个位指令的作用(如图5)。
图4 各个位的作用
这里要注意的是校验和,上面可能说得不太清楚,根据我的理解是先把BCC校验(异或校验)算出来,然后把得出来的二进制位全部取反,取反后得到的就是校验和。写个例子,比如根据上面的功能配置指令,我写出来了一帧配置指令:
20 00 2C 04 00 00 96 00 校验和
配置指令的意思是开启主动输出卡号,主动输出卡片离开数据,9600的波特率,开启蜂鸣器提醒。我现在开始要算校验和,根据指示我得出来00 2C 04 00 00 96 00。
然后计算BBC校验码,如图5。
图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所示配置:
图6 串口调试助手的相关配置
接下来我们查看修改模块地址指令(如图7)。
图7 修改模块地址指令
我们可以看到,我们要修改的有两个值,一个是原地址,一个是新地址,分别位于第2和第5个字节。由于读卡器出厂都是默认地址为0x00,原地址就填0x00。新地址的话填你想要的值,我填的是0x01,发送成功后会接受到反馈指令,如图8。
图8 修改读卡器地址
(2)测试读卡器功能
如果我们用默认功能配置的话,是开启主动输出卡号,主动输出卡片离开数据,9600的波特率,开启蜂鸣器提醒。所以我们先测试的时候是把卡片放到天线上去,可以听到蜂鸣器响一声,并且串口调试助手接受到数据(如图9)。卡片拿走后返回卡片离开数据(如图10)。(这里我使用的是地址为0x01的读卡器,所以数据帧第二个字节是01)
图9 检测到卡片时返回的数据
图10 卡片已离开
我们不仅要它读到卡号返回数据,还要随时能够确定读卡器天线上有没有卡片,接下来测试读卡指令,先看读卡指令的通讯格式(如图11)。
图11 寻卡指令格式
我们根据地址寻卡,比如地址为0x01的读卡器,我们就把第2字节的地址位改成0x01,然后计算校验值得到D9,指令是20 01 27 00 D9 03。如图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、成果展示
没读到卡时:
读卡器0读到卡时:
读卡器1读到卡时:
四、资源链接(百度云)
资源在这里,注意我为了项目需求将usart.c.h文件改名成了ESP8266.c.h,你就正常用就可以了。我用的是STM32C6T6,代码都是一样的。
有问题的话评论区拍我就行。
总结
整个实验还是挺简单的,就是简单做数据的处理和收发而已。下篇博客我会做超高频13.56MHz的RFID读卡器的使用教程,这个相对于低频读卡器来说,它没有主动读卡和卡片离开信息提醒,我们必须要不断读卡来更新它的状态,整个数据处理起来还是比较麻烦的。