17-RFID

模仿上文

Mifare讀寫器模組與Arduino接線示範

本單元使用的Mifare RFID-RC522讀寫器模組的外觀與接腳定義如下,模組採用的MFRC522晶片本身有支援UART, I2C和SPI介面,但是本文採用的程式庫僅支援SPI介面。

Arduino Uno板的接線示範如下,SPI介面的晶片線選擇通常接在Arduino數位10腳,但這不是強制性的,模組的Reset腳也可以接在其他腳位:

操控Mifare模組的MFRC522程式庫

本單元程式採用Miki Balboa開發的這個MFRC522程式庫來操控Mifare模組,若不使用程式庫,我們需要詳閱MFRC522晶片的規格書,了解讀寫器、卡片和微控制器之間的數據通訊流程,以及晶片內部的暫存器的指令位址,才能動手撰寫程式。

下載程式庫之後,請將它解壓縮到Arduino的libraries資料夾,再開啟Arduino IDE,即可從主功能表的「檔案→範例→MFRC522」指令底下找到一些範例程式。

底下列舉本單元使用到的MFRC522程式物件的方法和屬性:

    • MFRC522物件.PCD_Init():初始化MFRC522讀卡機模組

    • MFRC522物件.PICC_IsNewCardPresent():是否感應到新的卡片

    • MFRC522物件.PICC_ReadCardSerial():讀取卡片的資料

    • MFRC522物件.PICC_GetType():取得卡片類型

    • MFRC522物件.PICC_GetTypeName():取得卡片類型名稱

每張Mifare卡片都有個唯一的ID(unique identifier,簡稱UID),當讀寫機讀取到卡片的資料之後,UID的長度和內容,可從底下兩個屬性值取得:

    • MFRC522物件.uid.size:包含UID的長度

    • MFRC522物件.uid.uidByte:包含UID碼的陣列

讀取Mifare卡片的UID碼

讀取Mifare卡片的流程如下,我們的程式不需要理會其中的「防衝突處理」和「選卡」部份,讀寫器會幫我們搞定,但是在讀取資料之後,我們的程式要發出命令讓卡片進入停止(halt)狀態,避免讀寫器重複讀取同一張卡片:

SAK代表select acknowledge,直譯為「選擇應答」,是由卡片發給讀寫器,對於選擇卡片命令的回應,不同類型的Mifare卡片的SAK值不一樣(例如,Mifare Classic的SAK值為0x18),程式可藉此判別感應到的卡片類型。詳細的防衝突處理與SAK值判斷流程,請參閱NXP公司的“MIFARE ISO/IEC 14443 PICC Selection”技術文件(PDF格式)。

讀取Mifare卡片類型及其UID碼的程式如下:

#include <SPI.h>

#include <MFRC522.h> // 引用程式庫

#define RST_PIN A0 // 讀卡機的重置腳位

#define SS_PIN 10 // 晶片選擇腳位

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

void setup() {

Serial.begin(9600);

Serial.println("RFID reader is ready!");

SPI.begin();

mfrc522.PCD_Init(); // 初始化MFRC522讀卡機模組

}

void loop() {

// 確認是否有新卡片

if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {

byte *id = mfrc522.uid.uidByte; // 取得卡片的UID (第20行)

byte idSize = mfrc522.uid.size; // 取得UID的長度

Serial.print("PICC type: "); // 顯示卡片類型

// 根據卡片回應的SAK值(mfrc522.uid.sak)判斷卡片類型

MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); // (第25行)

Serial.println(mfrc522.PICC_GetTypeName(piccType));

Serial.print("UID Size: "); // 顯示卡片的UID長度值

Serial.println(idSize);


for (byte i = 0; i < idSize; i++) { // 逐一顯示UID碼

Serial.print("id[");

Serial.print(i);

Serial.print("]: ");

Serial.println(id[i], HEX); // 以16進位顯示UID值

}

Serial.println();

mfrc522.PICC_HaltA(); // 讓卡片進入停止模式

}

}

程式第20行宣告一個指向儲存UID值的指標變數(假設UID碼的長度為4):

第25行的“MFRC522::PICC_Type”代表引用在MFRC522類別(程式庫)裡面定義的PICC_Type這個資料類型,其中的雙冒號(::)代表範圍解析運算子(scope-resolution operator),用來表示“PICC_Type”定義在MFRC522程式庫裡面。如果不用雙冒號指出“PICC_Type”資料類型的來源,程式編譯器會產生未定義之類的錯誤。

上傳程式碼之後,開啟序列埠監控視窗,你可以嘗試一次讓Mifare模組感應多個卡片(筆者同時用3個),它將能逐一顯示每個卡片的類型和UID: