天天看點

arduino + RC522 讀寫字元串資料實驗描述RFID子產品基本知識硬體連接配接程式流程圖程式源碼

arduino + RC522 讀寫字元串資料

  • 實驗描述
  • RFID子產品基本知識
    • MFRC522庫
    • NXP_MFRC522讀寫器(Proximity Coupling Device)
    • PICC(Proximity Integrated Circuit Card)
  • 硬體連接配接
  • 程式流程圖
  • 程式源碼

實驗描述

本實驗将會實作一個通過序列槽發送指令讀取資訊或者寫入特定資訊到指定位置,我目前做的是實作對某藥品名稱、性狀、用法用量等具體資訊的存取,是以,此處我實作的是對藥品名稱進行讀寫,我在代碼中定義了一個有關藥品資訊的結構體,讀者可以通過在其中添加成員來實作添加資訊項的目的,在此記錄下來供以後參考,由于本人菜鳥一個且本實驗還未成熟,大佬發現有錯誤煩請指正。

RFID子產品基本知識

MFRC522庫

本實驗基于MFRC522庫進行開發,需要先加載此庫檔案。

NXP_MFRC522讀寫器(Proximity Coupling Device)

恩智浦生産的一種工作在13.56MHz電磁場下的RFID讀卡器,可以讀取MIFARE 4K、MIFARE 1K、MIFARE Mini等卡片。

PICC(Proximity Integrated Circuit Card)

一種使用ISO 14443A接口的RFID卡片,例如:MIFARE、NTAG203。

MIFARE 經常使用的又有MIFARE 4K,MIFARE 1K和MIFARE Mini幾種,由于我使用的時MIFARE 1K,是以我下面以MIFARE 1K為例進行介紹。

MIFARE 1K共有16個扇區,每個扇區4個塊,每個塊可以存儲16個位元組,是以似乎我們一共有16 x 4 x 16 Byte的存儲空間,即1KB。然而事實并非如此,每個扇區中都固定最後一個塊(稱之為Sector Trailer)我們不能存儲資料,而被用來存儲整個扇區通路控制有關的資料。具體每個字段是什麼意思我也不是也太清楚,可以查閱一下恩智浦公司相關産品的資料手冊(但是我知道對每個塊進行讀寫時需要使用Key B進行驗證,驗證通過後才能完成讀寫)Key B出廠時預設設定為FF FF FF FF FF FF。每個扇區中最後一個塊的内字段定義如下:

Bytes 0-5 Key A
Bytes 6-8 Access Bits
Bytes 9 User data
Bytes 10-15 Key B (or user data)

而對于扇區0來說,它的第0塊存儲的為該卡片的序列号等資訊,是以我們也是隻能讀取不能寫入使用者新資料。是以MIFARE 1K實際可用容量為[(15 x 3)+2 ] x 16 = 752 B,其餘MIFARE 4K 和 MIFARE Mini類似。是以,對于一個MIFARE 1K 我們實際可用的空間分布為:

Block0 UID、Type、etc…
Block1 UserData
Block2 UserData
Block3 Sector trailer
Block4 UserData
Block5 UserData
Block6 UserData
Block7 Sector trailer
Block8 UserData
Block9 UserData
Block10 UserData
Block11 Sector trailer
Block12 UserData
Block13 UserData
Block14 UserData
Block15 Sector trailer

硬體連接配接

MFRC522 Arduino UNO
RST 9
SDA(SS) 10
MOSI 11 / ICSP-4
MISO 12 / ICSP-1
SCK 13 / ICSP-3

程式流程圖

主程式運作過程:

程式源碼

/*
 * Write and Read personal data of a MIFARE RFID card using a RFID-RC522 reader
 * Uses MFRC522 - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. 
 * -----------------------------------------------------------------------------------------
 *             MFRC522      Arduino       Arduino   Arduino    Arduino          Arduino
 *             Reader/PCD   Uno/101       Mega      Nano v3    Leonardo/Micro   Pro Micro
 * Signal      Pin          Pin           Pin       Pin        Pin              Pin
 * -----------------------------------------------------------------------------------------
 * RST/Reset   RST          9             5         D9         RESET/ICSP-5     RST
 * SPI SS      SDA(SS)      10            53        D10        10               10
 * SPI MOSI    MOSI         11 / ICSP-4   51        D11        ICSP-4           16
 * SPI MISO    MISO         12 / ICSP-1   50        D12        ICSP-1           14
 * SPI SCK     SCK          13 / ICSP-3   52        D13        ICSP-3           15
 *
 * Hardware required:
 * Arduino
 * PCD (Proximity Coupling Device): NXP MFRC522 Contactless Reader IC
 * PICC (Proximity Integrated Circuit Card): A card or tag using the ISO 14443A interface, eg Mifare or NTAG203.
 * The reader can be found on eBay for around 5 dollars. Search for "mf-rc522" on ebay.com. 
 */

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

typedef struct{
  byte DrugName[48];  //藥品名稱
  byte Dosage[12];    //用法用量
  byte Remaining[4];  //剩餘量
}DrugInfo;

#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;
MFRC522::StatusCode status;

DrugInfo drugInfo;      //執行個體化一個藥品資訊的結構體變量

byte block;
byte len;

const byte drugNameBlockAddr[3] = {1,2,4};   //藥品名稱的存儲位址

void setup() {
  Serial.begin(9600);        // Initialize serial communications with the PC
  SPI.begin();               // Init SPI bus
  mfrc522.PCD_Init();        // Init MFRC522 card
  for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;    // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
  Serial.println(F("Write and Read personal data on a MIFARE PICC "));
}

void loop(){
  char cmd = ' ';
  byte count = 0;
  while(Serial.read() >= 0);  //清空在PICC卡讀寫期間的序列槽資料
  Serial.println("please input a command(0:read; 1:write):");
  while(Serial.available() <= 0);  //等待指令輸入
  delay(10);                       //等待資料全部進入緩沖區
  if(Serial.available() != 1)
  {
    Serial.println("error: Invalid command!");
    while(Serial.read() >= 0);
    return;
  }
  cmd = (char)Serial.read();
  if(cmd != '0' && cmd != '1')
  {
    Serial.println("error: Invalid command!");
    return;
  }

  
  /*###############################################################################################################################*/
  if(cmd == '0')
  {
    //read a PICC card
    Serial.println("Waiting for the appearance of the PICC card in one minute(read)...");

    // Look for new cards
    while ( ! mfrc522.PICC_IsNewCardPresent()) 
    {
      delay(1000);
      if(count++>60)
      {
        Serial.println("Waiting timeout...");
        count = 0;
        return;
      }
    }

    // Select one of the cards
    if ( ! mfrc522.PICC_ReadCardSerial()) {
      return;
    }

    Serial.println(F("**Card Detected:**"));


    mfrc522.PICC_DumpDetailsToSerial(&(mfrc522.uid)); //dump some details about the card

    //mfrc522.PICC_DumpToSerial(&(mfrc522.uid));      //uncomment this to see all blocks in hex

    Serial.print(F("Drug Name: "));

    len = 18;
    for(uint8_t i = 0; i < sizeof(drugNameBlockAddr);i++)
    {
      status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, drugNameBlockAddr[i], &key, &(mfrc522.uid)); //line 834 of MFRC522.cpp file
      if (status != MFRC522::STATUS_OK) {
        Serial.print(F("Authentication failed: "));
        Serial.println(mfrc522.GetStatusCodeName(status));
        return;
      }

      status = mfrc522.MIFARE_Read(drugNameBlockAddr[i], &drugInfo.DrugName[i*16], &len);
      if (status != MFRC522::STATUS_OK) {
        Serial.print(F("Reading failed: "));
        Serial.println(mfrc522.GetStatusCodeName(status));
        return;
      }
    }

    //PRINT FIRST NAME
    for (uint8_t i = 0; i < sizeof(drugInfo.DrugName); i++)
    {
      Serial.write(drugInfo.DrugName[i]); 
    }
    Serial.print(" ");

    Serial.println(F("\n**End Reading**\n"));

    mfrc522.PICC_HaltA();
    mfrc522.PCD_StopCrypto1();

  }
  /*###############################################################################################################################*/
  else if(cmd == '1')
  {
    //write a PICC card
    Serial.println("Waiting for the appearance of the PICC card in one minute(write)...");
    // Look for new cards
    while( ! mfrc522.PICC_IsNewCardPresent())
    {
      delay(1000);
      count++;
      if(count > 60)
      {
        count = 0;
        Serial.println("Waiting timeout...");
        return;
      }
    }
   // Select one of the cards
    if ( ! mfrc522.PICC_ReadCardSerial()) {
     return;
    }
    Serial.print(F("Card UID:"));    //Dump UID
    for (byte i = 0; i < mfrc522.uid.size; i++) {
      Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
      Serial.print(mfrc522.uid.uidByte[i], HEX);
    }
    Serial.print(F(" \nPICC type: "));   // Dump PICC type
    MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
    Serial.println(mfrc522.PICC_GetTypeName(piccType));
    
    for(byte i = 0; i < sizeof(drugInfo.DrugName); i++) drugInfo.DrugName[i] = ' ';
    while(Serial.read() >= 0);
    Serial.println("please input drug name(Less than 48 characters):");
    
    while(Serial.available()<=0)//等待輸入
    {
      delay(1000);
      count++;
      if(count > 300)
      {
        Serial.println("No drug name entered");
        count = 0;
        return;
      }
    }
    delay(10);//等待資料全部進入緩沖區
    int length = Serial.available();
    for(byte i = 0; i < length; i++)
    {
      drugInfo.DrugName[i] = Serial.read();
    }

    for(byte i = 0; i < sizeof(drugNameBlockAddr); i++)
    {
      status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, drugNameBlockAddr[i], &key, &(mfrc522.uid));
      if (status != MFRC522::STATUS_OK) {
        Serial.print(F("PCD_Authenticate() failed: "));
        Serial.println(mfrc522.GetStatusCodeName(status));
        return;
      }
      else Serial.println(F("PCD_Authenticate() success: "));

      // Write block
      status = mfrc522.MIFARE_Write(drugNameBlockAddr[i], &drugInfo.DrugName[i*16], 16);
      if (status != MFRC522::STATUS_OK) {
        Serial.print(F("MIFARE_Write() failed: "));
        Serial.println(mfrc522.GetStatusCodeName(status));
        return;
      }
      else Serial.println(F("MIFARE_Write() success: "));
    }
    
    /*###############################################################################################################################*/

    Serial.println(" ");
    mfrc522.PICC_HaltA(); // Halt PICC
    mfrc522.PCD_StopCrypto1();  // Stop encryption on PCD
  }
}