這次主要是練習操作RFID讀卡器對電子標籤進行讀取、寫入的操作,並且應用上一次演練的LCD裝置來進行顯示,而input的部分是利用到Serial Monitor,不過若是有小鍵盤搭配的話應該會比較好玩一點!
這次使用的素材如下:
1. Arduino Uno R3
2. LiquidCrystal_I2C*1
3. Mifare RFID-RC522模組*1
4. 杜邦線(公對母)*4 (LCD使用)
5. 杜邦線(公對母)*7 (RFID模組使用)
6. 麵包板
7. 220Ω*1
8. 蜂鳴器*1
9. LED燈(藍)*1
10. 麵包線*4
11. 電子標籤*2
2. 當電子標籤放在MFRC522上面,此時透過LCD顯示並進行金鑰、UID驗證,驗證都符合就會進入選單,看是要操作read or write的動作!
3. 此時搭配Serial Monitor進行選項輸入,輸入1表示進行讀取動作;輸入2表示進行寫入動作!
4. 讀取程式會固定讀取block 4的16 bytes內容後進行顯示!
5. 寫入程式會固定寫入資料到block 4進行覆蓋!
PS. 關於電子標籤的資料區段介紹(如共有幾個block)請自行查找囉~
二、簡單說明一下電路接法
#Mifare RFID-RC522 → Arduino UNO
VCC → V3.3
RST → 數位9
GND → GND
MISO → 數位12
MOSI → 數位11
SCK → 數位13
NSS → 數位10
IRQ → X(不用接)
#LiquidCrystal_I2C → Arduino UNO
VCC → V5
GND → GND
SDA → A4
SCL → A5
#其他
蜂鳴器(+) → 數位8
LED燈 → 數位7
三、程式說明
這支程式主要需使用到兩個外部Library,分別為
Arduino-LiquidCrystal-I2C-library
Arduino-MFRC522
依序載入及宣告的global變數如下:
3.1、初始化
3.2、標籤偵測
PS. LCD最多只有兩行列印空間
3.3、金鑰、UID驗證
而uidVerify這個函式是檢查標籤的uid是否有match變數existUID內紀錄的值,若有的話才可以進行讀取或寫入,算是多一層過濾的動作!
通過兩道驗證之後,接著LCD會印出選單供您進行操作,這邊需搭配Arduino IDE內的Serial Monitor進行input動作,在此設定輸入的timeout時間為5秒!
PS. 若有小鍵盤就不用如此麻煩
3.4、Read data from tag
3.5、Write data to tag
最後在進行完讀取或寫入的操作之後,除了呼叫PICC_HaltA()外,若需要再次重複偵測到這個標籤(拿開再靠近),還要呼叫PCD_StopCrypto1(),如此才可以重新感應到這個標籤!
"Remember to call PCD_StopCrypto1() after communicating with the authenticated PICC - otherwise no new communications can start."
最後DEMO影片如下:
這次使用的素材如下:
1. Arduino Uno R3
2. LiquidCrystal_I2C*1
3. Mifare RFID-RC522模組*1
4. 杜邦線(公對母)*4 (LCD使用)
5. 杜邦線(公對母)*7 (RFID模組使用)
6. 麵包板
7. 220Ω*1
8. 蜂鳴器*1
9. LED燈(藍)*1
10. 麵包線*4
11. 電子標籤*2
實際電路接法
一、演練效果說明
1. 板子接上電源後,初始化MFRC522、LCD等裝置2. 當電子標籤放在MFRC522上面,此時透過LCD顯示並進行金鑰、UID驗證,驗證都符合就會進入選單,看是要操作read or write的動作!
3. 此時搭配Serial Monitor進行選項輸入,輸入1表示進行讀取動作;輸入2表示進行寫入動作!
4. 讀取程式會固定讀取block 4的16 bytes內容後進行顯示!
5. 寫入程式會固定寫入資料到block 4進行覆蓋!
PS. 關於電子標籤的資料區段介紹(如共有幾個block)請自行查找囉~
二、簡單說明一下電路接法
#Mifare RFID-RC522 → Arduino UNO
VCC → V3.3
RST → 數位9
GND → GND
MISO → 數位12
MOSI → 數位11
SCK → 數位13
NSS → 數位10
IRQ → X(不用接)
#LiquidCrystal_I2C → Arduino UNO
VCC → V5
GND → GND
SDA → A4
SCL → A5
#其他
蜂鳴器(+) → 數位8
LED燈 → 數位7
三、程式說明
這支程式主要需使用到兩個外部Library,分別為
Arduino-LiquidCrystal-I2C-library
Arduino-MFRC522
依序載入及宣告的global變數如下:
#include <SPI.h>
#include <MFRC522.h>
#include <LiquidCrystal_I2C.h>
#define LED_PIN 7
#define BUZZER_PIN 8
#define RST_PIN 9 // Configurable, see typical pin layout above
#define SS_PIN 10 // Configurable, see typical pin layout above
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
MFRC522::MIFARE_Key key;
const byte existUID[] = {0x12,0x67,0x96,0xBB};
const byte blockIndex = 4;
const byte len = 18;
byte blockInfo[len]; //1 block: 16 bytes + external 2 bytes
// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 16, 2);
3.1、初始化
void setup() {
// put your setup code here, to run once:
Serial.begin(9600); // Initialize serial communications with the PC
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522 card
// Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;
randomSeed(analogRead(0)); //set random seed
lcd.begin();
lcd.noBacklight();
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
}
電子標籤要讀取或寫入都需要先經過金鑰驗證,在此金鑰預設值皆為0xFF3.2、標籤偵測
void loop() {
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial()) {
return;
}
lcd.backlight();
printLCD("**Card Detected:**");
//...
}
void printLCD(String msg){
printLCD(msg, 1000);
}
void printLCD(String msg, int milis){
lcd.clear();
int msgLen = msg.length();
int lcdLineLimit = 16;
lcd.setCursor(0, 0);
if(msgLen > lcdLineLimit){
lcd.print(msg.substring(0, lcdLineLimit));
lcd.setCursor(0, 1);
lcd.print(msg.substring(lcdLineLimit, lcdLineLimit * 2));
}else{
lcd.print(msg);
}
delay(milis);
}
打開MFRC522提供的example都會有前面這兩個判斷,一個是針對是否有新的標籤,另一個則是若同時有多個標籤時一次只會read一個! 當這兩個判斷式通過後LCD就會亮起來! 而printLCD函式預設在印出字串時維持1秒鐘的時間,若是指定的message長度超過16會自動排到第二行去!PS. LCD最多只有兩行列印空間
3.3、金鑰、UID驗證
void loop() {
//...
if(keyVerify(blockIndex, key, mfrc522.uid)) {
if(uidVerify()){
Serial.setTimeout(5000L) ; // wait until 5 seconds for input from serial
//Enter option and input by Serial Console
printLCD("Select Option: (1)Read(2)Write");
char option = getOptionInput();
if(option == '1')
readCard();
else if(option == '2')
writeCard();
else
printLCD("No option!!");
}
}
//...
}
char getOptionInput(){
byte buffer[len];
Serial.readBytes(buffer, len);
char inputOption = char(buffer[0]);
printLCD("You input option:"+(String(inputOption)));
return inputOption;
}
bool keyVerify(byte blockAddr, MFRC522::MIFARE_Key key, MFRC522::Uid uid){
MFRC522::StatusCode status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, blockAddr, &key, &(uid)); //line 834 of MFRC522.cpp file
if(status == MFRC522::STATUS_OK){
printLCD("Auth. Success!");
}else{
digitalWrite(BUZZER_PIN, HIGH);
enableBuzzer(255);
printLCD("Auth. Failed!");
return false;
}
return true;
}
bool uidVerify(){
byte *currUID = mfrc522.uid.uidByte;
byte idSize = mfrc522.uid.size;
if(memcmp(existUID, currUID, idSize) == 0){
enableBuzzer(50);
return true;
}else{
enableBuzzer(255);
printLCD("Failed!!Card does not exist!!", 2000);
return false;
}
}
void enableBuzzer(int count){
unsigned char i = 0;
for(i = 0 ; i < count ; i++){
digitalWrite(BUZZER_PIN, HIGH);
delay(1);
digitalWrite(BUZZER_PIN, LOW);
delay(1);
}
}
標籤被偵測到後,隨即進行金鑰驗證呼叫keyVerify(...),傳入的參數分別為哪個block、key值、還有這個標籤的UID,若驗證成功才可以對這個block的區塊進行資料讀取或寫入的操作!而uidVerify這個函式是檢查標籤的uid是否有match變數existUID內紀錄的值,若有的話才可以進行讀取或寫入,算是多一層過濾的動作!
通過兩道驗證之後,接著LCD會印出選單供您進行操作,這邊需搭配Arduino IDE內的Serial Monitor進行input動作,在此設定輸入的timeout時間為5秒!
PS. 若有小鍵盤就不用如此麻煩
3.4、Read data from tag
void readCard(){
digitalWrite(LED_PIN, HIGH);
if(readData(blockIndex, blockInfo, len)) {
int i = 0;
String str;
for(i = 0 ; i < len - 2 ; i++){
str += char(blockInfo[i]);
}
printLCD("Welcome!!"+str, 3000);
}
digitalWrite(LED_PIN, LOW);
}
bool readData(byte blockAddr, byte bufferArr[], byte len){
MFRC522::StatusCode status = mfrc522.MIFARE_Read(blockAddr, bufferArr, &len);
if(status != MFRC522::STATUS_OK){
enableBuzzer(255);
printLCD("Read Failed!");
return false;
}
return true;
}
在此需指定如前面驗證的block編號及buffer array(長度為18)進行讀取動作,接著再把read出來的資料轉成字串印在LCD上面!3.5、Write data to tag
void writeCard(){
digitalWrite(LED_PIN, HIGH);
Serial.setTimeout(10000L) ; // wait until 10 seconds for input from serial
printLCD("Type name, ending with # ");
byte currLen = Serial.readBytesUntil('#', (char *) blockInfo, len - 2) ; // read name from serial
//filter '\n' character
if(currLen > 0 && blockInfo[currLen - 1] == '\n'){
currLen--;
}
for (byte i = currLen; i < len - 2; i++) blockInfo[i] = ' '; // pad with spaces
if(currLen == 0){
printLCD("Wait Timeout...");
digitalWrite(LED_PIN, LOW);
return;
}
delay(1000);
if(writeData(blockIndex, blockInfo, len - 2)) {
String strData;
for (byte c = 0 ; c < len - 2 ; c++)
strData += char(blockInfo[c]);
printLCD("Write Success:"+strData, 3000);
}
digitalWrite(LED_PIN, LOW);
}
bool writeData(byte blockAddr, byte bufferArr[], byte len){
MFRC522::StatusCode status = mfrc522.MIFARE_Write(blockAddr, bufferArr, len);
if(status != MFRC522::STATUS_OK){
enableBuzzer(255);
printLCD("Write Failed!");
return false;
}
return true;
}
寫入的部分與讀取大同小異,只不過多了等待10秒的輸入畫面在Serial Monitor!最後在進行完讀取或寫入的操作之後,除了呼叫PICC_HaltA()外,若需要再次重複偵測到這個標籤(拿開再靠近),還要呼叫PCD_StopCrypto1(),如此才可以重新感應到這個標籤!
"Remember to call PCD_StopCrypto1() after communicating with the authenticated PICC - otherwise no new communications can start."
void loop() {
//...
lcd.clear();
lcd.noBacklight();
mfrc522.PICC_HaltA(); //stop reading
mfrc522.PCD_StopCrypto1();
//filter serial available data, avoid input option to get
while (Serial.available() > 0) {
Serial.println("filter...");
Serial.println(Serial.read());
}
delay(3000);
}
最後DEMO影片如下:
參考資料
嗨您好 方便私訊嗎? 想了解程式內容 感恩!
回覆刪除你直接將私訊的方式寄到我的信箱?
刪除