news 2026/9/7 4:37:55

ST25R3916实战:NFC读取全流程解析与天线调谐

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ST25R3916实战:NFC读取全流程解析与天线调谐

最近在做一款便携式 NFC 读写设备,主控选型时在 PN532、CR95HF 和 ST25R3916 之间犹豫了很久。PN532 资料多、上手快,但射频性能和高低温稳定性在工业场景下有点捉襟见肘;CR95HF 是 ST 自家的经典方案,不过协议支持相对保守。最后换到 ST25R3916 之后,才真正体会到“读卡器前端芯片”和“读卡器芯片”之间的差别。

这篇文章会把 ST25R3916 做 NFC 读取的完整思路整理出来,包括硬件连接、射频原理、驱动初始化、防冲突选卡、数据块读取、天线调谐,以及实际调试中遇到的高频问题。适合正在选型 NFC 读卡方案的嵌入式工程师,也适合刚接触 13.56MHz 射频开发、想从零把一张 ISO14443A 卡读出来的新手。

围绕“ST25R3916 NFC 读取”这个主题,文章会尽量把“为什么这么做”讲清楚,而不只贴一段能跑的代码。代码基于常见驱动框架编写,函数名和寄存器名会因驱动版本不同有差异,实际使用时请注意对照官方数据手册和驱动包调整。

1. 认识 ST25R3916:一颗专业的 NFC 前端芯片

1.1 “读 NFC”到底在读什么

很多人第一次接触 NFC 开发时,会以为“读 NFC”是一个单一动作:把卡片靠近天线,然后拿到一串 ID。实际上,这个动作背后包含了一整条射频通信链路。

NFC 工作在 13.56MHz 频段,读卡器和卡片之间通过电磁耦合通信。读卡器天线持续发射射频场,卡片进入场区后从射频场获取能量完成上电,双方再通过负载调制的方式交换数据。所以“读取一张 NFC 卡”至少包括这样几个环节:

  1. 建立射频场;
  2. 检测到场内有卡片进入;
  3. 发送协议命令,例如 ISO14443A 的 REQA;
  4. 执行防冲突循环,拿到完整的 UID;
  5. 选择卡片;
  6. 根据应用类型读取数据块或执行认证。

任何一个环节出问题,表现都是“读不到卡”或者“读卡不稳定”。ST25R3916 要做的,就是把射频前端这部分做好,把模拟链路的复杂度屏蔽掉,交给 MCU 一个相对干净的数字接口。

1.2 ST25R3916 的定位与核心特性

ST25R3916 是 ST 推出的一款高性能 NFC 读卡器前端芯片,定位是“HF Reader/Writer 前端”。它本身不跑协议栈,也不直接输出“卡的 UID”,而是负责射频信号的调制、解调、编码、解码,以及帧的收发。

这意味着你需要一颗 MCU 通过 SPI 或 I2C 接口控制它,给它下发命令、读取中断、处理收发数据。协议栈可以在 MCU 上自己写,也可以使用 ST 官方的 RFAL(RF Abstraction Layer)中间件。

ST25R3916 比较突出的特性包括:

  • 支持 ISO 14443A / 14443B、ISO 15693、FeliCa、ISO 18092 等多种协议;
  • 支持高射频输出功率,适合天线尺寸较大或需要更远读卡距离的场景;
  • 内置动态功耗控制(DPO),可以根据负载自动调整输出功率;
  • 支持有源波形整形(AAT),改善发射波形质量,减少谐波;
  • 支持自动天线调谐(AMT),天线失谐时可以自动补偿;
  • 集成低功耗卡片检测(LPCD),MCU 休眠时仍能检测卡片进入;
  • 芯片内部带 AES-128 协处理器,可用在安全认证类应用中。

这些特性让它在门禁、支付终端、工业读卡器、消费电子、安全令牌等场景中都很常见。像市面上一些 NFC 开发模块、安全密钥设备(例如带 NFC 的 YubiKey 类产品)、以及 PC 端调试用的 NFC Reader Tool 类工具,底层很多就是这类高性能前端芯片。

1.3 典型应用场景

从实际项目角度看,ST25R3916 适合的产品有这几类:

应用场景典型需求为什么选 ST25R3916
门禁读卡器识别 ISO14443A 卡 UID,要求读卡距离远、稳定射频输出功率高,配合天线调谐可以做到较远的读卡距离
工业读写设备长时间连续读卡,环境温度变化大射频参数可配置,支持自动天线调谐
支付终端支持多种协议,需要快速轮询多协议支持完善,轮询切换效率高
便携式 NFC 工具电池供电,需要低功耗LPCD 低功耗卡片检测,MCU 可以休眠
安全认证设备需要 AES 安全认证、防中继攻击内置 AES-128 协处理器,支持挑战响应机制

如果项目只需要“读个 UID”,用 ST25R3916 确实有点“杀鸡用牛刀”。但如果产品后面要兼容多种卡片、要过认证、要在恶劣环境下稳定工作,它的价值就体现出来了。

1.4 ST25R3916 与常见方案的比较

很多初学者会拿 ST25R3916 和 PN532 对比。这两个芯片定位不太一样:

  • PN532 是 NXP 的一体化 NFC 芯片,内部集成了 MCU 核和协议栈,用户通过 UART / I2C / SPI 发 HCI 指令就能读卡。优点是开发简单,缺点是射频性能、协议扩展性和灵活性有限。
  • ST25R3916 是纯前端芯片,没有协议栈,所有协议处理都在外部 MCU 上完成。开发门槛高一些,但灵活性和性能上限也更高。

CR95HF 是 ST 自家另一款经典读卡器芯片,同样需要外部 MCU,但协议支持比较少,主要面向 ISO14443 和 ISO15693。ST25R3916 在协议覆盖、发射功率、低功耗和天线调谐方面都比 CR95HF 更进一步。

所以选型时可以按这个思路判断:

  1. 只做 Demo、快速验证:选 PN532 或集成 NFC 模块;
  2. 产品化读卡器、工业设备:选 ST25R3916;
  3. 需要多种协议、复杂轮询、低功耗:优先考虑 ST25R3916;
  4. 预算敏感、只读 14443A:CR95HF 也可接受。

2. 环境准备与硬件接线

2.1 硬件清单

开始写代码之前,先把硬件准备好。我这里用的是常见的“MCU + ST25R3916 模块”组合:

硬件说明
ST25R3916 开发板或最小模块自带天线和匹配电路的最佳,前期省去天线调试
MCU 主控推荐 STM32 系列,本文示例以 STM32 为参考
NFC 卡片ISO14443A 类型卡,例如 Mifare Classic、NTAG21x
逻辑分析仪或示波器排查 SPI 通信和射频波形时会用到
供电3.3V,注意读卡器天线发射时电流较大,电源要稳定

如果买的是 ST 官方的评估板,板上通常已经画好了天线匹配电路,可以直接和 MCU 通过排针连接。如果是自己画板,天线部分建议先参考官方评估板的设计,不要一上来就自己创新。

2.2 与 MCU 的接口连接

ST25R3916 和 MCU 之间常用 SPI 通信,速率可以跑到几 MHz。连接关系比较固定:

ST25R3916 引脚连接对象说明
SPI_CLKMCU SPI SCK时钟
SPI_MOSIMCU SPI MOSIMCU 写芯片
SPI_MISOMCU SPI MISO芯片回数据
SPI_NSSMCU GPIO/SPI CS片选,低有效
IRQMCU 外部中断引脚芯片产生中断时拉高/低
RSTMCU GPIO硬件复位
VDD3.3V供电
VSSGND

IRQ 引脚很重要。读卡过程中芯片会有大量事件中断,比如“场已建立”“检测到卡片”“数据发送完成”“数据接收完成”“CRC 错误”。如果不用 IRQ,而是靠 MCU 轮询状态寄存器,会非常占用 CPU,而且容易丢事件。

2.3 软件环境与驱动来源

ST25R3916 的软件开发一般有两个层次:

  1. 直接操作寄存器:适合想深入理解射频底层的人,代码量较大,需要仔细对照数据手册。
  2. 使用 ST 官方中间件 RFAL:封装了协议层,提供轮询、激活、读写等 API,适合项目落地。

建议前期先用 RFAL 把业务功能跑通,遇到射频级别的疑难问题再回头查寄存器。这样效率最高。

需要注意,ST25R3916 的驱动库版本和 API 名称在不同时期有调整。本文代码演示的是通用思路,函数名和参数请以你下载的驱动包为准。

2.4 工程目录规划

一个相对清晰的 NFC 工程目录大概是这样的:

project/ ├── app/ │ ├── app_nfc.c // NFC 业务逻辑 │ └── app_nfc.h ├── bsp/ │ ├── bsp_spi.c // SPI 底层驱动 │ └── bsp_st25r3916.c // 芯片硬件初始化 ├── lib/ │ ├── st25r3916.c // 芯片驱动 │ ├── st25r3916.h │ ├── rfal.c // 射频抽象层 │ └── rfal_nfc.c ├── main.c └── Makefile 或 Keil/IAR 工程

把“芯片驱动”“协议抽象”“业务逻辑”分层,后面排查问题会轻松很多。

3. NFC 读取的核心原理

这一节是整个开发过程中最容易“知其然不知其所以然”的部分,值得耐心看。

3.1 13.56MHz 射频通信链路

ST25R3916 和卡片之间是无线通信,通信链路包含以下环节:

  1. MCU 通过 SPI 把要发送的帧数据写入 ST25R3916 的 FIFO;
  2. 芯片按照协议规定的编码方式(如 Miller、Manchester)调制载波,从天线发射;
  3. 卡片接收命令,处理后通过负载调制把响应数据传回;
  4. 芯片内部解调、解码,把收到的数据放入 FIFO,并触发中断;
  5. MCU 读取 FIFO,完成一次数据交换。

这里有一个容易忽略的点:射频通信失败不一定都是软件问题,天线阻抗匹配、发射功率、接收灵敏度都会影响成功率。所以调试 ST25R3916 时,“软件没问题但读卡距离很近”通常是天线匹配的问题,而不是代码逻辑的问题。

3.2 ISO14443A 读取流程拆解

以最常用的 ISO14443A 为例,读卡流程如下:

第一步,读卡器发送 REQA(0x26)或 WAKE-UP(0x52)命令,询问场区内有没有卡。

第二步,卡片应答 ATQA。如果场区内有多张卡,ATQA 可能来自多张卡,需要进入防冲突流程。

第三步,防冲突循环。读卡器发送防冲突命令,逐位比较,最终锁定一张卡,拿到完整 UID。这里用到的命令主要有:

命令说明
ANTICOLLISION_CL1(0x93 0x20)第一级防冲突,针对 UID 前 4 字节
SELECT_CL1(0x93 0x70)第一级选择,UID 前 4 字节确认后再选卡
级联 CL2(0x95)如果 UID 超过 4 字节,需要第二级防冲突
级联 CL3(0x97)如果 UID 超过 7 字节,需要第三级防冲突

第四步,选卡成功后,卡片进入 READY 状态。此时可以下发读写命令。以 Mifare Classic 为例,读单个块需要先认证,再读块;以 NTAG 为例,读页数据可以直接通过 READ 命令完成。

整个流程中,防冲突是最容易写错的。因为要考虑 UID 长度、级联标志、BCC 校验、NVB(有效位数)等多个字段。

3.3 寄存器、命令与中断的关系

ST25R3916 内部有大量寄存器,大致可以分成几类:

  • 模式配置寄存器:设置芯片工作模式、协议类型、发射接收配置;
  • 状态寄存器:查询芯片当前状态;
  • FIFO 控制寄存器:管理收发缓冲区;
  • 中断控制寄存器:使能或屏蔽各种中断源;
  • 定时器寄存器:配置协议超时时间。

开发时不需要背下所有寄存器,但建议把“初始化、发命令、读 FIFO、查中断”这条主链路对应的寄存器理解清楚。比如这样一条命令执行链路:

  1. 写 FIFO,把命令字节放入待发送缓冲区;
  2. 设置命令寄存器,触发芯片发送;
  3. 芯片自动按照协议编码、调制、发射;
  4. 等待卡片应答;
  5. 芯片收到响应后解调、解码,存入 FIFO,并置位中断标志;
  6. MCU 读到中断后,从 FIFO 取出响应数据。

这个模型适用于绝大多数协议的收发过程。

3.4 天线调谐:读卡稳定性的关键

ST25R3916 虽然集成度高,但天线部分仍然是模拟电路,需要仔细设计。天线线圈在 13.56MHz 下的等效模型是一个电感,需要并联谐振电容、串联匹配电容,把天线谐振点调到 13.56MHz,同时把阻抗匹配到芯片要求的范围。

天线调谐不好会出现这些现象:

  • 读卡距离很近,稍微偏离线圈中心就掉卡;
  • 发射功率提高后芯片温度明显升高;
  • 多张卡同时靠近时,选卡成功率下降;
  • 在不同温度环境下,读卡距离变化很大。

ST25R3916 支持自动天线调谐(AMT)功能,可以一定程度上补偿天线失谐,但不能完全替代天线设计。前期画板时还是应该参照官方评估板的叠层和线圈参数。

4. 从零读取一张 NFC 卡:完整实战

下面进入实战。以“MCU + ST25R3916 读取一张 ISO14443A 卡的 UID 和 NTAG 数据页”为例,分步骤实现。

4.1 初始化 ST25R3916

硬件初始化主要做三件事:复位、检查芯片通信、写入基础配置。

先看底层 SPI 寄存器读写封装:

// 文件路径:bsp/bsp_st25r3916.c #include "bsp_st25r3916.h" #include "bsp_spi.h" static uint8_t st25r3916_read_reg(uint16_t reg) { uint8_t buf[2]; uint8_t val = 0; buf[0] = (reg & 0x7F); // 读命令 buf[1] = 0x00; bsp_spi_cs_low(); bsp_spi_transfer(buf[0]); val = bsp_spi_transfer(0x00); // 读一个字节 bsp_spi_cs_high(); return val; } static void st25r3916_write_reg(uint16_t reg, uint8_t val) { uint8_t buf[2]; buf[0] = (reg | 0x80); // 写命令 buf[1] = val; bsp_spi_cs_low(); bsp_spi_transfer(buf[0]); bsp_spi_transfer(buf[1]); bsp_spi_cs_high(); }

注意,这里只是演示 SPI 读写寄存器的基本思路,不同驱动对寄存器地址的编码方式可能不同,有的还会区分直接地址和间接地址。

然后是芯片初始化:

// 文件路径:bsp/bsp_st25r3916.c uint8_t st25r3916_init(void) { // 硬件复位 bsp_st25r3916_rst_low(); bsp_delay_ms(10); bsp_st25r3916_rst_high(); bsp_delay_ms(10); // 读取芯片版本,确认通信正常 uint8_t id = st25r3916_read_reg(ST25R3916_REG_IC_IDENTITY); if ((id & 0xF0) != 0x10) { return 0; // 芯片通信异常 } // 基础配置:按数据手册推荐的初始化序列 st25r3916_write_reg(ST25R3916_REG_OP_CONTROL, 0x00); st25r3916_write_reg(ST25R3916_REG_MODE, 0x01); // 使能收发 st25r3916_write_reg(ST25R3916_REG_TX_DRIVER, 0x00); st25r3916_write_reg(ST25R3916_REG_RX_CONF1, 0x00); st25r3916_write_reg(ST25R3916_REG_RX_CONF2, 0x00); // 使能我们需要的中断 st25r3916_write_reg(ST25R3916_REG_IRQ_MASK, 0x00); st25r3916_write_reg(ST25R3916_REG_IRQ_MASK2, 0x00); return 1; }

这段代码里的寄存器名和默认值只是演示配置顺序的“骨架”。实际项目中请直接使用官方驱动包的初始化函数,或者严格按数据手册的初始化序列填写,不要照抄这里的数值。

4.2 开始轮询并检测卡片

初始化完成后,芯片默认没有打开射频场。读卡前需要让芯片发射射频场,然后等待卡片进入。

轮询一个 ISO14443A 卡的主逻辑大致如下:

// 文件路径:app/app_nfc.c #include "app_nfc.h" #include "st25r3916.h" #include "rfal_iso14443a.h" #define NFC_POLL_TIMEOUT 100 // ms typedef struct { uint8_t uid[10]; uint8_t uid_len; } nfc_card_info_t; static nfc_card_info_t s_card; uint8_t nfc_poll_iso14443a(void) { uint8_t buf[32]; uint16_t len = 0; rfal_iso14443a_initialize(); // 发送 REQA,等待 ATQA uint8_t atqa[2]; if (rfal_iso14443a_reqa(atqa) != ERR_NONE) { return 0; } // 防冲突,读取 UID if (rfal_iso14443a_anticollision(s_card.uid, &s_card.uid_len) != ERR_NONE) { return 0; } // 选卡 if (rfal_iso14443a_select(s_card.uid, s_card.uid_len) != ERR_NONE) { return 0; } return 1; }

如果你没有使用 RFAL,而是直接操作寄存器,那么“发送 REQA”这一步就是:

  1. 把 0x26 写入 FIFO;
  2. 触发发送命令;
  3. 等待接收中断;
  4. 从 FIFO 读回 ATQA。

用 RFAL 的好处是这些细节已经封装好了,业务代码可以专注于“读到卡之后干什么”。

4.3 防冲突,拿到完整 UID

防冲突是整个流程里最容易出问题的一步。如果你自己实现协议栈,建议按下面的思路写:

// 文件路径:lib/rfal_iso14443a.c uint8_t rfal_iso14443a_anticollision(uint8_t *uid, uint8_t *uid_len) { uint8_t cascade = 0x93; uint8_t buf[8]; uint8_t nvb = 0x20; // 初始为 0x20,表示全位有效 uint8_t bcc; uint8_t i; *uid_len = 0; for (uint8_t level = 1; level <= 3; level++) { // 发送防冲突命令,读取卡返回的 UID CLn 数据 if (rfal_send_anticollision(cascade, nvb, buf) != ERR_NONE) { return ERR_PROTOCOL; } // 检查 UID 中是否有级联标志 CT=0x88 // 如果存在,说明 UID 长度超过当前级,进入下一级 for (i = 0; i < 3; i++) { if (buf[i] == 0x88) { cascade = (level == 1) ? 0x95 : 0x97; memcpy(&uid[*uid_len], buf, 3); *uid_len += 3; break; } } // 保存有效 UID 字节 if (*uid_len == 0) { memcpy(&uid[*uid_len], buf, 4); *uid_len += 4; bcc = buf[4]; break; } } return ERR_NONE; }

注意,这只是一个示意实现,真实防冲突循环还要处理 NVB 变化、位碰撞检测、BCC 校验、级联标志判断等细节。建议直接使用官方协议栈,不要自己重复造轮子,除非你确实需要深入协议层做定制。

4.4 选卡并读取数据块

拿到 UID 后,轮到数据读取。不同卡片的数据读取方式差异很大:

  • NTAG21x 系列:通过 READ 命令直接按页读;
  • Mifare Classic:先认证扇区,再读块;
  • 身份证 / CPU 卡:内部有 COS,需要 APDU 指令。

这里演示 NTAG21x 的读页流程:

// 文件路径:app/app_nfc.c uint8_t nfc_read_ntag_page(uint8_t page, uint8_t *data_out, uint16_t *data_len) { uint8_t cmd[2]; uint8_t resp[64]; uint16_t resp_len = 0; // NTAG READ 命令:0x30 + 页地址 cmd[0] = 0x30; cmd[1] = page; if (rfal_transceive(cmd, 2, resp, &resp_len, NULL, RFAL_TXRX_FLAGS_DEFAULT) != ERR_NONE) { return 0; } // NTAG 读页返回 16 字节数据 if (resp_len >= 16) { memcpy(data_out, resp, 16); *data_len = 16; return 1; } return 0; }

所有的数据读取,最后都会落到收函数上。建议把所有协议命令封装成统一的 transceive 接口,上层业务只关心“发命令,收响应”,这样新增卡片类型时改动最小。

4.5 运行结果与说明

把工程编译烧录后,用串口打印日志,预期输出类似这样:

[INFO] ST25R3916 init OK, chip id = 0x10 [INFO] Poll ISO14443A... [INFO] Card detected! [INFO] UID: 04 A2 3B 5C 12 34 80 [INFO] UID len: 7 bytes [INFO] Select OK [INFO] Read page 0x03: 04 A2 3B 5C 12 34 80 01 03 00 00 ...

如果 UID 是 4 字节,说明是单级 UID;如果 UID 是 7 字节,说明是双级 UID,也就是内部有级联标志 CT=0x88 的卡片。两种卡在防冲突处理上略有差异,这也是很多人在“读不到完整 UID”时卡住的原因。

5. 多协议轮询与低功耗设计

5.1 支持哪些协议

ST25R3916 支持的协议比较多,常见的包括:

  • ISO14443A:Mifare Classic、Mifare DESFire、NTAG 系列、CPU 卡等;
  • ISO14443B:二代身份证、部分银行卡、公交卡;
  • ISO15693:图书管理、资产盘点标签;
  • FeliCa:日本和部分亚洲地区常用的公交卡标准;
  • ISO18092 / NFCIP-1:NFC 点对点通信。

如果你的产品需要同时兼容多种卡,ST25R3916 的多协议支持能力会比其他一体化芯片更灵活。

5.2 轮询配置思路

多协议读取的通用做法是“分时轮询”。比如每一轮按顺序检测:

  1. 先发 ISO14443A 的 REQA;
  2. 再发 ISO14443B 的 REQB;
  3. 再发 ISO15693 的 Inventory;
  4. 最后试 FeliCa 的 Polling。

每一轮检测都有超时时间,不能无限等一张卡响应。

这种轮询方式实现简单,但会带来一个问题:不同协议在同一个射频场里可能相互干扰。比如某些 ISO14443A 卡对 ISO15693 的 Inventory 命令会产生误响应。实际项目里,轮询顺序和跳转逻辑要根据目标卡片类型调整,必要时做成可配置项。

5.3 低功耗卡片检测 LPCD

对电池供电的产品来说,不能一直开着射频场轮询,否则功耗会很高。ST25R3916 有一个很实用的低功耗卡片检测功能:

  • MCU 进入休眠前,配置芯片进入 LPCD 模式;
  • 芯片自己周期性地发射短脉冲,检测场区负载变化;
  • 一旦发现疑似卡片进入,通过 IRQ 唤醒 MCU;
  • MCU 醒来后再执行完整的协议轮询。

这个功能可以把待机功耗做到很低的水平,同时保证“卡一靠近就响应”。对于便携式 NFC 设备来说,这个特性几乎可以算刚需。

6. 常见问题与排查思路

做 NFC 开发时,很多问题表面看是软件 bug,实际根子在射频链路或时序上。下面整理几个高频问题。

问题现象常见原因解决思路
芯片 ID 读不到SPI 接线错误、复位时序不对、供电不足检查 SPI 时钟极性和相位、片选逻辑;用逻辑分析仪抓波形
能检测到场,但收不到 ATQA天线失谐、发射功率太低、卡片类型不匹配先换官方评估板天线验证;检查天线匹配网络
收到 ATQA,但防冲突失败UID 长度处理错误、NVB 设置错误增加日志打印每轮防冲突的原始数据;对照协议手册检查级联逻辑
4 字节卡能读,7 字节卡读不到没有处理级联标志 CT=0x88检查防冲突循环是否支持多级级联
读卡距离很近天线 Q 值不合适、匹配电容偏移测量天线谐振频率;参考官方天线设计调整
掉卡、读卡经常失败电源纹波大、发射瞬间电压跌落在电源端加大电容,检查 3.3V 波形
多张卡同时靠近时选卡异常防冲突实现不完整换用官方协议栈,确保支持完整的位级冲突检测
天线附近有金属时读不到卡金属涡流导致天线失谐调整天线位置,增加铁氧体隔磁片

再展开说一下最容易被忽视的两个问题。

第一个是“天线失谐”。

很多开发者在自制天线后发现读卡距离不到 1cm,就怀疑芯片坏了。其实大概率是天线谐振点偏移了。天线设计时,线圈形状、匝数、PCB 走线宽度、铺铜距离都会影响等效电感。建议用网络分析仪测一下天线线圈在 13.56MHz 附近的阻抗,再决定匹配电容值。

第二个是“电源瞬态跌落”。

ST25R3916 发射射频场时,瞬间电流很大。如果 3.3V 供电能力不足,或者电源走线过长,发射瞬间电压会被拉低,导致卡片上电不足、芯片内部逻辑异常。排查方法是把示波器探头放在 ST25R3916 的 VDD 引脚上,观察发射瞬间的电压跌落幅度。

7. 工程最佳实践:天线、安全与调试

7.1 天线设计与匹配建议

天线是 NFC 读卡器最重要的模拟部件之一。关于 ST25R3916 的天线设计,几点经验值得记录:

  1. 前期不要自己发明天线,优先抄官方评估板的线圈尺寸和匹配电路;
  2. 天线谐振频率尽量精确调整到 13.56MHz,不要偏差超过几百 kHz;
  3. 根据应用场景控制 Q 值。Q 值高,读卡距离远,但带宽窄,容易受温度和环境金属影响;Q 值低,带宽宽,但读卡距离受影响。一般建议 Q 值落在 15 到 35 之间,具体看读卡距离和协议要求;
  4. 天线周围尽量避开大范围铺铜和金属结构件;
  5. 如果产品外壳是金属,需要在 PCB 天线和金属之间加铁氧体隔磁片;
  6. 量产前要做温度测试,因为电容值会随温度漂移,导致谐振点偏移。

如果环境温漂比较严重,可以考虑使能 ST25R3916 的自动天线调谐功能,让它在上电时自动微调匹配参数。

7.2 安全边界与合规

NFC 开发涉及安全和合规问题,这里重点提醒几点。

第一,关于“NFC 中继攻击”。读卡器在验证卡片时,如果只校验 UID,很容易被中继设备欺骗。攻击者可以把一张合法卡的信息通过设备中继到远端,绕过门禁或支付验证。防御思路是使用挑战-响应机制:读卡器生成随机数,卡片用密钥对随机数做加密运算并返回结果,读卡器验证结果正确性。ST25R3916 内置的 AES-128 协处理器就是做这类认证用的。

第二,关于“NFC 密钥库大全”这类资料。这类内容通常涉及破解和未授权访问,工程开发中不应依赖任何形式的密钥泄露资料。合法开发时,密钥应该由卡主或发卡方通过合规渠道提供,开发环境使用测试密钥,生产环境按权限管理规范保存密钥。

第三,涉及读取身份证或其他法定证件时,必须遵守当地法律法规,只在授权范围内处理数据,不在日志中记录敏感个人信息。

第四,产品量产前,电磁兼容(EMC)和射频认证必须做。ST25R3916 带了有源波形整形功能,可以改善发射频谱,帮助产品通过相关认证。

7.3 日志、测试和生产环境注意事项

读卡器开发调试阶段,日志设计得好,能省一半排查时间。建议至少记录以下信息:

  • 芯片初始化结果、读取到的芯片 ID;
  • 每轮轮询的协议类型和结果;
  • 防冲突过程中每一轮收到的原始数据;
  • 收发数据的长度和 CRC 校验结果;
  • 中断标志位的原始值。

日志输出建议做成分级开关,调试时打开详细日志,量产固件里只保留错误日志。

测试方面,不能只测一张卡。建议准备一个“卡片测试集”,覆盖:

  • 4 字节 UID 卡和 7 字节 UID 卡;
  • 不同厂商的 ISO14443A 卡;
  • ISO14443B 卡;
  • ISO15693 标签;
  • 两张以上卡片同时靠近的场景;
  • 卡片快速靠近、快速远离的场景;
  • 不同温度下的读卡距离测试;
  • 长时间连续读卡稳定性测试。

这些测试看起来很基础,但很多项目恰恰是栽在这些“没测过”的边界场景上。

7.4 代码与工程维护建议

驱动代码建议保持“分层”结构,至少分出这三层:

  1. 硬件抽象层(HAL):只负责 SPI 读写、GPIO、延时、中断;
  2. 芯片驱动层:只负责 ST25R3916 的寄存器和命令收发,不关心业务;
  3. 应用层:只关心“读到了什么卡、要做什么业务”。

分层之后,换 MCU 时只需要重写 HAL 层。升级 ST25R3916 驱动版本时,也只需要改驱动层,不影响业务代码。

另外,NFC 代码里的超时处理非常重要。收发函数必须带超时参数,不能无限等待卡片响应。如果一个读卡器的单次轮询卡了 5 秒,用户肯定会觉得“设备死机了”。

8. 总结与下一步

这篇围绕“ST25R3916 NFC 读取”的实战笔记,核心可以概括成几条主线:

第一,ST25R3916 是一颗“射频前端芯片”,不是“一键读卡”芯片。它的可玩性和性能上限高,但也要求开发者理解协议流程和射频链路。

第二,ISO14443A 的读取流程可以简化成四个动作:REQA、防冲突、SELECT、读写数据。把这条链路彻底弄懂,再学 ISO14443B、ISO15693 会轻松很多。

第三,读卡稳定性的天花板往往不在代码,而在天线和电源。天线匹配、电源纹波、环境温度和金属干扰,才是“时好时坏”问题的真正来源。

第四,安全开发是一条底线。防中继攻击要用挑战-响应机制,密钥管理要合规,不能依赖任何非授权渠道获取的密钥资料。

如果你刚接触 ST25R3916,下一步可以先做三件事:

  1. 用官方评估板 + 官方 RFAL 库,把“读 UID”跑通,体验完整的读卡流程;
  2. 用逻辑分析仪抓一次 REQA、防冲突、SELECT 的波形,对照时序理解协议;
  3. 测一下你的产品在不同温度和不同卡片下的读卡距离,找出不稳定因素。

等基础流程稳定后,再深入看低功耗 LPCD、自动天线调谐、多协议轮询这些进阶功能。希望这篇文章能帮你少踩一些坑。如果遇到具体报错,可以在评论区带上你的芯片型号、驱动版本和日志,大家一起排查。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 4:36:44

AJAX实战:从XMLHttpRequest到axios,蓝桥杯“组课神器”全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 4:34:08

BMS接口技术需求全解析:从硬件选型到协议测试

简介&#xff1a;《BMS与其他系统接口技术需求.doc》是一份面向智能楼宇和智慧建筑项目的系统集成工程师、弱电设计师及BMS调试人员的技术需求文档&#xff0c;基于IOTOS物联网平台系统梳理了BMS与消防报警、楼宇自控、视频监控、入侵报警、出入口控制、车库管理、能源管理及一…

作者头像 李华
网站建设 2026/9/7 4:33:16

弹性容错防线全景:多维限流、双桶平滑、熔断与四级降级

弹性容错防线全景&#xff1a;多维限流、双桶平滑、熔断与四级降级在微服务与高可用分布式架构中&#xff0c;“容错与弹性&#xff08;Resilience & Fault Tolerance&#xff09;”是保障系统在极端网络抖动、流量洪峰与下游依赖瘫痪时依然能够屹立不倒的核心生命线。 然而…

作者头像 李华
网站建设 2026/9/7 4:33:05

《Turing Complete》2.1版:从NAND门到CPU的硬核通关与全成就指南

如果你在Steam上翻过“硬核编程”或者“逻辑”这类标签&#xff0c;大概率早就撞见过《Turing Complete》这个名字。它不是那种点两下鼠标就开心的休闲益智&#xff0c;而是一个让你从一枚最底层的NAND门开始&#xff0c;一步步搭出内存、ALU、寄存器、指令集&#xff0c;最后造…

作者头像 李华
网站建设 2026/9/7 4:32:42

国产开关机芯片替代选型:关键参数对比与实测验证指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 4:32:10

Tampermonkey离线安装包全攻略:无网环境安装篡改猴

简介&#xff1a;篡改猴&#xff08;Tampermonkey&#xff09;5.1.0 离线安装包是为需要使用用户脚本管理器的浏览器用户准备的离线部署工具&#xff0c;尤其适合无法访问应用商店、身处内网环境或希望固定版本的前端爱好者和普通网友。资源按 zip 压缩包分发&#xff0c;体积仅…

作者头像 李华