一、实验目的
通过本实验,了解射频识别技术(RFID)的基本工作原理,掌握在Arduino项目中使用RFID读卡模块读取和写入标签信息的基本方法,熟悉RFID读卡模块仅读取指定标签内容的应用领域及设置方法。
二、实验要求
1、使用ESP 8266电路板、RC522 RFID读卡器(如图14-1所示)、RFID标签(如图14-2所示)和导线搭建实验电路并编写相应Arduino程序代码,通过标签靠近读卡器读取标签信息,在串口监视器中观察读取到的内容。
图6-1 RC522 RFID读卡器 图6-2 RC522 RFID标签
2、修改程序代码,实现RC522 RFID读卡器仅能读取指定RFID标签信息的功能。
3、修改程序代码,实现RC522 RFID读卡器向RFID标签中写入新信息并在串口监视器中显示的功能。
三、实验过程
1、搭建实验电路
使用导线分别连接面包板的电源总线正极和负极到电路板的3V3和GND接口;将RFID读卡器放置在面包板上,注意所有针脚必须在不同的行上,其中标注了3.3V和GND的针脚分别使用导线连接到面包板电源总线正极和负极上;标注了SDA的针脚使用导线连接到电路板D2(GPIO4)接口,标注了SCK的针脚连接到D5(GPIO14)接口,标注了MOSI的针脚连接到D7(GPIO13)接口,标注了MISO的针脚连接到D6(GPIO12)接口,标注了RST的针脚连接到D1(GPIO5)接口,不要连接任何线到标注了IRQ的针脚上。电路连接如图所示。
图6-3实验电路连接图
2、编写代码,实现读取RFID标签信息的功能
(1)在新建的Arduino程序窗口中输入如下代码:
//引入对应的库文件,需下载更新相应库文件
#include <SPI.h>
#include <MFRC522.h>
//定义针脚连接的GPIO接口号
#define RST_PIN 5
#define SS_PIN 4
//创建MFRC522实例
MFRC522 mfrc522(SS_PIN, RST_PIN);
void setup() {
//初始化各实例,并在串口监视器显示初始内容
ESP.wdtDisable();
Serial.begin(115200);
SPI.begin();
mfrc522.PCD_Init();
Serial.println("");
Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks"));
}
void loop() {
//寻找新的标签
if ( ! mfrc522.PICC_IsNewCardPresent()) {
return;
}
if ( ! mfrc522.PICC_ReadCardSerial()) {
return;
}
//调用相应库函数读取标签信息
mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
delay(5000);
}
(2)将USB线缆插入计算机,待程序上传成功后打开串口监视器,将RFID标签靠近读卡器,观察读取到的标签信息,正确的实验结果应包括UID、SAK、PICC type及各区块所存储的内容(以十六进制数的形式存储),如图所示。
图6-4串口监视器输出实验结果
3、编写代码,实现读取指定RFID标签信息的功能
(1)在新建的Arduino程序窗口中输入如下代码:
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 5
#define SS_PIN 4
MFRC522 mfrc522(SS_PIN, RST_PIN);
String read_rfid; //定义变量,用于存储要输出显示的字符串内容
//此处填写要读取的RFID标签的UID号(该信息可以从上一个实验结果中获取)
//注意去除中间的空格,所有的字母必须小写
String ok_rfid = "********";
void setup() {
ESP.wdtDisable();
Serial.begin(115200);
SPI.begin();
mfrc522.PCD_Init();
Serial.println("");
Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks"));
}
void dump_byte_array(byte *buffer, byte bufferSize) {
read_rfid="";
for (byte i = 0; i < bufferSize; i++) {
read_rfid=read_rfid + String(buffer[i], HEX);
}
}
void loop() {
if ( ! mfrc522.PICC_IsNewCardPresent()) {
return;
}
if ( ! mfrc522.PICC_ReadCardSerial()) {
return;
}
dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
Serial.println(read_rfid);
//判断读取到的标签UID号是否是指定标签的UID,若不是,则输出提示内容
if (!(read_rfid == ok_rfid)) {
Serial.println("Incorrect Tag");
return;
}
//若读取的是指定的标签,则读取并显示标签内容
mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
delay(5000);
}
(2)将USB线缆插入计算机,待程序上传成功后打开串口监视器,将RFID标签靠近读卡器,若欲读取标签的UID不是程序中设置的UID,则无法读取该标签信息,串口监视器中会出现如图14-5所示内容。
图6-5读取失败时串口监视器输出的实验结果
若欲读取标签的UID与程序中设置的UID一致,则可以成功读取该标签信息,串口监视器中会出现如图14-6所示内容。
图6-6读取成功时串口监视器输出的实验结果
4、编写代码,实现向RFID标签中写入信息的功能
(1)在新建的Arduino程序窗口中输入如下代码:
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 5
#define SS_PIN 4
MFRC522 mfrc522(SS_PIN, RST_PIN);
MFRC522::MIFARE_Key key;//定义密钥
void setup() {
MFRC522::StatusCode status;
Serial.begin(115200);
SPI.begin();
mfrc522.PCD_Init();
//使用0xFF作为基本密钥
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
Serial.println();
Serial.println(F("Scan a tag to write to it."));
}
void loop() {
if ( ! mfrc522.PICC_IsNewCardPresent())
return;
if ( ! mfrc522.PICC_ReadCardSerial())
return;
//显示标签的基本信息
Serial.print(F("Card UID:"));
dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
Serial.println();
Serial.print(F("PICC type: "));
MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
Serial.println(mfrc522.PICC_GetTypeName(piccType));
//判断卡的类型,该程序仅支持MIFARE Classic cards
if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI
&& piccType != MFRC522::PICC_TYPE_MIFARE_1K
&& piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
Serial.println(F("This sample only works with MIFARE Classic cards."));
return;
}
//定义要写入数据的位置和内容
byte sector= 1; //写入位置为sector 1
byte blockAddr= 5; //写入位置是sector 1的block 5
//要写入的信息如下,共16字节
byte dataBlock[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
byte trailerBlock = 7;
MFRC522::StatusCode status;
byte buffer[18];
byte size = sizeof(buffer);
//授权使用密钥A
Serial.println(F("Authenticating using key A..."));
status=(MFRC522::StatusCode)mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
if (status != MFRC522::STATUS_OK) {
Serial.print(F("PCD_Authenticate() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
//显示sector 1当前的数据,即写入前的数据
Serial.println(F("Current data in sector:"));
mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);
Serial.println();
Serial.print(F("Reading data from block ")); Serial.print(blockAddr);
Serial.println(F(" ..."));
status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("MIFARE_Read() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
Serial.print(F("Data in block ")); Serial.print(blockAddr); Serial.println(F(":"));
dump_byte_array(buffer, 16); Serial.println();
Serial.println();
//授权使用密钥B
Serial.println(F("Authenticating again using key B..."));
status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid));
if (status != MFRC522::STATUS_OK) {
Serial.print(F("PCD_Authenticate() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
//写入信息到相应位置
Serial.print(F("Writing data into block ")); Serial.print(blockAddr);
Serial.println(F(" ..."));
dump_byte_array(dataBlock, 16); Serial.println();
status = (MFRC522::StatusCode) mfrc522.MIFARE_Write(blockAddr, dataBlock, 16);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("MIFARE_Write() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
Serial.println();
//再次读取写入后的该位置数据信息
Serial.print(F("Reading data from block ")); Serial.print(blockAddr);
Serial.println(F(" ..."));
status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("MIFARE_Read() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
Serial.print(F("Data in block ")); Serial.print(blockAddr); Serial.println(F(":"));
dump_byte_array(buffer, 16); Serial.println();
//通过逐字节判断写入是否有误
Serial.println(F("Checking result..."));
byte count = 0;
for (byte i = 0; i < 16; i++) {
// Compare buffer (= what we've read) with dataBlock (= what we've written)
if (buffer[i] == dataBlock[i])
count++;
}
Serial.print(F("Number of bytes that match = ")); Serial.println(count);
if (count == 16) {
Serial.println(F("Success"));
} else {
Serial.println(F("Failure, no match"));
Serial.println(F(" perhaps the write didn't work properly..."));
}
Serial.println();
//读取整个sector的信息
Serial.println(F("Current data in sector:"));
mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);
Serial.println();
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
}
void dump_byte_array(byte *buffer, byte bufferSize) {
for (byte i = 0; i < bufferSize; i++) {
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], HEX);
}
}
(2)将USB线缆插入计算机,待程序上传成功后打开串口监视器,将RFID标签靠近读卡器,在串口监视器中观察是否成功写入数据信息,正确的结果如图14-7所示内容。
图6-7写入成功时串口监视器输出的实验结果