PN532 NFC模块代码例程
例程1:Arduino (Adafruit_PN532 库,I2C模式)
安装库:Adafruit PN532 by Adafruit
#include <Wire.h>
#include <Adafruit_PN532.h>
Adafruit_PN532 nfc(2, 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);
nfc.SAMConfig();
Serial.println("Waiting for NFC card...");
}
void loop() {
uint8_t uid[7] = {0};
uint8_t uidLength;
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();
uint8_t keyA[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
if (nfc.ntag2xx_IsNTAG215()) {
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
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);
}
uint8_t pn532_recv_frame(uint8_t *buf, uint8_t max_len) {
uint8_t byte;
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) {
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) {
uint8_t cmd[] = {0x4A, 0x01, 0x00};
pn532_send_frame(cmd, 3);
uint8_t resp[32];
uint8_t len = pn532_recv_frame(resp, 32);
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);
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 |