RFID Arduino控制

RFID(Radio Frequency Identification, 無線射頻辨識)是一種無線通訊技術,可以通過無線電訊號識別特定目標並讀寫相關數據,而無需識別系統與特定目標之間建立機械或者光學接觸。
無線電的訊號是通過調成無線電頻率的電磁場,把數據從附著在物品上的標籤上傳送出去,以自動辨識與追蹤該物品。某些標籤在識別時從識別器發出的電磁場中就可以得到能量,並不需要電池(透過磁場變化產生電流,再將產生的電流輸出訊號給識別的機器);也有的標籤本身擁有電源,並可以主動發出無線電波。

註:「射頻」這個詞聽器來有點像中國用語,但在國教院名詞資訊網中查得到這個翻譯。(https://terms.naer.edu.tw/detail/178799/

RFID 可在賣場電子商品條碼下面看到。取自:維基百科(https://zh.wikipedia.org/wiki/射频识别)

在我們身上常見的就是悠遊卡與房間的磁卡,可以將悠遊卡用有機溶劑溶解後就能取得裡面的線圈。(下面是大學時將他與科技之夜的壓克力票卡結合)

RFID也有模組可以讓我們製作出一些小專題,而現在常見的模組是基於RC522 IC所設計出的模組,他支援13.56 MHz的頻率讀取,因此我們的感應卡也需要購買符合該頻率的感應卡才能使用。

這邊插入一下常見的RFID頻率,如果使用錯誤的卡片會無法讀取資料。

取自:http://yes.nctu.edu.tw/Lecture/NewTech/C05/RFID/RFID.htm

對RFID本身有基本的認識後,接下來我們就可以將RC522模組連接上開發板,並使用程式讓開發板做出反應囉。

連接方式:

SDA -> 10
SCK ->13
MOSI ->11
MISO ->12
IRQ -> (NONE)
GND ->GND
RST -> 9

連接好之後,將Arduino連接上電腦,並開啟Arduino。

接下來進入Arduino的程式管理員中,輸入「MFRC522」,然後可以看到很多人寫的程式庫,這邊我們先下載較多人使用的「GithubCommunity」的程式庫。

從草稿碼 > 匯入程式庫 > 點選管理程式庫

點選安裝後,我們就可以開始讓我們的RC522開始讀取RFID晶片卡中的內容囉。

RFID讀卡程式:

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

#define RST_PIN         9          
#define SS_PIN          10  //就是模組上的SDA接腳


MFRC522 mfrc522;   // 建立MFRC522實體

void setup() {

  Serial.begin(9600); 

  SPI.begin();        // 初始化SPI介面

  mfrc522.PCD_Init(SS_PIN, RST_PIN); // 初始化MFRC522卡
  Serial.print(F("Reader "));
  Serial.print(F(": "));
  mfrc522.PCD_DumpVersionToSerial(); // 顯示讀卡設備的版本
  
}


void loop() {

  // 檢查是不是一張新的卡
  if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
      // 顯示卡片內容
      Serial.print(F("Card HEX UID:"));
      dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); // 顯示卡片的UID
      Serial.println();
      Serial.print(F("PICC type: "));
      MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
      Serial.println(mfrc522.PICC_GetTypeName(piccType));  //顯示卡片的類型

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

/**
 * 這個副程式把讀取到的UID,用16進位顯示出來
 */
void dump_byte_array(byte *buffer, byte bufferSize) {
  for (byte i = 0; i < bufferSize; i++) {
    Serial.print(buffer[i] < 0x10 ? " 0" : " ");
    Serial.print(buffer[i], HEX);
  }
}

點選右上方的「序列阜監控視窗」就會出現RFID卡中的內容囉。

接下來我們讓RFID卡感應後做一些反應吧。

注意,第一段程式碼讀出的HEX數值,只要在前方加上0x即可,如上方讀出F7,則下面辨識的卡片即可改為0xF7。

/*本程式參考趙英傑老師書中內容進行修改,歡迎大家上網搜尋「趙英傑 Arduino」 */

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

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

struct RFIDTag {    // 定義結構
   byte uid[4];
   char *name;
};
 
struct RFIDTag tags[] = {  // 初始化結構資料
   {{0xCD, 0xE8, 0x2D, 0x01}, "Light"},
   {{0x1A, 0x75, 0x3D, 0x1B}, "Dark"},   
};

byte totalTags = sizeof(tags) / sizeof(RFIDTag);

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

void setup() {
  Serial.begin(9600);
  Serial.println();
  Serial.println("RFID reader is ready!");

  SPI.begin();
  mfrc522.PCD_Init();   // 初始化MFRC522讀卡機模組
  pinMode(4, OUTPUT); //定義輸出馬達4,5,6,7
  pinMode(5, OUTPUT);
}

void light(){

  digitalWrite(4, 1);
  digitalWrite(5, 0);

}

void dark(){
  digitalWrite(4, 0);
  digitalWrite(5, 0);

}

void loop() {
    // 確認是否有新卡片
    if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
      byte *id = mfrc522.uid.uidByte;   // 取得卡片的UID
      byte idSize = mfrc522.uid.size;   // 取得UID的長度
      bool foundTag = false;            // 是否找到紀錄中的標籤,預設為「否」。
      for (byte i=0; i<totalTags; i++) {
        if (memcmp(tags[i].uid, id, idSize) == 0) {
          Serial.println(tags[i].name);  // 顯示標籤的名
          foundTag = true;  // 設定成「找到標籤了!」
          if (tags[i].name == "Light")light();
          else dark();
          break;            // 退出for迴圈
        }
      }

/*      if (!foundTag) {    // 若掃描到紀錄之外的標籤,則顯示"Wrong card!"。
        Serial.println("Wrong card!");

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

接下來如果將他與車子做結合呢?
這邊我們使用4, 5, 6, 7 四個腳位作為馬達控制。

/*本程式參考趙英傑老師書中內容進行修改,歡迎大家上網搜尋「趙英傑 Arduino」 */

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

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

struct RFIDTag {    // 定義結構
   byte uid[4];
   char *name;
};
 
struct RFIDTag tags[] = {  // 初始化結構資料
   {{0xCD, 0xE8, 0x2D, 0x01}, "Left"},
   {{0x1A, 0x75, 0x3D, 0x1B}, "Go"},   
   {{0x3E, 0x36, 0x2D, 0x01}, "Right"},
   {{0x8B,0x36,0x2D,0x01}, "Stop"}
};

byte totalTags = sizeof(tags) / sizeof(RFIDTag);

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

void setup() {
  Serial.begin(9600);
  Serial.println();
  Serial.println("RFID reader is ready!");

  SPI.begin();
  mfrc522.PCD_Init();   // 初始化MFRC522讀卡機模組
  pinMode(4, OUTPUT); //定義輸出馬達4,5,6,7
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
}

void go(){
  digitalWrite(6, 1);
  digitalWrite(7, 0);
  digitalWrite(4, 1);
  digitalWrite(5, 0);

}

void left(){
  digitalWrite(6, 0);
  digitalWrite(7, 0);
  digitalWrite(4, 1);
  digitalWrite(5, 0);

}

void right(){
  digitalWrite(6, 1);
  digitalWrite(7, 0);
  digitalWrite(4, 0);
  digitalWrite(5, 0);

}
void back(){
  digitalWrite(6, 0);
  digitalWrite(7, 1);
  digitalWrite(4, 0);
  digitalWrite(5, 1);

}

void stop(){
  digitalWrite(6, 0);
  digitalWrite(7, 0);
  digitalWrite(4, 0);
  digitalWrite(5, 0);

}


void loop() {
    // 確認是否有新卡片
    if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
      byte *id = mfrc522.uid.uidByte;   // 取得卡片的UID
      byte idSize = mfrc522.uid.size;   // 取得UID的長度
      bool foundTag = false;            // 是否找到紀錄中的標籤,預設為「否」。
      for (byte i=0; i<totalTags; i++) {
        if (memcmp(tags[i].uid, id, idSize) == 0) {
          Serial.println(tags[i].name);  // 顯示標籤的名
          foundTag = true;  // 設定成「找到標籤了!」
          if (tags[i].name == "Go")go();
          else if (tags[i].name == "Back")back();
          else if (tags[i].name == "Right")right();
          else if (tags[i].name == "Left")left();
          else stop();
          break;            // 退出for迴圈
        }
      }

/*      if (!foundTag) {    // 若掃描到紀錄之外的標籤,則顯示"Wrong card!"。
        Serial.println("Wrong card!");

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

透過以上的方式可以做出小車的移動控制,如先設定好到某個地方需要往前走幾秒、右轉、左轉等等,碰到另一個感測器之後再停下。

https://cad.onshape.com/documents/987397d601453a5365d2c7b7/w/de667708e188d90fdcba53e0/e/368b788affc88c080745ba20

另外我們也可以使用藍牙進行控制。

#include <SoftwareSerial.h>
char BTcmd;
SoftwareSerial BT(7,8); // RX, TX 這邊大家可以查看看SoftwareSerial的資料,他其實是可以自己定義要用哪些接腳作為Rx, Tx傳輸所用。
int MotorRight1=3;
int MotorRight2=4;
int MotorLeft1=5;
int MotorLeft2=6;
int MotorRight3=10;
int MotorRight4=11;
int MotorLeft3=12;
int MotorLeft4=13; //這邊我定義了4組直流馬達,大家使用時如果沒有打算用這麼多馬達的話,可以將後面4排刪掉

void setup()
{ 
  Serial.begin(9600); //這行是原本的Serial,我沒刪掉
  BT.begin(9600); //這是新定義的
  pinMode(MotorRight1, OUTPUT); 
  pinMode(MotorRight2, OUTPUT); 
  pinMode(MotorLeft1,  OUTPUT); 
  pinMode(MotorLeft2,  OUTPUT); 
  pinMode(MotorRight3, OUTPUT); 
  pinMode(MotorRight4, OUTPUT); 
  pinMode(MotorLeft3,  OUTPUT); 
  pinMode(MotorLeft4,  OUTPUT);  //將所有的馬達都設定為「輸出」
}

void go()// 前進,void 函數執行完成後,不傳回任何數值,後方go為自訂的函數名稱。
{
digitalWrite(MotorRight1,HIGH);
digitalWrite(MotorRight2,LOW);
digitalWrite(MotorLeft1,HIGH);
digitalWrite(MotorLeft2,LOW);
digitalWrite(MotorRight3,HIGH);
digitalWrite(MotorRight4,LOW);
digitalWrite(MotorLeft3,HIGH);
digitalWrite(MotorLeft4,LOW);
}

void left() //右轉
{
digitalWrite(MotorRight1,HIGH);
digitalWrite(MotorRight2,LOW);
digitalWrite(MotorLeft1,LOW);
digitalWrite(MotorLeft2,HIGH);
digitalWrite(MotorRight3,HIGH);
digitalWrite(MotorRight4,LOW);
digitalWrite(MotorLeft3,LOW);
digitalWrite(MotorLeft4,HIGH);
}

void right() //左轉
{
digitalWrite(MotorRight1,LOW);
digitalWrite(MotorRight2,HIGH);
digitalWrite(MotorLeft1,HIGH);
digitalWrite(MotorLeft2,LOW);
digitalWrite(MotorRight3,LOW);
digitalWrite(MotorRight4,HIGH);
digitalWrite(MotorLeft3,HIGH);
digitalWrite(MotorLeft4,LOW);
} 

void back()//
{
digitalWrite(MotorRight1,LOW);
digitalWrite(MotorRight2,HIGH);
digitalWrite(MotorLeft1,LOW);
digitalWrite(MotorLeft2,HIGH);
digitalWrite(MotorRight3,LOW);
digitalWrite(MotorRight4,HIGH);
digitalWrite(MotorLeft3,LOW);
digitalWrite(MotorLeft4,HIGH);     
} 

void stop() //停止
{
digitalWrite(MotorRight1,LOW);
digitalWrite(MotorRight2,LOW);
digitalWrite(MotorLeft1,LOW);
digitalWrite(MotorLeft2,LOW);
digitalWrite(MotorRight3,LOW);
digitalWrite(MotorRight4,LOW);
digitalWrite(MotorLeft3,LOW);
digitalWrite(MotorLeft4,LOW);    
}
       
void loop()
{
  if (BT.available()) //如果BT收讀取到資料則會跑以下的內容
{
  BTcmd= BT.read(); //BT
    if ('F' == BTcmd) go(); //如果讀取的數值為F,則執行go裡面的動作
    else if ('L' ==BTcmd) left();
    else if ('B' ==BTcmd) back();
    else if ('R' == BTcmd) right();
    else stop(); //else stop()
    }
else{

  delay(200);
  }
   Serial.flush();
}  

Android上面個人推薦:https://play.google.com/store/apps/details?id=braulio.calle.bluetoothRCcontroller

也可以另外做遙控器出來控制:

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google photo

您的留言將使用 Google 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s