Mifare RFID-RC522模組實驗(一):讀取Mifare RFID卡的UID識別碼

本文旨在補充《超圖解Arduino互動設計入門》第18章「RFID無線識別裝置與問答遊戲製作」單元,書本採用的RFID讀卡機模組是採用9600bps, TTL序列通訊介面,RFID的通訊頻率為125KHz。這種模組的接線和程式都很簡單,每當感測到RFID卡,讀卡機就把卡片的識別碼送往序列埠。

市售Arduino套件裡面的RFID模組,多半是Mifare(讀音:my-fare)規格,跟書本的不一樣,因此本文將補充說明Mifare的基本原理及其模組的接線,以及讀取卡片識別碼的程式。

Mifare是NXP(恩智普)半導體公司推出的非接觸型IC卡(也就是外表沒有金屬接點的卡片),在市場上獲得廣泛的採用,像是停車場的感應幣(token)、現金卡(如:台灣的悠遊卡)、員工識別證…等等。Mifare卡有不同的系列,如:Mifare Classic, Mifare UltraLight, Mifare Pro…等,主要的差別在於資料安全加密和驗證的等級。

Mifare卡內建EEPROM,應用程式可對它寫入和讀取數據,例如:停車票卡可紀錄車主的停車時間。Mifare還具備「防衝突處理」機制,也就是避免訊號干擾:若多張卡片同時出現在偵測範圍,Mifare讀寫器將能逐一選擇卡片進行處理。例如,假設超級市場裡的每個商品都貼上RFID標籤,結帳櫃台的RFID讀取設備若具備防干擾機制,將能自動掃描堆放在購物推車裡的所有商品,結帳人員不必再手動逐一掃描商品條碼,也不會重複計算。附帶一提,所有符合ISO/IEC 14443-A標準規範的RFID卡片都要有防衝突處理功能,而Mifare是依循ISO/IEC 14443-A規格建立的非接觸式IC卡。

底下是Mifare裝置的概略圖,它的卡片屬於被動式、無內建電源(也稱為「無源」),卡片所需的電力來自讀寫器的電磁場。

Mifare裝置的概略圖

啟動RFID讀寫器之後,讀寫器的天線將不停地發送電磁波,每當卡片進入此電磁場,卡片內部的線圈和電路將與此電磁場產生共振,從而獲得電能。無線充電器也是透過電磁感應、非直接連線方式獲取能量,RFID讀寫器和卡片兩端的線圈(天線)相當於變壓器裡的主線圈和副線圈(請參閱「測試Palm Touchstone(點金石)無線充電模組」貼文。

依照感應距離,非接觸型IC卡分成緊耦合型(close-coupled,需要緊貼感測器)、接近式(proximity,10cm以內)和鄰近式(vicinity,50cm以內),Mifare屬於接近式,這種類型的卡片簡稱為PICC(Proximity IC Card,接近式IC卡),讀寫器則簡稱PCD(Proximity Coupling Device,接近型耦合器)。

另一方面,某些RFID的應用場合,標籤的尺寸大小有固定的標準,像信用卡和金融卡,這一類的卡片長、寬和厚度,都要遵循國際ID-1標準(85.6 × 53.98 × 0.76mm),目前的技術沒有辦法把電池塞入這麼薄的卡片,所以非接觸型卡片只能採用無線供電方案。

當卡片被電磁能啟動(activate)之後,將等待接收與回應來自讀寫器的命令。微控器和Mifare讀寫器之間採用TTL數位訊號傳遞資料,為了用電波傳送數位訊號,必須將數位訊號加上載波調變,Mifare的載波頻率是13.56MHz。上圖的射頻訊號波形只是描述概念,數位訊號在調變成電波之前,從讀寫器發送的訊號會採用米勒(Miller)編碼,而從卡片發出訊息則經過曼徹斯特(Manchester)編碼。讀寫器在操作卡片時,都會經過三次雙向認證,互相驗證使用的合法性,而且通訊過程中的所有數據都經過加密,以確保安全。

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

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

Mifare RFID-RC522讀寫器模組

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

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

操控Mifare模組的MFRC522程式庫

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

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

儲存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)狀態,避免讀寫器重複讀取同一張卡片:

讀取Mifare卡片與衝突處理流程

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

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

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

指向儲存UID值的指標變數

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

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

序列埠監控視窗

除非這些卡片離開、再次進入感應區,否則它們不會被重複讀取。

延伸閱讀

25 thoughts on “Mifare RFID-RC522模組實驗(一):讀取Mifare RFID卡的UID識別碼

    1. hi scott:

      沒有錯喔~第一段指的是書本範例所採用的RFID模組(非Mifare),載波頻率是125KHz;本文採用的Mifare是13.56MHz。

      thanks,
      jeffrey

    2. 因為你第二段講的是HF,我以為你第一段打的頻率LF是打錯的,SORRY
      原來第一段是補充書的內容
      MIFARE是另外提出的
      看太快了,抱歉

  1. 趙老師我想請問一下~
    Mifare RFID-RC522線路圖接好了,程式庫也下載了
    程式驗證,上傳沒有題,
    序列視窗有出現
    RFID reader is ready
    可是卡片靠上去,序列視窗也都沒有反應!!!
    在想說是不是買到地雷模組了…

    老師你的模組都是在網路上買,還是在實體店面買的呢?

    1. hi johnny:

      有可能…假若你曾把它的電源誤接到5V,那它八成是故障了。
      模組大多是在網路上購買的。

      thanks,
      jeffrey

  2. 趙老師 請問一下 RFID-RC522這個模組到底該接3.3V,還是5V? 有些網站建議使用5V 那一陣子用了好像也沒問題
    最近要再使用的時候發現完全都無法讀卡片,我該怎麼確認RC522模組是正常的?再買一組來測試嗎?

  3. 你好
    請問可以借用網頁的第二張圖片來使用嗎?(MFRC522晶片那張)
    因為圖片畫得很精美
    想放進課程期末報告裡面使用

    謝謝~ :)

  4. 老師,請問一下
    為什麼我程式碼在驗證就出錯了
    MFRC522的程式庫我有丟進去了也更新到最新了
    目前發現兩個問題是
    1.’id’ was not declared in this scope
    byte *id = mfrc522.uid.uidByte; 的宣告好像就出問題了這邊有需要注意的嗎

    2.’class MFRC522′ has no member named ‘PICC_HaLtA’
    這邊的讓程式停止的程序不在他的城市庫裏面的意思嗎

    1. 如果連程式庫的範例都無法順利編譯,那應該是你選用了程式庫不支援的控制板。

      thanks,
      jeffrey

  5. 老師你好
    前面的問題我解決好了
    現在是能順利執行的
    但是我發現如果卡片uid有”0″的話
    會顯示空白

  6. 趙老師請問一下~
    Mifare RFID-RC522線路圖接好了,程式庫也下載了
    程式驗證,上傳沒有題,
    序列視窗有出現
    RFID reader is ready
    可是卡片靠上去,序列視窗也都沒有反應!!!

  7. 老師請問一下~
    我照著您書上寫的,可是卡片靠上去,都沒有反應!!!真是@#$#*%
    是因為新卡還沒資料所以沒反應嗎???

  8. 趙老師請問一下~

    顯示出來的識別碼要如何存取?
    我要在感應到正確卡片時點亮LED燈,但是我使用了其他不同的晶片它也會點亮

    我只接讀取HEX的值,不知道是不是我的判斷是錯誤,以下是我判斷的程式。
    謝謝指教。
    if (*id = HEX)
    {
    digitalWrite(led, HIGH);
    }
    else
    {
    digitalWrite(led, LOW);
    }

    1. Mifare RFID-RC522讀寫器模組採用SPI介面,所以理論上你可以同時連接多組,只要每個模組的SDA分別接到Arduino的不同接腳即可。可是,硬體上可行,軟體操作上應該會遇到資料衝突的問題,因為程式每一次只能選取一個SPI裝置,若在讀取A裝置資料的同時,B裝置有資料進來,就會漏接。

      所以,不要想太多,一個Arduino板只接一個Mifare RFID-RC522讀寫器模組,然後你把這些Arduino板當成I2C slave,其中一個當作I2C master,串接起來,這樣應該可以解決你的問題。

      thanks,
      jeffrey

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *