RC522模塊不但可以讀取標籤中的數據,還能將數據寫入標籤中,本篇介紹S50卡的寫卡操作。
1. S50卡介紹
S50非接觸式IC卡的容量爲1K字節EEPROM,又稱M1卡。內部EEPROM又分爲16個扇區,每個扇區分4個塊,以塊爲存取單位,每個塊由16個字節組成。
1. M1卡主要指標:
- 每個扇區有獨立的一組密碼和訪問控制。
- 每張卡有唯一32位序列號。
- 無電源,自帶天線,內含加密控制邏輯和通訊邏輯電路。
- 數據保存期爲10年,可改寫10萬次,讀無限次
- 工作頻率:13.56MHZ
- 通信速率:106 KBPS
- 工作溫度:-20℃~50℃(溼度爲90%)
2. M1卡存儲結構
存儲結構如下圖,16個扇區,每個扇區4個塊,可將16個扇區的64個塊按絕對地址編號0-63。
其中第0扇區的塊0,用於存放廠商代碼,一般前四字節爲UID,已經固化,一般不可更改。
每個扇區的塊0、塊1、塊2爲數據塊,可用於存儲數據,塊3爲控制塊,包括了密碼A,存取控制,密碼B。
3. 讀寫流程
每個扇區的密碼和存取控制都是獨立的,可根據實際需要設定各自的密碼及存取控制。出廠默認的密碼6個字節都爲0xFF。
扇區中每個塊的存取條件是由密碼和存取控制共同決定的,每個塊有相應的三個控制位,按照一定規則進行約束,具體可以參照M1卡數據手冊。
本篇演示向扇區1的塊0,絕對地址爲塊4中寫入數據。主要流程爲:模塊進行卡掃描讀取卡片信息,通過密碼進行身份認證,然後讀取寫入前的塊數據,然後再次進行身份認證並寫入自定義數據,然後再次身份認證讀取寫入後的塊數據來檢測是否寫入成功。
2. 實驗材料
- Uno R3開發板
- 配套USB數據線
- 麪包板及配套連接線
- RFID-RC522模塊及配套S50白卡和異形卡
3. 實驗步驟
1. 根據原理圖搭建電路圖。
RC522模塊的3.3V、GND分別對應連接開發板的3.3V、GND,模塊的MOSI、MISO、SCK分別連接開發板的SPI接口11、12、13,模塊的SDA、RST分別連接開發板數字管腳10、9。
實驗原理圖如下圖所示:
實物連接圖如下圖所示:
2. 新建sketch,拷貝如下代碼替換自動生成的代碼並進行保存。
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 9
#define SS_PIN 10
MFRC522 mfrc522(SS_PIN, RST_PIN);
MFRC522::MIFARE_Key key;
void setup() {
Serial.begin(9600);
while (!Serial); // 等待串口打開
SPI.begin();
mfrc522.PCD_Init();
// 出廠默認使用FF FF FF FF FF FF作爲密碼A和B
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
Serial.println(F("開始掃描卡進行讀寫..."));
Serial.print(F("使用密碼:"));
dump_byte_array(key.keyByte, MFRC522::MF_KEY_SIZE);
Serial.println();
Serial.println(F("數據將被寫入到#1扇區"));
}
void loop() {
//尋找新卡
if ( ! mfrc522.PICC_IsNewCardPresent())
return;
//驗證UID是否可讀
if ( ! mfrc522.PICC_ReadCardSerial())
return;
//顯示卡信息
Serial.print(F("卡 UID:"));
dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
Serial.println();
Serial.print(F("卡類型: "));
MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
Serial.println(mfrc522.PICC_GetTypeName(piccType));
// 檢查是否MIFARE卡類型
if ( piccType != MFRC522::PICC_TYPE_MIFARE_MINI
&& piccType != MFRC522::PICC_TYPE_MIFARE_1K
&& piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
Serial.println(F("不支持讀取此卡類型"));
return;
}
// 操作扇區1
// 扇區1包括:塊4~塊7
byte sector = 1;
byte blockAddr = 4;
byte dataBlock[] = {
0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x0C,
0x0D, 0x0E, 0x0F, 0x10
};//要寫入的數據
byte trailerBlock = 7;
MFRC522::StatusCode status;
byte buffer[18];
byte size = sizeof(buffer);
// 使用密碼A進行身份認證
Serial.println(F("使用密碼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("身份認證失敗 "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
// 顯示當前扇區數據
Serial.println(F("當前扇區數據:"));
mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);
Serial.println();
// 讀取寫入前塊數據
Serial.print(F("讀取寫入前塊")); Serial.print(blockAddr);
Serial.println(F("數據..."));
status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("讀取失敗 "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
Serial.print(F("塊")); Serial.print(blockAddr); Serial.println(F("數據:"));
dump_byte_array(buffer, 16); Serial.println();
Serial.println();
// 使用密碼B進行身份認證
Serial.println(F("使用密碼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("身份認證失敗 "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
//寫入數據
Serial.print(F("寫數據到塊")); 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("寫入失敗 "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
Serial.println();
//讀取寫入後塊數據
Serial.print(F("讀取寫入後塊")); Serial.print(blockAddr);
Serial.println(F("數據..."));
status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("讀取失敗 "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
Serial.print(F("塊")); Serial.print(blockAddr); Serial.println(F("塊:"));
dump_byte_array(buffer, 16); Serial.println();
// 顯示當前扇區數據
Serial.println(F("當前扇區數據:"));
mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);
Serial.println();
//使放置在讀卡區的IC卡進入休眠狀態,不再重複讀卡
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);
}
}
3. 連接開發板,設置好對應端口號和開發板類型,進行程序下載。
4. 實驗現象
打開串口監視器,波特率設置成與程序中相一致的9600。將卡靠近模塊,根據打印信息可看到數據被寫入到指定塊中。
關注公衆號「TonyCode」,更多精彩內容分享。
回覆「1024」獲取1000G學習資料。
個人博客