单片机基于CR95HF的NFC读卡器方案

张开发
2026/4/9 4:22:44 15 分钟阅读

分享文章

单片机基于CR95HF的NFC读卡器方案
在物联网产品开发过程中近距离与静态标签和动态标签无线通信的NFC读卡器比较丰富与MCU提供众多通信接口比如串口I2CSPI等等并且使用复杂的框架库和交互协议使得调试起来比较麻烦。CR95HF提供串口通信简单字节序的应答逻辑方便快速与NFC标签完成交互。ST公司的CR95HF具有SPI和UART串行连接的多协议无接触13.6MHz收发器IC可作为13.56MHz空中接口的模拟前端AFE支持ISO / IEC 14443 A和BISO / IEC 15693 单或双用户以及ISO / IEC 18092等协议能管理阅读器模式的帧编码和转换主要用在NFC中接近标准应用。CR95HF是用于非接触式应用的集成收发器IC。cr95hf.c使用串口阻塞方式与读卡器交互。#ifndef __CR95HF_H__ #define __CR95HF_H__ #include string.h #include usart3.h #include comtypes.h BOOLEAN CR95HF_Init(void); BOOLEAN CR95HF_Inventory(uint8_t*uid); BOOLEAN CR95HF_ReadBlock(uint8_t*text,uint8_t*textlen); #endif#include cr95hf.h /* 串口波特率57600 1.协议选择iso15693 LR family 02 02 01 05 成功返回 00 00 2.射频增益配置 09 04 68 01 01 50 成功返回 00 00 3.标签搜索 04 03 26 01 00 成功返回 80 0D 00 00 0C BC C1 11 00 24 02 E0(UID) 6F B1 00 no tag 87 00 4.获取标签系统信息 04 02 02 2B 成功返回 80 12 00 0F 0C BC C1 11 00 24 02 E0(UID) 00(DSFID) 00(AFI) 7F(MemorySize) 03(BlockSize) 24(IC Reference) AA 61 00 5.读块 04 03 02 20 00(00--7F) 遍历成功结果,每行从index 03取4个字节 TEXT存储结构:D1 01 textSize T(54) 02 en(65 6E) text 80 08 00 E1 40 40 05 FB 70 00 80 08 00 03 27 D1 01 EE 32 00 80 08 00 23 54 02 65 70 82 00 80 08 00 6E 22 E0 41 46 F4 00 80 08 00 F5 6A C4 A9 3D 35 00 80 08 00 26 5A 63 C7 A9 06 00 80 08 00 99 9E 34 03 E0 A2 00 80 08 00 FD F0 AB 30 33 C5 00 80 08 00 EF 43 3D AB 15 3D 00 80 08 00 A2 AA 8B 61 7A 32 00 80 08 00 4F A7 FF DE D8 28 00 80 08 00 E8 FE 00 00 0A 02 00 80 08 00 00 00 00 00 77 CF 00 80 08 00 00 00 00 00 77 CF 00 */ static const uint8_t protocol_sel[] {0x02,0x02,0x01,0x05}; static const uint8_t rf_gain[] {0x09,0x04,0x68,0x01,0x01,0x50}; static const uint8_t label_inventory[] {0x04,0x03,0x26,0x01,0x00}; static const uint8_t lable_system_info[] {0x04,0x02,0x02,0x2B}; static uint8_t read_single_block[] {0x04,0x03,0x02,0x20,0x00}; #define KEYWORDS _CR95HF_ #define KEYWORDS_LENGTH 8 /** 串口配置协议选择增益配置芯片初始化。 */ BOOLEAN CR95HF_Init(void) { uint8_t tmpbuf[2]; uint8_t trycnt; USART3_Init(57600); HAL_Delay(100); trycnt 0; memset(tmpbuf,0x01,sizeof(tmpbuf)); TRY_PROTOCOL_SEL_WRITE: USART3_SendBuffer((uint8_t*)protocol_sel,sizeof(protocol_sel)); USART3_ReceiveBuffer(tmpbuf,sizeof(tmpbuf)); if(!(tmpbuf[0] 0 tmpbuf[1] 0)){ if(trycnt 10) goto TRY_PROTOCOL_SEL_WRITE; else return FALSE; } trycnt 0; memset(tmpbuf,0x01,sizeof(tmpbuf)); TRY_RF_GAIN_WRITE: USART3_SendBuffer((uint8_t*)rf_gain,sizeof(rf_gain)); USART3_ReceiveBuffer(tmpbuf,2); if(!(tmpbuf[0] 0 tmpbuf[1] 0)){ if(trycnt 10) goto TRY_RF_GAIN_WRITE; else return FALSE; } return TRUE; } /** 搜索NFC标签并返回标签UID。 */ BOOLEAN CR95HF_Inventory(uint8_t*uid) { uint8_t tmpbuf[20]; uint8_t trycnt; uint8_t i; trycnt 0; memset(tmpbuf,0,sizeof(tmpbuf)); TRY_LABEL_INVENTORY_WRITE: USART3_SendBuffer((uint8_t*)label_inventory,sizeof(label_inventory)); USART3_ReceiveBuffer(tmpbuf,sizeof(tmpbuf)); //没有应答 if(tmpbuf[0] 0x00){ if(trycnt 10) goto TRY_LABEL_INVENTORY_WRITE; else return FALSE; } //搜索到标签 else if(tmpbuf[0] 0x80 tmpbuf[1] 0x0D) { if(uid NULL) return TRUE; memcpy(uid,tmpbuf[4],8); //需要颠倒一下 for(i0;i 4;i){ trycnt uid[i]; uid[i] uid[7 - i]; uid[7 - i] trycnt; } return TRUE; } //没有发现 else{ //tmpbuf[0] 0x87 return FALSE; } } /** 读取标签系统信息获取内存大小和块大小轮询所有块找出有标记信息的即为存储内容所在位置。 */ BOOLEAN CR95HF_ReadBlock(uint8_t*text,uint8_t*textlen) { #define SYSTEM_INFO_SIZE (24) #define READ_BLOCK_SIZE (10) uint8_t tmpbuf[SYSTEM_INFO_SIZE]; uint8_t readbuf[128]; uint8_t trycnt; uint8_t i,j; uint16_t memorysize; trycnt 0; memset(tmpbuf,0,SYSTEM_INFO_SIZE); TRY_LABEL_SYSTEM_INFO_WRITE: USART3_SendBuffer((uint8_t*)lable_system_info,sizeof(lable_system_info)); USART3_ReceiveBuffer(tmpbuf,SYSTEM_INFO_SIZE); //没有应答 if(tmpbuf[0] 0x00){ if(trycnt 10) goto TRY_LABEL_SYSTEM_INFO_WRITE; else return FALSE; } else if(tmpbuf[0] 0x80 tmpbuf[1] 0x12) { memorysize tmpbuf[14]; } else { return FALSE; } memset(readbuf,0,sizeof(readbuf)); for(i0;i memorysize / 4;i) { trycnt 0; memset(tmpbuf,0,READ_BLOCK_SIZE); TRY_READ_SINGLE_BLOCK_WRITE: read_single_block[4] i; USART3_SendBuffer((uint8_t*)read_single_block,sizeof(read_single_block)); USART3_ReceiveBuffer(tmpbuf,READ_BLOCK_SIZE); //没有应答 if(tmpbuf[0] 0x00){ if(trycnt 10) goto TRY_READ_SINGLE_BLOCK_WRITE; else return FALSE; } else if(tmpbuf[0] 0x80 tmpbuf[1] 0x08) { memcpy(readbuf[i 2],tmpbuf[3],4); if(tmpbuf[7] 0x77 tmpbuf[8] 0xCF) break; } else{ return FALSE; } } //逐字节比较关键字找出标记信息获取真实内容。 for(j0;j i 2;j) { if(readbuf[j] 0xD1 readbuf[j 1] 0x01) { *textlen readbuf[j 2] - 3 - KEYWORDS_LENGTH; if(readbuf[j 3] 0x54 readbuf[j 4] 0x02 readbuf[j 5] 0x65 readbuf[j 6] 0x6E) { if(strncmp(KEYWORDS,readbuf[j 7]),KEYWORDS_LENGTH)) return FALSE memcpy(text,readbuf[j 7 KEYWORDS_LENGTH],*textlen); return TRUE; } else break; } } return FALSE; } /*** for test if(CR95HF_Init()) { USART1_SendBuf(OKOK,4); } else{ USART1_SendBuf(FAILED,6); } uint8_t uid[8]; uint8_t readata[128]; uint8_t readlen; while(1) { if(CR95HF_Inventory(uid)) { if(CR95HF_ReadBlock(readata,readlen)) USART1_SendBuf(readata,readlen); } HAL_Delay(100); } */

更多文章