美文网首页ESP32ESP32
ESP32学习笔记(49)——RFID RC522使用

ESP32学习笔记(49)——RFID RC522使用

作者: Leung_ManWah | 来源:发表于2022-05-30 14:22 被阅读0次

    一、简介

    MF RC522 是应用于 13.56MHz 非接触式通信中高集成度读写卡系列芯片中的一员。是 NXP 公司针对“三表”应用推出的一款低电压、低成本、体积小的非接触式读写卡芯片,是智能仪表和便携式手持设备研发的较好选择。

    MFRC522数据手册: https://pan.baidu.com/s/10v68Z7sCFFSwPgrZ2eHtXw?pwd=d4fw 提取码:d4fw

    二、硬件连接

    功能口 引脚
    MISO 19
    MOSI 23
    SCLK 18
    CS 5
    RST 25

    三、添加SPI驱动

    查看 ESP32学习笔记(19)——SPI(主机)接口使用

    四、工程代码

    百度网盘:https://pan.baidu.com/s/1gCtsGrn28ZfV1OinTolJPw?pwd=d3po 提取码:d3po

    将文件解压到 esp-idf/examples 目录下:


    4.1 board_gpio.c

    /*********************************************************************
     * INCLUDES
     */
    #include "driver/gpio.h"
    
    #include "board_gpio.h"
    
    /*********************************************************************
     * PUBLIC FUNCTIONS
     */
    /**
     @brief NFC复位引脚初始化
     @param 无
     @return 无
    */
    void NFC_GPIO_Init(void)
    {
        gpio_pad_select_gpio(NFC_RST_GPIO_PIN);                 // 选择一个GPIO
        gpio_set_direction(NFC_RST_GPIO_PIN, GPIO_MODE_OUTPUT); // 把这个GPIO作为输出
    
        NFC_GPIO_Write(NFC_RST_HIGH);
    }
    
    /**
     @brief 配置NFC复位引脚工作模式
     @param mode -[in] 工作模式
     @return 无
    */
    void NFC_GPIO_Write(uint8_t mode)
    {
        gpio_set_level(NFC_RST_GPIO_PIN, mode);
    }
    

    4.2 board_gpio.h

    #ifndef _BOARD_GPIO_H_
    #define _BOARD_GPIO_H_
    
    /*********************************************************************
     * INCLUDES
     */
    #include "driver/gpio.h"
    
    /*********************************************************************
     * DEFINITIONS
     */
    #define NFC_RST_GPIO_PIN                GPIO_NUM_25         // NFC复位
    #define NFC_RST_LOW                     0x00
    #define NFC_RST_HIGH                    0x01
    
    /*********************************************************************
     * API FUNCTIONS
     */
    void NFC_GPIO_Init(void);
    void NFC_GPIO_Write(uint8_t mode);
    
    #endif /* _BOARD_GPIO_H_ */
    

    4.3 board_spi.c

    /*********************************************************************
     * INCLUDES
     */
    #include <string.h>
    #include "driver/spi_master.h"
    
    #include "board_spi.h"
    
    /*********************************************************************
     * LOCAL VARIABLES
     */
    static spi_device_handle_t s_spiHandle;
    
    /*********************************************************************
     * PUBLIC FUNCTIONS
     */
    /**
     @brief NFC SPI驱动初始化
     @param 无
     @return 无
    */
    void NFC_SPI_Init(void)
    {
        esp_err_t ret;
        
        spi_bus_config_t spiBusConfig =
        {
            .miso_io_num = NFC_SPI_MISO_PIN,                    // MISO信号线
            .mosi_io_num = NFC_SPI_MOSI_PIN,                    // MOSI信号线
            .sclk_io_num = NFC_SPI_SCLK_PIN,                    // SCLK信号线
            .quadwp_io_num = -1,                                // WP信号线,专用于QSPI的D2
            .quadhd_io_num = -1,                                // HD信号线,专用于QSPI的D3
            .max_transfer_sz = 64 * 8,                          // 最大传输数据大小
        };
    
        spi_device_interface_config_t spiDeviceConfig =
        {
            .clock_speed_hz = SPI_MASTER_FREQ_10M,              // Clock out at 10 MHz,
            .mode = 0,                                          // SPI mode 0
            /*
             * The timing requirements to read the busy signal from the EEPROM cannot be easily emulated
             * by SPI transactions. We need to control CS pin by SW to check the busy signal manually.
             */
            .spics_io_num = -1,
            .queue_size = 7,                                    // 传输队列大小,决定了等待传输数据的数量
        };
    
        //Initialize the SPI bus
        ret = spi_bus_initialize(SPI3_HOST, &spiBusConfig, DMA_CHAN);
        ESP_ERROR_CHECK(ret);
        ret = spi_bus_add_device(SPI3_HOST, &spiDeviceConfig, &s_spiHandle);
        ESP_ERROR_CHECK(ret);
    
        // 配置CS引脚
        gpio_pad_select_gpio(NFC_SPI_CS_PIN);                   // 选择一个GPIO
        gpio_set_direction(NFC_SPI_CS_PIN, GPIO_MODE_OUTPUT);   // 把这个GPIO作为输出
    }
    
    /**
     @brief NFC SPI写入数据
     @param pData -[in] 写入数据
     @param dataLen -[in] 写入数据长度
     @return 无
    */
    void NFC_SPI_Write(uint8_t *pData, uint32_t dataLen)
    {
        esp_err_t ret;
        spi_transaction_t t;
        if(0 == dataLen)                                        // no need to send anything
        {
            return;
        }
    
        memset(&t, 0, sizeof(t));                               // Zero out the transaction
        t.length = dataLen * 8;                                 // Len is in bytes, transaction length is in bits.
        t.tx_buffer = pData;                                    // Data
        ret = spi_device_polling_transmit(s_spiHandle, &t);     // Transmit!
        assert(ret == ESP_OK);                                  // Should have had no issues.
    }
    
    /**
     @brief NFC SPI读取数据
     @param pData -[out] 读取数据
     @param dataLen -[in] 读取数据长度
     @return 无
    */
    void NFC_SPI_Read(uint8_t *pData, uint32_t dataLen)
    {
        spi_transaction_t t;
        if(0 == dataLen)                                        // no need to receivce anything
        {
            return;
        }
    
        memset(&t, 0, sizeof(t));                               // Zero out the transaction
        t.length = dataLen * 8;                                 // Len is in bytes, transaction length is in bits.
        t.rx_buffer = pData;
        esp_err_t ret = spi_device_polling_transmit(s_spiHandle, &t);
        assert(ret == ESP_OK);
    }
    
    /****************************************************END OF FILE****************************************************/
    

    4.4 board_spi.h

    #ifndef _BOARD_SPI_H_
    #define _BOARD_SPI_H_
    
    /*********************************************************************
     * INCLUDES
     */
    #include "driver/gpio.h"
    
    /*********************************************************************
     * DEFINITIONS
     */
    #define NFC_SPI_MISO_PIN        GPIO_NUM_19
    #define NFC_SPI_MOSI_PIN        GPIO_NUM_23
    #define NFC_SPI_SCLK_PIN        GPIO_NUM_18
    #define NFC_SPI_CS_PIN          GPIO_NUM_5
    
    #define DMA_CHAN                2
    
    #define SPI_CS_LOW              gpio_set_level(NFC_SPI_CS_PIN, 0)
    #define SPI_CS_HIGH             gpio_set_level(NFC_SPI_CS_PIN, 1)
    
    /*********************************************************************
     * API FUNCTIONS
     */
    void NFC_SPI_Init(void);
    void NFC_SPI_Write(uint8_t *pData, uint32_t dataLen);
    void NFC_SPI_Read(uint8_t *pData, uint32_t dataLen);
    
    #endif /* _BOARD_SPI_H_ */
    

    4.5 board_mfrc522.c

    /*********************************************************************
     * INCLUDES
     */
    #include <string.h>
    #include "freertos/FreeRTOS.h"
    #include "freertos/task.h"
    #include "esp_log.h"
    
    #include "board_gpio.h"
    #include "board_spi.h"
    #include "board_mfrc522.h"
    
    static char pcdRequest(uint8_t reqCode, uint8_t *pTagType);
    static char pcdAnticoll(uint8_t *pSnr);
    static char pcdSelect(uint8_t *pSnr);
    static char pcdAuthState(uint8_t authMode, uint8_t addr, uint8_t *pKey, uint8_t *pSnr);
    static char pcdRead(uint8_t addr, uint8_t *pData);
    static char pcdWrite(uint8_t addr, uint8_t *pData);
    static void pcdReset(void);
    static void calulateCRC(uint8_t *pInData, uint8_t len, uint8_t *pOutData);
    static char pcdComMF522(uint8_t command, uint8_t *pInData, uint8_t inLenByte, uint8_t *pOutData, uint32_t *pOutLenBit);
    static void pcdAntennaOn(void);
    static void pcdAntennaOff(void);
    static void setBitMask(uint8_t reg, uint8_t mask);
    static void clearBitMask(uint8_t reg, uint8_t mask);
    static uint8_t readRawRc(uint8_t addr);
    static void writeRawRc(uint8_t addr, uint8_t writeData);
    static void delayMs(uint8_t time);
    
    /*********************************************************************
     * LOCAL VARIABLES
     */
    static uint8_t s_cardType[2];                                                   // 卡类型
    static uint8_t s_cardSerialNo[4];                                               // 卡序列号
    static uint8_t s_defaultKeyA[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};         // 默认密码A
    
    static const char *TAG = "MFRC522";
    
    /*********************************************************************
     * PUBLIC FUNCTIONS
     */
    /**
     @brief MFRC522的初始化函数
     @param 无
     @return 无
    */
    void MFRC522_Init(void)
    {
        pcdReset();                                 // 复位
        delayMs(5);
            ESP_LOGI(TAG, "reg: %02x" ,readRawRc(Status1Reg));
            ESP_LOGI(TAG, "reg: %02x" ,readRawRc(Status2Reg));
            ESP_LOGI(TAG, "reg: %02x" ,readRawRc(WaterLevelReg));
        pcdAntennaOn();                             // 开启天线发射
    }
    
    /**
     @brief MFRC522读取卡片块数据
     @param addr -[in] 块地址
     @return 状态值,0 - 成功;2 - 无卡;3 - 防冲撞失败;4 - 选卡失败;5 - 密码错误
    */
    uint8_t MFRC522_ReadCardDataBlock(uint8_t addr)
    {
        memset(s_cardSerialNo, 0, 4);
    
        if(pcdRequest(PICC_REQALL, s_cardType) == MI_OK)
        {
        }
        else
        {
            ESP_LOGI(TAG, "ERR: 2");
            return 2;                               // 无卡
        }
    
        if(pcdAnticoll(s_cardSerialNo) == MI_OK)
        {
        }
        else
        {
            ESP_LOGI(TAG, "ERR: 3");
            return 3;                               // 防冲撞失败
        }
    
        if(pcdSelect(s_cardSerialNo) == MI_OK)
        {
        }
        else
        {
            ESP_LOGI(TAG, "ERR: 4");
            return 4;                               // 选卡失败
        }
    
        if(pcdAuthState(0x60, addr, s_defaultKeyA, s_cardSerialNo) == MI_OK)
        {
            ESP_LOGI(TAG, "ERR: 0");
            return 0;
        }
        else
        {
            ESP_LOGI(TAG, "ERR: 5");
            return 5;                               // 密码错误
        }
    }
    
    /**
     @brief 读取卡片序列号
     @param pCardSerialNo -[out] 卡片序列号
     @return 0 - 读卡成功;2 - 无卡
    */
    uint8_t MFRC522_ReadCardSerialNo(uint8_t *pCardSerialNo)
    {
        uint8_t status = MFRC522_ReadCardDataBlock(4);          
        memcpy(pCardSerialNo, s_cardSerialNo, 4);
        return status;
    }
    
    
    /*********************************************************************
     * LOCAL FUNCTIONS
     */
    /**
     @brief 寻卡
     @param reqCode -[in] 寻卡方式,0x52 寻感应区内所有符合1443A标准的卡,0x26 寻未进入休眠状态的卡
     @param pTagType -[out] 卡片类型代码
                            0x4400 = Mifare_UltraLight
                            0x0400 = Mifare_One(S50)
                            0x0200 = Mifare_One(S70)
                            0x0800 = Mifare_Pro(X)
                            0x4403 = Mifare_DESFire
     @return 状态值,MI OK - 成功;MI_ERR - 失败
    */
    static char pcdRequest(uint8_t reqCode, uint8_t *pTagType)
    {
        char status;
        uint32_t len;
        uint8_t comMF522Buf[MAXRLEN];
    
        clearBitMask(Status2Reg, 0x08);
        writeRawRc(BitFramingReg, 0x07);
        setBitMask(TxControlReg, 0x03);
    
        comMF522Buf[0] = reqCode;
    
        status = pcdComMF522(PCD_TRANSCEIVE, comMF522Buf, 1, comMF522Buf, &len);    // 发送并接收数据
        if((status == MI_OK) && (len == 0x10))
        {
            ESP_LOGI(TAG, "mi_ok");
            *pTagType = comMF522Buf[0];
            *(pTagType+1) = comMF522Buf[1];
        }
        else
        {
            ESP_LOGI(TAG, "mi_err");
            status = MI_ERR;
        }
    
        return status;
    }
    
    /**
     @brief 防冲撞
     @param pSnr -[out] 卡片序列号,4字节
     @return 状态值,MI OK - 成功;MI_ERR - 失败
    */
    static char pcdAnticoll(uint8_t *pSnr)
    {
        char status;
        uint8_t i, snrCheck = 0;
        uint32_t len;
        uint8_t comMF522Buf[MAXRLEN];
    
        clearBitMask(Status2Reg, 0x08);             // 寄存器包含接收器和发送器和数据模式检测器的状态标志
        writeRawRc(BitFramingReg, 0x00);            // 不启动数据发送,接收的LSB位存放在位0,接收到的第二位放在位1,定义发送的最后一个字节位数为8
        clearBitMask(CollReg, 0x80);                // 所有接收的位在冲突后将被清除
    
        comMF522Buf[0] = PICC_ANTICOLL1;
        comMF522Buf[1] = 0x20;
    
        status = pcdComMF522(PCD_TRANSCEIVE, comMF522Buf, 2, comMF522Buf, &len);
    
        if(status == MI_OK)
        {
            for(i = 0; i < 4; i++)
            {
                *(pSnr + i) = comMF522Buf[i];
                snrCheck ^= comMF522Buf[i];
            }
            if(snrCheck != comMF522Buf[i])          // 返回四个字节,最后一个字节为校验位
            {
                status = MI_ERR;
            }
        }
    
        setBitMask(CollReg, 0x80);
    
        return status;
    }
    
    /**
     @brief 选定卡片
     @param pSnr -[in] 卡片序列号,4字节
     @return 状态值,MI OK - 成功;MI_ERR - 失败
    */
    static char pcdSelect(uint8_t *pSnr)
    {
        char status;
        uint8_t i;
        uint8_t comMF522Buf[MAXRLEN];
        uint32_t len;
    
        comMF522Buf[0] = PICC_ANTICOLL1;
        comMF522Buf[1] = 0x70;
        comMF522Buf[6] = 0;
    
        for(i = 0; i < 4; i++)
        {
            comMF522Buf[i + 2] = *(pSnr + i);
            comMF522Buf[6] ^= *(pSnr + i);
        }
    
        calulateCRC(comMF522Buf, 7, &comMF522Buf[7]);
    
        clearBitMask(Status2Reg, 0x08);
    
        status = pcdComMF522(PCD_TRANSCEIVE, comMF522Buf, 9, comMF522Buf, &len);
    
        if((status == MI_OK ) && (len == 0x18))
        {
            status = MI_OK;
        }
        else
        {
            status = MI_ERR;
        }
    
        return status;
    }
    
    /**
     @brief 验证卡片密码
     @param authMode -[in] 密码验证模式,0x60 验证A密钥,0x61 验证B密钥
     @param addr -[in] 块地址
     @param pKey -[in] 密码
     @param pSnr -[in] 卡片序列号,4字节
     @return 状态值,MI OK - 成功;MI_ERR - 失败
    */
    static char pcdAuthState(uint8_t authMode, uint8_t addr, uint8_t *pKey, uint8_t *pSnr)
    {
        char status;
        uint8_t i, comMF522Buf[MAXRLEN];
        uint32_t len;
    
        comMF522Buf[0] = authMode;
        comMF522Buf[1] = addr;
    
        for(i = 0; i < 6; i++)
        {
            comMF522Buf[i + 2] = *(pKey + i);
        }
    
        for(i = 0; i < 6; i++)
        {
            comMF522Buf[i + 8] = *(pSnr + i);
        }
    
        status = pcdComMF522(PCD_AUTHENT, comMF522Buf, 12, comMF522Buf, &len);
    
        if((status != MI_OK ) || ( ! (readRawRc(Status2Reg) & 0x08)))
        {
            status = MI_ERR;
        }
    
        return status;
    }
    
    /**
     @brief 读取M1卡一块数据
     @param addr -[in] 块地址
     @param pData -[out] 读出的数据,16字节
     @return 状态值,MI OK - 成功;MI_ERR - 失败
    */
    static char pcdRead(uint8_t addr, uint8_t *pData)
    {
        char status;
        uint8_t i, comMF522Buf[MAXRLEN];
        uint32_t len;
    
        comMF522Buf[0] = PICC_READ;
        comMF522Buf[1] = addr;
    
        calulateCRC(comMF522Buf, 2, &comMF522Buf[2]);
    
        status = pcdComMF522(PCD_TRANSCEIVE, comMF522Buf, 4, comMF522Buf, &len);
    
        if((status == MI_OK) && (len == 0x90))
        {
            for(i = 0; i < 16; i++)
            {
                *(pData + i) = comMF522Buf[i];
            }
        }
        else
        {
            status = MI_ERR;
        }
    
        return status;
    }
    
    /**
     @brief 写入M1卡一块数据
     @param addr -[in] 块地址
     @param pData -[out] 写入的数据,16字节
     @return 状态值,MI OK - 成功;MI_ERR - 失败
    */
    static char pcdWrite(uint8_t addr, uint8_t *pData)
    {
        char status;
        uint8_t i, comMF522Buf[MAXRLEN];
        uint32_t len;
    
        comMF522Buf[0] = PICC_WRITE;
        comMF522Buf[1] = addr;
    
        calulateCRC(comMF522Buf, 2, &comMF522Buf[2]);
    
        status = pcdComMF522(PCD_TRANSCEIVE, comMF522Buf, 4, comMF522Buf, &len);
        if((status != MI_OK) || (len != 4) || ((comMF522Buf[0] & 0x0F) != 0x0A))
        {
            status = MI_ERR;
        }
    
        if(status == MI_OK)
        {
            for(i = 0; i < 16; i++)
            {
                comMF522Buf[i] = *(pData + i);
            }
            calulateCRC(comMF522Buf, 16, &comMF522Buf[16]);
    
            status = pcdComMF522(PCD_TRANSCEIVE, comMF522Buf, 18, comMF522Buf, &len);
            if((status != MI_OK) || (len != 4) || ((comMF522Buf[0] & 0x0F) != 0x0A))
            {
                status = MI_ERR;
            }
        }
    
        return status;
    }
    
    /**
     @brief 复位RC522
     @return 无
    */
    static void pcdReset(void)
    {
        // 需先保持高电平,后给个下降沿
        NFC_GPIO_Write(NFC_RST_LOW);
        delayMs(5);
        NFC_GPIO_Write(NFC_RST_HIGH);
        delayMs(10);
    
        writeRawRc(CommandReg, PCD_RESETPHASE);     // 和MI卡通讯,CRC初始值0x6363
        delayMs(1);
        writeRawRc(ModeReg, 0x3D);
        writeRawRc(TReloadRegL, 30);
        writeRawRc(TReloadRegH, 0);
        writeRawRc(TModeReg, 0x8D);
        writeRawRc(TPrescalerReg, 0x3E);
        writeRawRc(TxASKReg, 0x40);
    }
    
    /**
     @brief 用MF522计算CRC16
     @param pInData -[in] 计算CRC16的数组
     @param len -[in] 计算CRC16的数组字节长度
     @param pOutData -[out] 存放计算结果存放的首地址
     @return 无
    */
    static void calulateCRC(uint8_t *pInData, uint8_t len, uint8_t *pOutData)
    {
        uint8_t i, n;
    
        clearBitMask(DivIrqReg, 0x04);
        writeRawRc(CommandReg, PCD_IDLE);
        setBitMask(FIFOLevelReg, 0x80);
    
        for(i = 0; i < len; i++)
        {
            writeRawRc(FIFODataReg, *(pInData + i));
        }
    
        writeRawRc(CommandReg, PCD_CALCCRC);
    
        i = 0xFF;
    
        do
        {
            n = readRawRc(DivIrqReg);
            i--;
        }
        while((i != 0) && ! (n & 0x04));
    
        pOutData[0] = readRawRc(CRCResultRegL);
        pOutData[1] = readRawRc(CRCResultRegM);
    }
    
    /**
     @brief 通过MFRC522和ISO14443卡通讯
     @param command -[in] RC522命令字
     @param pInData -[in] 通过RC522发送到卡片的数据
     @param inLenByte -[in] 发送数据的字节长度
     @param pOutData -[out] 接收到的卡片返回数据
     @param pOutLenBit -[out] 返回数据的位长度
     @return 状态值,MI OK - 成功;MI_ERR - 失败
    */
    static char pcdComMF522(uint8_t command, uint8_t *pInData, uint8_t inLenByte, uint8_t *pOutData, uint32_t *pOutLenBit)
    {
        char status = MI_ERR;
        uint8_t irqEn = 0x00;
        uint8_t waitFor = 0x00;
        uint8_t lastBits;
        uint8_t n;
        uint32_t i;
        uint8_t j;
    
        switch(command)
        {
        case PCD_AUTHENT:
            irqEn = 0x12;
            waitFor = 0x10;
            break;
        case PCD_TRANSCEIVE:
            irqEn = 0x77;
            waitFor = 0x30;
            break;
        default:
            break;
        }
    
        writeRawRc(ComIEnReg, irqEn | 0x80);
        clearBitMask(ComIrqReg, 0x80);
        writeRawRc(CommandReg, PCD_IDLE);
        setBitMask(FIFOLevelReg, 0x80);             // 清空FIFO
    
        for(i = 0; i < inLenByte; i++)
        {
            writeRawRc(FIFODataReg, pInData[i]);    // 数据写入FIFO
        }
        writeRawRc(CommandReg, command);            // 命令写入命令寄存器
    
        if(command == PCD_TRANSCEIVE)
        {
            setBitMask(BitFramingReg, 0x80);        // 开始发送
        }
    
        i = 6000;                                   // 根据时钟频率调整,操作M1卡最大等待时间25ms 2000?
        do
        {
            n = readRawRc(ComIrqReg);
            i--;
        }
        while((i != 0) && !(n & 0x01) && !(n & waitFor));
        clearBitMask(BitFramingReg, 0x80);
    
        if(i != 0)
        {
            j = readRawRc(ErrorReg);
            if(!(j & 0x1B))
            {
                status = MI_OK;
                if(n & irqEn & 0x01)
                {
                    status = MI_NOTAGERR;
                }
                if(command == PCD_TRANSCEIVE)
                {
                    n = readRawRc(FIFOLevelReg);
                    lastBits = readRawRc(ControlReg) & 0x07;
                    if(lastBits)
                    {
                        *pOutLenBit = (n - 1) * 8 + lastBits;
                    }
                    else
                    {
                        *pOutLenBit = n * 8;
                    }
                    if(n == 0)
                    {
                        n = 1;
                    }
                    if(n > MAXRLEN)
                    {
                        n = MAXRLEN;
                    }
                    for(i = 0; i < n; i++)
                    {
                        pOutData[i] = readRawRc(FIFODataReg);
                    }
                }
            }
            else
            {
              status = MI_ERR;
            }
        }
    
        setBitMask(ControlReg, 0x80);               // stop timer now
        writeRawRc(CommandReg, PCD_IDLE);
    
        return status;
    }
    
    /**
     @brief 开启天线【每次启动或关闭天线发射之间至少有1ms的间隔】
     @return 无
    */
    static void pcdAntennaOn(void)
    {
        uint8_t temp;
        temp = readRawRc(TxControlReg);
        if(!(temp & 0x03))
        {
            setBitMask(TxControlReg, 0x03);
        }
    }
    
    /**
     @brief 关闭天线
     @return 无
    */
    static void pcdAntennaOff(void)
    {
        clearBitMask(TxControlReg, 0x03);
    }
    
    /**
     @brief 置RC522寄存器位
     @param reg -[in] 寄存器地址
     @param mask -[in] 置位值
     @return 无
    */
    static void setBitMask(uint8_t reg, uint8_t mask)
    {
        char temp = 0x00;
        temp = readRawRc(reg) | mask;
        writeRawRc(reg, temp | mask);               // set bit mask
    }
    
    /**
     @brief 清RC522寄存器位
     @param reg -[in] 寄存器地址
     @param mask -[in] 清位值
     @return 无
    */
    static void clearBitMask(uint8_t reg, uint8_t mask)
    {
        char temp = 0x00;
        temp = readRawRc(reg) & (~mask);
        writeRawRc(reg, temp);                      // clear bit mask
    }
    
    /**
     @brief 写RC522寄存器
     @param addr -[in] 寄存器地址
     @param writeData -[in] 写入数据
     @return 无
    */
    static void writeRawRc(uint8_t addr, uint8_t writeData)
    {
        SPI_CS_LOW;
    
        addr <<= 1;
        addr &= 0x7e;
    
        NFC_SPI_Write(&addr, 1);
        NFC_SPI_Write(&writeData, 1);
    
        SPI_CS_HIGH;
    }
    
    /**
     @brief 读RC522寄存器
     @param addr -[in] 寄存器地址
     @return 读出一字节数据
    */
    static uint8_t readRawRc(uint8_t addr)
    {
        uint8_t readData;
    
        SPI_CS_LOW;
    
        addr <<= 1;
        addr |= 0x80;
    
        NFC_SPI_Write(&addr, 1);
        NFC_SPI_Read(&readData, 1);
    
        SPI_CS_HIGH;
    
        return readData;
    }
    
    /**
     @brief 毫秒级延时函数
     @param time -[in] 延时时间(毫秒)
     @return 无
    */
    static void delayMs(uint8_t time)
    {
        vTaskDelay(time / portTICK_PERIOD_MS);
    }
    
    /****************************************************END OF FILE****************************************************/
    

    4.6 board_mfrc522.h

    #ifndef _BOARD_MFRC522_H_
    #define _BOARD_MFRC522_H_
    
    /*********************************************************************
     * INCLUDES
     */
    
    /*********************************************************************
     * DEFINITIONS
     */
    #define MAXRLEN                   18
    
    //******************************************************************/
    // MFRC522命令字
    //******************************************************************/
    #define PCD_IDLE                  0x00           // 取消当前命令
    #define PCD_AUTHENT               0x0E           // 验证密钥
    #define PCD_RECEIVE               0x08           // 接收数据
    #define PCD_TRANSMIT              0x04           // 发送数据
    #define PCD_TRANSCEIVE            0x0C           // 发送并接收数据
    #define PCD_RESETPHASE            0x0F           // 复位
    #define PCD_CALCCRC               0x03           // CRC计算
    
    //******************************************************************/
    // Mifare_One卡片命令字
    //******************************************************************/
    #define PICC_REQIDL               0x26           // 寻天线区内未进入休眠状态
    #define PICC_REQALL               0x52           // 寻天线区内全部卡
    #define PICC_ANTICOLL1            0x93           // 防冲撞
    #define PICC_ANTICOLL2            0x95           // 防冲撞
    #define PICC_AUTHENT1A            0x60           // 验证A密钥
    #define PICC_AUTHENT1B            0x61           // 验证B密钥
    #define PICC_READ                 0x30           // 读块
    #define PICC_WRITE                0xA0           // 写块
    #define PICC_DECREMENT            0xC0           // 扣款
    #define PICC_INCREMENT            0xC1           // 充值
    #define PICC_RESTORE              0xC2           // 调块数据到缓冲区
    #define PICC_TRANSFER             0xB0           // 保存缓冲区中数据
    #define PICC_HALT                 0x50           // 休眠
    
    //******************************************************************/
    // MFRC522 FIFO长度定义
    //******************************************************************/
    #define DEF_FIFO_LENGTH           64             // FIFO size=64byte
    
    //******************************************************************/
    // MFRC522寄存器定义
    //******************************************************************/
    // PAGE 0
    #define RFU00                     0x00
    #define CommandReg                0x01
    #define ComIEnReg                 0x02
    #define DivlEnReg                 0x03
    #define ComIrqReg                 0x04
    #define DivIrqReg                 0x05
    #define ErrorReg                  0x06
    #define Status1Reg                0x07
    #define Status2Reg                0x08
    #define FIFODataReg               0x09
    #define FIFOLevelReg              0x0A
    #define WaterLevelReg             0x0B
    #define ControlReg                0x0C
    #define BitFramingReg             0x0D
    #define CollReg                   0x0E
    #define RFU0F                     0x0F
    // PAGE 1
    #define RFU10                     0x10
    #define ModeReg                   0x11
    #define TxModeReg                 0x12
    #define RxModeReg                 0x13
    #define TxControlReg              0x14
    #define TxASKReg                  0x15
    #define TxSelReg                  0x16
    #define RxSelReg                  0x17
    #define RxThresholdReg            0x18
    #define DemodReg                  0x19
    #define RFU1A                     0x1A
    #define RFU1B                     0x1B
    #define MifareReg                 0x1C
    #define RFU1D                     0x1D
    #define RFU1E                     0x1E
    #define SerialSpeedReg            0x1F
    // PAGE 2
    #define RFU20                     0x20
    #define CRCResultRegM             0x21
    #define CRCResultRegL             0x22
    #define RFU23                     0x23
    #define ModWidthReg               0x24
    #define RFU25                     0x25
    #define RFCfgReg                  0x26
    #define GsNReg                    0x27
    #define CWGsCfgReg                0x28
    #define ModGsCfgReg               0x29
    #define TModeReg                  0x2A
    #define TPrescalerReg             0x2B
    #define TReloadRegH               0x2C
    #define TReloadRegL               0x2D
    #define TCounterValueRegH         0x2E
    #define TCounterValueRegL         0x2F
    // PAGE 3
    #define RFU30                     0x30
    #define TestSel1Reg               0x31
    #define TestSel2Reg               0x32
    #define TestPinEnReg              0x33
    #define TestPinValueReg           0x34
    #define TestBusReg                0x35
    #define AutoTestReg               0x36
    #define VersionReg                0x37
    #define AnalogTestReg             0x38
    #define TestDAC1Reg               0x39
    #define TestDAC2Reg               0x3A
    #define TestADCReg                0x3B
    #define RFU3C                     0x3C
    #define RFU3D                     0x3D
    #define RFU3E                     0x3E
    #define RFU3F                     0x3F
    
    //******************************************************************/
    // MFRC522通讯返回错误代码
    //******************************************************************/
    #define MI_OK                     (char)0
    #define MI_NOTAGERR               (char)(-1)
    #define MI_ERR                    (char)(-2)
    
    /*********************************************************************
     * API FUNCTIONS
     */
    void MFRC522_Init(void);
    uint8_t MFRC522_ReadCardDataBlock(uint8_t addr);
    uint8_t MFRC522_ReadCardSerialNo(uint8_t *pCardSerialNo);
    
    #endif /* _BOARD_MFRC522_H_ */
    

    五、API调用

    需包含头文件 board_mfrc522.h

    5.1 MFRC522_Init()

    功能 MFRC522初始化函数
    函数定义 void MFRC522_Init(void)
    参数
    返回

    5.2 MFRC522_ReadCardDataBlock()

    功能 MFRC522读取卡片块数据
    函数定义 uint8_t MFRC522_ReadCardDataBlock(uint8_t blockAddr)
    参数 blockAddr:块地址
    返回 状态值,0 - 成功;2 - 无卡;3 - 防冲撞失败;4 - 选卡失败;5 - 密码错误

    5.3 MFRC522_ReadCardSerialNo()

    功能 读取卡片序列号
    函数定义 uint8_t MFRC522_ReadCardSerialNo(uint8_t *pCardSerialNo)
    参数 pCardSerialNo:卡片序列号
    返回 状态值,0 - 读卡成功;2 - 无卡

    六、使用例子

    1)添加头文件

    #include "board_gpio.h"
    #include "board_mfrc522.h"
    #include "board_spi.h"
    

    2)添加初始化代码(main.c的main函数中)
    首先调用 NFC_GPIO_Init() 初始化 RFID RC522 模块的 RST 引脚,然后调用 NFC_SPI_Init() 初始化 SPI 通信,最后调用 MFRC522_Init() 初始化 RC522 模块。

    /**@brief Application main function.
     */
    void app_main(void)
    {
        ESP_ERROR_CHECK(nvs_flash_init());
    
        NFC_GPIO_Init();
        NFC_SPI_Init();
        MFRC522_Init();
    
        /*-------------------------- 创建线程 ---------------------------*/
        xTaskCreate(monitor_task, "monitor_task", 2048, NULL, 4, NULL);
    }
    

    3)添加任务,定时读取数据块4

    static void monitor_task(void *arg)
    {
        while(1)                                                                // 任务都是一个无限循环,不能返回
        {
            uint8_t card[4];
            MFRC522_ReadCardSerialNo(card);
            ESP_LOGI(TAG, "card: %02x%02x%02x%02x", card[0], card[1], card[2], card[3]);
            vTaskDelay(500 / portTICK_PERIOD_MS);                                                        // 100ms
        }
    }
    

    4)复位后,可通过读取以下三个寄存器,判断SPI是否通信成功

    ESP_LOGI(TAG, "reg: %02x" ,readRawRc(Status1Reg));
    ESP_LOGI(TAG, "reg: %02x" ,readRawRc(Status2Reg));
    ESP_LOGI(TAG, "reg: %02x" ,readRawRc(WaterLevelReg));
    


    查看打印,返回值与数据手册中描述一致


    5)读取卡号



    • 由 Leung 写于 2022 年 5 月 30 日

    相关文章

      网友评论

        本文标题:ESP32学习笔记(49)——RFID RC522使用

        本文链接:https://www.haomeiwen.com/subject/bzxvprtx.html