2023年8月14日 星期一

RFID-RC522 module with ESP32 using Arduino IDE2

Purpose:

想利用ESP32+RFID-RC522來學習做一套門禁系統, 當感應到認可的卡片時, 可開門允許通過, 否則則警示非法卡片.

I want to use ESP32+RFID-RC522 to learn to make an access control system. When an approved card is sensed, the door can be opened to allow passage, otherwise it will warn of illegal cards.

Fundamental:

RFID 是一種無線通訊技術,以無線電波傳遞訊息,只要在電波範圍內,即可傳送訊號,不會傳輸屏障之問題。這種設備的運作為一個讀卡設備會發出一個電磁場,而感應卡內部有線圈,當線圈靠近磁場時,會產生感應電流,就可以做為電力傳輸資訊。另外,感應卡平常沒有靠近場時,內部晶片根本沒有電力可以工作,不用擔心卡片放在一起資料不見。
RFID設備所使用的頻段分為低頻(LF,125KHz)高頻(HF,13.56MHz)、 超高頻(UHF,868~915MHz)、微波(Microwave,2.45 & 5.814GHz),各個頻 段的設備有不同的物理特性,如讀取的距離與讀取的速度,因此在不同應用情境中會採用不同頻段的設備。

RFID is a wireless communication technology that uses radio waves to transmit information. 
As long as it is within the range of the radio waves, the signal can be transmitted without the problem of transmission barriers. 
The operation of this kind of equipment is that a card reading device will emit an electromagnetic field, and there is a coil inside the proximity card. 
When the coil is close to the magnetic field, an induced current will be generated, which can be used as power to transmit information. 
In addition, when the proximity card is not close to the field, the internal chip has no power to work at all, so there is no need to worry about the data missing when the cards are put together.
The frequency bands used by RFID equipment are divided into low frequency (LF, 125KHz), high frequency (HF, 13.56MHz), ultra high frequency (UHF, 868~915MHz), microwave (Microwave, 2.45 & 5.814GHz), the equipment of each frequency band is Different physical characteristics, such as reading distance and reading speed, so devices with different frequency bands will be used in different application scenarios.

圖一: RFID-RC522感應器13.56MHz
圖二: 感應卡MIFARE卡

RFID感應器是頻率為13.56MHz的 RFID-RC522,而他的感應卡為MIFARE卡,MIFARE卡又有分不同儲存容量的卡。MIFARE S50 內部儲存容量1Kbyte,MIFARE S70 內部儲存容量 4Kbytes,各劃分為 16 區與 64 區,每區都有獨立的 A / B 兩層存取控制密碼,每區有4個BLOCK,每個BLOCK有16個字節。
The RFID sensor is an RFID-RC522 with a frequency of 13.56MHz, and its proximity card is a MIFARE card, and the MIFARE card has different storage capacities. 
The internal storage capacity of MIFARE S50 is 1Kbyte, and the internal storage capacity of MIFARE S70 is 4Kbytes. 
Each area is divided into 16 areas and 64 areas. Each area has an independent A / B two-layer access control password. Each area has 4 BLOCKs. 16 bytes.
圖: Read Data


Bill of Material :
圖: RFID-RC522感應器13.56MHz
圖: 感應卡MIFARE卡
圖:ESP32
Circuit:

YouTube Demo:


Code Introduce:

#include <SPI.h>
#include <MFRC522.h>
//----------------------------------------------------------------------
//--------- Flag structure --------------------------------------
typedef struct _vFlag
{
  uint8_t BTFlag = 0;
  uint8_t DC_Flag = 0;
  uint8_t CANFlag = 0;
  uint8_t I2C_Flag = 0;
  uint8_t RFIDWrite = 0;
  uint8_t RFIDRead = 0;
  uint8_t sensor_Flag = 0;
  uint8_t sensor1_Flag = 0;
  uint8_t initial_Flag = 0;
  uint8_t FunctionFlag = 0;
} vFlag;
vFlag *flag_Ptr;
vFlag flag;
//--------- uart structure --------------------------------------
//----------uart--------------
#define LINE_BUFFER_LENGTH 64
typedef struct _vUart
{
  char c;
  int lineIndex = 0;
  int line1Index = 0;
  int BTlineIndex = 0;
  bool lineIsComment;
  bool lineSemiColon;
  //char *line;
  char line[128];
  //char line1[128];
  char BTline[20];
  //char R_line[20];
  //char L_line[20];
  String inputString;
  String BTinputString;
  String S1inputString;
  int V[16];
  char ctemp[30];
  char I2C_Data[80];
  int DC_Spped = 50;
  float Voltage[16];
  int Buffer[128];
  int StartCnt = 0;
  int ReadCnt = 0;
  int sensorValue = 0;
} vUart;
vUart *Uart_Ptr;
vUart Uart;
//-------------------------------------
//Typical pin layout used:
//* -----------------------------------------------------------------------------------------
// *             MFRC522                    
// *             Reader/PCD   ESP32          
// * Signal      Pin          Pin          
// * --------------------------------------
// * RST/Reset   RST          21            
// * SPI SS      SDA(SS)      5            
// * SPI MOSI    MOSI         23
// * SPI MISO    MISO         19
// * SPI SCK     SCK          18
//------ESP32 RFID setting ----------------
const int SPI_CS_PIN = 5;
const int INT_PIN = 21;

MFRC522 mfrc522;
MFRC522::MIFARE_Key key;
//16(sector),4(block)
byte sector = 15;  
byte block = 0;    

byte blockData[]    = {
        0x01, 0x02, 0x03, 0x04, //  1,  2,   3,  4,
        0x05, 0x06, 0x07, 0x08, //  5,  6,   7,  8,
        0x09, 0x0a, 0xff, 0x0b, //  9, 10, 255, 11,
        0x0c, 0x0d, 0x0e, 0x0f  // 12, 13, 14, 15
    };

byte buffer[18];

MFRC522::StatusCode status;

struct RFIDTag {    
   byte uid[4];
   char *name;
};

struct RFIDTag tags[] = {  
   {{60,209,110,133}, "employee1"},
   {{0xD4,0xD3,0xC0,0x61}, "employee2"},
   {{0xDC,0x14,0xD3,0x38}, "ESP32"}
};

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

char *reference;

//---------------------------------------------------------------------------------
#ifndef LED_BUILTIN
#define LED_BUILTIN 2
#endif
//----------------------------------------------------------------
TaskHandle_t hled;
TaskHandle_t huart;
//------------------------------------------------------------------------------
void initial()
{
  Serial.println(F("Create Task"));
  //----------------------------------------------------------------------
  xTaskCreatePinnedToCore(
    vUARTTask, "UARTTask" // A name just for humans
    ,
    1024 // This stack size can be checked & adjusted by reading the Stack Highwater
    ,
    NULL, 3 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,
    &huart //handle
    ,
    0);

  //--------------- create task----------------------------------
  xTaskCreatePinnedToCore(
    vLEDTask, "LEDTask" // A name just for humans
    ,
    1024 // This stack size can be checked & adjusted by reading the Stack Highwater
    ,
    NULL, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,
    &hled //handle
    ,
    0);
  //----------------------------------------
  //----------------------------------------------------------------------
  //vTaskSuspend(hfunction); //暫停TASK運行
  //----------------------------------------------------------------------
}

void setup()
{
  Serial.begin(9600);
  Serial.println(F("init"));
  initial();
  SPI.begin();
  pinMode(INT_PIN, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);
pinMode(16, OUTPUT);  //PASS
  pinMode(17, OUTPUT);
  mfrc522.PCD_Init(SPI_CS_PIN, INT_PIN);
  Serial.print(F("Reader "));
  Serial.print(F(": "));
  mfrc522.PCD_DumpVersionToSerial();
  Serial.println();
 
  for (byte i = 0; i < 6; i++)
  {
    key.keyByte[i] = 0xFF;
  }

}

void loop()
{
  Serial.print(F("Main at core:"));
  Serial.println(xPortGetCoreID());
  while(1)
  {
    if(flag.RFIDWrite==1)
    {
      if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial())
      {
       
        Serial.print(F("Card UID:"));
        dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
        Serial.println();
        Serial.print(F("PICC type: "));
        MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
        Serial.println(mfrc522.PICC_GetTypeName(piccType));
       
        writeBlock(sector, block, blockData);  
       
        mfrc522.PICC_HaltA();
        mfrc522.PCD_StopCrypto1();
      }
    }
   
    if(flag.RFIDRead==1)
    {
      if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial())
      {
        byte *id = mfrc522.uid.uidByte;
        byte idSize = mfrc522.uid.size;

        Serial.print(F("Card UID:"));
        dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
       
        Serial.println();
        Serial.print(F("PICC type: "));
        MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
        Serial.println(mfrc522.PICC_GetTypeName(piccType));  

        bool they_match = false;
        for (byte i=0; i<totalTags; i++)
        {
          if (memcmp(tags[i].uid, id, idSize) == 0)
          {
            Serial.println(tags[i].name);  
            they_match = true;
            break;
          }
        }


        if(they_match)
        {
          Serial.print(F("Access Granted!"));
digitalWrite(16, HIGH);
        }else
        {
          Serial.print(F("Access Denied!"));
digitalWrite(17, HIGH);
        }
 
        mfrc522.PICC_HaltA();  
vTaskDelay(1000);
        digitalWrite(16, LOW);
        digitalWrite(17, LOW);
      }
    }//---1
    if(flag.RFIDRead==2)
    {
      if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial())
      {
        // Dump debug info about the card; PICC_HaltA() is automatically called
        mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
       
      }
    }
    if(flag.RFIDRead==3)
    {
      if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial())
      {
       
        Serial.print(F("Card UID:"));
        dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
        Serial.println();
        Serial.print(F("PICC type: "));
        MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
        Serial.println(mfrc522.PICC_GetTypeName(piccType));
       
        readBlock(sector, block, buffer);      

        mfrc522.PICC_HaltA();
        mfrc522.PCD_StopCrypto1();
      }
    }
    vTaskDelay(5);
  }
}
//-------------------------------------------
void vUARTTask(void *pvParameters)
{
  (void)pvParameters;

  Serial.print(F("UARTTask at core:"));
  Serial.println(xPortGetCoreID());
  vTaskDelay(100);
  for (;;)
  {
    while (Serial.available() > 0)
    {
      Uart.c = Serial.read();
 
      if ((Uart.c == '\n') || (Uart.c == '\r'))
      { // End of line reached
        if (Uart.lineIndex > 0)
        { // Line is complete. Then execute!
          Uart.line[Uart.lineIndex] = '\0'; // Terminate string
          //Serial.println( F("Debug") );
          //Serial.println( Uart.inputString );
          processCommand(Uart.line); // do something with the command
          Uart.lineIndex = 0;
          Uart.inputString = "";
        }
        else
        {
          // Empty or comment line. Skip block.
        }
        Uart.lineIsComment = false;
        Uart.lineSemiColon = false;
        Serial.println(F("ok>"));
      }
      else
      {
        //Serial.println( c );
        if ((Uart.lineIsComment) || (Uart.lineSemiColon))
        {
          if (Uart.c == ')')
            Uart.lineIsComment = false; // End of comment. Resume line.
        }
        else
        {
          if (Uart.c == '/')
          { // Block delete not supported. Ignore character.
          }
          else if (Uart.c == '~')
          { // Enable comments flag and ignore all characters until ')' or EOL.
            Uart.lineIsComment = true;
          }
          else if (Uart.c == ';')
          {
            Uart.lineSemiColon = true;
          }
          else if (Uart.lineIndex >= LINE_BUFFER_LENGTH - 1)
          {
            Serial.println("ERROR - lineBuffer overflow");
            Uart.lineIsComment = false;
            Uart.lineSemiColon = false;
          }
          else if (Uart.c >= 'a' && Uart.c <= 'z')
          { // Upcase lowercase
            Uart.line[Uart.lineIndex] = Uart.c - 'a' + 'A';
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += (char)(Uart.c - 'a' + 'A');
          }
          else
          {
            Uart.line[Uart.lineIndex] = Uart.c;
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += Uart.c;
          }
        }
      }
    } //while (Serial.available() > 0)
    vTaskDelay(5);
  }
}
//-------------------------------------------------------------------------
static void vLEDTask(void *pvParameters)
{
  (void)pvParameters;

  Serial.println(F("LEDTask at core:"));
  Serial.println(xPortGetCoreID());
  pinMode(LED_BUILTIN, OUTPUT);
  for (;;)
  {
    digitalWrite(LED_BUILTIN, HIGH);
    vTaskDelay(200);
    digitalWrite(LED_BUILTIN, LOW);
    vTaskDelay(200);
  }
}
//----------------------------------------
void processCommand(char *data)
{
  int len, xlen, ylen, zlen, alen;
  int tempDIO;
  String stemp;

  len = Uart.inputString.length();
  //---------------------------------------
  if (strstr(data, "VER") != NULL)
  {
    Serial.println(F("ESP32_20230811"));
  }
  //-------------- RFID --------------------
  if (strstr(data, "RFID_WRITE_ON") != NULL)
  {
    flag.RFIDWrite = 1;
    flag.RFIDRead = 0;
    Serial.println(F("RFID_WRITE_ON"));
  }
  if (strstr(data, "RFID_WRITE_OFF") != NULL)
  {
    flag.RFIDWrite = 0;
    flag.RFIDRead = 0;
    Serial.println(F("RFID_WRITE_OFF"));
  }
  if (strstr(data, "RFID_READ_1") != NULL)
  {
    flag.RFIDRead = 1;
    flag.RFIDWrite = 0;
    Serial.println(F("RFID_READ_1"));
  }
  if (strstr(data, "RFID_READ_2") != NULL)
  {
    flag.RFIDRead =2;
    flag.RFIDWrite = 0;
    Serial.println(F("RFID_READ_2"));
  }
  if (strstr(data, "RFID_READ_3") != NULL)
  {
    flag.RFIDRead =3;
    flag.RFIDWrite = 0;
    Serial.println(F("RFID_READ_3"));
  }
  if (strstr(data, "RFID_READ_OFF") != NULL)
  {
    flag.RFIDRead = 0;
    flag.RFIDWrite = 0;
    Serial.println(F("RFID_READ_OFF"));
  }
}
//-----------------------------------------

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);
  }
}

void writeBlock(byte _sector, byte _block, byte _blockData[])
{
  if (_sector < 0 || _sector > 15 || _block < 0 || _block > 3) {
   
    Serial.println(F("Wrong sector or block number."));
    return;
  }

  if (_sector == 0 && _block == 0) {
    Serial.println(F("First block is read-only."));
    return;
  }

  byte blockNum = _sector * 4 + _block;
  byte trailerBlock = _sector * 4 + 3;  


  Serial.println(F("Authenticating using key A..."));
  status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
      Serial.print(F("PCD_Authenticate() failed: "));
      Serial.println(mfrc522.GetStatusCodeName(status));
      return;
  }

  Serial.print(F("Writing data into block ")); Serial.print(blockNum);
  Serial.println(F(" ..."));
  dump_byte_array(_blockData, 16); Serial.println();

  status = (MFRC522::StatusCode) mfrc522.MIFARE_Write(blockNum, _blockData, 16);

  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  Serial.println(F("Data was written."));
}
//----------------------------------------------
void readBlock(byte _sector, byte _block, byte _blockData[])
{
  if (_sector < 0 || _sector > 15 || _block < 0 || _block > 3)
{
    Serial.println(F("Wrong sector or block number."));
    return;
  }

  byte blockNum = _sector * 4 + _block;  
  byte trailerBlock = _sector * 4 + 3;  

  // Authenticate using key A
  Serial.println(F("Authenticating using key A..."));
  status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
      Serial.print(F("PCD_Authenticate() failed: "));
      Serial.println(mfrc522.GetStatusCodeName(status));
      return;
  }

  byte buffersize = 18;
  status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockNum, _blockData, &buffersize);

  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_read() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  Serial.print(F("Data in block ")); Serial.print(blockNum); Serial.println(F(":"));
  dump_byte_array(_blockData, 16); Serial.println();
  Serial.println();

  Serial.println(F("Data was read."));
}
//-----------------------------------------




沒有留言:

張貼留言