Arduino提高篇20—S50卡數據讀寫

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。

M1卡存儲結構

其中第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學習資料。
個人博客
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章