Python)

知识库
知识库文档
/firmware/通信模块/PN532/PN532 NFC模块代码例程 (Arduino/ESP32/STM32/Python).md

文档

PN532 NFC模块代码例程


例程1:Arduino (Adafruit_PN532 库,I2C模式)

安装库:Adafruit PN532 by Adafruit

#include <Wire.h>
#include <Adafruit_PN532.h>

// I2C 模式
Adafruit_PN532 nfc(/*IRQ=*/2, /*RST=*/3);

void setup() {
    Serial.begin(115200);
    nfc.begin();

    uint32_t versiondata = nfc.getFirmwareVersion();
    if (!versiondata) {
        Serial.println("PN532 not found!");
        while (1);
    }
    Serial.print("Found PN532, FW: 0x");
    Serial.println(versiondata, HEX);

    // SAM配置:普通模式
    nfc.SAMConfig();
    Serial.println("Waiting for NFC card...");
}

void loop() {
    uint8_t uid[7] = {0};
    uint8_t uidLength;

    // 寻 Mifare Classic 卡
    bool success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
    if (success) {
        Serial.print("Found card, UID: ");
        for (uint8_t i = 0; i < uidLength; i++) {
            Serial.print(uid[i] < 0x10 ? " 0" : " ");
            Serial.print(uid[i], HEX);
        }
        Serial.println();

        // 认证并读取扇区0块0
        uint8_t keyA[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
        if (nfc.ntag2xx_IsNTAG215()) {
            // 用 NDEF 方式读
            uint8_t data[128];
            uint8_t len;
            if (nfc.ntag2xx_ReadPage(4, data)) {
                Serial.print("NDEF Data: ");
                for (uint8_t i = 0; i < 16; i++) {
                    Serial.print(data[i], HEX); Serial.print(" ");
                }
                Serial.println();
            }
        }
    }
    delay(300);
}

例程2:Arduino (SPI 模式)

#include <SPI.h>
#include <Adafruit_PN532.h>

#define PN532_SS   10
#define PN532_IRQ  2
#define PN532_RST  3

Adafruit_PN532 nfc(PN532_SS, PN532_IRQ, PN532_RST);

void setup() {
    Serial.begin(115200);
    SPI.begin();
    nfc.begin();

    uint32_t ver = nfc.getFirmwareVersion();
    if (!ver) {
        Serial.println("PN532 SPI not responding!");
        while (1);
    }
    Serial.printf("PN532 v%d.%d\n", (ver >> 24) & 0xFF, (ver >> 16) & 0xFF);
    nfc.SAMConfig();
}

void loop() {
    uint8_t uid[7], uidLen;
    if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLen, 500)) {
        Serial.print("UID: ");
        for (uint8_t i = 0; i < uidLen; i++)
            Serial.printf("%02X ", uid[i]);
        Serial.println();
    }
}

例程3:STM32 HAL (裸帧通信,UART模式)

#include "stm32f1xx_hal.h"

#define PN532_UART      huart2

/* ========== PN532 帧发送 ========== */
void pn532_send_frame(uint8_t *data, uint8_t len) {
    uint8_t frame[270];
    uint8_t idx = 0;

    frame[idx++] = 0x00;            // PREAMBLE
    frame[idx++] = 0x00;            // START1
    frame[idx++] = 0xFF;            // START2

    uint8_t LEN = len + 1;          // DATA + TFI
    frame[idx++] = LEN;
    frame[idx++] = ~LEN + 1;        // LCS

    frame[idx++] = 0xD4;            // TFI (Host→PN532)

    uint8_t dcs = 0xD4;
    for (uint8_t i = 0; i < len; i++) {
        frame[idx++] = data[i];
        dcs += data[i];
    }
    frame[idx++] = ~dcs + 1;         // DCS
    frame[idx++] = 0x00;             // POSTAMBLE

    HAL_UART_Transmit(&PN532_UART, frame, idx, 100);
}

/* ========== PN532 帧接收(简化版) ========== */
uint8_t pn532_recv_frame(uint8_t *buf, uint8_t max_len) {
    uint8_t byte;
    // 等待 START: 0x00 0xFF
    do { HAL_UART_Receive(&PN532_UART, &byte, 1, 50); } while (byte != 0x00);
    HAL_UART_Receive(&PN532_UART, &byte, 1, 50);
    if (byte != 0xFF) return 0;

    uint8_t len, lcs;
    HAL_UART_Receive(&PN532_UART, &len, 1, 50);
    HAL_UART_Receive(&PN532_UART, &lcs, 1, 50);
    if ((len + lcs) != 0x00) return 0;  // LCS校验

    uint8_t tfi;
    HAL_UART_Receive(&PN532_UART, &tfi, 1, 50);
    if (tfi != 0xD5) return 0;          // 非PN532响应

    uint8_t data_len = len - 1;
    for (uint8_t i = 0; i < data_len; i++) {
        HAL_UART_Receive(&PN532_UART, &buf[i], 1, 50);
    }

    uint8_t dcs, post;
    HAL_UART_Receive(&PN532_UART, &dcs, 1, 50);
    HAL_UART_Receive(&PN532_UART, &post, 1, 50);

    return data_len;
}

/* ========== 初始化 ========== */
void pn532_init(void) {
    // SAM配置 (命令0x14)
    uint8_t sam_cmd[] = {0x14, 0x01, 0x14, 0x01}; // 普通模式, timeout=1s
    pn532_send_frame(sam_cmd, 4);

    uint8_t resp[32];
    uint8_t len = pn532_recv_frame(resp, 32);
    if (len > 0 && resp[0] == 0x15) {
        printf("PN532 SAM configured OK\r\n");
    }
}

/* ========== 寻卡 ========== */
uint8_t pn532_find_card(uint8_t *uid, uint8_t *uid_len) {
    // InListPassiveTarget (0x4A), max 1 card, type=14443A (0x00)
    uint8_t cmd[] = {0x4A, 0x01, 0x00};
    pn532_send_frame(cmd, 3);

    uint8_t resp[32];
    uint8_t len = pn532_recv_frame(resp, 32);

    // resp: [0x4B] [NbTg] [Tg] [SENS_RES_hi] [SENS_RES_lo] [SEL_RES] [UID_len] [UID...]
    if (len >= 6 && resp[0] == 0x4B && resp[1] == 0x01) {
        *uid_len = resp[6];
        for (uint8_t i = 0; i < *uid_len; i++)
            uid[i] = resp[7 + i];
        return 1;
    }
    return 0;
}

/* ========== 完整演示 ========== */
void pn532_demo(void) {
    pn532_init();
    printf("PN532 RFID/NFC Demo\r\n");

    while (1) {
        uint8_t uid[7], uid_len = 0;
        if (pn532_find_card(uid, &uid_len)) {
            printf("Card UID: ");
            for (uint8_t i = 0; i < uid_len; i++)
                printf("%02X ", uid[i]);
            printf("\r\n");
        }
        HAL_Delay(500);
    }
}

例程4:树莓派 Python (libnfc / pn532-i2c)

#!/usr/bin/env python3
"""
PN532 I2C 模式 Python 驱动
依赖: pip3 install pn532pi
接线: SDA→GPIO2(BCM), SCL→GPIO3(BCM), VCC→3.3V, GND→GND
"""

import time
from pn532pi import Pn532, Pn532I2c

# I2C 初始化 (bus=1)
PN532_I2C = Pn532I2c(1)
nfc = Pn532(PN532_I2C)

def setup():
    nfc.begin()
    ver = nfc.getFirmwareVersion()
    if ver is None:
        print("PN532 not found!")
        return False
    print(f"PN532 firmware: {ver[0]:02X}{ver[1]:02X}")
    nfc.SAMConfig()
    print("Ready. Tap NFC card/tag...")
    return True

def read_nfc():
    success, uid = nfc.readPassiveTargetID(
        nfc.MIFARE_ISO14443A, timeout=1000
    )
    if success:
        print(f"UID: {' '.join(f'{b:02X}' for b in uid)}")

        # 尝试读取 NDEF (NTAG 系列)
        try:
            # NTAG215 从 page 4 开始为用户数据区
            data = nfc.ntag2xx_ReadPage(4)
            if data:
                print(f"Page 4: {' '.join(f'{b:02X}' for b in data)}")
        except:
            pass
    return success

if __name__ == "__main__":
    if setup():
        while True:
            read_nfc()
            time.sleep(0.3)

例程5:ESP32 (PN532 HSU 高速UART模式)

#include <HardwareSerial.h>

#define PN532_RX  16
#define PN532_TX  17
#define PN532_RST 18

HardwareSerial pn532_serial(2);

// 帧收发函数(参考 STM32 例程结构)
// ... pn532_send_frame / pn532_recv_frame 略,同 STM32 逻辑 ...

void setup() {
    Serial.begin(115200);
    pn532_serial.begin(115200, SERIAL_8N1, PN532_RX, PN532_TX);

    pinMode(PN532_RST, OUTPUT);
    digitalWrite(PN532_RST, LOW);
    delay(100);
    digitalWrite(PN532_RST, HIGH);
    delay(500);

    pn532_init();
    Serial.println("PN532 HSU mode ready.");
}

void loop() {
    uint8_t uid[7], uid_len;
    if (pn532_find_card(uid, &uid_len)) {
        Serial.print("UID: ");
        for (int i = 0; i < uid_len; i++) {
            Serial.printf("%02X ", uid[i]);
        }
        Serial.println();
    }
    delay(300);
}

PN532 命令速查表

命令名 命令码 参数 说明
GetFirmwareVersion 0x02 返回芯片+固件版本
SAMConfiguration 0x14 Mode(1B) Timeout(1B) IRQ(1B) 普通模式: 0x14,0x01,0x14,0x01
InListPassiveTarget 0x4A MaxTg(1B) BrTy(1B) 寻14443A卡: 0x4A,0x01,0x00
InDataExchange 0x40 Tg(1B) + APDU 读写MIFARE卡数据
TgInitAsTarget 0x8C Mode + SENS + NFCID + ... 卡模拟模式
InJumpForDEP 0x56 Active/Passive + BR + ... NFC P2P 连接
InATR 0x50 Tg + Attribute 获取卡ATR信息

常见问题

现象 原因 解决方案
找不到PN532 I2C地址/接口模式不对 确认拨码开关,I2C地址默认0x48
固件版本返回0 通信异常 检查接线、接口模式、供电
寻卡返回0张卡 SAM未配置 务必先执行SAMConfig
读卡数据全0 认证失败 MIFARE卡需先认证扇区
卡模拟手机不识别 SENS_RES不兼容 调整SENS_RES为0x0008

信息

路径
/firmware/通信模块/PN532/PN532 NFC模块代码例程 (Arduino/ESP32/STM32/Python).md
更新时间
2026/5/26