2024年2月10日 星期六

寫入與讀取Mifare卡片資料的程式碼

 寫入與讀取Mifare卡片資料的程式碼

https://swf.com.tw/?p=941


寫入與讀取



讀取



讀取
/*
源自於
https://swf.com.tw/?p=941
使用到的MFRC522程式物件的方法和屬性:
MFRC522物件.PCD_Authenticate():驗證金鑰,相當於比對輸入密碼和卡片裡的密碼,唯通過驗證才能存取區段資料。
MFRC522物件.GetStatusCodeName():取得狀態碼的名稱
MFRC522物件.MIFARE_Read():讀取指定區塊的內容
MFRC522物件.MIFARE_Write():在指定區塊寫入資料
MFRC522物件.PICC_DumpMifareClassicSectorToSerial():在序列埠監控視窗顯示指定的區段內容
*/

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN      27        // 讀卡機的重置腳位
#define SS_PIN       5        // 晶片選擇腳位

MFRC522 mfrc522(SS_PIN, RST_PIN);    // 建立MFRC522物件

MFRC522::MIFARE_Key key;  // 儲存金鑰

byte sector = 15;   // 指定讀寫的「區段」,可能值:0~15
byte block = 1;     // 指定讀寫的「區塊」,可能值:0~3
byte blockData[16];
//byte blockData = "KeepHacking";   // 最多可存入16個字元
// 若要清除區塊內容,請寫入16個 0
//byte blockData[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

// 暫存讀取區塊內容的陣列,MIFARE_Read()方法要求至少要18位元組空間,來存放16位元組。
byte buffer[18];
bool WrOK=false;
bool RdOK=false;
byte WrCNT=0;

MFRC522::StatusCode status;
//===================================================================
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;   // 控制區塊編號

  // 驗證金鑰
  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."));
  WrOK=true;

}

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;   // 控制區塊編號

  // 驗證金鑰
  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."));
  RdOK=true;

}

void setup() {
  Serial.begin(115200);
  SPI.begin();               // 初始化SPI介面
  mfrc522.PCD_Init();        // 初始化MFRC522卡片

  Serial.println(F("Please scan MIFARE Classic card..."));

  // 準備金鑰(用於key A和key B),出廠預設為6組 0xFF。
  for (byte i = 0; i < 6; i++) {
    key.keyByte[i] = 0xFF;
  }

}

void loop() {
  // 查看是否感應到卡片
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    return;  // 退回loop迴圈的開頭
  }

  // 選取一張卡片
  if ( ! mfrc522.PICC_ReadCardSerial()) {  // 若傳回1,代表已讀取到卡片的ID
    return;
  }
 
 
  //===================================================================
  RdOK=false;
  readBlock(sector, block, buffer);      // 區段編號、區塊編號、存放讀取資料的陣列
  if (RdOK==true) {
    Serial.println("Read OK");
  }
  else
  {
    Serial.println("Read failure");  
  }

  Serial.print(F("Read block: "));        // 顯示儲存讀取資料的陣列元素值
  for (byte i = 0 ; i < 16 ; i++) {
    Serial.write (buffer[i]);
  }
  Serial.println();

  // 令卡片進入停止狀態
  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1(); // stop encryption on PCD
  WrCNT+=1;
  if (WrCNT==100)
    WrCNT=0;
}


寫入與讀取

/*

源自於
https://swf.com.tw/?p=941
使用到的MFRC522程式物件的方法和屬性:
MFRC522物件.PCD_Authenticate():驗證金鑰,相當於比對輸入密碼和卡片裡的密碼,唯通過驗證才能存取區段資料。
MFRC522物件.GetStatusCodeName():取得狀態碼的名稱
MFRC522物件.MIFARE_Read():讀取指定區塊的內容
MFRC522物件.MIFARE_Write():在指定區塊寫入資料
MFRC522物件.PICC_DumpMifareClassicSectorToSerial():在序列埠監控視窗顯示指定的區段內容
*/

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN      27        // 讀卡機的重置腳位
#define SS_PIN       5        // 晶片選擇腳位

MFRC522 mfrc522(SS_PIN, RST_PIN);    // 建立MFRC522物件

MFRC522::MIFARE_Key key;  // 儲存金鑰

byte sector = 15;   // 指定讀寫的「區段」,可能值:0~15
byte block = 1;     // 指定讀寫的「區塊」,可能值:0~3
byte blockData[16];
//byte blockData = "KeepHacking";   // 最多可存入16個字元
// 若要清除區塊內容,請寫入16個 0
//byte blockData[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

// 暫存讀取區塊內容的陣列,MIFARE_Read()方法要求至少要18位元組空間,來存放16位元組。
byte buffer[18];
bool WrOK=false;
bool RdOK=false;
byte WrCNT=0;

MFRC522::StatusCode status;
//===================================================================
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;   // 控制區塊編號

  // 驗證金鑰
  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."));
  WrOK=true;

}

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;   // 控制區塊編號

  // 驗證金鑰
  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."));
  RdOK=true;

}

void setup() {
  Serial.begin(115200);
  SPI.begin();               // 初始化SPI介面
  mfrc522.PCD_Init();        // 初始化MFRC522卡片

  Serial.println(F("Please scan MIFARE Classic card..."));

  // 準備金鑰(用於key A和key B),出廠預設為6組 0xFF。
  for (byte i = 0; i < 6; i++) {
    key.keyByte[i] = 0xFF;
  }

}

void loop() {
  // 查看是否感應到卡片
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    return;  // 退回loop迴圈的開頭
  }

  // 選取一張卡片
  if ( ! mfrc522.PICC_ReadCardSerial()) {  // 若傳回1,代表已讀取到卡片的ID
    return;
  }
 
  WrOK=false;

  String WriteSTR="alex9ufo RFID";   // 最多可存入16個字元
  String stringOne = String(WrCNT, DEC);
  WriteSTR+=stringOne;
  WriteSTR.getBytes(blockData, 16);
  for (byte i = 0 ; i < 16 ; i++) {
    Serial.write (blockData[i]);
  }
  writeBlock(sector, block, blockData);  // 區段編號、區塊編號、包含寫入資料的陣列
 
  if (WrOK==true) {
    Serial.println("Write OK");
  } else
  {
    Serial.println("Write failure");  
  }

  //===================================================================
  RdOK=false;
  readBlock(sector, block, buffer);      // 區段編號、區塊編號、存放讀取資料的陣列
  if (RdOK==true) {
    Serial.println("Read OK");
  }
  else
  {
    Serial.println("Read failure");  
  }

  Serial.print(F("Read block: "));        // 顯示儲存讀取資料的陣列元素值
  for (byte i = 0 ; i < 16 ; i++) {
    Serial.write (buffer[i]);
  }
  Serial.println();

  // 令卡片進入停止狀態
  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1(); // stop encryption on PCD
  WrCNT+=1;
  if (WrCNT==100)
    WrCNT=0;
}

沒有留言:

張貼留言

Messaging API作為替代方案

  LINE超好用功能要沒了!LINE Notify明年3月底終止服務,有什麼替代方案? LINE Notify將於2025年3月31日結束服務,官方建議改用Messaging API作為替代方案。 //CHANNEL_ACCESS_TOKEN = 'Messaging ...