2015年9月13日 星期日

Arduino - RFID

器材:
  1. Arduino UNO 開發版 *1
  2. RFID RC522 模組
  3. SPI Library (見備註)
  4. MFRC522 Library (見備註)

PIN 腳對應表:
RFID RC522
Arudino UNO
3.3V
3.3V
RST
9
GND
GND
IRQ
MISO
12
MOSI
11
SCK
13
SDA/NSS
10

完整程式碼如下:

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

 #define SS_PIN 10  
 #define RST_PIN 9  
 MFRC522 mfrc522(SS_PIN, RST_PIN);  
 MFRC522::MIFARE_Key key;  

 int block=2;  
 byte blockcontent[16] = {"Hello world"};  
 byte readbackblock[18];  

 void setup() {  
   Serial.begin(9600);  
   SPI.begin();  
   mfrc522.PCD_Init();  
   Serial.println("Scan a MIFARE Classic card");  
   for (byte i = 0; i < 6; i++) {  
     key.keyByte[i] = 0xFF;  
   }  
 }  

 void loop(){  
     mfrc522.PCD_Init();  
     if ( ! mfrc522.PICC_IsNewCardPresent()) {  
       return;  
     }  
     if ( !mfrc522.PICC_ReadCardSerial()) {  
       return;  
     }  
     Serial.println("card selected");  
     readBlock(block, readbackblock);  
     Serial.print("read block: ");  
     for (int j=0 ; j<16 ; j++){  
     Serial.write (readbackblock[j]);  
   }  
   Serial.println("");     
 }

 int writeBlock(int blockNumber, byte arrayAddress[]){  
   int largestModulo4Number=blockNumber/4*4;  
   int trailerBlock=largestModulo4Number+3;  
     if (blockNumber > 2 && (blockNumber+1)%4 == 0){  
       Serial.print(blockNumber);  
       Serial.println(" is a trailer block:");  
       return 2;  
     }  
   Serial.print(blockNumber);  
   Serial.println(" is a data block:");  
   byte status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));  
   if (status != MFRC522::STATUS_OK) {  
     Serial.print("PCD_Authenticate() failed: ");  
     Serial.println(mfrc522.GetStatusCodeName(status));  
     return 3;//return "3" as error message  
   }  
   status = mfrc522.MIFARE_Write(blockNumber, arrayAddress, 16);  
   if (status != MFRC522::STATUS_OK) {  
     Serial.print("MIFARE_Write() failed: ");  
     Serial.println(mfrc522.GetStatusCodeName(status));  
     return 4;//return "4" as error message  
   }  
   Serial.println("block was written");  
 }  

 int readBlock(int blockNumber, byte arrayAddress[]) {  
   int largestModulo4Number=blockNumber/4*4;  
   int trailerBlock=largestModulo4Number+3;  
   byte status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));  
   if (status != MFRC522::STATUS_OK) {  
     Serial.print("PCD_Authenticate() failed (read): ");  
     Serial.println(mfrc522.GetStatusCodeName(status));  
     return 3;//return "3" as error message  
   }  
   byte buffersize = 18;//we need to define a variable with the read buffer size, since the MIFARE_Read method below needs a pointer to the variable that contains the size...   
   status = mfrc522.MIFARE_Read(blockNumber, arrayAddress, &buffersize);//&buffersize is a pointer to the buffersize variable; MIFARE_Read requires a pointer instead of just a number  
   if (status != MFRC522::STATUS_OK) {  
     Serial.print("MIFARE_read() failed: ");  
     Serial.println(mfrc522.GetStatusCodeName(status));  
     return 4;  
   }  
   Serial.println("block was read");  
   delay(500);  
 }  

Step1. 貼上程式碼

Step2. 燒入程式
如果你把上面的程式碼整個貼上,你會發現無法執行,因為你並沒有SPI和MFRC522的Library,所以第一步驟要先從Library加入,可以參考此連結。

Step3. 插上RFID模組, PIN腳請參考上方PIN腳對應表

Step4. 測試
打開Serial Monitor 如果成功,會照順序出現以下畫面:

 表示RFID已經初始化成功

Hello World就是上方程式碼預設寫入的內容,後面方框是沒有資料的意思。

Step5. 了解程式碼
 #include <SPI.h>  
 #include <MFRC522.h>  

 #define SS_PIN 10  
 #define RST_PIN 9  
 MFRC522 mfrc522(SS_PIN, RST_PIN);  
 MFRC522::MIFARE_Key key;
以上都僅僅是定義 RFID 開發需要用到的工具,還有對應的PIN

int block=2;  
 byte blockcontent[16] = {"Hello world"};  
 byte readbackblock[18]; 
block 可以理解成開鎖的位置,一般市面上買到的白卡都會在2的位置,若是要正確讀取或者寫值,就是要輸入正確的block位置。

bloclcontent 是一個長度為16的 byte 陣列,紀錄的要寫入 RFID 白卡的內容,因為是教學需要,所以在一開始就預設好,學習之後可以在loop()內任意修改。

readbackblock 是存著讀取 RFID 卡後存資料的變數。

void setup() {  
   Serial.begin(9600);  
   SPI.begin();  
   mfrc522.PCD_Init();  
   Serial.println("Scan a MIFARE Classic card");  
   for (byte i = 0; i < 6; i++) {  
     key.keyByte[i] = 0xFF;  
   }  
 }  
setup() 內就是照做就好。
目的是為了讓 RFID 可以正常使用。
Serial所做的事情是為了讓操作的人可以瞭解現在執行的狀況。

     mfrc522.PCD_Init();  
     if ( ! mfrc522.PICC_IsNewCardPresent()) {  
       return;  
     }  
     if ( !mfrc522.PICC_ReadCardSerial()) {  
       return;  
     }  
在loop()內的一開始就要加入上面的動作,而且一定要放在loop內,是為了讓使用者可以一直讀取卡片。

若將 mfrc522.PCD_Init() 放在 setup()內,就只能讀取一次卡片。

下面兩個執行的動作照順序是:判斷是不是另外一張卡片;卡片是否可以被讀取。之後可以你可以在這兩個function的{}加入其他動作,像是Serial.print()告知使用者發生什麼樣的錯誤,導致無法讀取卡片。

     writeBlock(block, blockcontent);
     readBlock(block, readbackblock);  
     Serial.print("read block: ");  
     for (int j=0 ; j<16 ; j++){  
         Serial.write (readbackblock[j]);  
     }  

writeBlock() 是將 blockcontent 的內容寫入卡片內。這是因為是示範用,所以直接寫在讀取的動作前面,正常是不可能這樣使用的,而且通常寫入需要一段時間,想像你在7-11使用悠遊卡也不是馬上就好。

readBlock() 是讀取的動作,而讀取到的資料就放在 readbackblock 內。

而讀取後就是要顯示,一般分為兩種,這裡是把所有資料給顯示出來,常用的方式就用 for 迴圈,注意:這裏要用Serial.write()才會正常把"Hello world"給顯示出來,你可以稍微試試看使用Serial.print(),看看會有什麼不一樣的結果顯示,Tip : 可以朝 ASCII 思考。

備註:
連結:在Arduino 內加入 Library 
下載:MFRC522 Library

沒有留言 :

張貼留言