PN532模块的使用及NFC近场通信的原理简单介绍
NFC(Near Field Communication)是一种非接触式的近场通信协议,可以理解为无线通信的一种,在我们的日常生活中有广泛的应用场景,允许设备在彼此靠近时进行数据交换和通信。其基于基于RFID技术,工作频率为13.56 MHz,允许设备在靠近时进行数据交换。主要功能包括读取、写入数据,实现点对点通信和设备控制等。
一、什么是NFC
NFC(Near Field Communication)是一种非接触式的近场通信协议,可以理解为无线通信的一种,在我们的日常生活中有广泛的应用场景,允许设备在彼此靠近时进行数据交换和通信。其基于基于RFID技术,工作频率为13.56 MHz,允许设备在靠近时进行数据交换。主要功能包括读取、写入数据,实现点对点通信和设备控制等。
二、PN532模块
PN532是一款高性能的NFC/RFID控制器,支持多种通信协议,如ISO14443 A/B、Mifare、FeliCa等。它具备读写功能,可与多种IC卡通信,广泛应用于门禁系统、交通卡支付、智能海报等领域。具备低功耗、高集成度特点,适用于便携设备。可嵌入手机、平板等,实现移动支付等功能。
在我们的stm32开发场景中,我们通常购买相应的模块来进行开发。
该模块通过开关的调节来进行不同通信协议之间的转换,具体转换关系如图(不同厂商的板子都应有相应的标注):
图一:背面标注

图二:正面标注
不同协议的接口在图一中均有标注。
三、命令码书写及其解释
代码书写:
#include "pn532.h"
uint8_t aRxBuffer[15]; //接收唤醒数据
uint8_t bRxBuffer[25]; //接收寻卡数据
uint8_t Enter[] = "\r\n"; //回车换行
uint8_t hello0[]="Your PN532 has woken up successfully";
uint8_t hello1[]="Your PN532 has been successfully found";
uint8_t hello2[]="UID";
uint8_t UID[4]; //存储 UID
uint8_t UID_HOST[4]={0XC2,0X99,0X4A,0X1B}; //存储 UID
/*******************************************************************************
* @函数名称 nfc_WakeUp
* @函数说明 PN532自带一个休眠功能,要使用PN532对NFC卡片进行读写的时候要激活一下(唤醒),一般放在程序的开头,调用一次即可。
55 55 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF 03 FD D4 14 01 17 00 (24)
成功唤醒 返回给STM32 00 00 FF 00 FF 00 00 00 FF 02 FE D5 15 16 00 (15)
* @输入参数 无
* @输出参数 无
* @返回参数 无
*******************************************************************************/
void nfc_WakeUp(void)//唤醒
{
u8 adata[24]={0x55,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x03,0xFD,0xD4,0x14,0x01,0x17,0x00,};
HAL_UART_Transmit(&huart2,(uint8_t *)&adata,sizeof(adata),0xFFFF);
HAL_UART_Receive(&huart2,(uint8_t *)&aRxBuffer,15,0xFFFF);
//UART2接收PN532返回给单片机的数据: 00 00 FF 00 FF 00 00 00 FF 02 FE D5 15 16 00
if (HAL_UART_GetState(&huart2) != HAL_UART_STATE_BUSY_TX)
{
// HAL_UART_Transmit(&huart1, (uint8_t*)hello0,sizeof(hello0), 0xFFFF);//Your PN532 has woken up successfully
// HAL_UART_Transmit(&huart1,(uint8_t *)&aRxBuffer,sizeof(aRxBuffer),0xFFFF);
// HAL_UART_Transmit(&huart1, (uint8_t*)Enter,2, 0xFFFF);
}
}
/*******************************************************************************
* @函数名称 nfc_look
* @函数说明 寻卡是涉及到卡片的第一个步骤,nfc对卡的操作都是先寻找卡的,
若寻不到卡,则后续的读写操作将无法进行;
反之,若寻到卡,则后续的读写操作过程中将不再对卡片进行身份确认。
寻卡命令:00 00 FF 04 FC D4 4A 01 00 E1 00 (11)
成功找到 返回给STM32 00 00 FF 00 FF 00 00 00 FF 0C F4 D5 4B 01 01 00 04 08 04 C2 99 4A 1B 0E 00 (25)
* @输入参数 无
* @输出参数 无
* @返回参数 无
*******************************************************************************/
void nfc_look(void)//寻卡
{
u8 i;
u8 bdata[11]={0x00,0x00,0xFF,0x04,0xFC,0xD4,0x4A,0x01,0x00,0xE1,0x00};
HAL_UART_Transmit(&huart2,(uint8_t *)&bdata,sizeof(bdata),0xFFFF);
HAL_UART_Receive(&huart2,(uint8_t *)&bRxBuffer,25,0xFFFF);
if (HAL_UART_GetState(&huart2) != HAL_UART_STATE_BUSY_TX)
{
// HAL_UART_Transmit(&huart1, (uint8_t*)hello1,sizeof(hello1), 0xFFFF);//"Your PN532 has been successfully found";
// HAL_UART_Transmit(&huart1,(uint8_t *)&bRxBuffer,sizeof(bRxBuffer),0xFFFF);
HAL_UART_Transmit(&huart1, (uint8_t*)Enter,2, 0xFFFF);
//
//
UID[0]=bRxBuffer[19];
UID[1]=bRxBuffer[20];
UID[2]=bRxBuffer[21];
UID[3]=bRxBuffer[22];
//
//
// HAL_UART_Transmit(&huart1, (uint8_t *)hello2,sizeof(hello2), 0xFFFF);
HAL_UART_Transmit(&huart1,(uint8_t *)&UID,4,0xFFFF);
// HAL_UART_Transmit(&huart1, (uint8_t*)Enter,2, 0xFFFF);
}
}
int uid_check(void)//UID核验
{
for(int i = 0; i < sizeof(UID_HOST); i++)
{
if(UID[i]!=UID_HOST[i])
{
break;
}
}
return 1;
}
void control(void)
{
if(uid_check()==1)
{
test();
}
}
void test(void)//方便测试
{
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
HAL_Delay(500);
printf("test成功");
}
/**
* 函数功能: 重定向c库函数printf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/**
* 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
#ifndef __PN532_H__
#define __PN532_H__
#include "stm32f1xx_hal.h"
#include "gpio.h"
#include "usart.h"
#include <stdio.h>
#include <string.h>
typedef uint32_t u32;///32位
typedef uint16_t u16;///16位
typedef uint8_t u8;///8位
void nfc_WakeUp(void);//唤醒
void nfc_look(void);//寻卡
int uid_check(void);
void control(void);
void test(void);//方便测试
int fputc(int ch, FILE *f);
int fgetc(FILE *f);
#endif
关键代码段解释:
这里先补充一下NFC通信的原理方便看懂源码。
首先NFC所包含的信息是一个数据帧(是数据传输中的基本单位,由若干字节组成,包含帧头、数据、校验码和帧尾等部分。它规定了数据的传输格式)。我们这里假设数据帧存成一个数组
u8 bdata[11]={0x00,0x00,0xFF,0x04,0xFC,0xD4,0x4A,0x01,0x00,0xE1,0x00};
可以看到该数组由11个十六进制的数字组成下面是各个数字的具体含义:
-
0x00, 0x00:帧头,用于标识数据帧的开始。 -
0xFF:帧头结束标志。 -
0x04:数据长度,表示后面数据的字节数(不包括校验和)。 -
0xFC:长度的补码,0x04的补码。 -
0xD4:指令类型,表示这是一个发送给PN532的命令。 -
0x4A:具体命令码,表示寻卡命令。 -
0x01:参数,表示寻卡模式(0x01表示寻卡模式为ISO14443A)。 -
0x00:保留字节。 -
0xE1:校验和,用于数据完整性校验。 -
0x00:帧尾。
其中的指令类型可以有很多种,也是其中应该变化的部分。
我们看寻卡函数中如下代码
HAL_UART_Transmit(&huart2,(uint8_t *)&bdata,sizeof(bdata),0xFFFF);
通过HAL_UART_Transmit函数将这个数据帧发送给PN532模块。
这里我们的pn532模块会返回一个数值给我们,调用相关的函数进行接收操作:
HAL_UART_Receive(&huart2,(uint8_t *)&bRxBuffer,25,0xFFFF);
假设接收的信息如下:
00 00 FF 00 FF 00 00 00 FF 0C F4 D5 4B 01 01 00 04 08 04 C2 99 4A 1B 0E 00
具体含义如下:
-
00 00 FF 00 FF:帧头和帧头结束标志。 -
00 00 00:保留字节。 -
FF:帧头结束标志。 -
0C:返回数据长度。 -
F4:长度的补码。 -
D5:指令类型,表示这是PN532返回的数据。 -
4B:返回的命令码,与发送的0x4A对应。 -
01:返回状态码,表示操作成功。 -
01:返回的卡片数量。 -
00:保留字节。 -
04:卡片UID长度。 -
08 04 C2 99 4A 1B:卡片的UID(唯一标识符)。 -
0E:校验和。 -
00:帧尾。该信息的关键就在于卡片的UID,卡片中存储的不同的UID可以赋予卡片不同的身份,是我们NFC能够行使其功能的关键。
寻卡函数再对UID信息进行存储:
UID[0]=bRxBuffer[19]; UID[1]=bRxBuffer[20]; UID[2]=bRxBuffer[21]; UID[3]=bRxBuffer[22];bRxBuffer[19]到bRxBuffer[22]是返回数据中的卡片UID部分。
寻卡函数会通过检查返回数据中的状态码01来判断是否成功找到卡片。如果状态码为01,表示寻卡成功,卡片的UID会被存储到UID数组中。
寻卡成功后,函数发送UID信息。
HAL_UART_Transmit(&huart1,(uint8_t *)&UID,4,0xFFFF);
更多推荐



所有评论(0)