PN532 NFC HAT
| ||||||||||||||||||||||||||
|
说明
产品介绍
PN532 NFC HAT 是专为树莓派设计的 NFC 扩展板,采用PN532主控,同时支持I2C、SPI和串口通信,可以给树莓派扩展 NFC 通讯功能。
PN532是一个高度集成的、工作于13.56MHz的非接触读写芯片。它包含80C51微控制器内核,集成了40Kbytes ROM 和 1Kbytes RAM。
PN532把调制和解调的概念完全集成在13.56MHz的各种非接触通信方式和协议中,具有易于使用的固件,适用于不同的模式,以及不同的主机控制接口。
产品参数
- 工作电压 3.3V / 5V。
- 出厂通信波特率:115200 bps
- 支持ISO/IEC 14443A / MIFARE
- 在读写器模式中支持ISO/IEC 14443B
- 该NFC模块工作于13.56MHz频段
注意事项
- 本模块只能用于读写已知密码或者默认密码的NFC卡,无法用于破解加密的卡。例如Mifare Classic卡所有块(除了第0块)的默认的密码均为0xFFFFFFFFFFFF,只有在这个密码没有修改的情况下,才能进行读写。
- 通常无法用于复制卡,除非该卡所有块的密码均未经修改。如果没有正确密码,那么PN532无法是读取对应的块的。
- 无法用于模拟完整的卡。因为卡的ID一般为4 字节,而由于PN532的安全策略,它会把模拟的卡第一字节固定为0x08。参见:http://www.nfc-tools.org/index.php?title=PN53x 。
开箱测试
用户可以用电脑通过串口快速验证PN532的功能,无需树莓派。验证的时候需要一个串口转USB模块(如 FT232 模块)。
- 1. 硬件连接
PN532 NFC HAT | 串口模块 |
---|---|
3V3 | 3.3V |
GND | GND |
TX | RX |
RX | TX |
- 2. 通过跳线帽把I0设置为L,I1设置为L
- 3. 把串口模块通过USB线连接到电脑
- 4. 打开串口调试助手软件,设置串口
- 波特率(Baud rate):115200
- 数据位(Data bits):8
- 停止位(Stop bits):1
- 校验位(Parity):None
- 流控制(Flow control):None
- 6. 选择对应的串口号并打开串口。
- 7. 发送此帧用于唤醒模块:
55 55 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF 03 FD D4 14 01 17 00
(参见PN532 User Manual的HSU wake up condition章节)
模块的响应帧:
00 00 FF 00 FF 00 00 00 FF 02 FE D5 15 16 00
- 8. 发送此帧用于探测Mifare Classic 卡(随附的蓝色水滴形卡片,下称“卡”)
00 00 FF 04 FC D4 4A 01 00 E1 00
把卡贴近模块的线圈部分,模块会响应:
00 00 FF 0C F4 D5 4B 01 01 00 04 08 04 XXXXXXXXXX 00
该帧中的XXXXXXXXXX 是指4字节的卡ID和1字节的校验码。(参见PN532 User Manual的InListPassiveTarget章节)
示例程序使用
PN532 NFC HAT 支持三个接口:串口、I2C和SPI。用户可以根据需要采用不同的接口,让树莓派和模块进行通讯。把模块连接到树莓派之后,需要通过I0、I1跳线选择工作模式。还需要通过拨码开关,让模块的接口连接到树莓派的对应接口。
请根据自己的实际使用情况选用接口:
- UART:树莓派的 UART 默认情况下用于 Shell 通讯,如果你的UART用来和树莓派进行通讯,而又想要用UART通讯,则应使用USB转串口模块连接树莓派和PN532 NFC HAT,并且示例程序串口的初始化应改成/dev/ttyUSB0(根据实际情况填写,可通过 ls /dev | grep ttyUSB 进行查看),而不是使用示例程序程序默认值/dev/ttyS0
- I2C:树莓派不支持I2C接口的Clock Stretching,而PN532的I2C工作的时候可能会使用Clock Stretching(从机会主动拉低I2C的SCL)。这会导致树莓派无法控制所有的I2C设备,包括PN532!如果你的I2C挂载了多个设备,则不宜采用I2C和PN532进行通讯。
- SPI:PN532 NFC HAT的SPI接口使用了D4 (BCM)作为片选。如果其他程序用到这个管脚的话,则不宜使用 SPI 接口进行通讯。
树莓派程序
从#示例程序下载例程,解压,并将raspberrypi文件夹复制到树莓派的/home/pi目录下。你可先将程序复制到/boot/,再复制到/home/pi
或者在树莓派终端运行:
sudo apt-get install p7zip-full wget http://www.waveshare.net/w/upload/6/67/Pn532-nfc-hat-code.7z 7z x Pn532-nfc-hat-code.7z -r -o./Pn532-nfc-hat-code sudo chmod 777 -R Pn532-nfc-hat-code/
- SPI通信
1. 使用跳线帽,把I0设置为L,l1设置为H
2. 用跳线帽连接RSTPDN->D20
3. 将拨码开关设置为
SCK | MISO | MOSI | NSS | SCL | SDA | RX | TX |
ON | ON | ON | ON | OFF | OFF | OFF | OFF |
4. 将PN532 NFC HAT插入到树莓派的40PIN GPIO上
PN532 NFC HAT | Raspberry Pi (BCM) |
---|---|
SCK | SCK |
MISO | MISO |
MOSI | MOSI |
NSS | P4 |
5. 启用SPI接口
打开树莓派终端,执行sudo raspi-config进入配置界面
选择Interfacing Options -> SPI -> Yes
6. 执行示例程序(以example_get_uid.py和rpi_get_uid.c为例)
打开终端,进入到程序目录:
cd ~/raspberrypi/
1) python程序:
进入python程序目录: cd ~/raspberrypi/python/
修改example_get_uid.py文件,初始化pn532对象相关语句改成:
pn532 = PN532_SPI(debug=False, reset=20, cs=4) #pn532 = PN532_I2C(debug=False, reset=20, req=16) #pn532 = PN532_UART(debug=False, reset=20)
修改完之后保存,并运行例程 sudo python3 example_get_uid.py
2) C 程序:
进入c程序目录:cd ~/raspberrypi/c/example/
修改rpi_get_uid.c,初始化pn532相关语句改为:
PN532_SPI_Init(&pn532); //PN532_I2C_Init(&pn532); //PN532_UART_Init(&pn532);
保存文件,并重新编译:sudo make
运行程序:
./rpi_get_uid.exe
7. 预期结果:将卡贴近模块的线圈部分,可以读取卡的UID信息
- UART通信
1. 使用跳线帽,把I0设置为L,l1设置为L
2. 用跳线帽连接RSTPDN ->D20
3. 将拨码开关设置为
SCK | MISO | MOSI | NSS | SCL | SDA | RX | TX |
OFF | OFF | OFF | OFF | OFF | OFF | ON | ON |
4. 将PN532 NFC HAT插入到树莓派的40PIN GPIO上
PN532 NFC HAT | Raspberry Pi |
---|---|
RX | TX |
TX | RX |
5. 启动树莓派串口。默认情况下,树莓派的串口用于登录Shell终端,如果需要使用串口和外部设备通信的话,需要手动开启硬件串口
打开树莓派终端,输入sudo raspi-config 进入配置界面
选择Interfacing Options-> Serial -> No -> Yes
【注】这里开启硬件串口之后,可能需要重启,正常重启即可
6. 运行示例程序(以example_get_uid.py和rpi_get_uid.c为例)
打开终端,进入到程序目录:
cd ~/raspberrypi/
1) python程序:
进入python程序目录: cd ~/raspberrypi/python/
修改example_get_uid.py文件,初始化pn532对象相关语句改成:
#pn532 = PN532_SPI(debug=False, reset=20, cs=4) #pn532 = PN532_I2C(debug=False, reset=20, req=16) pn532 = PN532_UART(debug=False, reset=20)
修改完之后保存,并运行例程
python3 example_get_uid.py
2) C 程序:
进入c程序目录:cd ~/raspberrypi/c/example/
修改rpi_get_uid.c,初始化pn532相关语句改为:
//PN532_SPI_Init(&pn532); //PN532_I2C_Init(&pn532); PN532_UART_Init(&pn532);
保存文件,并重新编译:sudo make
运行程序:
./rpi_get_uid.exe
7. 预期结果:将卡贴近模块的线圈部分,可以读取卡的UID信息
- 如果例程运行失败的话,可以用以下例程测试串口:
cd ~/raspberrypi/python/ python3 example_uart_hex.py
输入16进制编码的原始数据然后回车发送,终端会显示发送的数据和接收到的细腻。例如发送以下数据唤醒模块:
55 55 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF 03 FD D4 14 01 17 00
终端显示模块的响应数据:
00 00 FF 00 FF 00 00 00 FF 02 FE D5 15 16 00
- I2C通信
1. 使用跳线帽,把I0设置为H,l1设置为L
2. 用跳线帽连接RSTPDN ->D20, 连接INT0 -> D16(避免Clock Stretching)
3. 将拨码开关设置为
SCK | MISO | MOSI | NSS | SCL | SDA | RX | TX |
OFF | OFF | OFF | OFF | ON | ON | OFF | OFF |
4. 将PN532 NFC HAT插入到树莓派的40PIN GPIO上
PN532 NFC HAT | Raspberry Pi |
---|---|
SCL | SCL |
SDA | SDA |
5. 启动树莓派I2C接口。
打开树莓派终端,输入sudo raspi-config 进入配置界面
选择Interfacing Options-> I2C -> Yes
6. 运行示例程序(以example_get_uid.py和rpi_get_uid.c为例)
打开终端,进入到程序目录:
cd ~/raspberrypi/
1) python程序:
进入python程序目录: cd ~/raspberrypi/python/
修改example_get_uid.py文件,初始化pn532对象相关语句改成:
#pn532 = PN532_SPI(debug=False, reset=20, cs=4) pn532 = PN532_I2C(debug=False, reset=20, req=16) #pn532 = PN532_UART(debug=False, reset=20)
修改完之后保存,并运行例程
python3 example_get_uid.py
2) C 程序:
进入c程序目录:cd ~/raspberrypi/c/example/
修改rpi_get_uid.c,初始化pn532相关语句改为:
//PN532_SPI_Init(&pn532); PN532_I2C_Init(&pn532); //PN532_UART_Init(&pn532);
保存文件,并重新编译:sudo make
运行程序:
./rpi_get_uid.exe
7. 预期结果:将卡贴近模块的线圈部分,可以读取卡的UID信息
Arduino 程序
1. 电脑需要安装Arduino IDE。
2. 在Arduino的项目文件夹下(默认为C:\Program Files (x86)\Arduino\libraries,可通过Arduino IDE的文件首选项项目文件夹位置进行指定)创建新文件夹,名字改成pn532。
3. 把 pn532.c、pn532.h、pn532_uno.cpp、pn532_uno.h这四个文件复制到Arduino\libraries\pn532 文件夹下。
4. 示例程序位于examples\arduino目录下。
5. 下面以Arduino UNO 开发板为例
- SPI通信
1. 通过跳线帽,把I0设置为L,l1设置为H
2. 设置拨码开关为:
SCK | MISO | MOSI | NSS | SCL | SDA | RX | TX |
ON | ON | ON | ON | OFF | OFF | OFF | OFF |
3. 连接PN532 NFC HAT与Arduino:
PN532 NFC HAT | Arduino UNO |
---|---|
SCK | D13 |
MISO | D12 |
MOSI | D11 |
NSS | D4 |
4. 执行示例程序(以examples\arduino\uno_get_uid\ uno_get_uid.ino 为例):
双击打开 uno_get_uid.ino文件,初始化pn532相关语句改为:
PN532_SPI_Init(&pn532); //PN532_I2C_Init(&pn532);
编译和上传程序到Arduino UNO
打开串口监视器,按下Arduino UNO的复位键
5. 预期结果: 把卡贴近模块的线圈部分,即可读取卡的UID
- I2C通信
1. 使用跳线帽,把l0设置为L,l1设置为H
2. 拨码开关设置为
SCK | MISO | MOSI | NSS | SCL | SDA | RX | TX |
OFF | OFF | OFF | OFF | ON | ON | OFF | OFF |
3. 连接PN532 NFC HAT和Arduino UNO
PN532 NFC HAT | Arduino UNO |
---|---|
SCL | A5 |
SDA | A4 |
4. 执行示例程序(以examples\arduino\uno_get_uid\ uno_get_uid.ino 为例):
双击打开 uno_get_uid.ino文件,初始化pn532相关语句改为:
//PN532_SPI_Init(&pn532); PN532_I2C_Init(&pn532);
编译和上传程序到Arduino UNO
打开串口监视器,按下Arduino UNO的复位键
5. 预期结果: 把卡贴近模块的线圈部分,即可读取卡的UID
STM32程序
示例程序使用的开发板是Open103C,主控芯片是STM32F103CBT6。STM32程序我们只提供SPI通信方式,如果需要其他通信方式,需要自行添加
- 下载工程
1. 使用keil打开工程文件(例程\MDK-ARM\pn532_stm32.uvprojx),点击 Rebuild 编译工程。
2. 选择下载器:Options for Target -> Debug选项卡-> Use,默认情况下是 ST-Link Debugger。
3. 选择下载接口:Options for Target -> Debug选项卡 -> Settings -> Debug 选项卡 -> Port,默认情况下是 JTAG.
4. 通过下载器,连接开发板和电脑。
5. 点击 Download 下载工程。
- 硬件连接
1. 通过跳线帽,把 I0 设置为 L,I1 设置为 H。
2. 拨码开关设置为
SCK | MISO | MOSI | NSS | SCL | SDA | RX | TX |
ON | ON | ON | ON | OFF | OFF | OFF | OFF |
3. 连接PN532 NFC HAT和STM32开发板
PN532 NFC HAT | STM32F103CBT6 |
---|---|
SCK | PA5 |
MISO | PA6 |
MOSI | PA7 |
NSS | PA4 |
4. 通过USB串口线或者串口模块,连接STM32 开发板的UART1接口(PA9->RX, PA10->TX)到电脑
5. 打开串口监视器,按下STM32开发板的复位键
6. 预期结果: 把卡贴近模块的线圈部分,即可获取卡的 UID。
程序说明
上面的演示是以获取 Mifare Classic 卡的 ID 作为例子(example_get_uid.py / rpi_get_uid.exe / uno_get_uid.ino / stm32_get_uid),下面将对其他示例程序进行说明。
【注意】
使用这些程序之前,请根据实际情况,设置 PN532 NFC HAT 的I0 / I1 跳线以及拨码开关。拨码开关不能同时设置为ON,否则无法接收到正确的数据。简单起见,这里用0表示拨码开关拨到OFF,用1表示拨码开关拨到ON。
- 使用UART接口的时候,[I1..I0]跳线应设置为LL,拨码开关设置为00000011
- 使用I2C接口的时候,[I1..I0]跳线应设置为LH,拨码开关设置为00001100。
- 使用SPI接口的时候,[I1..I0]跳线应设置为HL,拨码开关设置为11110000。
读取Mifare Classic卡内容
程序 | 开发板 |
example_dump_mifare.py | Raspberry Pi |
rpi_dump_mifare.c | Raspberry Pi |
uno_dump_mifare.ino | Arduino UNO |
stm32_dump_mifare/MDK-ARM/pn532_stm32.uvprojx | STM32F103CBT6 |
预期结果:把Mifare Classic 卡贴近PN532 NFC HAT,卡的内容会被打印出来
0 : 37 F9 20 69 87 08 04 00 62 63 64 65 66 67 68 69 1 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3 : 00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF 4 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 5 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 : 00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF 8 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 9 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 11 : 00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF … … 63 : 00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF
说明:
- 每一行的显示内容是对应的块的内容
- 第0块的前4字节是Mifare Classic卡的UID,第5字节是校验位,是前4字节的异或结果
- 常规的卡的第0块(UID)是无法修改的
- 每4个块属于同一个扇区(sector),共用同一个密码,例如4N~4N+3块属于同一个扇区。
- 第4N+3块是密码块,相应的,如果要读取4N~4N+2块的内容,就必须使用4N+3块所记录的密码
- 容量为1K的卡,一共有64个块
以读取第6块为例,必须使用对应扇区的密码,即第7块的前6个字节(KEY A)或者后6字节(KEY B)的密码
7 : 00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF
前6个字节为KEY A,默认为FF FF FF FF FF FF,但是其读取结果永远为00 00 00 00 00 00。后6字节为KEY B,使用明文存储,Mifare Classic卡默认的KEY A和KEY B均为FF FF FF FF FF FF。
中间的4个字节是访问控制位(Access Bits)。默认值FF 07 80 69,这个数值用于扇区得写的访问权限控制,用户如果对其写入不合适的数值,将会导致卡被锁死。
例如byte6写入0xFF,那么byte7的高4位必须为0b0000, byte 8的低4位必须为0b0000。具体参见MF1S50YYX_V1.pdf 的 Access conditions for data blocks 节
产品随附的卡是魔法卡,通过预留的后门可以解锁,但是用户应当知道,如果使用常规的 Mifare 卡,一旦把访问控制位写错,将会无法修复。所以在写卡的时候要特别注意
读写Mifare Classic卡
程序 | 开发板 |
example_rw_mifare.py | Raspberry Pi |
rpi_rw_mifare.c | Raspberry Pi |
uno_rw_mifare.ino | Arduino UNO |
stm32_rw_mifare/MDK-ARM/pn532_stm32.uvprojx | STM32F103CBT6 |
预期结果:把Mifare Classic卡贴近PN532 NFC HAT,第6块的内容会被改写成00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F。
说明:
- 写入第6块的内容之前,需要保证第6块对应的密码为0xFF FF FF FF FF FF。这个密码即为第7块的前6个字节(读取结果永远为0x00 00 00 00 00 00)。
- 如果用户修改示例程序、试图写入第N+3块的内容,应该特别小心。因为这部分的内容是N ~ N+2块的密码。应当记住写入的密码,如果忘记密码,那么所在扇区的所有块都将无法读写。
读取NTAG2XX整卡内容
程序 | 开发板 |
example_dump_ntag2.py | Raspberry Pi |
rpi_dump_ntag2.c | Raspberry Pi |
uno_dump_ntag2.ino | Arduino UNO |
stm32_dump_ntag2/MDK-ARM/pn532_stm32.uvprojx | STM32F103CBT6 |
预期结果:把Ntag215卡贴近PN532 NFC HAT,卡的内容会被打印出来
0: 04 85 32 3b 1: 92 a8 64 80 2: de 48 00 00 3: e1 10 3e 00 4: 03 00 fe 00 5: 00 00 00 00 6: 00 00 00 00 7: 00 00 00 00 … … 134: 00 00 00 00
说明:
- Ntag215 卡片需要用户自行购买。
- 根据习惯,Ntag215 的页(page)相当于Mifare 的块(block),一行代表一页。
- 第0页的前3字节是UID0-UID2,第4字节是校验位,是前3字节和0x88 (Cascade Tag,由ISO/IEC 14443-3 Type A 定义)的异或结果。
- 第1页的4个字节是UID3-UID6。
- 第2页的第1字节是校验位,是UID3-UID6的异或结果
读写NTAG2XX卡
程序 | 开发板 |
example_rw_ntag2.py | Raspberry Pi |
rpi_rw_ntag2.c | Raspberry Pi |
uno_rw_ntag2.ino | Arduino UNO |
stm32_rw_ntag2/MDK-ARM/pn532_stm32.uvprojx | STM32F103CBT6 |
预期结果:把NTAG215卡贴近PN532 NFC HAT,第6块的内容会被改写成00 01 02 03。
说明:
- 第2页的最后两个字节用于标记并锁定03h到0Fh的对应的页为只读,并且这个操作不可逆。使用的时候应该注意这个情况。见NTAG213/215/216 的Static lock bytes (NTAG21x) 节。
- 要锁定第10h页之后的数据,则把对应的地址写入28h页(NTAG213)或82h页(NTAG215)或E2h页(NTAG216)的前3字节,第4字节读取结果永远是0xBD。见NTAG213/215/216 的Dynamic Lock Bytes节
- Ntag2xx卡的功能详情请参见 NTAG213/215/216 手册的相关内容。
设置PN532的GPIO电平
程序 | 开发板 |
example_write_gpio.py | Raspberry Pi |
rpi_write_gpio.c | Raspberry Pi |
uno_write_gpio.ino | Arduino UNO |
stm32_write_gpio/MDK-ARM/pn532_stm32.uvprojx | STM32F103CBT6 |
预期结果:打印PN532的GPIO电平
Pin P30: 1 Pin P31: 0 Pin P32: 1 Pin P33: 0 Pin P34: 1 Pin P35: 0 Pin P71: 0 Pin P72: 1 Pin I0: 1 Pin I1: 0
说明:
程序尝试设置管脚电平:P30 -> 高,P31 -> 低,P33 -> 低,P35 -> 低,P71 -> 低,P72 -> 高
注意:
- P32是 int0,一旦写入低电平,将会导致模块复位。
- P34是SIC_CLK,读取的结果是高电平。
- P71是MISO,在SPI模式下,读取的结果是高电平。
- P72是SCK,在SPI模式下,读取的结果是高电平。
- 模块上电的时候, PN532 会根据I0/I1的电平设置通讯接口。之后可以移除跳线帽,作为普通的GPIO使用。
PN532的P30 – P35电平会在硬件复位(RSTPDN置低2ms然后置高)之后,恢复为高电平。
读取PN532的GPIO电平
程序 | 开发板 |
example_read_gpio.py | Raspberry Pi |
rpi_read_gpio.c | Raspberry Pi |
uno_read_gpio.ino | Arduino UNO |
stm32_read_gpio/MDK-ARM/pn532_stm32.uvprojx | STM32F103CBT6 |
预期结果:会打印PN532的GPIO电平
Port P3: 0x3f Port P7: 0x07 Port I: 0x07 Pin P30: 1 Pin P31: 1 Pin P32: 1 Pin P33: 1 Pin P34: 1 Pin P35: 1 Pin I0: 1 Pin I1: 0
说明:
- PN532的P30 – P35电平会在硬件复位(RSTPDN置低2ms然后置高)之后,恢复为高电平。
资料
文档
程序
相关教程
FAQ
可以用以下程序格式化NFC卡:
wget https://www.waveshare.net/w/upload/8/85/Pn532test.zip unzip Pn532test.zip cd pn532test/ sudo sh install.sh sudo python3 test.py