NFC技术近年来得到了极大的应用,但可查的教程很少,国内做开源硬件的公司dfrobot也在出过一个NFC模块——NFC近场通讯模块 Arduino兼容。
个人用过这块板子,感觉很顺手,搜罗了几篇DF社区的文章,大家可以作为实例参考。
其他文章:
开源NFC模块示例(一):arduino NFC近场通讯模块的简易教程和评测
开源NFC模块示例(二):与Arduino UNO开发板的配合
开源NFC模块示例(三):Arduino NFC模块使用方法分享,PN532模块,S50卡
开源NFC模块示例(四):如何制作Makerspace 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卡的存储机制吧,来张性感照片:
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,可以参照附件的程序,(附件上传总是不成功,请复制此链接下载:http://mc.dfrobot.com.cn/forum.php?mod=attachment&aid=MjMxOTJ8Mzc4ZmFlYzB8MTU1NTk5ODcxNnw2OTE3MHwxMzQ0MA== )
同时参照@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[35];
unsigned char UID[4]={0xD1,0xAA,0x40,0xEA};
unsigned char secret[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
unsigned char dataWriteIntoCard[16]={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[i]);
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[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};//wake up NFC module
for(int i=0;i<24;i++) //send command
{
UART1_Send_Byte(wake[i]);
}
}
void Scan()
{
const unsigned char cmdUID[11]={ 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 ID and target amount
//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&(SUM(0 0 FF C F4 D5 4B 1 1 0 4 8 4 D1 AA 40 EA))
unsigned char NFC_UID[5],count=0;
for(int i=0;i<11;i++) UART1_Send_Byte(cmdUID[i]);
delay(10);
readAck(25);
delay(10);
}
int passWordCheck(int block,unsigned char id[],unsigned char st[])
{
//---------head------- card 1 check blocknumber password 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
// 0 0 FF 0 FF 0 0 0 FF 3 FD D5 41 27 C3 0
unsigned char cmdPassWord[22]={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[9]=block;
for(int i=10;i<16;i++) cmdPassWord[i]=st[i-10];// 密码
for(int i=16;i<20;i++) cmdPassWord[i]=UID[i-16];// UID
for(int i=0;i<20;i++) sum+=cmdPassWord[i];
cmdPassWord[20]=0xff-sum&0xff;
Serial.println("passWordSend: ");
for(int i=0;i<22;i++) {Serial.print(cmdPassWord[i],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[i]);
delay(100);
while(Serial1.available())
{
receive_ACK[count]=Serial1.read();
count++;
}
// readAck(16);delay(10);
Serial.println("passWordRes: ");
for(int i=0;i<16;i++) {Serial.print(receive_ACK[i],HEX); Serial.print(" ");}
Serial.println();
if(checkDCS(16)==1 && receive_ACK[12]==0x41 && receive_ACK[13]==0x00) return 1;
else return 0;
}
void readData(int block)// 读取数据 block---要读取的块
{
//----head--------- cmd card 1 readcmd block 07 DCS+POST
//00 00 ff 05 fb D4 40 01 30 07 B4 00 //读第7块
//out: 00 00 FF 00 FF 00 //ACK
//------------------41 00for right 41 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[12]={0x00,0x00,0xff,0x05,0xfb,0xD4,0x40,0x01,0x30,0x07,0xB4,0x00};
unsigned char sum=0,count=0;
cmdRead[9]=block;
for(int i=0;i<10;i++) sum+=cmdRead[i];
cmdRead[10]=0xff-sum&0xff;
while(Serial1.available()) char xx=Serial1.read();//clear the serial data
//Serial.print("readDCS:");Serial.println(cmdRead[10],HEX);
for(int i=0;i<12;i++){UART1_Send_Byte(cmdRead[i]);}
delay(10);
while(Serial1.available())
{
receive_ACK[count]=Serial1.read();
//// Serial.print(count);Serial.print(":");
// Serial.print(receive_ACK[count],HEX);
// Serial.print(" ");
count++;
}
Serial.println("Read data: ");
for(int i=0;i= 100
Serial1.flush();// complete the transmission of outgoing serial data
#endif
}
char checkDCS(int x) // NFC S50卡 DCS校验检测子函数
{
unsigned char sum=0,dcs=0;
for(int i=6;i
参考链接:
NFC的PN532 读写命令格式:http://wenku.baidu.com/link?url=erLduczaC8U8HmSE3X503nMa6JVpfPAeXIkbsPiXn_hB1NN3hlEhdfRo6SsqCTqDGAc6FCrTNUWDg6Z9wWRik0yzq8_XO37IfPH4nsuawH_
Mifare1卡说明文档:http://wenku.baidu.com/view/4784445477232f60ddcca1f6.html
以及DFRobot的NPC模块 wiki:http://wiki.dfrobot.com.cn/index.php/(SKU:DFR0231)NFC近场通讯模块_Arduino兼容
作者:Holiday
转载自:DF创客社区
推荐项目阅读:
使用SPRESENSE电路板的POV显示器
【ardunio项目】如何制作深受儿童喜爱的木制收音机
Arduino“反应计时器” - 我的孩子喜欢玩这个
ESP32项目:邮件警报
物联网植物监测仪,用 Particle Photon制作、IFTTT监测
更多:创客项目