前陣子太忙沒空把很久之前的東西記錄下來,趁現在有空紀錄一下
該篇針對RC522進行讀寫Mifare白卡做一個實驗記錄,要注意RFID有很多種協議並不是卡片靠近就一定能讀取或寫入,我們這邊以協議:ISO1443A的卡片作為範例
基本上去賣場Mifare就可以找到了,協議基本上都是ISO1443A,但買之前最好還是確認一下,另外就是RFID的IC也要確認是否有支援你所要用的協議
範例是使用UNO來做的,請先依照下面說明將線接好
UNO RC522
9 RST
10 SDA(SS)
11 MOSI
12 MISO
13 SCK
以下是讀取的程式碼
/*
* Typical pin layout used:
* -----------------------------------------------------------------------------------------
* MFRC522 Arduino Arduino Arduino Arduino Arduino
* Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro
* Signal Pin Pin Pin Pin Pin Pin
* -----------------------------------------------------------------------------------------
* RST/Reset RST 9 5 D9 RESET/ICSP-5 RST
* SPI SS SDA(SS) 10 53 D10 10 10
* SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16
* SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14
* SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15
*
* More pin layouts for other boards can be found here: https://github.com/miguelbalboa/rfid#pin-layout
*/
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 9 // Configurable, see typical pin layout above
#define SS_PIN 10 // Configurable, see typical pin layout above
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
void setup() {
Serial.begin(115200); // Initialize serial communications with the PC
while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522
delay(4); // Optional delay. Some board do need more time after init to be ready, see Readme
mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details
Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks..."));
}
void loop() {
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
if ( ! mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial()) {
return;
}
// Dump debug info about the card; PICC_HaltA() is automatically called
mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
delay(1500);
}
卡片靠近後,在監控視窗就可以看到卡片讀取出來的全部訊息了
那網路上常講所謂的UID指的就是扇區0裡面的第0列的前四個也就是 EF 78 89 AE
接下來是寫入的程式碼,該範例會先寫入,再重新讀取,然後顯示出來
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 9 // MFRC522的复位引脚
#define SS_PIN 10 // MFRC522的SPI SS引脚
MFRC522 mfrc522(SS_PIN, RST_PIN); // 创建MFRC522实例
/* 设置新的UID */
#define NEW_UID {0xEF, 0x87, 0x79, 0xEE}
MFRC522::MIFARE_Key key; // 储存密钥
byte sector = 15; // 指定读写的扇区,可能值:0~15
byte block = 1; // 指定读写的块,可能值:0~3
byte blockData[16] = "ssssskkkkkbbbbbb"; // 最多可存入16个字节的数据
void setup() {
Serial.begin(115200); // 初始化串口通信
while (!Serial); // 如果没有打开串口端口,则不执行任何操作(针对基于ATMEGA32U4的Arduino)
SPI.begin(); // 初始化SPI总线
mfrc522.PCD_Init(); // 初始化MFRC522卡片
Serial.println(F("Warning: this example overwrites the UID of your UID changeable card, use with care!"));
// 准备密钥 - 出厂时所有密钥都设置为FFFFFFFFFFFFh。
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
}
//
void writeBlock(byte _sector, byte _block, byte _blockData[]) {
if (_sector < 0 || _sector > 15 || _block < 0 || _block > 3) {
// 显示「區段或區塊碼錯誤」,然後結束函式。
Serial.println(F("Wrong sector or block number."));
return;
}
if (_sector == 0 && _block == 0) {
// 显示「第一個區塊只能讀取」,然後結束函式。
Serial.println(F("First block is read-only."));
return;
}
byte blockNum = _sector * 4 + _block; // 計算區塊的實際編號(0~63)
byte trailerBlock = _sector * 4 + 3; // 控制區塊編號
// 驗證金鑰
MFRC522::StatusCode 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;
}
// 在指定區塊寫入16位元組資料
status = (MFRC522::StatusCode) mfrc522.MIFARE_Write(blockNum, _blockData, 16);
// 若寫入不成功…
if (status != MFRC522::STATUS_OK) {
// 顯示錯誤訊息
Serial.print(F("MIFARE_Write() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
// 顯示「寫入成功!」
Serial.println(F("Data was written."));
}
void readBlock(byte _sector, byte _block, byte _blockData[]) {
if (_sector < 0 || _sector > 15 || _block < 0 || _block > 3) {
// 顯示「區段或區塊碼錯誤」,然後結束函式。
Serial.println(F("Wrong sector or block number."));
return;
}
byte blockNum = _sector * 4 + _block; // 計算區塊的實際編號(0~63)
byte trailerBlock = _sector * 4 + 3; // 控制區塊編號
// 驗證金鑰
MFRC522::StatusCode 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;
}
byte buffersize = 18;
status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockNum, _blockData, &buffersize);
// 若讀取不成功…
if (status != MFRC522::STATUS_OK) {
// 顯示錯誤訊息
Serial.print(F("MIFARE_read() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
// 顯示「讀取成功!」
Serial.println(F("Data was read."));
}
//
void loop() {
// 重置循环如果传感器/读卡器上没有新卡。当空闲时,这会节省整个过程。如果有卡,选择一张。
if ( ! mfrc522.PICC_IsNewCardPresent() || ! mfrc522.PICC_ReadCardSerial() ) {
delay(50);
return;
}
// 现在已选择一张卡。UID和SAK在mfrc522.uid中。
// 显示UID
Serial.print(F("Card UID:"));
for (byte i = 0; i < mfrc522.uid.size; i++) {
Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print(mfrc522.uid.uidByte[i], HEX);
}
Serial.println();
// 设置新的UID
byte newUid[] = NEW_UID;
if ( mfrc522.MIFARE_SetUid(newUid, (byte)4, true) ) {
Serial.println(F("Wrote new UID to card."));
}
// Halt PICC and re-select it so DumpToSerial doesn't get confused
mfrc522.PICC_HaltA();
if ( ! mfrc522.PICC_IsNewCardPresent() || ! mfrc522.PICC_ReadCardSerial() ) {
return;
}
// 读取并写入卡片数据
writeBlock(sector, block, blockData);
readBlock(sector, block, blockData); // 可以选择读取已写入的数据进行验证
// 显示新的UID和内容
Serial.println(F("New UID and contents:"));
mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
delay(2000);
}
下圖就是程式碼中修改資料的地方
以下是修改完後的結果,可以看到我在扇區15跟0的資料及UID已經成功寫入了