介绍
NXP PN532 NFC/RFID控制器模块,支持13.56MHz全协议读写,兼容ISO/IEC 14443A/B、FeliCa、ISO/IEC 18092(NFCIP-1)点对点和卡模拟模式,SPI/I2C/UART三接口,最大读写距离70mm,支持NFC标签读写、MIFARE全系列、NTAG等,适合门禁、支付、双向NFC通信等场景
NXP PN532 NFC/RFID控制器模块,支持13.56MHz全协议读写,兼容ISO/IEC 14443A/B、FeliCa、ISO/IEC 18092(NFCIP-1)点对点和卡模拟模式,SPI/I2C/UART三接口,最大读写距离70mm,支持NFC标签读写、MIFARE全系列、NTAG等,适合门禁、支付、双向NFC通信等场景
| 参数 | 值 |
|---|---|
| 封装 | 模块尺寸约 43×41mm, 板载PCB天线 |
| 接口 | SPI(最高5Mbps) / I2C(100/400kHz) / HSU高速UART(1.2Mbps) |
| 特色 | 支持NFC主动/被动目标模式, 片上固件免二次开发 |
| 芯片 | NXP PN532 |
| NFC模式 | 读写器/卡模拟/点对点(P2P) |
| FIFO缓冲 | 512字节收发 |
| 供电电压 | DC 3.3V (模块通常带LDO支持5V输入) |
| 工作温度 | -30°C ~ +85°C |
| 工作电流 | 典型60mA, 峰值120mA, 待机<100μA |
| 工作频率 | 13.56MHz |
| 支持协议 | ISO/IEC 14443A/B, MIFARE Classic/Ultralight/Plus/DESFire, FeliCa, ISO/IEC 18092 NFCIP-1, NTAG21x |
| 读写距离 | 最大70mm (取决于天线和卡类型) |
| 逻辑电平 | 3.3V (部分模块板载电平转换兼容5V MCU) |
| 最大发射功率 | +23dBm |
# PN532 NFC模块代码例程
---
## 例程1:Arduino (Adafruit_PN532 库,I2C模式)
### 安装库:`Adafruit PN532` by Adafruit
```cpp
#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 模式)
```cpp
#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模式)
```c
#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)
```python
#!/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模式)
```cpp
#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 |
暂无参考文献