简介:ACR122U-A9 SDK+全套软件是一套面向NFC应用开发者的专业工具包,适合从事移动支付、门禁系统、智能卡读取及身份验证等项目的初学者与进阶开发者。资源围绕13.56MHz频段的ACR122U-A9读写器展开,提供驱动、API库文件、示例代码、中文文档及调试工具,并附带读写解密软件,可完成卡片数据的读取、写入与加解密操作,帮助开发者快速搭建NFC开发与测试环境。压缩包为rar格式,整体约95.68MB,文件类型以驱动、库文件、示例源码、说明文档及配套工具为主,覆盖从环境配置到功能验证的完整链路。目前已有1975人学习下载,全中文界面与文档降低了语言门槛,便于对照示例理解API调用方式,并在此基础上扩展移动支付、智能门锁等创新应用。
1. ACR122U-A9 的 SDK 包里到底装了什么:从开箱到能读卡
手里拿到一台 ACR122U-A9,插上电脑,灯亮了,但接下来该干什么?很多人卡在这一步——设备管理器里能看到它,却不知道怎么让它吐出一张卡的 UID。这个 SDK 加全套软件的资源包,解决的就是从「插上设备」到「跑通第一行读卡代码」之间的空白。ACR122U-A9 是一款基于 13.56MHz 频段的 USB 接口 NFC 读写器,支持 ISO 14443 Type A/B、MIFARE、FeliCa 等常见协议,在门禁复制、NFC 标签读写、校园卡分析这类场景里出场率极高。资源包里通常包含驱动、SDK 开发包、PC/SC 工具、示例源码和诊断软件,适合刚接触 NFC 的嵌入式工程师、做门禁系统的开发者,以及需要批量读写标签的产线人员。下面按实际拆包顺序,把每个环节的操作和参数讲清楚。
2. 驱动与 PC/SC 栈:让系统认卡的第一步
2.1 为什么 ACR122U-A9 依赖 PC/SC 而不是厂商私有驱动
ACR122U-A9 在 Windows 和 Linux 下都走 CCID 协议,操作系统把它识别为一个标准智能卡读卡器,上层通过 PC/SC 接口通信。这意味着你不需要装厂商的私有驱动就能让系统认到设备,但要让 SDK 里的 API 正常工作,PC/SC 服务必须处于运行状态。Windows 自带 Smart Card 服务,Linux 需要 pcscd 守护进程。很多人插上设备后设备管理器显示正常,但 SDK 调用返回「No reader available」,八成是 PC/SC 服务没起来或者被其他进程占用了。
常见做法是先用系统自带的诊断工具确认读卡器可见。Windows 下可以用certutil -scinfo查看智能卡读卡器列表,Linux 下用pcsc_scan更直观。如果pcsc_scan能看到 ACR122U 并且插卡后有 ATR 输出,说明底层链路通了,再往上跑 SDK 就不会在通信层翻车。
2.2 Windows 下的驱动安装与验证步骤
先装驱动还是先插设备,这个顺序有讲究。ACR122U-A9 在 Win10/Win11 下通常免驱,系统会自动加载微软的 CCID 驱动。但如果你的系统版本较老或者之前装过其他读卡器驱动,可能会出现驱动冲突。资源包里的驱动安装程序一般包含 ACS 的 CCID 驱动和 PC/SC 中间件,建议先卸载旧驱动再装。
# Windows 下验证读卡器是否被 PC/SC 识别 # 方法一:用 certutil 查看 certutil -scinfo # 方法二:用资源包里的 PCSC Diagnostic 工具 # 打开后点击 "Start" 按钮,观察 Reader 列表 # 正常应显示:ACS ACR122U PICC Interface 0certutil -scinfo会列出系统当前识别的所有智能卡读卡器。如果列表里出现 ACS ACR122U 字样,说明驱动和 PC/SC 栈都正常。如果只看到 Microsoft 虚拟智能卡读卡器而没有 ACR122U,检查 USB 线是否支持数据传输(有些线只供电)、换一个 USB 口、确认设备管理器里没有黄色感叹号。
2.3 Linux 下 pcscd 配置与权限处理
Linux 下 ACR122U-A9 的坑主要集中在权限和 pcscd 版本上。Ubuntu 20.04 之后的版本默认安装的 pcsc-lite 版本较新,对 ACR122U 的兼容性不错,但普通用户默认没有访问智能卡设备的权限。
# 安装 pcsc 工具链 sudo apt install pcscd pcsc-tools libccid # 启动 pcscd 服务 sudo systemctl start pcscd sudo systemctl enable pcscd # 验证读卡器 pcsc_scan # 如果提示权限不足,把当前用户加入 scard 组 sudo usermod -aG scard $USER # 重新登录后生效pcsc_scan会持续输出读卡器状态和卡片事件。插卡后如果看到Card inserted和 ATR 字符串,说明 PC/SC 层完全正常。如果pcsc_scan报SCardEstablishContext failed,检查 pcscd 是否在运行;如果报No readers found,检查 libccid 是否安装、USB 设备是否被系统识别(lsusb应能看到 ACS 厂商 ID)。
提示:Linux 下如果同时装了多个智能卡相关服务(如 opensc、pcscd 的 snap 版本),可能出现设备抢占。用
systemctl status pcscd确认只有一个 pcscd 实例在跑。
3. SDK 目录结构与 API 调用:从读 UID 到发 APDU
3.1 SDK 里各文件夹的用途与选型建议
ACR122U-A9 的 SDK 包通常包含以下几个核心目录:Drivers放驱动安装文件,Tools放 PC/SC 诊断工具和固件升级工具,Examples放各语言的示例代码,Doc放 API 手册和协议说明。示例代码一般覆盖 C#、Java、Python、VB.NET 等语言,选哪个取决于你的项目技术栈。做 Windows 桌面工具用 C# 最省事,做跨平台脚本用 Python 最快,做 Android 集成则需要用 Java 的 PC/SC 封装或者走 USB 直连。
我一般建议先跑通Examples里最简单的读 UID 示例,确认 SDK 的 API 能正常调用,再根据自己的需求改。不要一上来就啃 API 手册,手册是查参数用的,不是入门教程。
3.2 用 Python 读一张卡的 UID:最小可运行代码
Python 下操作 ACR122U-A9 最常用的库是pyscard,它是对 PC/SC 接口的 Python 封装。资源包里如果有 Python 示例,通常也是基于 pyscard 的。下面这段代码演示了连接读卡器、等待卡片、读取 UID 的完整流程。
from smartcard.System import readers from smartcard.util import toHexString # 获取所有读卡器,筛选 ACR122U r = readers() if not r: print("未检测到读卡器") exit() reader = r[0] print(f"使用读卡器: {reader}") # 建立连接 connection = reader.createConnection() connection.connect() # 发送 APDU 获取 UID # FF CA 00 00 00 是 PC/SC 规范中获取 UID 的标准指令 GET_UID = [0xFF, 0xCA, 0x00, 0x00, 0x00] data, sw1, sw2 = connection.transmit(GET_UID) if sw1 == 0x90 and sw2 == 0x00: print(f"卡片 UID: {toHexString(data)}") else: print(f"读卡失败, SW1={hex(sw1)}, SW2={hex(sw2)}") connection.disconnect()readers()返回系统所有 PC/SC 读卡器列表,多读卡器环境下需要按名称筛选。createConnection()建立与卡片的逻辑连接,connect()会等待卡片进入场区。transmit()发送 APDU 指令并返回响应数据加状态字。FF CA 00 00 00是 PC/SC 规范定义的伪 APDU,专门用于获取卡片 UID,Le 字段为 00 表示期望返回最大长度。状态字90 00表示成功,其他值需要查 ISO 7816-4 的状态字定义。
3.3 发送自定义 APDU 操作 MIFARE 扇区
读 UID 只是热身,真正做门禁分析或标签写入时需要发自定义 APDU。MIFARE Classic 卡的扇区读写需要先验证密钥,再执行读块或写块操作。ACR122U-A9 支持直接透传 MIFARE 指令,通过FF 00 00 00开头的伪 APDU 封装。
# 验证 MIFARE Classic 扇区密钥 # 默认密钥 A 通常是 FF FF FF FF FF FF LOAD_KEY = [0xFF, 0x82, 0x00, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] AUTH_BLOCK = [0xFF, 0x86, 0x00, 0x00, 0x05, 0x01, 0x00, 0x04, 0x60, 0x00] # 先加载密钥到读卡器 data, sw1, sw2 = connection.transmit(LOAD_KEY) if sw1 != 0x90: print(f"密钥加载失败: {hex(sw1)} {hex(sw2)}") # 验证块 4(扇区 1 的第一个块) data, sw1, sw2 = connection.transmit(AUTH_BLOCK) if sw1 == 0x90: print("扇区 1 验证成功") # 读取块 4 READ_BLOCK = [0xFF, 0xB0, 0x00, 0x04, 0x10] data, sw1, sw2 = connection.transmit(READ_BLOCK) if sw1 == 0x90: print(f"块 4 数据: {toHexString(data)}") else: print(f"验证失败: {hex(sw1)} {hex(sw2)}")FF 82 00 00 06是加载密钥到读卡器内部密钥槽的指令,后面跟 6 字节密钥值。FF 86 00 00 05是验证指令,参数依次为密钥类型(0x60 表示 Key A)、块号、密钥槽号。验证通过后FF B0 00 04 10读取块 4 的 16 字节数据。这里的关键参数是块号和密钥类型,MIFARE Classic 1K 的扇区 0 块 0 是厂商块不可写,数据块从块 1 开始。
注意:不同厂商的 MIFARE 卡默认密钥可能不同,全 FF 只是最常见的情况。遇到验证失败先确认卡片类型和密钥,不要反复试导致卡片锁定。
4. 避坑与排查:ACR122U-A9 翻车实录
4.1 读卡器灯亮但 SDK 报 No Reader Available
现象是设备管理器或 lsusb 能看到 ACR122U,但 SDK 调用返回找不到读卡器。原因通常是 PC/SC 服务未运行或被其他进程占用。Windows 下检查 Smart Card 服务是否启动,Linux 下检查 pcscd 是否在跑。解决方法是重启 PC/SC 服务,并确认没有其他智能卡软件(如银行 U 盾驱动)独占设备。
4.2 读 UID 成功但读扇区返回 6A 82
现象是FF CA 00 00 00能拿到 UID,但验证密钥或读块时返回6A 82(文件或应用未找到)。原因是卡片不是 MIFARE Classic,可能是 MIFARE Ultralight 或 NTAG 系列,这些卡没有扇区概念,不能用扇区读写指令。解决方法是先用FF CA 00 00 00拿到 UID 后查卡类型,或者用FF 00 00 00系列指令探测卡片能力。
4.3 Linux 下 pcscd 频繁崩溃或读卡器掉线
现象是pcsc_scan运行一段时间后报错退出,或者读卡器突然从列表消失。原因是 pcsc-lite 版本与 libccid 版本不匹配,或者 USB 供电不足。解决方法是升级到发行版最新的 pcsc-lite 和 libccid,换一个供电充足的 USB 口,避免使用 USB Hub。
4.4 写块操作后卡片数据错乱
现象是写入 MIFARE 卡后读出来的数据与预期不符,或者卡片无法再被识别。原因是写块时没有先读取原数据做备份,或者写入了错误的块号导致厂商块被覆盖。解决方法是写之前先读一遍目标块确认可写,写操作只针对数据块,绝对不要碰块 0。养成写前备份的习惯,这是血泪经验。
4.5 SDK 示例代码编译报错缺少 DLL
现象是运行 SDK 里的 C# 或 Java 示例时提示缺少winscard.dll或pcsclite.so。原因是示例项目引用了 PC/SC 的动态库但运行环境没有正确配置。解决方法是确认系统已安装 PC/SC 运行时,Windows 下winscard.dll在 System32 目录,Linux 下安装libpcsclite1和libpcsclite-dev。
5. 进阶技巧:用脚本批量读写 NFC 标签并校验
5.1 批量写入 NDEF 格式的 URL 标签
单张读写跑通后,实际产线或资产管理场景往往需要批量写入。下面这段脚本演示了循环等待卡片、写入 NDEF 格式 URL、校验写入结果的完整流程。NDEF 是 NFC Forum 定义的数据交换格式,URL 记录是最常用的类型之一。
import time from smartcard.System import readers from smartcard.util import toHexString def write_ndef_url(connection, url): """写入 NDEF URL 记录到 NTAG 或 MIFARE Ultralight""" # NDEF 头 + URL 记录 # 这里简化处理,实际需按 NDEF 规范编码 uri_bytes = [ord(c) for c in url] # 写入起始块 4(NTAG 用户区起始) # 先发写指令,再发数据 for i in range(0, len(uri_bytes), 4): chunk = uri_bytes[i:i+4] while len(chunk) < 4: chunk.append(0x00) block_num = 4 + i // 4 WRITE_BLOCK = [0xFF, 0xD6, 0x00, block_num, 0x04] + chunk data, sw1, sw2 = connection.transmit(WRITE_BLOCK) if sw1 != 0x90: return False, f"块 {block_num} 写入失败" return True, "写入成功" def read_ndef_url(connection, start_block=4, length=16): """读取并解析 NDEF URL""" result = [] for i in range(length): block_num = start_block + i READ_BLOCK = [0xFF, 0xB0, 0x00, block_num, 0x04] data, sw1, sw2 = connection.transmit(READ_BLOCK) if sw1 == 0x90: result.extend(data) else: break return bytes(result) # 主循环 r = readers() reader = r[0] print("等待卡片...") while True: try: connection = reader.createConnection() connection.connect() uid, sw1, sw2 = connection.transmit([0xFF, 0xCA, 0x00, 0x00, 0x00]) print(f"检测到卡片 UID: {toHexString(uid)}") ok, msg = write_ndef_url(connection, "https://example.com/nfc/001") print(msg) if ok: raw = read_ndef_url(connection) print(f"回读数据: {toHexString(list(raw))}") connection.disconnect() time.sleep(1) # 等待卡片移开 except Exception as e: time.sleep(0.5)FF D6 00 块号 04是写块指令,后面跟 4 字节数据。NTAG 系列的用户区通常从块 4 开始,每块 4 字节。写入后立即回读校验是批量操作的基本习惯,避免写坏卡而不自知。主循环里的time.sleep(1)是给操作员留出移卡时间,产线场景可以改成检测卡片移除事件。
5.2 用 ACR122U-A9 做卡片类型自动识别
不同卡片类型的读写指令不同,批量处理时先识别卡类型能避免很多无效操作。下面这个判断逻辑基于 ATR 和 SAK 值,是实际项目里比较可靠的做法。
| 卡片类型 | ATR 特征 | SAK 值 | 可用指令 |
|---|---|---|---|
| MIFARE Classic 1K | 3B 8F 80 01 | 0x08 | 扇区读写 |
| MIFARE Ultralight | 3B 8F 80 01 | 0x00 | 页读写 |
| NTAG213/215/216 | 3B 8F 80 01 | 0x00 | 页读写 + NDEF |
| MIFARE DESFire | 3B 81 80 01 | 0x20 | APDU 指令集 |
| ISO 14443-4 卡 | 3B 80 80 01 | 0x20 | T=CL APDU |
识别逻辑是先connect()拿到 ATR,再发FF CA 00 00 00拿 UID,然后根据 ATR 和 SAK 查表判断。SAK 值需要通过FF 00 00 00系列指令获取,不同读卡器固件版本返回格式可能略有差异。我一般会在脚本里维护一个卡片类型映射表,遇到未知类型就记录 ATR 和 SAK 值,后续再补进表里。
5.3 固件升级与工具链版本管理
ACR122U-A9 的固件升级工具在资源包的Tools目录里,升级前务必确认当前固件版本和目标版本。固件升级失败会导致读卡器变砖,虽然通常可以通过重新刷写恢复,但过程比较折腾。我的习惯是:新设备到手先记录固件版本,非必要不升级;如果遇到兼容性问题必须升级,先在一台设备上验证,确认稳定后再批量操作。
工具链版本方面,PC/SC 相关库的版本兼容性比想象中敏感。Windows 下不同版本的winscard.dll对同一段代码的行为可能不同,Linux 下 pcsc-lite 和 libccid 的版本组合也有讲究。从那以后我每次部署新环境都强制走一遍pcsc_scan加最小读卡脚本的验证流程,确认底层链路没问题再上业务代码。希望帮到你。
本文还有配套的精品资源,点击获取