请选择 进入手机版 | 继续访问电脑版
凡是官网购买产品,均可以获得积分,(积分可以用来下载技术资料)还可以获得精致技术支持。零知实验室可提供全套电子方案定制服务,了解详情请咨询客服。           
查看: 18018|回复: 318

使用PN532串口NFC模块读写NFC卡片

  [复制链接]
发表于 2018-5-18 12:58:39 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
官网模块购买地址:http://www.lingzhilab.com/index.php/home/goods/introduction?gid=104
http://www.lingzhilab.com/index.php/home/goods/introduction?gid=256

第一章:原理讲解

一、数据帧结构
2018-05-18_121446.png
下面详细解释一下:
  • PREAMBLE1 byte4
      这个就是所谓的帧头,也称为前导码,一般是00
  • START CODE2 bytes (0x00 and 0xFF)
      开始码 2个字节,分别是 00和FF

  • LEN1 byte indicating the number of bytes in the data field (TFI and PD0 to PDn)
      这个是数据长度,一个TFI和n个PD

  • LCS1 Packet Length Checksum LCS byte that satisfies the relation:  Lower byte of [LEN + LCS] = 0x00,
      这个是LEN的补码,也就是(LEN取反+1)

  • TFI1 byte frame identifier, the value of this byte depends on the way of the message
      - D4h in case of a frame from the host controller to the PN532,
      - D5h in case of a frame from the PN532 to the host controller.
      表示数据流向 ,D4 表示 数据发向PN532,D5 表示 PN532数据发出

  • DATALEN-1 bytes of Packet Data Information,The first byte PD0 is the Command Code,
      这才是我们想要发的数据,DATA的第一个字节PD0为控制字符,其余为普通数据。该包长度为 LEN-1

  • DCS1 Data Checksum DCS byte that satisfies the relation: Lower byte of [TFI + PD0 + PD1 + … + PDn + DCS] = 0x00,
      DCS 其实其实就是把这些十六进制数加起来,后两位取补码即可。即(TFI + PD0 + PD1 + … + PDn)累加和,取后两位的补码。

  • POSTAMBLE1 byte2
      帧尾 一般为 00
    The amount of data that can be exchanged using this frame structure is limited to 255  bytes (including TFI).
    最后一句话了,这种的数据结构只能有255 个data (包括TFI),还有几种种结构,这里先不说了。

二、读写实例分析
      使用的是pn532为主控芯片的NFC串口模块,来读写M1卡,注意下所有数字为16进制形式。用usb转串口模块将pn532与电脑连接,串口助手发送选择hex。波特率 默认 115200  数据位8 校验位 无  停止位1 流控无。
      硬件连接正常后开始操作,以下为详细步骤分析:

1. 唤醒PN532:
[Bash shell] 纯文本查看 复制代码
PC->PN532: 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->PC: 00 00 FF 00 FF 00 00 00 FF 02 FE D5 15 16 00

其实第一条不符合普通的发送格式,比较特殊。如果没有正常返回,检查硬件连接和波特率。

2.获取卡UID,也就是卡的唯一ID号,全球就这一个(理论上)
[Bash shell] 纯文本查看 复制代码
PC->PN532: 00 00 FF 04 FC D4 4A 02 00 E0 00

分析:
   04 //代表有四个数据分别是 D4 4A 02 00
   FC //这是04的补码
   4a //命令
   02 //卡数量,0--2
   00 //波特率 106K
   E0 //校验位  D4+4A+02+00=0x0120  取后两位20的补码为E0。至于补码怎么计算自己百度吧。

[Bash shell] 纯文本查看 复制代码
PN532->PC:  00 00 FF 00 FF 00 
                   00 00 FF 0C F4 D5 4B 01 01 00 04 08 04 A1 9F F5 5E 3B 00 

分析:
    00 00 FF 00 FF 00  //ACK
    00 00 FF 0C F4
    D5 //PN532 到 MCU
    4B //响应命令
    01 //目标卡1
    01 //目标卡数量,最大为0x02,最小为0
    00 04 //atq
    08    //卡容量 08=1K
    04    //4个字节UID
    02 F5 13 BE //UID
    06 00 //DCS+POST
到这一步总体来说还算顺利,主要是因为可以发送完命令在再刷卡也行,也可以把卡一直放上。

3、密钥验证,注意验证完秘钥,卡不能离开,需要一直放在上面,才能顺利的完成下面读写操作,还有注意替第二个步骤的UID,最后根据自己的UID计算校验位即倒数第二位。
[Bash shell] 纯文本查看 复制代码
PC->PN532:  00 00 fF 0F F1 D4 40 01 60 07 FF FF FF FF FF FFA1 9F F5 5E C2 00

分析:   
     40 //命令
     01 //卡1
     60 //密钥验证命令
     07 //块号
     ff ff ff ff ff ff //密钥
     A1 9F F5 5E //UID 替换为步骤2得到的UID
     C2 //检验位,根据替换的UID计算,计方法跟步骤2一样。

[Bash shell] 纯文本查看 复制代码
PN532->PC: 00 00 FF 00 FF 00 
                  00 00 FF 03 FD D5 41 00 EA 00 

分析:
    41 00 //正确状态

4.开始读卡,M1卡有16个扇区,每个扇区4个块。
游客,如果您要查看本帖隐藏内容请回复



第二章:资料分享

网络搜集相关资料:
链接:https://pan.baidu.com/s/1BwuSZiECQWmkHDTRghuYNw

游客,如果您要查看本帖隐藏内容请回复

附件资料:
1、上位机及STM32平台示例代码等
PN532-mfoc-mfcuk-GUI by 蛐蛐V2.0.rar (763.04 KB, 下载次数: 24)

Z0057-PN532资料.rar

4.39 MB, 下载次数: 14747, 下载积分: 积分 -5

PN532测试软件.zip

7.87 MB, 下载次数: 15069, 下载积分: 积分 -5

回复

使用道具 举报

 楼主| 发表于 2018-11-6 09:12:51 | 显示全部楼层
回复

使用道具 举报

 楼主| 发表于 2018-11-26 18:54:48 | 显示全部楼层
下面我们在零知平台上使用PN532进行读写卡操作。

1、硬件(1)模块

(2)连线

这里连线非常简单,零知PN532 NFC扩展板和零知标准板可以直插直用,无需其他任何接线,非常方便:

IMG_20191114_122339.jpg

2、程序编写

我们打开零知开发工具,然后选择示例程序:


                               
登录/注册后可看大图


这里有很多示例,我们先使用最简单的读取ID号,选择readMifareClassic这个示例,打开后验证并上传到零知标准板。

3、验证结果

将程序上传到零知板后,打开串口调试窗口,然后我们用白卡接近下就可以看到打印了它的ID等信息:


                               
登录/注册后可看大图


读取到了信息了:

333.jpg

pn532-testing.7z

3.11 KB, 下载次数: 69, 下载积分: 积分 -5

回复

使用道具 举报

 楼主| 发表于 2018-11-26 19:16:49 | 显示全部楼层
以下为NTAG213,NFC标签卡片的操作,基于STM32平台的主要代码,供参考(在STM32F411上测试过):

使用方法可以参考下面的nfc_test() 函数。

文件:nfc.h
[C++] 纯文本查看 复制代码
#ifndef NFC_H
#define NFC_H

#define UID_LEN                7
#define BRTY_0                0x00 //ISO1443-A, 106kbps

#include "OMW.h"

void nfc_init(void);
uint8_t nfc_test();

#endif


使用示例:

[C++] 纯文本查看 复制代码
uint8_t nfc_test()
{
        uint8_t temp = 0;
        uint8_t uid[8] = {0};
        uint8_t i = 0;
        uint8_t read_data[16] = {0};
        uint8_t block_num;
        uint8_t write_data[16] = {0x00};
        uint8_t read_err = 0;
        
        nfc_WakeUp();

        if (nfc_InListPassiveTarget(1, BRTY_0, uid) == 1)
        {
//                SEGGER_RTT_printf(0, "uid:");
//                for(i=0; i<UID_LEN; i++)
//                {
//                        SEGGER_RTT_printf(0, "%x ", uid[i]);
//                }
//                SEGGER_RTT_printf(0, "\r\n");

                
                block_num = 0x06;
                
//                write_data[0] = 0x04;
//                write_data[1] = 0x00;
//                write_data[2] = 0x00;
//                write_data[3] = 0x00;
//                
//                nfc_write_area(write_data, block_num);
                
                while( nfc_read_area(block_num, read_data) == 0)
                {
                        read_err ++;
                        delayms(200);
                        
                        if(read_err >= 3)
                                break;
                }
                SEGGER_RTT_printf(0, "read block[0x%x]:",block_num);

        }

}


使用的USART配置:

[C++] 纯文本查看 复制代码
#include "usart.h"
#include "stm32f4xx_usart.h"
#include "SEGGER_RTT.h"

// UART1_TX        PB6
// UART1_RX        PB7
extern uint8_t Uart1_recv_frame_done;
extern uint8_t Uart1_recv_buff[64];
extern uint8_t Uart1_recv_counter;

// UART2_TX        PA2
// UART2_RX        PA3

extern uint8_t Uart2_recv_frame_done;
extern uint8_t Uart2_recv_buff[64];
extern uint8_t Uart2_recv_counter;

/**************************************** UART1 ******************************************/
// UART1_TX        PB6
// UART1_RX        PB7

void NVIC_USART1_Config(void)
{
        NVIC_InitTypeDef NVIC_InitStructure;
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
        
        NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x00;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02;
        NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
        NVIC_Init(&NVIC_InitStructure);
}

void USART1_Config(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        
        
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB , ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
        
        GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1); 
        GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);
        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
        GPIO_Init(GPIOB, &GPIO_InitStructure);            
                        
        NVIC_USART1_Config();

        USART_InitStructure.USART_BaudRate=115200;
        USART_InitStructure.USART_WordLength=USART_WordLength_8b;
        USART_InitStructure.USART_StopBits=USART_StopBits_1;
        USART_InitStructure.USART_Parity=USART_Parity_No;
        USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
        
        USART_Init(USART1,&USART_InitStructure);
        
        USART_ClearFlag(USART1, USART_FLAG_TC);
        
        USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
        USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
        
        USART_Cmd(USART1,ENABLE);        
}

void USART1_IRQHandler(void)
{
        uint8_t clear;
        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//receive one byte done
        {
                Uart1_recv_buff[Uart1_recv_counter++] = USART_ReceiveData(USART1);
                //SEGGER_RTT_printf(0, "%x ", Uart1_recv_buff[Uart1_recv_counter-1]);
        }
        else if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)//receive one frame data done
        {
                clear = USART1->SR;
                clear = USART1->DR;
                Uart1_recv_frame_done = 1;
        }
}

void uart1_send(uint8_t *data, uint8_t len)
{
        uint8_t i = 0;
        for(i=0; i<len; i++)
        {
                while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
                USART_SendData(USART1, (uint8_t)(data[i]));
        }
}

void uart1_send_byte(uint8_t byte)
{
        while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
        USART_SendData(USART1, (uint8_t)(byte));
}

/**************************************** UART1 END ******************************************/

/**************************************** UART2 ******************************************/


// UART2_TX        PA2
// UART2_RX        PA3

void NVIC_USART2_Config(void)
{
        NVIC_InitTypeDef NVIC_InitStructure;
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
        
        NVIC_InitStructure.NVIC_IRQChannel=USART2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x00;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02;
        NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
        NVIC_Init(&NVIC_InitStructure);
}

void USART2_Config(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        
        
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA , ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
        
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2); 
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
        GPIO_Init(GPIOA, &GPIO_InitStructure);            
                        
        NVIC_USART2_Config();

        USART_InitStructure.USART_BaudRate=115200;
        USART_InitStructure.USART_WordLength=USART_WordLength_8b;
        USART_InitStructure.USART_StopBits=USART_StopBits_1;
        USART_InitStructure.USART_Parity=USART_Parity_No;
        USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
        
        USART_Init(USART2,&USART_InitStructure);
        
        USART_ClearFlag(USART2, USART_FLAG_TC);
        
        USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
        USART_ITConfig(USART2,USART_IT_IDLE,ENABLE);
        
        USART_Cmd(USART2,ENABLE);        
}

void USART2_IRQHandler(void)
{
        uint8_t clear;
        if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)//receive one byte done
        {
                Uart2_recv_buff[Uart2_recv_counter++] = USART_ReceiveData(USART2);
                //SEGGER_RTT_printf(0, "%x ", Uart2_recv_buff[Uart2_recv_counter]);
        }
        else if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)//receive one frame data done
        {
                clear = USART2->SR;
                clear = USART2->DR;
                Uart2_recv_frame_done = 1;
        }
}

void uart2_send(uint8_t *data, uint8_t len)
{
        uint8_t i = 0;
        for(i=0; i<len; i++)
        {
                while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
                USART_SendData(USART2, (uint8_t)(data[i]));
        }
}

void uart2_send_byte(uint8_t byte)
{
        while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
        USART_SendData(USART2, (uint8_t)(byte));
}
/**************************************** UART2 END ******************************************/



文件nfc.c,具体的实现,唤醒、寻卡、读写操作,和上面的过程是一样的,只是卡的类型不同,操作的命令有所区别:
游客,如果您要查看本帖隐藏内容请回复


回复

使用道具 举报

发表于 2018-10-9 16:30:29 | 显示全部楼层
查看更多
回复

使用道具 举报

发表于 2018-10-10 15:45:14 | 显示全部楼层
摸索中,求指教!
回复

使用道具 举报

 楼主| 发表于 2018-10-10 20:33:40 | 显示全部楼层
keyvan 发表于 2018-10-10 15:45
摸索中,求指教!

有问题可以直接发帖~
回复

使用道具 举报

发表于 2018-10-23 17:17:04 | 显示全部楼层
请问一下第四步,怎么读扇区?
回复

使用道具 举报

 楼主| 发表于 2018-10-23 19:31:06 | 显示全部楼层
hithhc 发表于 2018-10-23 17:17
请问一下第四步,怎么读扇区?

上面有例子的,有啥问题么?
回复

使用道具 举报

发表于 2018-11-3 12:20:27 | 显示全部楼层
希望有视频教程
回复

使用道具 举报

 楼主| 发表于 2018-11-3 15:07:43 | 显示全部楼层
YY2001 发表于 2018-11-3 12:20
希望有视频教程

会有的
回复

使用道具 举报

发表于 2018-11-5 17:28:25 | 显示全部楼层
一直搞不懂如何操作,这下懂了不少
回复

使用道具 举报

发表于 2018-11-9 12:12:18 | 显示全部楼层
,学习一下,谢谢楼主
回复

使用道具 举报

发表于 2018-11-12 14:29:03 | 显示全部楼层
需要这个资料做P2P
回复

使用道具 举报

发表于 2018-11-15 10:37:27 | 显示全部楼层
学习一下
回复

使用道具 举报

发表于 2018-11-15 18:24:25 | 显示全部楼层
学习学习
回复

使用道具 举报

发表于 2018-11-17 00:02:13 | 显示全部楼层
wolai学习了 感谢楼主 紫薯布丁
回复

使用道具 举报

发表于 2018-11-18 22:59:21 | 显示全部楼层
板子刚到, 现在看看技术文档
回复

使用道具 举报

发表于 2018-11-19 23:28:14 | 显示全部楼层
学习当中,才到模块
回复

使用道具 举报

发表于 2018-11-23 09:04:58 | 显示全部楼层
看看 :
回复

使用道具 举报

发表于 2018-11-23 16:28:01 | 显示全部楼层
研究一下,从小对这个兴趣就比较大
回复

使用道具 举报

发表于 2018-11-25 18:13:54 | 显示全部楼层
新手上路,看看教程
回复

使用道具 举报

 楼主| 发表于 2018-11-26 11:17:50 | 显示全部楼层
下面使用上位机进行读写测试:

1、上位机软件:

NFC上位机.zip (4.28 MB, 下载次数: 13985)
回复

使用道具 举报

发表于 2018-11-26 21:14:05 | 显示全部楼层
请问如何把一张没有初始化过的M1卡进行初始化?
回复

使用道具 举报

 楼主| 发表于 2018-11-27 08:56:51 | 显示全部楼层
hanyuhang 发表于 2018-11-26 21:14
请问如何把一张没有初始化过的M1卡进行初始化?

直接读写就可以啊?你需要什么样的初始化呢?做加密
回复

使用道具 举报

发表于 2018-11-27 13:57:36 | 显示全部楼层
学习以下
回复

使用道具 举报

发表于 2018-11-29 09:07:28 | 显示全部楼层
请问如何解密扇区
回复

使用道具 举报

发表于 2018-11-29 16:14:06 | 显示全部楼层
学习一下
回复

使用道具 举报

发表于 2018-12-1 20:48:03 | 显示全部楼层
看看
学学习一下看看
学学习一下
回复

使用道具 举报

发表于 2018-12-2 14:14:13 | 显示全部楼层
这个能读取带nfc功能的手机吗
回复

使用道具 举报

发表于 2018-12-2 21:11:26 | 显示全部楼层
看看,学习一下,感觉很高深
回复

使用道具 举报

 楼主| 发表于 2018-12-3 09:17:59 | 显示全部楼层
jn3393 发表于 2018-12-2 14:14
这个能读取带nfc功能的手机吗

可以的
回复

使用道具 举报

发表于 2018-12-5 15:39:56 | 显示全部楼层
谢谢,很好,非常感谢,学习了
回复

使用道具 举报

发表于 2018-12-8 15:36:57 | 显示全部楼层
厉害了我的哥
回复

使用道具 举报

发表于 2018-12-8 18:58:53 | 显示全部楼层
感谢感谢
回复

使用道具 举报

发表于 2018-12-10 13:44:29 | 显示全部楼层

请问一下第四步,怎么读扇区?
回复

使用道具 举报

 楼主| 发表于 2018-12-10 14:12:42 | 显示全部楼层
sxxfco 发表于 2018-12-10 13:44
请问一下第四步,怎么读扇区?

隐藏内容回帖可见
回复

使用道具 举报

发表于 2018-12-11 18:26:28 | 显示全部楼层
查看更多
回复

使用道具 举报

发表于 2018-12-13 15:55:38 | 显示全部楼层
46546131654654321
回复

使用道具 举报

发表于 2018-12-13 16:21:24 | 显示全部楼层
楼主咨询一下PN532怎么做低功耗,RC522的低功耗我是把RST脚拉高,这个时候整个功耗只有几十uA,PN532应该怎么做到最低功耗呢,包括低功耗的剪卡,可以指导一下嘛  谢了
回复

使用道具 举报

 楼主| 发表于 2018-12-13 17:15:37 | 显示全部楼层
bumbdong 发表于 2018-12-13 16:21
楼主咨询一下PN532怎么做低功耗,RC522的低功耗我是把RST脚拉高,这个时候整个功耗只有几十uA,PN532应该怎 ...

请阅读文档,文档上已经很清楚了:硬件上RSTPDN控制,软件有个寄存器可以进入Power Down。
12.png



回复

使用道具 举报

发表于 2018-12-13 22:32:01 | 显示全部楼层
前来学习的
回复

使用道具 举报

发表于 2018-12-14 15:47:06 | 显示全部楼层
.......................................
回复

使用道具 举报

发表于 2018-12-15 12:24:05 | 显示全部楼层
围观一下吧
回复

使用道具 举报

发表于 2018-12-18 13:47:50 | 显示全部楼层
:P:P:P:P:P:P:P:P:P:P:P:P:P:P:P
回复

使用道具 举报

发表于 2018-12-18 21:19:07 | 显示全部楼层
查看更多内容
回复

使用道具 举报

发表于 2018-12-19 06:13:50 | 显示全部楼层
未发现设备
回复

使用道具 举报

 楼主| 发表于 2018-12-19 08:59:30 | 显示全部楼层

检查接线、模块设置为串口接口模式
回复

使用道具 举报

发表于 2018-12-20 20:25:45 | 显示全部楼层
学习。。。学习。。好好学习
回复

使用道具 举报

发表于 2018-12-22 00:09:02 | 显示全部楼层
学习一波
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版| 小黑屋| 零知实验室 ( 粤ICP备17040594号-3 )

GMT+8, 2020-2-25 20:50 , Processed in 0.095725 second(s), 20 queries .

快速回复 返回顶部 返回列表