Holiday 发表于 2016-1-17 20:25:11

ArduinoNFC模块使用方法分享,PN532模块,S50卡

Arduino NFC模块使用方法分享
先推荐购买链接:中文商城:https://www.dfrobot.com.cn/goods-762.html
近场通信(Near Field Communication,NFC),又称近距离无线通信,是一种短距离的高频无线通信技术,允许电子设备之间进行非接触式点对点数据传输(在十厘米内)交换数据。这个技术由免接触式射频识别(RFID)演变而来,并向下兼容RFID------这世道,写个教程还要想想怎么开头------这世道,写个开头还是抄来的------Attention:题主使用的是PN532模块和S50卡。(╯‵□′)╯︵┴─┴好了,言归正传。首先,完成一个S50卡读写操作的步骤:唤醒----识别卡----密码验证------读写
By the way:波特率115200,数据位8,停止位1,奇偶校验none
首先说唤醒:应该是PN532带了一个休眠功能,要使用PN532对NFC卡片进行读写的时候要先唤醒一下。过程很简单,写程序的时候加在setup里就可以了,一般就只运行一遍就好。看看发送的命令(十六进制):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就会返回00 00 FF 00 FF 00 00 00 FF 02 FE D5 15 16 00基本唤醒没什么好说的,这个步骤还不管卡片上面事情,所以你要是没得到相应的回复,不要怀疑你的nfc卡出了问题。检查下接线吧。。
接下来就是识别卡片:相比较唤醒,识别卡片的步骤就重要的多了,现实中那种对不起砍错人了的事是不会在nfc的世界出现的。nfc对卡的操作都是要先认识卡的。因为读写的操作中不会对卡进行身份确认。识别命令:00 00 ff 04 fc d4 4a 02 00 e0 00上面数据中,4a---命令代码,02----卡数量,一般选1就好,最大是2,返回(举个栗子):00 00 FF 00 FF 00 00 00 FF C F4 D5 4B 01 01 00 04 08 04 D1 AA 40 EA 29 00//0 0 FF 0 FF 0 ----ACK//0 0 FF C F4 //D5---数据方向是PN532 to Arduino//4B----响应命令//1 1----目标卡1,目标卡数量//0 4----atq //8----capacity of the cardis 8K//4 ---- 4 numbers of the UID//D1 AA 40 EA----UID //29 0------DCSPOST---DCS=0xff-0xff&(SUM(0 0 FF C F4 D5 4B 1 1 0 4 8 4 D1 AA 40 EA))
粉红色的就是我们找到的卡的UID,也就是卡的身份证号码,这个号码可以用来识别是哪张卡。DCS的计算就是前面数加起来得到一个和SUM,然后取SUM的后两位(二进制的低八位)0xFF-SUM=DCS, 是用来校验数据传输的。
当然,如果识别出了问题可能会有其他乱码,至于乱码是什么意思,求你去看看pn532的datasheet和使用说明,其实只要不是这个格式的基本就是你程序问题,和卡以及模块无关。。。
好了,来到了激动人心的密码验证环节了先来看看s50卡的存储机制吧,来张性感照片:

1024 x 8 bit EEPROM存储器分为16区,每区4块,每块16字节,已图上红色框框里的14号区为例,每个区的第四块(块编号3,程序员是从0数数的)负责存放这个区的密码,在第四块内有密码A,控制为,密码B,一般默认的是密码A,控制为是控制某个块的读写,增减,传输,储存的。详细信息参见这里
一般你就知道密码是在第放哪里的就好了,其它的不用管。
所以,一个区里四个块的密码是一样的
所以,你在第7块用的密码是和6块一样的,但是第7块用的密码和第8块就不是一个了,虽然出厂都是一个。
验证要发送的数据为:0x00,0x00,0xFF,0x0F,0xF1,0xD4,0x40,0x01,0x60,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xD1,0xAA,0x40,0xEA,0xC2,0x00
解释一下//               数据头             卡1   密码验证命令    块号               密码                   UID(身份证号)    DCS         POST//00 00 FF 0F F1 D4 40      01         60                07          FF FF FF FF FF FF          02 F5 13 BE         C2         00
TIPS:你要改的部分是块号,密码,和UID,DCS,其它的别改就好。DCS每次在程序里自动计算就好
如果成功,返回:out: 00 00 FF 00 FF 00 00 00 FF 03 FD D5 41 00 EA 00 其中:41 00 表示正确状态,很多时候你会收到 4117之类的数据,你多半是瞎改过这个区的密码,要不就是没唤醒和寻卡。抠鼻。。。


终于到读写了,刚才说的区和块的注意点最好看懂了再操作写这个功能,不然手贱锁芯片的事不要太容易就发生,不过好的情况是,锁了一个区,还有其它区可以用
读取数据的命令:0x00,0x00,0xff,0x05,0xfb,0xD4,0x40,0x01,0x30,0x07,0xB4,0x00
各数据的解释://   ----head---------   cmd   card 1   readcmd   block number   DCS+POST//00 00 ff 05 f b D4       40         01             30                  07                  B4 00   //读第7块
命令发送没什么好说的,成功的话你会看到回复:
00 00 FF 00 FF 00 00 00 FF 13 ED D5 41 00 01 01 02 02 03 03 04 04 05 05 06 06 07 07 08 08 A2 00 其中:00 00 FF 00 FF 00-------数据头00 00 FF 13 ED D5-----写东西的时候天气不好,所以没去查什么意思41 00----------去读成功标志位,你要是总出现4103,please check your code,多半是操作问题,按照唤醒,寻卡,密码验证,读写的顺序准没错01 01 02 02 03 03 04 04 05 05 06 06 07 07 08 08-----------之前我写进去的数据A2 00------------DCS和POST
来看看写卡:00 00 ff 15 EB D4 40 01 A0 06 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F CD 00各数据解释:00 00 ff 15 EB D4-------Just ignore its ***king meaning40------------写命令01------------卡106------------块号00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F------------要写进去的数据CD 00-----------DCS+POST
如果成功,回复:00 00 00 FF 00 FF 00 00 00 FF 03 FD D5 41 00 EA 00
这个和前面类似,基本写操作完成就是这几个数据,成功的标志是 41 00, 做好DCS的校验基本不会出什么问题。

附件是NFC的UID读取代码和NFC的读写代码例子,严禁吐槽代码写得不漂亮,红字表严肃。

代码是基于Leonardo控制板写的,因为Leonardo两个串口,做调试什么的比较方便。如果您身边只有UNO,可以参照附件的程序,同时参照@Cain 的NFC帖子,你要是说没有IIC1602显示器,(╯‵□′)╯︵┴─┴

nfc卡片上0区有个地方是写这个卡身份证号码的地方,那个地方不能写,只能读。
贴一下代码吧,方便以后复制。
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#define print1Byte(args) Serial1.write(args)
#define print1lnByte(args)Serial1.write(args),Serial1.println()
#else
#include "WProgram.h"
#define print1Byte(args) Serial1.print(args,BYTE)
#define print1lnByte(args)Serial1.println(args,BYTE)
#endif

unsigned char receive_ACK;
unsigned char UID={0xD1,0xAA,0x40,0xEA};
unsigned char secret={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
unsigned char dataWriteIntoCard={0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08};

int ctr=0;

void setup()
{
Serial.begin(9600);
Serial1.begin(115200);

wakeUp();
delay(10);
readAck(15);
for(int i=0;i<15;i++)Serial.print(receive_ACK);
Serial.println();

}

void loop()
{
Scan();
if(passWordCheck(0x08,UID,secret)==1)
{   
   Serial.println("passed");   
if(ctr<4)   //写4次后就不写了,s50卡的使用寿命是写10W次,读不限,放心用
{
      writeData(0x08,dataWriteIntoCard);
      Serial.println("written");
      ctr++;
}
delay(2000);
readData(0x08);   
}
delay(4000);
}

void wakeUp()
{
const unsigned char wake={
0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xfd, 0xd4, 0x14, 0x01, 0x17, 0x00};//wake up NFC module
for(int i=0;i<24;i++) //send command
{
    UART1_Send_Byte(wake);
}
}

void Scan()
{
const unsigned char cmdUID={ 0x00, 0x00, 0xFF, 0x04, 0xFC, 0xD4, 0x4A, 0x01, 0x00, 0xE1, 0x00};
//0 0 FF 0 FF 0 0 0 FF C F4 D5 4B 1 1 0 4 8 4 D1 AA 40 EA 29 0
//0 0 FF 0 FF 0 ----ACK
//0 0 FF C F4
//D5---PN532 to Arduino
//4B----respond command
//1 1----target IDand target amount
//0 4----atq
//8----capacity of the cardis 8K
//4 ---- 4 numbers of the UID
//D1 AA 40 EA----UID
//29 0------DCSPOST---DCS=0xff&(SUM(0 0 FF C F4 D5 4B 1 1 0 4 8 4 D1 AA 40 EA))
unsigned char NFC_UID,count=0;
for(int i=0;i<11;i++)UART1_Send_Byte(cmdUID);
delay(10);
readAck(25);
delay(10);
}


int passWordCheck(int block,unsigned char id[],unsigned char st[])
{
//---------head-------card 1check blocknumberpassword               UID D1 AA 40 EA      DCS+POST
//00 00 FF 0F F1 D4 40    01   60    07          FF FF FF FF FF FF       02 F5 13 BE         C2 00

//out: 00 00 FF 00 FF 00 00 00 FF 03 FD D5 41 00 EA 00------41 00 //正确状态    16Bytes
//   00FF 0FF 000FF3 FD D5 41 27 C3 0
unsigned char cmdPassWord={0x00,0x00,0xFF,0x0F,0xF1,0xD4,0x40,0x01,0x60,\
                                 0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xD1,0xAA,0x40,0xEA,0xC2,0x00};                                 
unsigned char sum=0,count=0;
cmdPassWord=block;
for(int i=10;i<16;i++) cmdPassWord=st;// 密码
for(int i=16;i<20;i++) cmdPassWord=UID;// UID
for(int i=0;i<20;i++) sum+=cmdPassWord;
cmdPassWord=0xff-sum&0xff;

Serial.println("passWordSend: ");
for(int i=0;i<22;i++){Serial.print(cmdPassWord,HEX); Serial.print(" ");}
Serial.println();


while(Serial1.available())   char xx=Serial1.read();//clear the serial data

for (int i=0;i<22;i++)UART1_Send_Byte(cmdPassWord);
delay(100);
while(Serial1.available())
   {
      receive_ACK=Serial1.read();
      count++;
   }
// readAck(16);delay(10);
Serial.println("passWordRes: ");
for(int i=0;i<16;i++){Serial.print(receive_ACK,HEX); Serial.print(" ");}
Serial.println();

if(checkDCS(16)==1 && receive_ACK==0x41 && receive_ACK==0x00)return 1;
else return 0;
}

void readData(int block)// 读取数据block---要读取的块
{
//----head--------- cmdcard 1   readcmd   block 07DCS+POST
//00 00 ff 05 fb D440    01      30      07      B4 00 //读第7块
//out: 00 00 FF 00 FF 00 //ACK
//------------------41 00for right41 03wrong      data                                           DCS+POST
//00 00 FF 13 ED D5 41 00                        00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF   01 00//7块

//test back:00 00 FF 00 FF 00 00 00 FF 13 ED D5 41 00 01 01 02 02 03 03 04 04 05 05 06 06 07 07 08 08 A2 00
unsigned char cmdRead={0x00,0x00,0xff,0x05,0xfb,0xD4,0x40,0x01,0x30,0x07,0xB4,0x00};
unsigned char sum=0,count=0;
cmdRead=block;
for(int i=0;i<10;i++) sum+=cmdRead;
cmdRead=0xff-sum&0xff;

while(Serial1.available())   char xx=Serial1.read();//clear the serial data

//Serial.print("readDCS:");Serial.println(cmdRead,HEX);
for(int i=0;i<12;i++){UART1_Send_Byte(cmdRead);}
delay(10);
while(Serial1.available())
   {
      receive_ACK=Serial1.read();
////      Serial.print(count);Serial.print(":");
//      Serial.print(receive_ACK,HEX);
//      Serial.print(" ");
      count++;
   }
   
Serial.println("Read data:   ");
for(int i=0;i<count;i++){Serial.print(receive_ACK,HEX); Serial.print(" ");}
Serial.println();
//    DCS校验是否成功      这两位数据上为0x41和0x00则表示操作成功
if(checkDCS(32)==1 && receive_ACK==0x41 && receive_ACK==0x00)Serial.println("Finish Reading");

Serial.println(" ");
}

void writeData(int block,unsigned char dwic[])//block:待写入数据的块,dwic[]待写入的数据
{
//00 00 ff 15 EB D4 40 01 A0 06 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F CD 00
unsigned char cmdWrite[]={0x00,0x00,0xff,0x15,0xEB,0xD4,0x40,0x01,0xA0, \
                            0x06,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, \
                            0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xCD,0x00};
unsigned char sum=0,count=0;
cmdWrite=block;
for(int i=10;i<26;i++) cmdWrite=dwic;// 待写入的数据
for(int i=0;i<26;i++) sum+=cmdWrite;//加和
cmdWrite=0xff-sum&0xff;//计算DCS

while(Serial1.available())   char xx=Serial1.read();//clear the serial data

for(int i=0;i<28;i++) UART1_Send_Byte(cmdWrite);
while(Serial1.available())
   {
      receive_ACK=Serial1.read();
      count++;
   }
   
Serial.print("Write respond:   ");
for(int i=0;i<17;i++){Serial.print(receive_ACK,HEX); Serial.print(" ");}
Serial.println("   Write respond End ");
if(checkDCS(17)==1 && receive_ACK==0x41 && receive_ACK==0x00)
{
    Serial.println("WriteFinish!");
}
}

void readAck(int x) //读取x个串口发来的数据
{
unsigned char i;
for(i=0;i<x;i++)
{
    receive_ACK= Serial1.read();
}
}

void UART1_Send_Byte(unsigned char command_data)// 按照固定格式发送命令
{
print1Byte(command_data);
#if defined(ARDUINO) && ARDUINO >= 100
    Serial1.flush();// complete the transmission of outgoing serial data
#endif
}

char checkDCS(int x)//NFCS50卡DCS校验检测子函数
{
unsigned char sum=0,dcs=0;
for(int i=6;i<x-2;i++)
{
    sum+=receive_ACK;
}
dcs=0xff-sum&0xff;
if(dcs==receive_ACK)return 1;
else   return 0;
}

参考链接:NFC的PN532 读写命令格式Mifare1卡说明文档
以及DFRobot的产品wiki

嗯,基本就是这么多了。

https://mc.dfrobot.com.cn/data/attachment/forum/201311/25/165042vit9cz7t80g8qhc9.jpg
看帖回帖,是美德
{:5_153:}

丄帝De咗臂 发表于 2016-1-17 21:09:42

学习沙发

dsweiliang 发表于 2016-1-17 22:58:05

xuexixuexi

kongweiyena 发表于 2016-1-23 16:22:00

:lol厉害厉害,学习了。之前看文档弄得头昏脑涨的,楼主讲的很简明

Holiday 发表于 2016-1-29 11:50:21

kongweiyena 发表于 2016-1-23 16:22
厉害厉害,学习了。之前看文档弄得头昏脑涨的,楼主讲的很简明

::lol:lol一起学习

Jason_G 发表于 2016-10-11 17:10:09

学习了{:5_161:}

映雪—斗牛士 发表于 2017-4-18 22:01:02

学习了,楼主讲解的很有意思

djk0125 发表于 2017-9-11 20:16:27

新人来报到!学习了 !!

甲子如风 发表于 2017-10-5 09:21:32

你好我下载了福建的代码 可以说是.C   我怎么能打开呢

Burningon 发表于 2018-7-27 14:36:25

楼主您好,最近在学习nfc,用的是您推荐购买的那块黑色的板子,我是使用电脑串口进行调试的,能够唤醒并返回正确的唤醒回应,但一输入寻卡命令,它就只返回一个包头,00 00 FF 00 FF 00,请问这是为什么呢

luna 发表于 2019-4-23 13:59:06

我为美德代言
页: [1]
查看完整版本: ArduinoNFC模块使用方法分享,PN532模块,S50卡