树莓派NFC扩展板教程

产品介绍

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串口模块
3V33.3V
GNDGND
TXRX
RXTX


2. 通过跳线帽把I0设置为L,I1设置为L
3. 把串口模块通过USB线连接到电脑
4. 打开串口调试助手软件,设置串口
  • 波特率(Baud rate):115200
  • 数据位(Data bits):8
  • 停止位(Stop bits):1
  • 校验位(Parity):None
  • 流控制(Flow control):None
5. 勾选"HEX发送”和“HEX显示”

6. 选择对应的串口号并打开串口。
7. 发送此帧用于唤醒模块:
  1. 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章节)

模块的响应帧:

  1. 00 00 FF 00 FF 00 00 00 FF 02 FE D5 15 16 00
8. 发送此帧用于探测Mifare Classic 卡(随附的蓝色水滴形卡片,下称“卡”)
  1. 00 00 FF 04 FC D4 4A 01 00 E1 00

把卡贴近模块的线圈部分,模块会响应:

  1. 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 或者在树莓派终端运行:

  1. sudo apt-get install p7zip-full
  2. wget http://www.waveshare.net/w/upload/6/67/Pn532-nfc-hat-code.7z
  3. 7z x Pn532-nfc-hat-code.7z -r -o./Pn532-nfc-hat-code
  4. sudo chmod 777 -R Pn532-nfc-hat-code/
SPI通信

1. 使用跳线帽,把I0设置为L,l1设置为H

2. 用跳线帽连接RSTPDN->D20

3. 将拨码开关设置为

SCKMISOMOSINSSSCLSDARXTX
ONONONONOFFOFFOFFOFF

4. 将PN532 NFC HAT插入到树莓派的40PIN GPIO上

PN532 NFC HAT通过SPI引脚连接树莓派
PN532 NFC HATRaspberry Pi (BCM)
SCKSCK
MISOMISO
MOSIMOSI
NSSP4

5. 启用SPI接口

打开树莓派终端,执行sudo raspi-config进入配置界面

选择Interfacing Options -> SPI -> Yes

6. 执行示例程序(以example_get_uid.py和rpi_get_uid.c为例)

打开终端,进入到程序目录:

  1. cd ~/raspberrypi/

1) python程序:

进入python程序目录: cd ~/raspberrypi/python/

修改example_get_uid.py文件,初始化pn532对象相关语句改成:

  1. pn532 = PN532_SPI(debug=False, reset=20, cs=4)
  2. #pn532 = PN532_I2C(debug=False, reset=20, req=16)
  3. #pn532 = PN532_UART(debug=False, reset=20)

修改完之后保存,并运行例程

  1. python3 example_get_uid.py

2) C 程序:

进入c程序目录:cd ~/raspberrypi/c/example/

修改rpi_get_uid.c,初始化pn532相关语句改为:

  1. PN532_SPI_Init(&pn532);
  2. //PN532_I2C_Init(&pn532);
  3. //PN532_UART_Init(&pn532);

保存文件,并重新编译:sudo make

运行程序:

  1. ./rpi_get_uid.exe

7. 预期结果:将卡贴近模块的线圈部分,可以读取卡的UID信息

UART通信

1. 使用跳线帽,把I0设置为L,l1设置为L

2. 用跳线帽连接RSTPDN ->D20

3. 将拨码开关设置为

SCKMISOMOSINSSSCLSDARXTX
OFFOFFOFFOFFOFFOFFONON

4. 将PN532 NFC HAT插入到树莓派的40PIN GPIO上

PN532 NFC HAT通过UART引脚连接树莓派
PN532 NFC HATRaspberry Pi
RXTX
TXRX

5. 启动树莓派串口。默认情况下,树莓派的串口用于登录Shell终端,如果需要使用串口和外部设备通信的话,需要手动开启硬件串口

打开树莓派终端,输入sudo raspi-config 进入配置界面

选择Interfacing Options-> Serial -> No -> Yes

【注】这里开启硬件串口之后,可能需要重启,正常重启即可

6. 运行示例程序(以example_get_uid.py和rpi_get_uid.c为例)

打开终端,进入到程序目录:

  1. cd ~/raspberrypi/

1) python程序:

进入python程序目录: cd ~/raspberrypi/python/

修改example_get_uid.py文件,初始化pn532对象相关语句改成:

  1. #pn532 = PN532_SPI(debug=False, reset=20, cs=4)
  2. #pn532 = PN532_I2C(debug=False, reset=20, req=16)
  3. pn532 = PN532_UART(debug=False, reset=20)

修改完之后保存,并运行例程

  1. python3 example_get_uid.py

2) C 程序:

进入c程序目录:cd ~/raspberrypi/c/example/

修改rpi_get_uid.c,初始化pn532相关语句改为:

  1. //PN532_SPI_Init(&pn532);
  2. //PN532_I2C_Init(&pn532);
  3. PN532_UART_Init(&pn532);

保存文件,并重新编译:sudo make

运行程序:

  1. ./rpi_get_uid.exe

7. 预期结果:将卡贴近模块的线圈部分,可以读取卡的UID信息

如果例程运行失败的话,可以用以下例程测试串口:
  1. cd ~/raspberrypi/python/
  2. python3 example_uart_hex.py

输入16进制编码的原始数据然后回车发送,终端会显示发送的数据和接收到的细腻。例如发送以下数据唤醒模块:

  1. 55 55 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF 03 FD D4 14 01 17 00

终端显示模块的响应数据:

  1. 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. 将拨码开关设置为

SCKMISOMOSINSSSCLSDARXTX
OFFOFFOFFOFFONONOFFOFF

4. 将PN532 NFC HAT插入到树莓派的40PIN GPIO上

PN532 NFC HAT通过I2C引脚连接树莓派
PN532 NFC HATRaspberry Pi
SCLSCL
SDASDA

5. 启动树莓派I2C接口。

打开树莓派终端,输入sudo raspi-config 进入配置界面

选择Interfacing Options-> I2C -> Yes


6. 运行示例程序(以example_get_uid.py和rpi_get_uid.c为例)

打开终端,进入到程序目录:

  1. cd ~/raspberrypi/

1) python程序:

进入python程序目录: cd ~/raspberrypi/python/

修改example_get_uid.py文件,初始化pn532对象相关语句改成:

  1. #pn532 = PN532_SPI(debug=False, reset=20, cs=4)
  2. pn532 = PN532_I2C(debug=False, reset=20, req=16)
  3. #pn532 = PN532_UART(debug=False, reset=20)

修改完之后保存,并运行例程

  1. python3 example_get_uid.py

2) C 程序:

进入c程序目录:cd ~/raspberrypi/c/example/

修改rpi_get_uid.c,初始化pn532相关语句改为:

  1. //PN532_SPI_Init(&pn532);
  2. PN532_I2C_Init(&pn532);
  3. //PN532_UART_Init(&pn532);

保存文件,并重新编译:sudo make

运行程序:

  1. ./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. 设置拨码开关为:

SCKMISOMOSINSSSCLSDARXTX
ONONONONOFFOFFOFFOFF

3. 连接PN532 NFC HAT与Arduino:

PN532 NFC HAT通过SPI接口连接Arduino UNO
PN532 NFC HATArduino UNO
SCKD13
MISOD12
MOSID11
NSSD4

4. 执行示例程序(以examples\arduino\uno_get_uid\ uno_get_uid.ino 为例):

双击打开 uno_get_uid.ino文件,初始化pn532相关语句改为:

  1. PN532_SPI_Init(&pn532);
  2. //PN532_I2C_Init(&pn532);

编译和上传程序到Arduino UNO

打开串口监视器,按下Arduino UNO的复位键

5. 预期结果: 把卡贴近模块的线圈部分,即可读取卡的UID

I2C通信

1. 使用跳线帽,把l0设置为L,l1设置为H

2. 拨码开关设置为

SCKMISOMOSINSSSCLSDARXTX
OFFOFFOFFOFFONONOFFOFF

3. 连接PN532 NFC HAT和Arduino UNO

PN532 NFC HAT通过I2C接口连接Arduino UNO
PN532 NFC HATArduino UNO
SCLA5
SDAA4

4. 执行示例程序(以examples\arduino\uno_get_uid\ uno_get_uid.ino 为例):

双击打开 uno_get_uid.ino文件,初始化pn532相关语句改为:

  1. //PN532_SPI_Init(&pn532);
  2. 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. 拨码开关设置为

SCKMISOMOSINSSSCLSDARXTX
ONONONONOFFOFFOFFOFF

3. 连接PN532 NFC HAT和STM32开发板

PN532 NFC HAT通过SPI接口连接STM32
PN532 NFC HATSTM32F103CBT6
SCKPA5
MISOPA6
MOSIPA7
NSSPA4

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.pyRaspberry Pi
rpi_dump_mifare.cRaspberry Pi
uno_dump_mifare.inoArduino UNO
stm32_dump_mifare/MDK-ARM/pn532_stm32.uvprojxSTM32F103CBT6


预期结果:把Mifare Classic 卡贴近PN532 NFC HAT,卡的内容会被打印出来

  1. 0 : 37 F9 20 69 87 08 04 00 62 63 64 65 66 67 68 69
  2. 1 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  3. 2 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  4. 3 : 00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF
  5. 4 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  6. 5 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  7. 6 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  8. 7 : 00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF
  9. 8 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  10. 9 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  11. 10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  12. 11 : 00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF
  13. 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)的密码

  1. 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.pyRaspberry Pi
rpi_rw_mifare.cRaspberry Pi
uno_rw_mifare.inoArduino UNO
stm32_rw_mifare/MDK-ARM/pn532_stm32.uvprojxSTM32F103CBT6


预期结果:把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.pyRaspberry Pi
rpi_dump_ntag2.cRaspberry Pi
uno_dump_ntag2.inoArduino UNO
stm32_dump_ntag2/MDK-ARM/pn532_stm32.uvprojxSTM32F103CBT6

预期结果:把Ntag215卡贴近PN532 NFC HAT,卡的内容会被打印出来

  1. 0: 04 85 32 3b
  2. 1: 92 a8 64 80
  3. 2: de 48 00 00
  4. 3: e1 10 3e 00
  5. 4: 03 00 fe 00
  6. 5: 00 00 00 00
  7. 6: 00 00 00 00
  8. 7: 00 00 00 00
  9. 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.pyRaspberry Pi
rpi_rw_ntag2.cRaspberry Pi
uno_rw_ntag2.inoArduino UNO
stm32_rw_ntag2/MDK-ARM/pn532_stm32.uvprojxSTM32F103CBT6

预期结果:把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.pyRaspberry Pi
rpi_write_gpio.cRaspberry Pi
uno_write_gpio.inoArduino UNO
stm32_write_gpio/MDK-ARM/pn532_stm32.uvprojxSTM32F103CBT6

预期结果:打印PN532的GPIO电平

  1. Pin P30: 1
  2. Pin P31: 0
  3. Pin P32: 1
  4. Pin P33: 0
  5. Pin P34: 1
  6. Pin P35: 0
  7. Pin P71: 0
  8. Pin P72: 1
  9. Pin I0: 1
  10. 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.pyRaspberry Pi
rpi_read_gpio.cRaspberry Pi
uno_read_gpio.inoArduino UNO
stm32_read_gpio/MDK-ARM/pn532_stm32.uvprojxSTM32F103CBT6

预期结果:会打印PN532的GPIO电平

  1. Port P3: 0x3f
  2. Port P7: 0x07
  3. Port I: 0x07
  4. Pin P30: 1
  5. Pin P31: 1
  6. Pin P32: 1
  7. Pin P33: 1
  8. Pin P34: 1
  9. Pin P35: 1
  10. Pin I0: 1
  11. Pin I1: 0

说明:

  • PN532的P30 – P35电平会在硬件复位(RSTPDN置低2ms然后置高)之后,恢复为高电平。