新闻  |   论坛  |   博客  |   在线研讨会
ESP32驱动MFRC522 RFID模块读写IC卡数据
优信电子 | 2025-05-28 16:33:08    阅读:8   发布文章

前言

RFID是Radio-Fequency Identification射频识别的缩写。RFID使用电磁场在短距离内传输数据,它可用于人员识别、刷卡交易,商品的电子标签等。工作原理为,ID磁卡进入到磁场后,接受读写器发出的射频信号,凭借感应电流所获得的能量发送出存储在芯片中的产品信息,读写器读取到信息并解码后,送至处理单元进行数据处理。

MFRC522是高度集成的非接触式( 13.56MHz)读写卡芯片。此发送模块利用调制和解调的原理,并将它们完全集成到各种非接触式通信方法和协议中(13.56MHz)。

MFRC522的内部发送器部分可驱动读写器天线与ISO 14443A/MIFARE卡和应答机的通信,无需其它的电路。接收器部分提供一个功能强大和高效的解调和译码电路,用来处理兼容ISO 14443A/MIFARE的卡和应答机的信号。通信距离可达50mm,取决于天线的长度和调谐。数字电路部分处理完整的ISO 14443A帧和错误检测(奇偶&CRC)。

支持MIFARE标准器件,如S50、S70,UID卡,支持MIFARE Classic加密。支持MIFARE更高速的非接触式通信,双向数据传输速率高达424kbit/s。内部64字节的发送和接收FIFO缓冲区。10Mbit/s的SPI接口I2C接口,快速模式的速率为400kbit/s,高速模式的速率为3400kbit/s串行UART,传输速率高达1228.8kbit/s, 帧取决于RS232接口,电压电平取决于提供的管脚电压

本文将介绍ESP32开发板驱动MFRC522 RFID模块,读取RFID卡原始数据、获取RFID卡的UID,并将个人数据添加到RFID卡中。

ESP32开发板与MFRC522模块接线

下图为SPI通信接线图
在这里插入图片描述

ESP32MFRC522
GPIO5SDA引脚作为SPI通信时的CS片选
GPIO18SCK
GPIO23MOSI
GPIO19MISO
不接IRQ
GNDGND
GPIO21RST
3V33.3V

读取S50 IC白卡与S50 IC钥匙卡扣原始数据

Arduino IDE中安装RFID_MFRCC522驱动库
在这里插入图片描述

#include <MFRC522v2.h>#include <MFRC522DriverSPI.h>//#include <MFRC522DriverI2C.h>#include <MFRC522DriverPinSimple.h>#include <MFRC522Debug.h>// Learn more about using SPI/I2C or check the pin assigment for your board: https://github.com/OSSLibraries/Arduino_MFRC522v2#pin-layoutMFRC522DriverPinSimple ss_pin(5);MFRC522DriverSPI driver{ss_pin}; // Create SPI driver//MFRC522DriverI2C driver{};     // Create I2C driverMFRC522 mfrc522{driver};         // Create MFRC522 instancevoid setup() {
  Serial.begin(115200);  // Initialize serial communication
  while (!Serial);       // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4).
  
  mfrc522.PCD_Init();    // Init MFRC522 board.
  MFRC522Debug::PCD_DumpVersionToSerial(mfrc522, Serial);	// Show details of PCD - MFRC522 Card Reader details.
  Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks..."));}void loop() {
  // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
  if (!mfrc522.PICC_IsNewCardPresent()) {
    return;
  }

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

  // Dump debug info about the card; PICC_HaltA() is automatically called.
  MFRC522Debug::PICC_DumpToSerial(mfrc522, Serial, &(mfrc522.uid));

  delay(2000);}

程序中PICC表示IC卡(proximity integrated circuit cards)
PCD表示读写模块MFRC522(proximity coupling device)
编译上传程序到ESP32开发板 ,打开串口打印,把IC卡靠近MFRC522读写模块,可在串口上打印出IC内存储的数据
在这里插入图片描述
在这里插入图片描述
从串口打印出的信息可知道
IC卡的存储分布结构划分为16个(0-15)扇区,每个扇区包含4个(0-3)存储块,每个存储块包含16个字节的存储(0-15)

扇区0上的存储块0存储着IC卡的出厂信息,第0-4字节为UUID(如43 17 EE 05),一个校验字节,剩余的为出厂写入的数据。存储块0为只读模式,一般不可更改(部分克隆卡可修改)。

每个扇区的前3个存储块可用于存储数据,每个扇区的最后一个存储块为扇区尾块Sector Trailer。
每个扇区尾块固定为 16字节,其数据结构如下:

0~5 Key A(6字节),扇区的第一个访问密钥(默认通常为 FF FF FF FF FF FF 或厂商预设值)。

6~8 Access Bits(4字节),存储该扇区的访问权限控制位(实际只用了3字节,第9字节为备用)。

10~15 Key B(6字节),扇区的第二个访问密钥(可选,部分应用可能不用或与Key A相同)。

每个扇区的最后一个块是安全核心,决定了该扇区的访问规则。操作时务必谨慎,建议先读取并备份原始数据(需密钥验证),再尝试修改。

IC卡的类型为MIFARE 1KB 用户可用的净存储容量为:
16扇区 X 3存储块 X 16字节 - 16字节=752字节

UID为 43 17 EE 05 不同的卡的UID会不一样

读写用户数据到指定的存储块

#include <MFRC522v2.h>#include <MFRC522DriverSPI.h>//#include <MFRC522DriverI2C.h>#include <MFRC522DriverPinSimple.h>#include <MFRC522Debug.h>// Learn more about using SPI/I2C or check the pin assigment for your board: https://github.com/OSSLibraries/Arduino_MFRC522v2#pin-layoutMFRC522DriverPinSimple ss_pin(5);MFRC522DriverSPI driver{ss_pin}; // Create SPI driver//MFRC522DriverI2C driver{};     // Create I2C driverMFRC522 mfrc522{driver};         // Create MFRC522 instanceMFRC522::MIFARE_Key key;byte blockAddress = 2;byte newBlockData[17] = {"www.yourcee.com"};//byte newBlockData[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};   // CLEAR DATAbyte bufferblocksize = 18;byte blockDataRead[18];void setup() {
  Serial.begin(115200);  // Initialize serial communication
  while (!Serial);       // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4).
  
  mfrc522.PCD_Init();    // Init MFRC522 board.
  Serial.println(F("Warning: this example overwrites a block in your card, use with care!"));
 
  // Prepare key - all keys are set to FFFFFFFFFFFF at chip delivery from the factory.
  for (byte i = 0; i < 6; i++) {
    key.keyByte[i] = 0xFF;
  }}void loop() {
  // Check if a new card is present
  if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) {
    delay(500);
    return;
  }

  // Display card UID
  Serial.print("----------------\nCard UID: ");
  MFRC522Debug::PrintUID(Serial, (mfrc522.uid));
  Serial.println();

  // Authenticate the specified block using KEY_A = 0x60
  if (mfrc522.PCD_Authenticate(0x60, blockAddress, &key, &(mfrc522.uid)) != 0) {
    Serial.println("Authentication failed.");
    return;
  }
  
  // Write data to the specified block
  if (mfrc522.MIFARE_Write(blockAddress, newBlockData, 16) != 0) {
    Serial.println("Write failed.");
  } else {
    Serial.print("Data written successfully in block: ");
    Serial.println(blockAddress);
  }

  // Authenticate the specified block using KEY_A = 0x60
  if (mfrc522.PCD_Authenticate(0x60, blockAddress, &key, &(mfrc522.uid)) != 0) {
    Serial.println("Authentication failed.");
    return;
  }

  // Read data from the specified block
  if (mfrc522.MIFARE_Read(blockAddress, blockDataRead, &bufferblocksize) != 0) {
    Serial.println("Read failed.");
  } else {
    Serial.println("Read successfully!");
    Serial.print("Data in block ");
    Serial.print(blockAddress);
    Serial.print(": ");
    for (byte i = 0; i < 16; i++) {
      Serial.print((char)blockDataRead[i]);  // Print as character
    }
    Serial.println();
  }
  
  // Halt communication with the card
  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();

  delay(2000);  // Delay for readability}

byte blockAddress = 2;
定义了一个名为blockAddress的变量。这个变量指定了IC卡内将要写入或读取数据的块。blockAddress被设置为2,将与卡片内存的第2个块进行交互。如果你想写入不同的块,你可以更改这个值。

byte newBlockData[17] = {“www.yourcee.com”};
保存您想要写入卡中的数据,不超过16个字节

byte newBlockData[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
如果您想清除块数据,取消注释这行代码

for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
IC卡的默认密钥也在以上行中设置。默认情况下,工厂密钥的所有字节都是0xFF。这个密钥允许访问卡的数据块。

if (mfrc522.PCD_Authenticate(0x60, blockAddress, &key, &(mfrc522.uid)) != 0) {
Serial.println(“Authentication failed.”);
return;
}
代码尝试使用默认密钥(在本例中为块2)对卡片上的特定块进行认证。0x60是一个指定使用KEY_A进行认证的命令。KEY_A是RFID卡上可用的两个密钥(KEY_A和KEY_B)之一,每个密钥提供不同的权限。使用0x60意味着代码正在尝试用KEY_A进行认证,而默认情况下,在MIFARE RFID卡上KEY_A是0xFF 0xFF 0xFF 0xFF 0xFF。

编译上传程序到ESP32开发板 ,打开串口监视器,并把IC卡 靠近MFRC522读写模块,串口显示出写入并读取到指定存储块的数据
在这里插入图片描述

总结

本实验只是对空白的MIFARE Classic IC卡进行简单的读写验证,由于IC卡大都有秘钥,至于破解IC卡,复制C卡需要大家进一步探索研究了。


*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客