esp32s3,读取RFID标签里面的数据

writeMifareClassicMemory()- 针对MIFARE Classic卡片

MIFARE Classic按照扇区进行读写,这种标签需要秘钥进行读写

每个扇区(Sector)包含:

  • 块0-2:数据块(16字节/块)

  • 块3:控制块(包含密钥A、访问控制位、密钥B)

  • 总共16个扇区(MIFARE 1K)

总共64个扇区

writeMifareUltralightMemory()- 针对MIFARE Ultralight卡片,这种标签不需要秘钥

  • 页0-3:系统页(包含UID、锁定位)

  • 页4-39:用户数据页(4字节/页)

  • 总共40页,每个页4字节

卡片页数是否可读写是按照页数2的数据进行判断的如页数2的数据是 9B 48 00 00(16进制,4字节) 从左到右,1代表连续两个页不可写,0代表连续的两个页可写,所以要读写这一类型的卡片,需要先读数据,确定哪些页是可以读写的。

代码如下

复制代码
#include <SPI.h>
#include <MFRC522.h>

// ESP32-S3引脚定义
// 请根据你的实际接线修改以下引脚
#define RST_PIN  9    // 复位引脚,根据你的连接修改
#define SS_PIN   10   // 片选引脚,根据你的连接修改

MFRC522 mfrc522(SS_PIN, RST_PIN);

// 默认密钥(通常用于MIFARE Classic卡片)
MFRC522::MIFARE_Key key;

// 要写入的数据
String writeData = "HELLO";
int mode = 1; // 1=读取模式, 2=写入模式

void setup() {
    Serial.begin(115200);
    Serial.println("ESP32-S3 RC522 RFID读写程序");
    Serial.println("输入命令:");
    Serial.println("  1 - 读取RFID标签");
    Serial.println("  2 - 写入'HELLO'到RFID标签(20-25页)");
    Serial.println("当前模式: 读取模式");
    
    // 初始化SPI
    SPI.begin();  // 使用默认SPI引脚
    
    // 初始化RC522
    mfrc522.PCD_Init();
    
    // 设置天线增益(可选)
    mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_38dB);
    
    // 准备默认密钥
    for (byte i = 0; i < 6; i++) {
        key.keyByte[i] = 0xFF;  // 默认密钥通常是FF FF FF FF FF FF
    }
    
    // 显示RC522版本信息
    byte version = mfrc522.PCD_ReadRegister(MFRC522::VersionReg);
    Serial.print("MFRC522版本: 0x");
    Serial.print(version, HEX);
    if (version == 0x91) {
        Serial.println(" = v1.0");
    } else if (version == 0x92) {
        Serial.println(" = v2.0");
    } else if (version == 0x88) {
        Serial.println(" = CLONE 0x88");
    } else if (version == 0x90) {
        Serial.println(" = CLONE 0x90");
    } else {
        Serial.println(" (未知)");
    }
    
    Serial.println("RC522初始化完成,等待卡片...");
    Serial.println("注意:如果无法读取卡片,请检查SPI引脚连接是否正确");
}

void loop() {
    // 检查串口输入
    if (Serial.available()) {
        char input = Serial.read();
        
        if (input == '1') {
            mode = 1;
            Serial.println("模式切换为: 读取模式");
        } else if (input == '2') {
            mode = 2;
            Serial.println("模式切换为: 写入模式");
            Serial.println("准备写入数据: 'HELLO' (20-25页)");
            Serial.println("请放置要写入的RFID标签...");
        } else if (input == '\n' || input == '\r') {
            // 忽略换行符
        } else {
            Serial.print("未知命令: '");
            Serial.print(input);
            Serial.println("'");
            Serial.println("可用命令: 1=读取, 2=写入");
        }
    }
    
    // 检查是否有新卡片
    if (!mfrc522.PICC_IsNewCardPresent()) {
        delay(50);
        return;
    }
    
    // 选择一张卡片
    if (!mfrc522.PICC_ReadCardSerial()) {
        delay(50);
        return;
    }
    
    Serial.println("\n=== 检测到RFID标签 ===");
    
    // 显示UID
    Serial.print("UID值(HEX): ");
    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.println();
    
    // 显示卡片类型
    MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
    Serial.print("卡片类型: ");
    Serial.println(mfrc522.PICC_GetTypeName(piccType));
    
    // 根据模式执行读取或写入操作
    if (mode == 1) {
        // 读取模式
        Serial.println("执行读取操作...");
        
        // 根据卡片类型读取内存
        switch (piccType) {
            case MFRC522::PICC_TYPE_MIFARE_MINI:
            case MFRC522::PICC_TYPE_MIFARE_1K:
            case MFRC522::PICC_TYPE_MIFARE_4K:
                Serial.println("读取MIFARE Classic卡片内存:");
                readMifareClassicMemory();
                break;
                
            case MFRC522::PICC_TYPE_MIFARE_UL:
                Serial.println("读取MIFARE Ultralight卡片内存:");
                readMifareUltralightMemory();
                break;
                
            case MFRC522::PICC_TYPE_ISO_14443_4:
            case MFRC522::PICC_TYPE_ISO_18092:
            case MFRC522::PICC_TYPE_MIFARE_DESFIRE:
                Serial.println("此卡片类型需要特殊协议,无法直接读取所有内存");
                break;
                
            default:
                Serial.println("未知或不受支持的卡片类型");
                break;
        }
    } else if (mode == 2) {
        // 写入模式
        Serial.println("执行写入操作...");
        Serial.print("写入数据: '");
        Serial.print(writeData);
        Serial.println("' (20-25页)");
        
        // 根据卡片类型写入内存
        switch (piccType) {
            case MFRC522::PICC_TYPE_MIFARE_MINI:
            case MFRC522::PICC_TYPE_MIFARE_1K:
            case MFRC522::PICC_TYPE_MIFARE_4K:
                Serial.println("写入到MIFARE Classic卡片...");
                writeMifareClassicMemory();
                break;
                
            case MFRC522::PICC_TYPE_MIFARE_UL:
                Serial.println("写入到MIFARE Ultralight卡片...");
                writeMifareUltralightMemory();
                break;
                
            case MFRC522::PICC_TYPE_ISO_14443_4:
            case MFRC522::PICC_TYPE_ISO_18092:
            case MFRC522::PICC_TYPE_MIFARE_DESFIRE:
                Serial.println("此卡片类型不支持直接写入");
                break;
                
            default:
                Serial.println("未知或不受支持的卡片类型");
                break;
        }
        
        // 写入完成后自动切换回读取模式
        mode = 1;
        Serial.println("写入完成,已自动切换回读取模式");
    }
    
    // 使卡片进入休眠状态
    mfrc522.PICC_HaltA();
    mfrc522.PCD_StopCrypto1();
    
    Serial.println("==================================");
    delay(1000);
}

// 读取MIFARE Classic类型卡片的内存
void readMifareClassicMemory() {
    MFRC522::StatusCode status;
    byte buffer[18];
    byte size = sizeof(buffer);
    
    // 计算扇区数量
    byte no_of_sectors = 16;  // MIFARE 1K默认有16个扇区
    if (mfrc522.uid.sak == 0x18) {  // MIFARE 4K
        no_of_sectors = 40;
    }
    
    Serial.println("扇区\t块\t数据(十六进制)\t\t\t\t数据(ASCII)");
    Serial.println("----------------------------------------------------------------");
    
    for (byte sector = 0; sector < no_of_sectors; sector++) {
        for (byte block = 0; block < 4; block++) {
            // 计算绝对块地址
            byte absoluteBlock = (sector * 4) + block;
            
            // 每个扇区的最后一个块是控制块,不进行认证读取
            if (block == 3) {
                Serial.print("扇区 ");
                Serial.print(sector, DEC);
                Serial.print(" 块 ");
                Serial.print(block, DEC);
                Serial.println(": [控制块,跳过]");
                continue;
            }
            
            // 认证当前扇区
            status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 
                                            absoluteBlock, &key, &(mfrc522.uid));
            if (status != MFRC522::STATUS_OK) {
                Serial.print("扇区 ");
                Serial.print(sector, DEC);
                Serial.print(" 认证失败: ");
                Serial.println(mfrc522.GetStatusCodeName(status));
                break;  // 当前扇区认证失败,跳过该扇区
            }
            
            // 读取数据块
            status = mfrc522.MIFARE_Read(absoluteBlock, buffer, &size);
            if (status != MFRC522::STATUS_OK) {
                Serial.print("扇区 ");
                Serial.print(sector, DEC);
                Serial.print(" 块 ");
                Serial.print(block, DEC);
                Serial.print(" 读取失败: ");
                Serial.println(mfrc522.GetStatusCodeName(status));
                continue;
            }
            
            // 显示读取的数据
            Serial.print(sector, DEC);
            Serial.print("\t");
            Serial.print(block, DEC);
            Serial.print("\t");
            
            // 显示十六进制数据
            for (byte i = 0; i < 16; i++) {
                if (buffer[i] < 0x10) {
                    Serial.print("0");
                }
                Serial.print(buffer[i], HEX);
                Serial.print(" ");
            }
            
            Serial.print("\t");
            
            // 显示ASCII数据
            for (byte i = 0; i < 16; i++) {
                if (buffer[i] < 32 || buffer[i] > 126) {  // 不可打印字符
                    Serial.print(".");
                } else {
                    Serial.print((char)buffer[i]);
                }
            }
            Serial.println();
        }
    }
}

// 读取MIFARE Ultralight类型卡片的内存
void readMifareUltralightMemory() {
    MFRC522::StatusCode status;
    byte buffer[18];
    byte size = sizeof(buffer);
    
    Serial.println("页\t数据(十六进制)\t\t\t数据(ASCII)");
    Serial.println("------------------------------------------------");
    
    // Ultralight卡片通常有16页,每页4字节
    // 但有些卡片可能有更多页,这里读取0-39页
    for (byte page = 0; page < 40; page++) {
        // 跳过前4页(包含UID和锁定位)
        if (page < 4) {
            Serial.print(page, DEC);
            Serial.print("\t[系统页,跳过]");
            Serial.println();
            continue;
        }
        
        // 检查页数是否有效
        if (page >= 40) {  // 如果卡片没有这么多页,可能会读取失败
            break;
        }
        
        // 读取页
        status = mfrc522.MIFARE_Read(page, buffer, &size);
        if (status != MFRC522::STATUS_OK) {
            Serial.print("页 ");
            Serial.print(page, DEC);
            Serial.print(" 读取失败: ");
            Serial.println(mfrc522.GetStatusCodeName(status));
            continue;
        }
        
        // 显示页号和数据
        Serial.print(page, DEC);
        Serial.print("\t");
        
        // 显示十六进制数据
        for (byte i = 0; i < 4; i++) {
            if (buffer[i] < 0x10) {
                Serial.print("0");
            }
            Serial.print(buffer[i], HEX);
            Serial.print(" ");
        }
        
        // 填充对齐
        Serial.print("\t\t");
        
        // 显示ASCII数据
        for (byte i = 0; i < 4; i++) {
            if (buffer[i] < 32 || buffer[i] > 126) {  // 不可打印字符
                Serial.print(".");
            } else {
                Serial.print((char)buffer[i]);
            }
        }
        Serial.println();
    }
}

// 写入数据到MIFARE Classic卡片
void writeMifareClassicMemory() {
    MFRC522::StatusCode status;
    
    // 选择扇区0的块1进行写入(块0是UID,块3是控制块)
    byte blockAddr = 1;  // 扇区0的块1
    
    // 认证当前扇区
    status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 
                                     blockAddr, &key, &(mfrc522.uid));
    if (status != MFRC522::STATUS_OK) {
        Serial.print("认证失败: ");
        Serial.println(mfrc522.GetStatusCodeName(status));
        return;
    }
    
    // 准备要写入的数据
    byte dataBuffer[16];
    
    // 清空缓冲区
    for (byte i = 0; i < 16; i++) {
        dataBuffer[i] = 0;
    }
    
    // 复制"HELLO"到缓冲区
    writeData.getBytes(dataBuffer, 16);
    
    // 写入数据
    status = mfrc522.MIFARE_Write(blockAddr, dataBuffer, 16);
    if (status != MFRC522::STATUS_OK) {
        Serial.print("写入失败: ");
        Serial.println(mfrc522.GetStatusCodeName(status));
        return;
    }
    
    Serial.print("写入成功! 数据已写入到块 ");
    Serial.println(blockAddr, DEC);
    
    // 验证写入的数据
    byte readBuffer[18];
    byte size = sizeof(readBuffer);
    
    status = mfrc522.MIFARE_Read(blockAddr, readBuffer, &size);
    if (status != MFRC522::STATUS_OK) {
        Serial.print("验证读取失败: ");
        Serial.println(mfrc522.GetStatusCodeName(status));
        return;
    }
    
    Serial.print("验证读取的数据: ");
    for (byte i = 0; i < 5; i++) {  // 只显示前5个字节
        if (readBuffer[i] >= 32 && readBuffer[i] <= 126) {
            Serial.print((char)readBuffer[i]);
        } else {
            Serial.print(".");
        }
    }
    Serial.println();
}

// 写入数据到MIFARE Ultralight卡片
void writeMifareUltralightMemory() {
    MFRC522::StatusCode status;
    
    // 修改:写入20-25页,共6页
    byte startPage = 20;  // 从第20页开始写入
    byte endPage = 25;    // 写入到第25页
    byte pagesCount = endPage - startPage + 1;  // 总共6页
    
    Serial.print("写入范围: 第");
    Serial.print(startPage, DEC);
    Serial.print("页到第");
    Serial.print(endPage, DEC);
    Serial.print("页 (共");
    Serial.print(pagesCount, DEC);
    Serial.println("页)");
    
    // 检查卡片是否有足够的页
    if (endPage >= 40) {  // 假设卡片最多有40页
        Serial.println("错误: 卡片页数不足!");
        return;
    }
    
    // 准备要写入的数据
    // 每页4字节,总共6页 = 24字节
    byte dataBuffer[24];  // 6页 * 4字节/页 = 24字节
    
    // 清空缓冲区
    for (byte i = 0; i < 24; i++) {
        dataBuffer[i] = 0;
    }
    
    // 复制"HELLO"到缓冲区的前5个字节
    writeData.getBytes(dataBuffer, 5);
    
    // 在数据后添加结束符'\0' (可选)
    dataBuffer[4] = 'O';
    dataBuffer[5] = '\0';
    
    // 在数据中添加一些额外信息
    dataBuffer[6] = 'R';
    dataBuffer[7] = 'F';
    dataBuffer[8] = 'I';
    dataBuffer[9] = 'D';
    
    // 写入时间戳或版本信息
    dataBuffer[10] = 0x01;  // 版本1
    dataBuffer[11] = 0x00;  // 保留
    
    // 显示要写入的数据
    Serial.print("要写入的数据(HEX): ");
    for (byte i = 0; i < 24; i++) {
        if (dataBuffer[i] < 0x10) {
            Serial.print("0");
        }
        Serial.print(dataBuffer[i], HEX);
        Serial.print(" ");
    }
    Serial.println();
    
    Serial.print("要写入的数据(ASCII): ");
    for (byte i = 0; i < 12; i++) {  // 只显示前12个字节
        if (dataBuffer[i] >= 32 && dataBuffer[i] <= 126) {
            Serial.print((char)dataBuffer[i]);
        } else if (dataBuffer[i] == 0) {
            Serial.print("\\0");
        } else {
            Serial.print(".");
        }
    }
    Serial.println();
    
    // 写入数据到20-25页
    Serial.println("开始写入...");
    bool writeSuccess = true;
    
    for (byte page = 0; page < pagesCount; page++) {
        byte currentPage = startPage + page;
        byte dataOffset = page * 4;  // 每页4字节
        
        // 写入当前页,20页开始写
        status = mfrc522.MIFARE_Ultralight_Write(currentPage, &dataBuffer[dataOffset], 4);
        
        if (status != MFRC522::STATUS_OK) {
            Serial.print("写入第 ");
            Serial.print(currentPage, DEC);
            Serial.print(" 页失败: ");
            Serial.println(mfrc522.GetStatusCodeName(status));
            writeSuccess = false;
            break;
        }
        
        Serial.print("成功写入第 ");
        Serial.print(currentPage, DEC);
        Serial.println(" 页");
        
        // 添加延迟,避免写入过快
        delay(10);
    }
    
    if (!writeSuccess) {
        Serial.println("写入过程中发生错误!");
        return;
    }
    
    Serial.print("写入成功! 数据已写入到第 ");
    Serial.print(startPage, DEC);
    Serial.print(" 页到第 ");
    Serial.print(endPage, DEC);
    Serial.println(" 页");
    
    // 验证写入的数据
    byte readBuffer[18];
    byte size = sizeof(readBuffer);
    
    Serial.println("\n验证写入的数据:");
    Serial.println("页\t数据(十六进制)\t\t数据(ASCII)");
    Serial.println("----------------------------------------");
    
    for (byte page = 0; page < pagesCount; page++) {
        byte currentPage = startPage + page;
        
        status = mfrc522.MIFARE_Read(currentPage, readBuffer, &size);
        if (status != MFRC522::STATUS_OK) {
            Serial.print("第 ");
            Serial.print(currentPage, DEC);
            Serial.print(" 页验证读取失败: ");
            Serial.println(mfrc522.GetStatusCodeName(status));
            continue;
        }
        
        // 显示页号和数据
        Serial.print(currentPage, DEC);
        Serial.print("\t");
        
        // 显示十六进制
        for (byte i = 0; i < 4; i++) {
            if (readBuffer[i] < 0x10) {
                Serial.print("0");
            }
            Serial.print(readBuffer[i], HEX);
            Serial.print(" ");
        }
        
        Serial.print("\t");
        
        // 显示ASCII
        for (byte i = 0; i < 4; i++) {
            if (readBuffer[i] >= 32 && readBuffer[i] <= 126) {
                Serial.print((char)readBuffer[i]);
            } else if (readBuffer[i] == 0) {
                Serial.print("\\0");
            } else {
                Serial.print(".");
            }
        }
        Serial.println();
    }
    
    // 验证原始数据
    Serial.println("\n原始数据验证:");
    bool verificationPassed = true;
    
    for (byte page = 0; page < pagesCount; page++) {
        byte currentPage = startPage + page;
        byte dataOffset = page * 4;
        
        status = mfrc522.MIFARE_Read(currentPage, readBuffer, &size);
        if (status != MFRC522::STATUS_OK) {
            Serial.print("第 ");
            Serial.print(currentPage, DEC);
            Serial.println(" 页读取失败,验证未通过");
            verificationPassed = false;
            continue;
        }
        
        // 比较数据
        for (byte i = 0; i < 4; i++) {
            if (readBuffer[i] != dataBuffer[dataOffset + i]) {
                Serial.print("第 ");
                Serial.print(currentPage, DEC);
                Serial.print(" 页第 ");
                Serial.print(i, DEC);
                Serial.print(" 字节不匹配: 期望=0x");
                Serial.print(dataBuffer[dataOffset + i], HEX);
                Serial.print(", 实际=0x");
                Serial.println(readBuffer[i], HEX);
                verificationPassed = false;
            }
        }
    }
    
    if (verificationPassed) {
        Serial.println("数据验证通过!");
    } else {
        Serial.println("数据验证失败!");
    }
}
相关推荐
清月电子2 小时前
杰理AC109N系列AC1082 AC1074 AC1090 芯片停产替代及资料说明
人工智能·单片机·嵌入式硬件·物联网
智嵌电子2 小时前
【笔记篇】【硬件基础篇】模拟电子技术基础 (童诗白) 第10章 模拟电子电路读图
笔记·单片机·嵌入式硬件
一颗青果3 小时前
51单片机 计算指令
单片机·嵌入式硬件·51单片机
一路往蓝-Anbo3 小时前
【第20期】延时的艺术:HAL_Delay vs vTaskDelay
c语言·数据结构·stm32·单片机·嵌入式硬件
LCG米5 小时前
低功耗设计艺术:基于STM32U3系列MCU实现人类存在检测(仅6%占空比)
stm32·单片机·嵌入式硬件
zd8451015005 小时前
[LWIP] 如何启LWIP用调试信息输出
单片机
v先v关v住v获v取6 小时前
桌面级五轴机械臂cad1张总图+三维图+设计说明书
科技·单片机·51单片机
电子工程师-C516 小时前
基于51单片机的智能调温淋浴器
单片机·嵌入式硬件·51单片机
番茄灭世神7 小时前
32位ARM单片机视频教程第一篇
arm开发·单片机·嵌入式·gd32·pn学堂