41570浏览
查看: 41570|回复: 10

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

[复制链接]
Arduino NFC模块使用方法分享

先推荐购买链接:
中文商城:

近场通信(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 card  is 8K
//4 ---- 4 numbers of the UID
//D1 AA 40 EA----UID
//29 0------DCS  POST---  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卡的存储机制吧,来张性感照片:
ArduinoNFC模块使用方法分享,PN532模块,S50卡图1

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 表示正确状态,很多时候你会收到 41  17之类的数据,你多半是瞎改过这个区的密码,要不就是没唤醒和寻卡。抠鼻。。。



终于到读写了,
刚才说的区和块的注意点最好看懂了再操作写这个功能,不然手贱锁芯片的事不要太容易就发生,不过好的情况是,
锁了一个区,还有其它区可以用

读取数据的命令:
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----------去读成功标志位,你要是总出现  41  03,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 meaning
40------------写命令
01------------卡1
06------------块号
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区有个地方是写这个卡身份证号码的地方,那个地方不能写,只能读。

贴一下代码吧,方便以后复制。
  1. #if defined(ARDUINO) && ARDUINO >= 100
  2. #include "Arduino.h"
  3. #define print1Byte(args) Serial1.write(args)
  4. #define print1lnByte(args)  Serial1.write(args),Serial1.println()
  5. #else
  6. #include "WProgram.h"
  7. #define print1Byte(args) Serial1.print(args,BYTE)
  8. #define print1lnByte(args)  Serial1.println(args,BYTE)
  9. #endif
  10. unsigned char receive_ACK[35];
  11. unsigned char UID[4]={0xD1,0xAA,0x40,0xEA};
  12. unsigned char secret[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
  13. unsigned char dataWriteIntoCard[16]={0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08};
  14. int ctr=0;
  15. void setup()
  16. {
  17.   Serial.begin(9600);
  18.   Serial1.begin(115200);
  19.   wakeUp();
  20.   delay(10);
  21.   readAck(15);
  22.   for(int i=0;i<15;i++)  Serial.print(receive_ACK[i]);
  23.   Serial.println();
  24. }
  25. void loop()
  26. {
  27.   Scan();
  28.   if(passWordCheck(0x08,UID,secret)==1)
  29. {   
  30.    Serial.println("passed");   
  31.   if(ctr<4)   //  写4次后就不写了,s50卡的使用寿命是写10W次,读不限,放心用
  32.   {  
  33.         writeData(0x08,dataWriteIntoCard);
  34.         Serial.println("written");
  35.         ctr++;
  36.   }
  37.   delay(2000);
  38.   readData(0x08);   
  39.   }
  40.   delay(4000);
  41. }
  42. void wakeUp()
  43. {
  44.   const unsigned char wake[24]={
  45.   0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
  46.   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xfd, 0xd4, 0x14, 0x01, 0x17, 0x00};//wake up NFC module
  47.   for(int i=0;i<24;i++) //send command
  48.   {
  49.     UART1_Send_Byte(wake[i]);
  50.   }
  51. }
  52. void Scan()
  53. {
  54.   const unsigned char cmdUID[11]={ 0x00, 0x00, 0xFF, 0x04, 0xFC, 0xD4, 0x4A, 0x01, 0x00, 0xE1, 0x00};
  55.   //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
  56.   //0 0 FF 0 FF 0 ----ACK
  57.   //0 0 FF C F4
  58.   //D5---PN532 to Arduino
  59.   //4B----respond command
  60.   //1 1----target ID  and target amount
  61.   //0 4----atq
  62.   //8----capacity of the card  is 8K
  63.   //4 ---- 4 numbers of the UID
  64.   //D1 AA 40 EA----UID
  65.   //29 0------DCS  POST---  DCS=0xff&(SUM(0 0 FF C F4 D5 4B 1 1 0 4 8 4 D1 AA 40 EA))
  66.   unsigned char NFC_UID[5],count=0;
  67.   for(int i=0;i<11;i++)  UART1_Send_Byte(cmdUID[i]);
  68.   delay(10);
  69.   readAck(25);
  70.   delay(10);
  71. }
  72. int passWordCheck(int block,unsigned char id[],unsigned char st[])
  73. {
  74.   //---------head-------  card 1  check blocknumber  password               UID D1 AA 40 EA      DCS+POST
  75.   //00 00 FF 0F F1 D4 40    01     60    07          FF FF FF FF FF FF       02 F5 13 BE           C2 00
  76.   
  77.   //out: 00 00 FF 00 FF 00 00 00 FF 03 FD D5 41 00 EA 00  ------41 00 //正确状态    16Bytes
  78.   //     0  0  FF 0  FF 0  0  0  FF  3 FD D5 41 27 C3 0
  79.   unsigned char cmdPassWord[22]={0x00,0x00,0xFF,0x0F,0xF1,0xD4,0x40,0x01,0x60,\
  80.                                  0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xD1,0xAA,0x40,0xEA,0xC2,0x00};                                 
  81.   unsigned char sum=0,count=0;
  82.   cmdPassWord[9]=block;
  83.   for(int i=10;i<16;i++) cmdPassWord[i]=st[i-10];// 密码
  84.   for(int i=16;i<20;i++) cmdPassWord[i]=UID[i-16];// UID
  85.   for(int i=0;i<20;i++) sum+=cmdPassWord[i];
  86.   cmdPassWord[20]=0xff-sum&0xff;
  87.   
  88.   Serial.println("passWordSend: ");
  89.   for(int i=0;i<22;i++)  {Serial.print(cmdPassWord[i],HEX); Serial.print(" ");}
  90.   Serial.println();
  91.   
  92.   while(Serial1.available())   char xx=Serial1.read();//clear the serial data
  93.   
  94.   for (int i=0;i<22;i++)  UART1_Send_Byte(cmdPassWord[i]);
  95.   delay(100);
  96.   while(Serial1.available())
  97.      {
  98.         receive_ACK[count]=Serial1.read();
  99.         count++;
  100.      }
  101. // readAck(16);delay(10);
  102.   Serial.println("passWordRes: ");
  103.   for(int i=0;i<16;i++)  {Serial.print(receive_ACK[i],HEX); Serial.print(" ");}
  104.   Serial.println();
  105.   
  106.   if(checkDCS(16)==1 && receive_ACK[12]==0x41 && receive_ACK[13]==0x00)  return 1;
  107.   else return 0;
  108. }
  109. void readData(int block)// 读取数据  block---要读取的块
  110. {
  111.   //----head--------- cmd  card 1   readcmd   block 07  DCS+POST
  112.   //00 00 ff 05 fb D4  40    01      30        07        B4 00 //读第7块
  113.   //out: 00 00 FF 00 FF 00 //ACK
  114.   //------------------41 00for right  41 03wrong        data                                           DCS+POST
  115.   //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块
  116.   //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
  117.   unsigned char cmdRead[12]={0x00,0x00,0xff,0x05,0xfb,0xD4,0x40,0x01,0x30,0x07,0xB4,0x00};
  118.   unsigned char sum=0,count=0;
  119.   cmdRead[9]=block;
  120.   for(int i=0;i<10;i++) sum+=cmdRead[i];
  121.   cmdRead[10]=0xff-sum&0xff;
  122.   
  123.   while(Serial1.available())   char xx=Serial1.read();//clear the serial data
  124.   
  125.   //Serial.print("readDCS:");Serial.println(cmdRead[10],HEX);
  126.   for(int i=0;i<12;i++){UART1_Send_Byte(cmdRead[i]);}
  127.   delay(10);
  128.   while(Serial1.available())
  129.      {
  130.         receive_ACK[count]=Serial1.read();
  131. ////        Serial.print(count);Serial.print(":");
  132. //        Serial.print(receive_ACK[count],HEX);
  133. //        Serial.print(" ");
  134.         count++;
  135.      }
  136.      
  137.   Serial.println("Read data:   ");
  138.   for(int i=0;i<count;i++)  {Serial.print(receive_ACK[i],HEX); Serial.print(" ");}
  139.   Serial.println();
  140.   //    DCS校验是否成功        这两位数据上为0x41和0x00则表示操作成功
  141.   if(checkDCS(32)==1 && receive_ACK[12]==0x41 && receive_ACK[13]==0x00)  Serial.println("Finish Reading");
  142.   
  143.   Serial.println(" ");
  144. }
  145. void writeData(int block,unsigned char dwic[])//  block:待写入数据的块,dwic[]待写入的数据
  146. {
  147.   //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
  148.   unsigned char cmdWrite[]={0x00,0x00,0xff,0x15,0xEB,0xD4,0x40,0x01,0xA0, \
  149.                             0x06,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, \
  150.                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xCD,0x00};
  151.   unsigned char sum=0,count=0;
  152.   cmdWrite[9]=block;
  153.   for(int i=10;i<26;i++) cmdWrite[i]=dwic[i-10];// 待写入的数据
  154.   for(int i=0;i<26;i++) sum+=cmdWrite[i];//加和
  155.   cmdWrite[26]=0xff-sum&0xff;//  计算DCS
  156.   
  157.   while(Serial1.available())   char xx=Serial1.read();//clear the serial data
  158.   
  159.   for(int i=0;i<28;i++) UART1_Send_Byte(cmdWrite[i]);
  160.   while(Serial1.available())
  161.      {
  162.         receive_ACK[count]=Serial1.read();
  163.         count++;
  164.      }
  165.      
  166.   Serial.print("Write respond:   ");
  167.   for(int i=0;i<17;i++)  {Serial.print(receive_ACK[i],HEX); Serial.print(" ");}
  168.   Serial.println("     Write respond End ");
  169.   if(checkDCS(17)==1 && receive_ACK[13]==0x41 && receive_ACK[14]==0x00)
  170.   {
  171.     Serial.println("WriteFinish!");
  172.   }
  173. }
  174. void readAck(int x) //读取x个串口发来的数据
  175. {
  176.   unsigned char i;
  177.   for(i=0;i<x;i++)
  178.   {
  179.     receive_ACK[i]= Serial1.read();
  180.   }
  181. }
  182. void UART1_Send_Byte(unsigned char command_data)  // 按照固定格式发送命令
  183. {
  184.   print1Byte(command_data);
  185.   #if defined(ARDUINO) && ARDUINO >= 100
  186.     Serial1.flush();// complete the transmission of outgoing serial data
  187.   #endif
  188. }
  189. char checkDCS(int x)  //  NFC  S50卡  DCS校验检测子函数
  190. {
  191.   unsigned char sum=0,dcs=0;
  192.   for(int i=6;i<x-2;i++)
  193.   {
  194.     sum+=receive_ACK[i];
  195.   }
  196.   dcs=0xff-sum&0xff;
  197.   if(dcs==receive_ACK[x-2])  return 1;
  198.   else   return 0;
  199. }
复制代码

参考链接:
以及DFRobot的产品wiki

嗯,基本就是这么多了。


看帖回帖,是美德

{:5_153:}

NFC代码分享.zip

3.62 KB, 下载次数: 761

丄帝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

学习了
回复

使用道具 举报

映雪—斗牛士  学徒

发表于 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

我为美德代言
回复

使用道具 举报

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

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail