当前位置:   article > 正文

基于STM32F103系列的RFID低频读卡器设计项目(保姆级教程)_stm32 rfid识别

stm32 rfid识别

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


前言

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

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


一、前置准备

        本文使用的主控芯片是STM32F103系列,低频读卡器是淘宝电商畅科科技出品的125KHz ID卡读卡器模块(如图1),分为天线和读卡器本体,还有一张125KHz的ID卡(买模块送卡)。使用的通讯协议是RS485(之所以选择这个协议是因为支持多模块通讯,也就是可以用单片机的一个串口连接多个读卡器模块),所以你需要准备一个RS485转TTL模块。这里有一个注意事项:两个读卡器模块的天线距离要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 校验和 03

配置指令的意思是开启主动输出卡号,主动输出卡片离开数据,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 03

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

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())。(复制代码时建议复制下面完整版)

  1. /*
  2. 函数名称: NVIC_Configuration
  3. 函数参数: void
  4. 函数返回值:static void
  5. 函数功能: 中断结构体配置
  6. */
  7. static void NVIC_Configuration(void)
  8. {
  9. NVIC_InitTypeDef NVIC_InitStructure;
  10. /* 嵌套向量中断控制器组选择 */
  11. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  12. /* 配置USART为中断源 */
  13. NVIC_InitStructure.NVIC_IRQChannel = RFID_LF_USART_IRQ;
  14. /* 抢断优先级*/
  15. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  16. /* 子优先级 */
  17. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  18. /* 使能中断 */
  19. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  20. /* 初始化配置NVIC */
  21. NVIC_Init(&NVIC_InitStructure);
  22. }
  23. /*
  24. 函数名称: USART_Config
  25. 函数参数: void
  26. 函数返回值:void
  27. 函数功能: PA2--TX PA3--RX 串口2初始化
  28. */
  29. void RFID_USART_Config(void)
  30. {
  31. GPIO_InitTypeDef GPIO_InitStructure;
  32. USART_InitTypeDef USART_InitStructure;
  33. // 打开串口GPIO的时钟
  34. RFID_LF_USART_GPIO_APBxClkCmd(RFID_LF_USART_GPIO_CLK, ENABLE);
  35. // 打开串口外设的时钟
  36. RFID_LF_USART_APBxClkCmd(RFID_LF_USART_CLK, ENABLE);
  37. // 将USART Tx的GPIO配置为推挽复用模式
  38. GPIO_InitStructure.GPIO_Pin = RFID_LF_USART_TX_GPIO_PIN;
  39. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  40. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  41. GPIO_Init(RFID_LF_USART_TX_GPIO_PORT, &GPIO_InitStructure);
  42. // 将USART Rx的GPIO配置为浮空输入模式
  43. GPIO_InitStructure.GPIO_Pin = RFID_LF_USART_RX_GPIO_PIN;
  44. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  45. GPIO_Init(RFID_LF_USART_RX_GPIO_PORT, &GPIO_InitStructure);
  46. // 配置串口的工作参数
  47. // 配置波特率
  48. USART_InitStructure.USART_BaudRate = RFID_LF_USART_BAUDRATE;
  49. // 配置 针数据字长
  50. USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  51. // 配置停止位
  52. USART_InitStructure.USART_StopBits = USART_StopBits_1;
  53. // 配置校验位
  54. USART_InitStructure.USART_Parity = USART_Parity_No ;
  55. // 配置硬件流控制
  56. USART_InitStructure.USART_HardwareFlowControl =
  57. USART_HardwareFlowControl_None;
  58. // 配置工作模式,收发一起
  59. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  60. // 完成串口的初始化配置
  61. USART_Init(RFID_LF_USARTx, &USART_InitStructure);
  62. // 串口中断优先级配置
  63. NVIC_Configuration();
  64. // 使能串口接收中断
  65. USART_ITConfig(RFID_LF_USARTx, USART_IT_RXNE, ENABLE);
  66. USART_ITConfig ( RFID_LF_USARTx, USART_IT_IDLE, ENABLE ); //使能串口总线空闲中断
  67. // 使能串口
  68. USART_Cmd(RFID_LF_USARTx, ENABLE);
  69. }
  70. /*
  71. 函数名称: RFID_LF_USART_IRQHandler
  72. 函数参数: void
  73. 函数返回值:void
  74. 函数功能: 接收一帧数据并且进行解析
  75. */
  76. unsigned char RFID_LF_buff[512];
  77. int RFID_LF_cnt = 0;
  78. void RFID_LF_USART_IRQHandler(void)
  79. {
  80. static u8 i = 0;
  81. //判断是接收中断触发
  82. if(USART_GetITStatus(RFID_LF_USARTx,USART_IT_RXNE))
  83. {
  84. //清除中断标志位
  85. USART_ClearITPendingBit(RFID_LF_USARTx,USART_IT_RXNE);
  86. //紧急事件
  87. RFID_LF_buff[i++] = USART_ReceiveData(RFID_LF_USARTx);
  88. RFID_LF_cnt++;
  89. }
  90. //判断是空闲中断触发
  91. if(USART_GetITStatus(RFID_LF_USARTx,USART_IT_IDLE))
  92. {
  93. //清除中断标志位
  94. RFID_LF_USARTx->SR;
  95. RFID_LF_USARTx->DR;
  96. //紧急事件
  97. RFID_LF_buff[i] = '\0';
  98. i = 0;
  99. RFID_LF_GetData();
  100. }
  101. }

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

  1. struct RFID_status
  2. {
  3. int read_ok_flag; //表示是否读到卡
  4. int R_read; //表示读到的是哪个编号
  5. int R_no_read;
  6. int R_hadRead; //表示哪个读卡器已经读到过卡了
  7. }status;
  8. /*
  9. 函数名称: RFID_LF_GetData
  10. 函数参数: void
  11. 函数返回值:void
  12. 函数功能: 分析数据
  13. */
  14. void RFID_LF_GetData(void)
  15. {
  16. int i = 0,j = 0;
  17. if(RFID_LF_cnt == ID_cnt) //读到的数据位数为卡号时
  18. {
  19. status.read_ok_flag = 1; //读卡成功标志位置1
  20. if(RFID_LF_buff[1] == 0x00 && RFID_LF_buff[2] == 0x27) //当读到的数据确实是卡号时,并且读卡器是0
  21. {
  22. memcpy(R0_ID,RFID_LF_buff+4,5*sizeof(unsigned char));
  23. status.R_read = 1;
  24. status.R_hadRead = 1;
  25. }
  26. else if(RFID_LF_buff[1] == 0x01 && RFID_LF_buff[2] == 0x27) //当读到的数据确实是卡号时,并且读卡器是1
  27. {
  28. memcpy(R1_ID,RFID_LF_buff+4,5*sizeof(unsigned char));
  29. status.R_read = 2;
  30. status.R_hadRead = 2;
  31. }
  32. }
  33. if(RFID_LF_cnt == fail_LF_cnt) //读到的数据为卡号不存在时
  34. {
  35. if(RFID_LF_buff[1] == 0x00) //读写器是0
  36. {
  37. status.R_no_read = 1;
  38. }
  39. else if(RFID_LF_buff[1] == 0x01) //读写器是1
  40. {
  41. status.R_no_read = 1;
  42. }
  43. }
  44. RFID_display(); //显示卡号
  45. RFID_LF_cnt = 0;
  46. memset(RFID_LF_buff, 0, sizeof(RFID_LF_buff));//将内存的指针指到首地址----清空缓存
  47. }
  48. /*
  49. 函数名称: RFID_display
  50. 函数参数: void
  51. 函数返回值:void
  52. 函数功能: 显示卡号
  53. */
  54. void RFID_display(void)
  55. {
  56. int i = 0;
  57. if(status.read_ok_flag == 1)
  58. {
  59. if(status.R_read == 1)
  60. {
  61. printf("读写器0检测到卡片,卡号:");
  62. for(i = 0;i < card_ID_cnt;i++)
  63. {
  64. printf("%X ",R0_ID[i]);
  65. }
  66. printf("\n");
  67. }
  68. if(status.R_read == 2)
  69. {
  70. printf("读写器1检测到卡片,卡号:");
  71. for(i = 0;i < card_ID_cnt;i++)
  72. {
  73. printf("%X ",R1_ID[i]);
  74. }
  75. printf("\n");
  76. }
  77. }
  78. else
  79. {
  80. if(status.R_no_read == 1)
  81. {
  82. printf("读写器0未检测到卡片\n");
  83. printf("\n");
  84. }
  85. if(status.R_no_read == 2)
  86. {
  87. printf("读写器1未检测到卡片\n");
  88. printf("\n");
  89. }
  90. }
  91. status.read_ok_flag = 0;
  92. status.R_read = 0;
  93. status.R_no_read = 0;
  94. memset(R0_ID, 0, sizeof(R0_ID));//将内存的指针指到首地址----清空缓存
  95. memset(R1_ID, 0, sizeof(R1_ID));//将内存的指针指到首地址----清空缓存
  96. }

        最后再写个寻卡命令

  1. /*
  2. 函数名称: RDID_SendCmd
  3. 函数参数: USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num
  4. 函数返回值:void
  5. 函数功能: 给RFID模块发送指令
  6. */
  7. void RFID_SendCmd( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
  8. {
  9. uint8_t i;
  10. for(i=0; i<num; i++)
  11. {
  12. /* 发送一个字节数据到USART */
  13. Usart_SendByte(pUSARTx,array[i]);
  14. }
  15. /* 等待发送完成 */
  16. while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
  17. }
  18. /*
  19. 函数名称: Find_LF_Card
  20. 函数参数: u8 reader
  21. 函数返回值:u8
  22. 函数功能: 低频指定读卡器寻卡函数,参数指定哪个读卡器(只有编号0或1)读卡,返回值为1表示读到卡了
  23. */
  24. u8 Find_LF_Card(u8 reader)
  25. {
  26. if(reader == 0)
  27. {
  28. //读写器0的单次寻卡
  29. RFID_SendCmd(RFID_LF_USARTx,find_R0_cmd,find_LF_cmd_cnt); //单次寻卡
  30. while(USART_GetFlagStatus(RFID_LF_USARTx,USART_FLAG_TC)!=SET);
  31. if(status.R_hadRead == 1) //说明读到卡了
  32. {
  33. printf("寻卡成功\n");
  34. status.R_hadRead = 0;
  35. return 1;
  36. }
  37. else
  38. {
  39. printf("寻卡失败\n");
  40. return 0;
  41. }
  42. }
  43. else if(reader == 1)
  44. {
  45. //读写器1的单次寻卡
  46. RFID_SendCmd(RFID_LF_USARTx,find_R1_cmd,find_LF_cmd_cnt); //单次寻卡
  47. while(USART_GetFlagStatus(RFID_LF_USARTx,USART_FLAG_TC)!=SET);
  48. if(status.R_hadRead == 2) //说明读到卡了
  49. {
  50. status.R_hadRead = 0;
  51. return 1;
  52. }
  53. else
  54. return 0;
  55. }
  56. return 0;
  57. }

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

  1. #define ID_cnt 11 //读到ID卡返回的数据数
  2. #define fail_LF_cnt 7 //无卡时返回的数据数
  3. #define find_LF_cmd_cnt 6 //读卡指令的字节数
  4. #define card_ID_cnt 5 //卡号的数据数
  5. //RFID_LF相关命令
  6. //单次询问读写器0指令
  7. unsigned char find_R0_cmd[find_LF_cmd_cnt] = {0x20,0x00,0x27,0x00,0xD8,0x03};
  8. //单次询问读写器1指令
  9. unsigned char find_R1_cmd[find_LF_cmd_cnt] = {0x20,0x01,0x27,0x00,0xD9,0x03};
  10. //用来存放读写器0读出的卡号
  11. unsigned char R0_ID[20];
  12. //用来存放读写器1读出的卡号
  13. unsigned char R1_ID[20];

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

RFID_LF.c

  1. #include "RFID_LF.h"
  2. //RFID_LF相关命令
  3. //单次询问读写器0指令
  4. unsigned char find_R0_cmd[find_LF_cmd_cnt] = {0x20,0x00,0x27,0x00,0xD8,0x03};
  5. //单次询问读写器1指令
  6. unsigned char find_R1_cmd[find_LF_cmd_cnt] = {0x20,0x01,0x27,0x00,0xD9,0x03};
  7. //用来存放读写器0读出的卡号
  8. unsigned char R0_ID[20];
  9. //用来存放读写器1读出的卡号
  10. unsigned char R1_ID[20];
  11. //内部函数声明
  12. void RFID_SendCmd( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num);
  13. void RFID_LF_GetData(void);
  14. void RFID_display(void);
  15. struct RFID_status
  16. {
  17. int read_ok_flag; //表示是否读到卡
  18. int R_read; //表示读到的是哪个编号
  19. int R_no_read;
  20. int R_hadRead; //表示哪个读卡器已经读到过卡了
  21. }status;
  22. /*
  23. 函数名称: NVIC_Configuration
  24. 函数参数: void
  25. 函数返回值:static void
  26. 函数功能: 中断结构体配置
  27. */
  28. static void NVIC_Configuration(void)
  29. {
  30. NVIC_InitTypeDef NVIC_InitStructure;
  31. /* 嵌套向量中断控制器组选择 */
  32. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  33. /* 配置USART为中断源 */
  34. NVIC_InitStructure.NVIC_IRQChannel = RFID_LF_USART_IRQ;
  35. /* 抢断优先级*/
  36. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  37. /* 子优先级 */
  38. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  39. /* 使能中断 */
  40. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  41. /* 初始化配置NVIC */
  42. NVIC_Init(&NVIC_InitStructure);
  43. }
  44. /*
  45. 函数名称: USART_Config
  46. 函数参数: void
  47. 函数返回值:void
  48. 函数功能: PA2--TX PA3--RX 串口2初始化
  49. */
  50. void RFID_USART_Config(void)
  51. {
  52. GPIO_InitTypeDef GPIO_InitStructure;
  53. USART_InitTypeDef USART_InitStructure;
  54. // 打开串口GPIO的时钟
  55. RFID_LF_USART_GPIO_APBxClkCmd(RFID_LF_USART_GPIO_CLK, ENABLE);
  56. // 打开串口外设的时钟
  57. RFID_LF_USART_APBxClkCmd(RFID_LF_USART_CLK, ENABLE);
  58. // 将USART Tx的GPIO配置为推挽复用模式
  59. GPIO_InitStructure.GPIO_Pin = RFID_LF_USART_TX_GPIO_PIN;
  60. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  61. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  62. GPIO_Init(RFID_LF_USART_TX_GPIO_PORT, &GPIO_InitStructure);
  63. // 将USART Rx的GPIO配置为浮空输入模式
  64. GPIO_InitStructure.GPIO_Pin = RFID_LF_USART_RX_GPIO_PIN;
  65. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  66. GPIO_Init(RFID_LF_USART_RX_GPIO_PORT, &GPIO_InitStructure);
  67. // 配置串口的工作参数
  68. // 配置波特率
  69. USART_InitStructure.USART_BaudRate = RFID_LF_USART_BAUDRATE;
  70. // 配置 针数据字长
  71. USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  72. // 配置停止位
  73. USART_InitStructure.USART_StopBits = USART_StopBits_1;
  74. // 配置校验位
  75. USART_InitStructure.USART_Parity = USART_Parity_No ;
  76. // 配置硬件流控制
  77. USART_InitStructure.USART_HardwareFlowControl =
  78. USART_HardwareFlowControl_None;
  79. // 配置工作模式,收发一起
  80. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  81. // 完成串口的初始化配置
  82. USART_Init(RFID_LF_USARTx, &USART_InitStructure);
  83. // 串口中断优先级配置
  84. NVIC_Configuration();
  85. // 使能串口接收中断
  86. USART_ITConfig(RFID_LF_USARTx, USART_IT_RXNE, ENABLE);
  87. USART_ITConfig ( RFID_LF_USARTx, USART_IT_IDLE, ENABLE ); //使能串口总线空闲中断
  88. // 使能串口
  89. USART_Cmd(RFID_LF_USARTx, ENABLE);
  90. }
  91. /*
  92. 函数名称: RFID_LF_USART_IRQHandler
  93. 函数参数: void
  94. 函数返回值:void
  95. 函数功能: 接收一帧数据并且进行解析
  96. */
  97. unsigned char RFID_LF_buff[512];
  98. int RFID_LF_cnt = 0;
  99. void RFID_LF_USART_IRQHandler(void)
  100. {
  101. static u8 i = 0;
  102. //判断是接收中断触发
  103. if(USART_GetITStatus(RFID_LF_USARTx,USART_IT_RXNE))
  104. {
  105. //清除中断标志位
  106. USART_ClearITPendingBit(RFID_LF_USARTx,USART_IT_RXNE);
  107. //紧急事件
  108. RFID_LF_buff[i++] = USART_ReceiveData(RFID_LF_USARTx);
  109. RFID_LF_cnt++;
  110. }
  111. //判断是空闲中断触发
  112. if(USART_GetITStatus(RFID_LF_USARTx,USART_IT_IDLE))
  113. {
  114. //清除中断标志位
  115. RFID_LF_USARTx->SR;
  116. RFID_LF_USARTx->DR;
  117. //紧急事件
  118. RFID_LF_buff[i] = '\0';
  119. i = 0;
  120. RFID_LF_GetData();
  121. }
  122. }
  123. /*
  124. 函数名称: RFID_Init
  125. 函数参数: void
  126. 函数返回值:void
  127. 函数功能: 启用RFID模块
  128. */
  129. void RFID_LF_Init(void)
  130. {
  131. RFID_USART_Config();
  132. status.read_ok_flag = 0;
  133. status.R_read = 0;
  134. status.R_no_read = 0;
  135. printf("\t\n天线初始化成功\t\n");
  136. }
  137. /*
  138. 函数名称: RFID_display
  139. 函数参数: void
  140. 函数返回值:void
  141. 函数功能: 显示卡号
  142. */
  143. void RFID_display(void)
  144. {
  145. int i = 0;
  146. if(status.read_ok_flag == 1)
  147. {
  148. if(status.R_read == 1)
  149. {
  150. printf("读写器0检测到卡片,卡号:");
  151. for(i = 0;i < card_ID_cnt;i++)
  152. {
  153. printf("%X ",R0_ID[i]);
  154. }
  155. printf("\n");
  156. }
  157. if(status.R_read == 2)
  158. {
  159. printf("读写器1检测到卡片,卡号:");
  160. for(i = 0;i < card_ID_cnt;i++)
  161. {
  162. printf("%X ",R1_ID[i]);
  163. }
  164. printf("\n");
  165. }
  166. }
  167. else
  168. {
  169. if(status.R_no_read == 1)
  170. {
  171. printf("读写器0未检测到卡片\n");
  172. printf("\n");
  173. }
  174. if(status.R_no_read == 2)
  175. {
  176. printf("读写器1未检测到卡片\n");
  177. printf("\n");
  178. }
  179. }
  180. status.read_ok_flag = 0;
  181. status.R_read = 0;
  182. status.R_no_read = 0;
  183. memset(R0_ID, 0, sizeof(R0_ID));//将内存的指针指到首地址----清空缓存
  184. memset(R1_ID, 0, sizeof(R1_ID));//将内存的指针指到首地址----清空缓存
  185. }
  186. /*
  187. 函数名称: RFID_LF_GetData
  188. 函数参数: void
  189. 函数返回值:void
  190. 函数功能: 分析数据
  191. */
  192. void RFID_LF_GetData(void)
  193. {
  194. int i = 0,j = 0;
  195. if(RFID_LF_cnt == ID_cnt) //读到的数据位数为卡号时
  196. {
  197. status.read_ok_flag = 1; //读卡成功标志位置1
  198. if(RFID_LF_buff[1] == 0x00 && RFID_LF_buff[2] == 0x27) //当读到的数据确实是卡号时,并且读卡器是0
  199. {
  200. memcpy(R0_ID,RFID_LF_buff+4,5*sizeof(unsigned char));
  201. status.R_read = 1;
  202. status.R_hadRead = 1;
  203. }
  204. else if(RFID_LF_buff[1] == 0x01 && RFID_LF_buff[2] == 0x27) //当读到的数据确实是卡号时,并且读卡器是1
  205. {
  206. memcpy(R1_ID,RFID_LF_buff+4,5*sizeof(unsigned char));
  207. status.R_read = 2;
  208. status.R_hadRead = 2;
  209. }
  210. }
  211. if(RFID_LF_cnt == fail_LF_cnt) //读到的数据为卡号不存在时
  212. {
  213. if(RFID_LF_buff[1] == 0x00) //读写器是0
  214. {
  215. status.R_no_read = 1;
  216. }
  217. else if(RFID_LF_buff[1] == 0x01) //读写器是1
  218. {
  219. status.R_no_read = 1;
  220. }
  221. }
  222. RFID_display(); //显示卡号
  223. RFID_LF_cnt = 0;
  224. memset(RFID_LF_buff, 0, sizeof(RFID_LF_buff));//将内存的指针指到首地址----清空缓存
  225. }
  226. void RFID_SendCmd( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
  227. {
  228. uint8_t i;
  229. for(i=0; i<num; i++)
  230. {
  231. /* 发送一个字节数据到USART */
  232. Usart_SendByte(pUSARTx,array[i]);
  233. }
  234. /* 等待发送完成 */
  235. while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
  236. }
  237. /*
  238. 函数名称: Find_LF_Card
  239. 函数参数: u8 reader
  240. 函数返回值:u8
  241. 函数功能: 低频指定读卡器寻卡函数,参数指定哪个读卡器(只有编号0或1)读卡,返回值为1表示读到卡了
  242. */
  243. u8 Find_LF_Card(u8 reader)
  244. {
  245. if(reader == 0)
  246. {
  247. //读写器0的单次寻卡
  248. RFID_SendCmd(RFID_LF_USARTx,find_R0_cmd,find_LF_cmd_cnt); //单次寻卡
  249. while(USART_GetFlagStatus(RFID_LF_USARTx,USART_FLAG_TC)!=SET);
  250. if(status.R_hadRead == 1) //说明读到卡了
  251. {
  252. printf("寻卡成功\n");
  253. status.R_hadRead = 0;
  254. return 1;
  255. }
  256. else
  257. {
  258. printf("寻卡失败\n");
  259. return 0;
  260. }
  261. }
  262. else if(reader == 1)
  263. {
  264. //读写器1的单次寻卡
  265. RFID_SendCmd(RFID_LF_USARTx,find_R1_cmd,find_LF_cmd_cnt); //单次寻卡
  266. while(USART_GetFlagStatus(RFID_LF_USARTx,USART_FLAG_TC)!=SET);
  267. if(status.R_hadRead == 2) //说明读到卡了
  268. {
  269. status.R_hadRead = 0;
  270. return 1;
  271. }
  272. else
  273. return 0;
  274. }
  275. return 0;
  276. }

        RFID_LF.h

  1. #ifndef __RFID_LF_H__
  2. #define __RFID_LF_H__
  3. #include "stm32f10x.h"
  4. #include "ESP8266.h"
  5. #include "string.h"
  6. #include "delay.h"
  7. //RFID模块用到串口2
  8. //要改用其他串口就在这里改
  9. // 串口2-USART2
  10. #define RFID_LF_USARTx USART2
  11. #define RFID_LF_USART_CLK RCC_APB1Periph_USART2
  12. #define RFID_LF_USART_APBxClkCmd RCC_APB1PeriphClockCmd
  13. #define RFID_LF_USART_BAUDRATE 9600
  14. // USART GPIO 引脚宏定义
  15. #define RFID_LF_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
  16. #define RFID_LF_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
  17. #define RFID_LF_USART_TX_GPIO_PORT GPIOA
  18. #define RFID_LF_USART_TX_GPIO_PIN GPIO_Pin_2
  19. #define RFID_LF_USART_RX_GPIO_PORT GPIOA
  20. #define RFID_LF_USART_RX_GPIO_PIN GPIO_Pin_3
  21. #define RFID_LF_USART_IRQ USART2_IRQn
  22. #define RFID_LF_USART_IRQHandler USART2_IRQHandler
  23. //陈皮项目RFID读卡可能用到的参数
  24. #define ID_cnt 11 //读到ID卡返回的数据数
  25. #define fail_LF_cnt 7 //无卡时返回的数据数
  26. #define find_LF_cmd_cnt 6 //读卡指令的字节数
  27. #define card_ID_cnt 5 //卡号的数据数
  28. //宏定义读卡器编号
  29. #define R0 0
  30. #define R1 1
  31. void RFID_LF_Init(void);
  32. u8 Find_LF_Card(u8 reader);
  33. #endif //__RFID_LF_H__

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

  1. #include "stm32f10x.h"
  2. #include "delay.h"
  3. #include "RFID_LF.h"
  4. #include "ESP8266.h"
  5. int main(void)
  6. {
  7. //模块初始化
  8. ESP8266_Usart_Init();
  9. RFID_LF_Init();
  10. Delay_Init();
  11. printf("程序开始\n");
  12. while(1)
  13. {
  14. delay_ms(500);
  15. Find_LF_Card(0);
  16. delay_ms(500);
  17. Find_LF_Card(1);
  18. }
  19. }

 3、成果展示

        没读到卡时:

        读卡器0读到卡时:

        读卡器1读到卡时:

四、资源链接(百度云)

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

百度网盘下载

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


总结

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/744208
推荐阅读
相关标签
  

闽ICP备14008679号