NFC Unit

该库用于驱动 Unit NFC(I2C 接口的 ST25R3916)。它可发现 ISO14443 Type A 标签,识别芯片类型(Classic、Ultralight / NTAG 系列、DESFire、Plus 等),并为支持的标签类型提供高级读写辅助接口。

支持以下产品:

NFCUnit

UiFlow2 应用示例

检测卡片

在 UiFlow2 中打开 cores3_unit_nfc_example.m5f2 项目。

该示例会轮询读卡器,在屏幕上显示 UID、类型名称和用户内存大小,并在检测到卡片时播放短提示音。

UiFlow2 代码块:

cores3_unit_nfc_example.png

示例输出:

None

MicroPython 应用示例

检测卡片

该示例会轮询读卡器,在屏幕上显示 UID、类型名称和用户内存大小,并在检测到卡片时播放短提示音。

MicroPython 代码块:

  1# SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
  2#
  3# SPDX-License-Identifier: MIT
  4
  5import os, sys, io
  6import M5
  7from M5 import *
  8import m5ui
  9import lvgl as lv
 10from hardware import Pin
 11from hardware import I2C
 12from unit import NFCUnit
 13import time
 14
 15
 16page0 = None
 17label_title = None
 18label_uid = None
 19label_type = None
 20label_size = None
 21i2c0 = None
 22nfc_0 = None
 23card_0 = None
 24card_uid = None
 25new = None
 26card_type = None
 27card_memory = None
 28write_buf = None
 29count = None
 30last_time = None
 31
 32
 33def setup():
 34    global \
 35        page0, \
 36        label_title, \
 37        label_uid, \
 38        label_type, \
 39        label_size, \
 40        i2c0, \
 41        nfc_0, \
 42        card_0, \
 43        card_uid, \
 44        new, \
 45        card_type, \
 46        card_memory, \
 47        write_buf, \
 48        count, \
 49        last_time
 50
 51    M5.begin()
 52    Widgets.setRotation(1)
 53    m5ui.init()
 54    page0 = m5ui.M5Page(bg_c=0x000000)
 55    label_title = m5ui.M5Label(
 56        "NFC Card detect",
 57        x=58,
 58        y=5,
 59        text_c=0x14ACDB,
 60        bg_c=0x000000,
 61        bg_opa=0,
 62        font=lv.font_montserrat_24,
 63        parent=page0,
 64    )
 65    label_uid = m5ui.M5Label(
 66        "UID:",
 67        x=18,
 68        y=70,
 69        text_c=0xFFFFFF,
 70        bg_c=0x000000,
 71        bg_opa=0,
 72        font=lv.font_montserrat_16,
 73        parent=page0,
 74    )
 75    label_type = m5ui.M5Label(
 76        "Type:",
 77        x=10,
 78        y=100,
 79        text_c=0xFFFFFF,
 80        bg_c=0x000000,
 81        bg_opa=0,
 82        font=lv.font_montserrat_16,
 83        parent=page0,
 84    )
 85    label_size = m5ui.M5Label(
 86        "Size:",
 87        x=16,
 88        y=130,
 89        text_c=0xFFFFFF,
 90        bg_c=0x000000,
 91        bg_opa=0,
 92        font=lv.font_montserrat_16,
 93        parent=page0,
 94    )
 95
 96    i2c0 = I2C(0, scl=Pin(1), sda=Pin(2), freq=400000)
 97    nfc_0 = NFCUnit(i2c0)
 98    page0.screen_load()
 99    Speaker.begin()
100    Speaker.setVolumePercentage(0.5)
101    new = True
102    write_buf = bytearray(16)
103    write_buf[0] = 0x12
104    count = 0
105
106
107def loop():
108    global \
109        page0, \
110        label_title, \
111        label_uid, \
112        label_type, \
113        label_size, \
114        i2c0, \
115        nfc_0, \
116        card_0, \
117        card_uid, \
118        new, \
119        card_type, \
120        card_memory, \
121        write_buf, \
122        count, \
123        last_time
124    M5.update()
125    card_0 = nfc_0.detect()
126    if card_0:
127        card_uid = card_0.uid_str
128        card_type = card_0.type_name
129        card_memory = card_0.user_memory
130        label_uid.set_text(str((str("UID: ") + str(card_uid))))
131        label_type.set_text(str((str("Type: ") + str(card_type))))
132        label_size.set_text(str((str("Size: ") + str(card_memory))))
133        if (time.ticks_diff((time.ticks_ms()), last_time)) >= 3000 or new:
134            last_time = time.ticks_ms()
135            Speaker.tone(900, 100)
136            print((str("read data befor write ") + str((nfc_0.read(card_0, 1)))))
137            count = (count if isinstance(count, (int, float)) else 0) + 1
138            write_buf[-1] = 0x12 + count
139            time.sleep_ms(100)
140            if nfc_0.write(card_0, 1, write_buf):
141                print("write success")
142                time.sleep_ms(100)
143                print((str("read data after write ") + str((nfc_0.read(card_0, 1)))))
144        new = False
145    else:
146        new = True
147
148
149if __name__ == "__main__":
150    try:
151        setup()
152        while True:
153            loop()
154    except (Exception, KeyboardInterrupt) as e:
155        try:
156            m5ui.deinit()
157            from utility import print_error_msg
158
159            print_error_msg(e)
160        except ImportError:
161            print("please update to latest firmware")

示例输出:

None

API参考

NFCUnit

class unit.nfc.NFCUnit

Unit NFC 的驱动程序。请传入已配置好的 I2C 总线实例(例如来自 hardware.I2C)。

参数:

i2c – 用于与 ST25R3916 通信的 I2C 总线。

UiFlow2 代码块:

init.png

MicroPython 代码块:

from hardware import Pin, I2C
from unit import NFCUnit

i2c0 = I2C(0, scl=Pin(1), sda=Pin(2), freq=400000)
nfc = NFCUnit(i2c0)
detect()

轮询射频场内的 Type A 标签。

返回:

如果找到并识别到标签,则返回 unit.nfc.Card 实例;否则返回 None

UiFlow2 代码块:

detect.png

MicroPython 代码块:

card = nfc.detect()
if card:
    print(card.uid_str, card.type_name)
write(card, index, data)

写入一个**地址单元**。

备注

当前仅支持 MIFARE Classic。

data 必须为 16 字节;index 为块号。扇区尾块和 0 号块需要卡片提供有效的密钥/访问规则。

参数:
返回:

成功返回 True,否则返回 False

UiFlow2 代码块:

write.png

MicroPython 代码块:

ok = nfc.write(card, index, data)
read(card, index)

读取当前标签的一个地址单元。

  • MIFARE Classic:index 为全局块号(从 0 开始)。成功时返回 16 字节,否则返回 None。

  • Type 2 系列(Ultralight / NTAG / ST25TA / 适用时 ISO18092):index 为页号。成功时返回 4 字节,否则返回 None。

  • 其他芯片类型:返回 None(请在该辅助接口之外使用芯片专用流程)。

参数:
  • card (unit.nfc.Card) – 由 detect() 返回的标签。

  • index (int) – 块索引(Classic)或页索引(Type 2)。

返回:

bytesNone

UiFlow2 代码块:

read.png

MicroPython 代码块:

data = nfc.read(card, index)
halt()

发送 HLTA 命令,将 Type A PICC 置于 HALT 状态。

UiFlow2 代码块:

halt.png

MicroPython 代码块:

nfc.halt()
rf_off()

关闭读卡器 RF 场。

UiFlow2 代码块:

rf_off.png

MicroPython 代码块:

nfc.rf_off()
rf_on()

开启读卡器 RF 场。

UiFlow2 代码块:

rf_on.png

MicroPython 代码块:

nfc.rf_on()

Card

class unit.nfc.Card

当检测到标签时,由 NFCUnit.detect() 返回的对象。包含防冲突结果及由协议栈解析出的类型元数据(固件实现中的 SAK/ATQA/version/ATS 路径)。

属性

UiFlow2 代码块:

attribute.png

uid

bytes — UID 字节串(长度为 uid_len)。

type_id

int — 此驱动使用的内部类型 id(与 unit/nfc.pyTYPE_NAMES 表一致)。

type_name

str — 由固件识别逻辑解析出的芯片标签;字符串与 unit/nfc.pyTYPE_NAMES 一致。type_id 对应下表行(未知或未分类标签使用 Unknown)。

type_idtype_name``(在 ``TYPE_NAMES 中的索引)

type_id

type_name

0

Unknown

1

MIFARE_Classic_Mini

2

MIFARE_Classic_1K

3

MIFARE_Classic_2K

4

MIFARE_Classic_4K

5

MIFARE_Ultralight

6

MIFARE_Ultralight_EV1_1

7

MIFARE_Ultralight_EV1_2

8

MIFARE_Ultralight_Nano

9

MIFARE_UltralightC

10

NTAG_203

11

NTAG_210u

12

NTAG_210

13

NTAG_212

14

NTAG_213

15

NTAG_215

16

NTAG_216

17

ST25TA_512B

18

ST25TA_2K

19

ST25TA_16K

20

ST25TA_64K

21

ISO_14443_4

22

MIFARE_Plus_2K

23

MIFARE_Plus_4K

24

MIFARE_Plus_SE

25

MIFARE_DESFire_2K

26

MIFARE_DESFire_4K

27

MIFARE_DESFire_8K

28

MIFARE_DESFire_Light

29

NTAG_4XX

30

ISO_18092

user_memory

int — Advertised user memory size in bytes for known types (0 if unknown; used for Type 2 dump heuristics).

uid_str

UID as upper-case hex string.

is_classic()

type_id 属于 MIFARE Classic 系列 id(Mini / 1K / 2K / 4K),则返回 True

UiFlow2 代码块:

is_classic.png

MicroPython 代码块:

card.is_classic()