STM32驱动RC522

news2025/1/8 19:00:13

STM32驱动RC522

  • 开发环境:STM32CUBEMX+Keil5
  • 使用平台:STM32F401CCU6
  • 该内容由网上内容改编,若不合适,请联系删除。
  • 一、使用STM32CUBEMX配置SPI
  • 二、驱动部分
  • 三、主函数调用
  • 四、移值攻略

开发环境:STM32CUBEMX+Keil5

使用平台:STM32F401CCU6

该内容由网上内容改编,若不合适,请联系删除。

一、使用STM32CUBEMX配置SPI

//配置两个普通的IO口做reset和片选

在这里插入图片描述

二、驱动部分

//文件名:rc522.c
#include "RC522.h"

//三目运算符true取前面那个
#define RS522_RST(N) HAL_GPIO_WritePin(RC522_RST_GPIO_Port, RC522_RST_Pin, N==1?GPIO_PIN_SET:GPIO_PIN_RESET)
#define RS522_NSS(N) HAL_GPIO_WritePin(RC522_CS_GPIO_Port, RC522_CS_Pin, N==1?GPIO_PIN_SET:GPIO_PIN_RESET)
#define osDelay HAL_Delay
/**************************************************************************************
* 函数名称:MFRC_Init
* 功能描述:MFRC初始化
* 入口参数:无
* 出口参数:无
* 返 回 值:无
* 说    明:MFRC的SPI接口速率为0~10Mbps
***************************************************************************************/
void MFRC_Init(void)
{
    RS522_NSS(1);
    RS522_RST(1);
}

/**************************************************************************************
* 函数名称: SPI_RW_Byte
* 功能描述: 模拟SPI读写一个字节
* 入口参数: -byte:要发送的数据
* 出口参数: -byte:接收到的数据
***************************************************************************************/
static uint8_t ret;       //些函数是HAL与标准库不同和地方,【读写函数】
uint8_t SPI2_RW_Byte(uint8_t byte)
{
    HAL_SPI_TransmitReceive(&hspi3, &byte, &ret, 1, 10);//把byte写入,并读出一个值 存入ret 
    return   ret;                 //入口是byte的地址,读取时用的也是ret的地址;1:一次只写入一个值 10:timeout     
}   

/**************************************************************************************
* 函数名称:MFRC_WriteReg
* 功能描述:写一个寄存器
* 入口参数:-addr:待写的寄存器地址
*           -data:待写的寄存器数据
* 出口参数:无
* 返 回 值:无
* 说    明:无
***************************************************************************************/
void MFRC_WriteReg(uint8_t addr, uint8_t data)
{
    uint8_t AddrByte;
    AddrByte = (addr << 1 ) & 0x7E; //求出地址字节
    RS522_NSS(0);                   //NSS拉低
    SPI2_RW_Byte(AddrByte);         //写地址字节
    SPI2_RW_Byte(data);             //写数据
    RS522_NSS(1);                   //NSS拉高
}


/**************************************************************************************
* 函数名称:MFRC_ReadReg
* 功能描述:读一个寄存器
* 入口参数:-addr:待读的寄存器地址
* 出口参数:无
* 返 回 值:-data:读到寄存器的数据
* 说    明:无
***************************************************************************************/
uint8_t MFRC_ReadReg(uint8_t addr)
{
    uint8_t AddrByte, data;
    AddrByte = ((addr << 1 ) & 0x7E ) | 0x80;   //求出地址字节
    RS522_NSS(0);                               //NSS拉低
    SPI2_RW_Byte(AddrByte);                     //写地址字节
    data = SPI2_RW_Byte(0x00);                  //读数据
    RS522_NSS(1);                               //NSS拉高
    return data;
}


/**************************************************************************************
* 函数名称:MFRC_SetBitMask
* 功能描述:设置寄存器的位
* 入口参数:-addr:待设置的寄存器地址
*           -mask:待设置寄存器的位(可同时设置多个bit)
* 出口参数:无
* 返 回 值:无
* 说    明:无
***************************************************************************************/
void MFRC_SetBitMask(uint8_t addr, uint8_t mask)
{
    uint8_t temp;
    temp = MFRC_ReadReg(addr);                  //先读回寄存器的值
    MFRC_WriteReg(addr, temp | mask);           //处理过的数据再写入寄存器
}


/**************************************************************************************
* 函数名称:MFRC_ClrBitMask
* 功能描述:清除寄存器的位
* 入口参数:-addr:待清除的寄存器地址
*           -mask:待清除寄存器的位(可同时清除多个bit)
* 出口参数:无
* 返 回 值:无
* 说    明:无
***************************************************************************************/
void MFRC_ClrBitMask(uint8_t addr, uint8_t mask)
{
    uint8_t temp;
    temp = MFRC_ReadReg(addr);                  //先读回寄存器的值
    MFRC_WriteReg(addr, temp & ~mask);          //处理过的数据再写入寄存器
}


/**************************************************************************************
* 函数名称:MFRC_CalulateCRC
* 功能描述:用MFRC计算CRC结果
* 入口参数:-pInData:带进行CRC计算的数据
*           -len:带进行CRC计算的数据长度
*           -pOutData:CRC计算结果
* 出口参数:-pOutData:CRC计算结果
* 返 回 值:无
* 说    明:无
***************************************************************************************/
void MFRC_CalulateCRC(uint8_t *pInData, uint8_t len, uint8_t *pOutData)
{
    uint8_t temp;
    uint32_t i;
    MFRC_ClrBitMask(MFRC_DivIrqReg, 0x04);                  //使能CRC中断
    MFRC_WriteReg(MFRC_CommandReg, MFRC_IDLE);              //取消当前命令的执行
    MFRC_SetBitMask(MFRC_FIFOLevelReg, 0x80);               //清除FIFO及其标志位
    for(i = 0; i < len; i++)                                //将待CRC计算的数据写入FIFO
    {
        MFRC_WriteReg(MFRC_FIFODataReg, *(pInData + i));
    }
    MFRC_WriteReg(MFRC_CommandReg, MFRC_CALCCRC);           //执行CRC计算
    i = 100000;
    do
    {
        temp = MFRC_ReadReg(MFRC_DivIrqReg);                //读取DivIrqReg寄存器的值
        i--;
    }
    while((i != 0) && !(temp & 0x04));                      //等待CRC计算完成
    pOutData[0] = MFRC_ReadReg(MFRC_CRCResultRegL);         //读取CRC计算结果
    pOutData[1] = MFRC_ReadReg(MFRC_CRCResultRegM);
}


/**************************************************************************************
* 函数名称:MFRC_CmdFrame
* 功能描述:MFRC522和ISO14443A卡通讯的命令帧函数
* 入口参数:-cmd:MFRC522命令字
*           -pIndata:MFRC522发送给MF1卡的数据的缓冲区首地址
*           -InLenByte:发送数据的字节长度
*           -pOutdata:用于接收MF1卡片返回数据的缓冲区首地址
*           -pOutLenBit:MF1卡返回数据的位长度
* 出口参数:-pOutdata:用于接收MF1卡片返回数据的缓冲区首地址
*           -pOutLenBit:用于MF1卡返回数据位长度的首地址
* 返 回 值:-status:错误代码(MFRC_OK、MFRC_NOTAGERR、MFRC_ERR)
* 说    明:无
***************************************************************************************/
char MFRC_CmdFrame(uint8_t cmd, uint8_t *pInData, uint8_t InLenByte, uint8_t *pOutData, uint16_t *pOutLenBit)
{
    uint8_t lastBits;
    uint8_t n;
    uint32_t i;
    char status = MFRC_ERR;
    uint8_t irqEn   = 0x00;
    uint8_t waitFor = 0x00;

    /*根据命令设置标志位*/
    switch(cmd)
    {
        case MFRC_AUTHENT:                  //Mifare认证
            irqEn = 0x12;
            waitFor = 0x10;                 //idleIRq中断标志
            break;
        case MFRC_TRANSCEIVE:               //发送并接收数据
            irqEn = 0x77;
            waitFor = 0x30;                 //RxIRq和idleIRq中断标志
            break;
    }

    /*发送命令帧前准备*/
    MFRC_WriteReg(MFRC_ComIEnReg, irqEn | 0x80);    //开中断
    MFRC_ClrBitMask(MFRC_ComIrqReg, 0x80);          //清除中断标志位SET1
    MFRC_WriteReg(MFRC_CommandReg, MFRC_IDLE);      //取消当前命令的执行
    MFRC_SetBitMask(MFRC_FIFOLevelReg, 0x80);       //清除FIFO缓冲区及其标志位

    /*发送命令帧*/
    for(i = 0; i < InLenByte; i++)                  //写入命令参数
    {
        MFRC_WriteReg(MFRC_FIFODataReg, pInData[i]);
    }
    MFRC_WriteReg(MFRC_CommandReg, cmd);            //执行命令
    if(cmd == MFRC_TRANSCEIVE)
    {
        MFRC_SetBitMask(MFRC_BitFramingReg, 0x80);  //启动发送
    }
    i = 300000;                                     //根据时钟频率调整,操作M1卡最大等待时间25ms
    do
    {
        n = MFRC_ReadReg(MFRC_ComIrqReg);
        i--;
    }
    while((i != 0) && !(n & 0x01) && !(n & waitFor));     //等待命令完成
    MFRC_ClrBitMask(MFRC_BitFramingReg, 0x80);          //停止发送

    /*处理接收的数据*/
    if(i != 0)
    {
        if(!(MFRC_ReadReg(MFRC_ErrorReg) & 0x1B))
        {
            status = MFRC_OK;
            if(n & irqEn & 0x01)
            {
                status = MFRC_NOTAGERR;
            }
            if(cmd == MFRC_TRANSCEIVE)
            {
                n = MFRC_ReadReg(MFRC_FIFOLevelReg);
                lastBits = MFRC_ReadReg(MFRC_ControlReg) & 0x07;
                if (lastBits)
                {
                    *pOutLenBit = (n - 1) * 8 + lastBits;
                }
                else
                {
                    *pOutLenBit = n * 8;
                }
                if(n == 0)
                {
                    n = 1;
                }
                if(n > MFRC_MAXRLEN)
                {
                    n = MFRC_MAXRLEN;
                }
                for(i = 0; i < n; i++)
                {
                    pOutData[i] = MFRC_ReadReg(MFRC_FIFODataReg);
                }
            }
        }
        else
        {
            status = MFRC_ERR;
        }
    }

    MFRC_SetBitMask(MFRC_ControlReg, 0x80);               //停止定时器运行
    MFRC_WriteReg(MFRC_CommandReg, MFRC_IDLE);            //取消当前命令的执行

    return status;
}


/**************************************************************************************
* 函数名称:PCD_Reset
* 功能描述:PCD复位
* 入口参数:无
* 出口参数:无
* 返 回 值:无
* 说    明:无
***************************************************************************************/
void PCD_Reset(void)
{
    /*硬复位*/
    RS522_RST(1);//用到我们的复位引脚
    osDelay(2);
    RS522_RST(0);
    osDelay(2);
    RS522_RST(1);
    osDelay(2);

    /*软复位*/
    MFRC_WriteReg(MFRC_CommandReg, MFRC_RESETPHASE);
    osDelay(2);

    /*复位后的初始化配置*/
    MFRC_WriteReg(MFRC_ModeReg, 0x3D);              //CRC初始值0x6363
    MFRC_WriteReg(MFRC_TReloadRegL, 30);            //定时器重装值
    MFRC_WriteReg(MFRC_TReloadRegH, 0);
    MFRC_WriteReg(MFRC_TModeReg, 0x8D);             //定时器设置
    MFRC_WriteReg(MFRC_TPrescalerReg, 0x3E);        //定时器预分频值
    MFRC_WriteReg(MFRC_TxAutoReg, 0x40);            //100%ASK

    PCD_AntennaOff();                               //关天线
    osDelay(2);
    PCD_AntennaOn();                                //开天线
}


/**************************************************************************************
* 函数名称:PCD_AntennaOn
* 功能描述:开启天线,使能PCD发送能量载波信号
* 入口参数:无
* 出口参数:无
* 返 回 值:无
* 说    明:每次开启或关闭天线之间应至少有1ms的间隔
***************************************************************************************/
void PCD_AntennaOn(void)
{
    uint8_t temp;
    temp = MFRC_ReadReg(MFRC_TxControlReg);
    if (!(temp & 0x03))
    {
        MFRC_SetBitMask(MFRC_TxControlReg, 0x03);
    }
}


/**************************************************************************************
* 函数名称:PCD_AntennaOff
* 功能描述:关闭天线,失能PCD发送能量载波信号
* 入口参数:无
* 出口参数:无
* 返 回 值:无
* 说    明:每次开启或关闭天线之间应至少有1ms的间隔
***************************************************************************************/
void PCD_AntennaOff(void)
{
    MFRC_ClrBitMask(MFRC_TxControlReg, 0x03);
}

/***************************************************************************************
* 函数名称:PCD_Init
* 功能描述:读写器初始化
* 入口参数:无
* 出口参数:无
* 返 回 值:无
* 说    明:无
***************************************************************************************/
void PCD_Init(void)
{
    MFRC_Init();      //MFRC管脚配置
    PCD_Reset();      //PCD复位  并初始化配置
    PCD_AntennaOff(); //关闭天线
    PCD_AntennaOn();   //开启天线
    PCD_Reset();
}

/***************************************************************************************
* 函数名称:PCD_Request
* 功能描述:寻卡
* 入口参数: -RequestMode:寻卡方式
*                 PICC_REQIDL:寻天线区内未进入休眠状态
*                 PICC_REQALL:寻天线区内全部卡
*             -pCardType:用于保存卡片类型
* 出口参数:-pCardType:卡片类型
*                       0x4400:Mifare_UltraLight
*                       0x0400:Mifare_One(S50)
*                       0x0200:Mifare_One(S70)
*                       0x0800:Mifare_Pro(X)
*                       0x4403:Mifare_DESFire
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:无
***************************************************************************************/
char PCD_Request(uint8_t RequestMode, uint8_t *pCardType)
{
    int status;
    uint16_t unLen;
    uint8_t CmdFrameBuf[MFRC_MAXRLEN];

    MFRC_ClrBitMask(MFRC_Status2Reg, 0x08);//关内部温度传感器
    MFRC_WriteReg(MFRC_BitFramingReg, 0x07); //存储模式,发送模式,是否启动发送等
    MFRC_SetBitMask(MFRC_TxControlReg, 0x03);//配置调制信号13.56MHZ

    CmdFrameBuf[0] = RequestMode;

    status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 1, CmdFrameBuf, &unLen);

    if((status == PCD_OK) && (unLen == 0x10))
    {
        *pCardType = CmdFrameBuf[0];
        *(pCardType + 1) = CmdFrameBuf[1];
    }

    return status;
}

/***************************************************************************************
* 函数名称:PCD_Anticoll
* 功能描述:防冲突,获取卡号
* 入口参数:-pSnr:用于保存卡片序列号,4字节
* 出口参数:-pSnr:卡片序列号,4字节
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:无
***************************************************************************************/
char PCD_Anticoll(uint8_t *pSnr)
{
    char status;
    uint8_t i, snr_check = 0;
    uint16_t  unLen;
    uint8_t CmdFrameBuf[MFRC_MAXRLEN];

    MFRC_ClrBitMask(MFRC_Status2Reg, 0x08);
    MFRC_WriteReg(MFRC_BitFramingReg, 0x00);
    MFRC_ClrBitMask(MFRC_CollReg, 0x80);

    CmdFrameBuf[0] = PICC_ANTICOLL1;
    CmdFrameBuf[1] = 0x20;

    status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 2, CmdFrameBuf, &unLen);
	
    if(status == PCD_OK)
    {
		
        for(i = 0; i < 4; i++)
        {
            *(pSnr + i)  = CmdFrameBuf[i];
            snr_check ^= CmdFrameBuf[i];
        }
        if(snr_check != CmdFrameBuf[i])
        {
            status = PCD_ERR;
        }
		
    }
	/*
		switch (status)
		{
			case PCD_OK:					
                printf("search card OK\r\n");break;
			case PCD_ERR:					
                printf("search cardERROR\r\n");break;
			case PCD_NOTAGERR:		
                printf("no card \r\n");break;
		}
*/
    MFRC_SetBitMask(MFRC_CollReg, 0x80);
	
    return status;
}

/***************************************************************************************
* 函数名称:PCD_Select
* 功能描述:选卡
* 入口参数:-pSnr:卡片序列号,4字节
* 出口参数:无
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:无
***************************************************************************************/
char PCD_Select(uint8_t *pSnr)
{
    char status;
    uint8_t i;
    uint16_t unLen;
    uint8_t CmdFrameBuf[MFRC_MAXRLEN];

    CmdFrameBuf[0] = PICC_ANTICOLL1;
    CmdFrameBuf[1] = 0x70;
    CmdFrameBuf[6] = 0;
    for(i = 0; i < 4; i++)
    {
        CmdFrameBuf[i + 2] = *(pSnr + i);
        CmdFrameBuf[6]  ^= *(pSnr + i);
    }
    MFRC_CalulateCRC(CmdFrameBuf, 7, &CmdFrameBuf[7]);

    MFRC_ClrBitMask(MFRC_Status2Reg, 0x08);

    status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 9, CmdFrameBuf, &unLen);

    if((status == PCD_OK) && (unLen == 0x18))
    {
        status = PCD_OK;
    }
    else
    {
        status = PCD_ERR;
    }
    return status;
}

/***************************************************************************************
* 函数名称:PCD_AuthState
* 功能描述:验证卡片密码
* 入口参数:-AuthMode:验证模式
*                   PICC_AUTHENT1A:验证A密码
*                   PICC_AUTHENT1B:验证B密码
*           -BlockAddr:块地址(0~63)
*           -pKey:密码
*           -pSnr:卡片序列号,4字节
* 出口参数:无
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:验证密码时,以扇区为单位,BlockAddr参数可以是同一个扇区的任意块
***************************************************************************************/
char PCD_AuthState(uint8_t AuthMode, uint8_t BlockAddr, uint8_t *pKey, uint8_t *pSnr)
{
    char status;
    uint16_t unLen;
    uint8_t i, CmdFrameBuf[MFRC_MAXRLEN];
    CmdFrameBuf[0] = AuthMode;
    CmdFrameBuf[1] = BlockAddr;
    for(i = 0; i < 6; i++)
    {
        CmdFrameBuf[i + 2] = *(pKey + i);
    }
    for(i = 0; i < 4; i++)
    {
        CmdFrameBuf[i + 8] = *(pSnr + i);
    }

    status = MFRC_CmdFrame(MFRC_AUTHENT, CmdFrameBuf, 12, CmdFrameBuf, &unLen);
    if((status != PCD_OK) || (!(MFRC_ReadReg(MFRC_Status2Reg) & 0x08)))
    {
        status = PCD_ERR;
    }

    return status;
}

/***************************************************************************************
* 函数名称:PCD_WriteBlock
* 功能描述:读MF1卡数据块
* 入口参数:-BlockAddr:块地址
*           -pData: 用于保存待写入的数据,16字节
* 出口参数:无
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:无
***************************************************************************************/
char PCD_WriteBlock(uint8_t BlockAddr, uint8_t *pData)
{
    char status;
    uint16_t unLen;
    uint8_t i, CmdFrameBuf[MFRC_MAXRLEN];

    CmdFrameBuf[0] = PICC_WRITE;
    CmdFrameBuf[1] = BlockAddr;
    MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);

    status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);

    if((status != PCD_OK) || (unLen != 4) || ((CmdFrameBuf[0] & 0x0F) != 0x0A))
    {
        status = PCD_ERR;
    }

    if(status == PCD_OK)
    {
        for(i = 0; i < 16; i++)
        {
            CmdFrameBuf[i] = *(pData + i);
        }
        MFRC_CalulateCRC(CmdFrameBuf, 16, &CmdFrameBuf[16]);

        status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 18, CmdFrameBuf, &unLen);

        if((status != PCD_OK) || (unLen != 4) || ((CmdFrameBuf[0] & 0x0F) != 0x0A))
        {
            status = PCD_ERR;
        }
    }

    return status;
}

/***************************************************************************************
* 函数名称:PCD_ReadBlock
* 功能描述:读MF1卡数据块
* 入口参数:-BlockAddr:块地址
*           -pData: 用于保存读出的数据,16字节
* 出口参数:-pData: 用于保存读出的数据,16字节
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:无
***************************************************************************************/
char PCD_ReadBlock(uint8_t BlockAddr, uint8_t *pData)
{
    char status;
    uint16_t unLen;
    uint8_t i, CmdFrameBuf[MFRC_MAXRLEN];

    CmdFrameBuf[0] = PICC_READ;
    CmdFrameBuf[1] = BlockAddr;
    MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);

    status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);
    if((status == PCD_OK) && (unLen == 0x90))
    {
        for(i = 0; i < 16; i++)
        {
            *(pData + i) = CmdFrameBuf[i];
        }
    }
    else
    {
        status = PCD_ERR;
    }

    return status;
}


/***************************************************************************************
* 函数名称:PCD_Value
* 功能描述:对MF1卡数据块增减值操作
* 入口参数:
*           -BlockAddr:块地址
*           -pValue:四字节增值的值,低位在前
*           -mode:数值块操作模式
*                  PICC_INCREMENT:增值
*                PICC_DECREMENT:减值
* 出口参数:无
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:无
***************************************************************************************/
char PCD_Value(uint8_t mode, uint8_t BlockAddr, uint8_t *pValue)
{
    //0XC1        1           Increment[4]={0x03, 0x01, 0x01, 0x01};
    char status;
    uint16_t unLen;
    uint8_t i, CmdFrameBuf[MFRC_MAXRLEN];

    CmdFrameBuf[0] = mode;
    CmdFrameBuf[1] = BlockAddr;
    MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);

    status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);

    if((status != PCD_OK) || (unLen != 4) || ((CmdFrameBuf[0] & 0x0F) != 0x0A))
    {
        status = PCD_ERR;
    }

    if(status == PCD_OK)
    {
        for(i = 0; i < 16; i++)
        {
            CmdFrameBuf[i] = *(pValue + i);
        }
        MFRC_CalulateCRC(CmdFrameBuf, 4, &CmdFrameBuf[4]);
        unLen = 0;
        status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 6, CmdFrameBuf, &unLen);
        if(status != PCD_ERR)
        {
            status = PCD_OK;
        }
    }

    if(status == PCD_OK)
    {
        CmdFrameBuf[0] = PICC_TRANSFER;
        CmdFrameBuf[1] = BlockAddr;
        MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);

        status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);

        if((status != PCD_OK) || (unLen != 4) || ((CmdFrameBuf[0] & 0x0F) != 0x0A))
        {
            status = PCD_ERR;
        }
    }
    return status;
}

/***************************************************************************************
* 函数名称:PCD_BakValue
* 功能描述:备份钱包(块转存)
* 入口参数:-sourceBlockAddr:源块地址
*          -goalBlockAddr   :目标块地址
* 出口参数:无
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:只能在同一个扇区内转存
***************************************************************************************/
char PCD_BakValue(uint8_t sourceBlockAddr, uint8_t goalBlockAddr)
{
    char status;
    uint16_t  unLen;
    uint8_t CmdFrameBuf[MFRC_MAXRLEN];

    CmdFrameBuf[0] = PICC_RESTORE;
    CmdFrameBuf[1] = sourceBlockAddr;
    MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);
    status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);
    if((status != PCD_OK) || (unLen != 4) || ((CmdFrameBuf[0] & 0x0F) != 0x0A))
    {
        status = PCD_ERR;
    }

    if(status == PCD_OK)
    {
        CmdFrameBuf[0] = 0;
        CmdFrameBuf[1] = 0;
        CmdFrameBuf[2] = 0;
        CmdFrameBuf[3] = 0;
        MFRC_CalulateCRC(CmdFrameBuf, 4, &CmdFrameBuf[4]);
        status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 6, CmdFrameBuf, &unLen);
        if(status != PCD_ERR)
        {
            status = PCD_OK;
        }
    }

    if(status != PCD_OK)
    {
        return PCD_ERR;
    }

    CmdFrameBuf[0] = PICC_TRANSFER;
    CmdFrameBuf[1] = goalBlockAddr;
    MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);
    status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);
    if((status != PCD_OK) || (unLen != 4) || ((CmdFrameBuf[0] & 0x0F) != 0x0A))
    {
        status = PCD_ERR;
    }

    return status;
}

/***************************************************************************************
* 函数名称:PCD_Halt
* 功能描述:命令卡片进入休眠状态
* 入口参数:无
* 出口参数:无
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:无
***************************************************************************************/
char PCD_Halt(void)
{
    char status;
    uint16_t unLen;
    uint8_t CmdFrameBuf[MFRC_MAXRLEN];

    CmdFrameBuf[0] = PICC_HALT;
    CmdFrameBuf[1] = 0;
    MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);

    status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);

    return status;
}


//文件名:RC522.h
#ifndef _RC522_H
#define _RC522_H

//头文件
//************************************************
#include "gpio.h"//要一些引脚上的宏定义
#include "spi.h"//硬件SPI的定义
#include "usart.h"
#include "main.h"//Laber User上的宏定义
//************************************************
/*
引脚定义
		RST		-->B7
		SDA(CS) -->B6
		MOSI    -->B5
		MISO    -->B4
		SCK     -->B3
*/
 
#define RC522_RST_GPIO_Port GPIOB
#define RC522_RST_Pin GPIO_PIN_7
#define RC522_CS_GPIO_Port  GPIOB
#define RC522_CS_Pin  GPIO_PIN_6

//MFRC522驱动程序
//************************************************

/*MFRC522寄存器定义*/
//PAGE0
#define MFRC_RFU00              	0x00    
#define MFRC_CommandReg         	0x01    
#define MFRC_ComIEnReg             	0x02    
#define MFRC_DivlEnReg             	0x03    
#define MFRC_ComIrqReg             	0x04    
#define MFRC_DivIrqReg             	0x05
#define MFRC_ErrorReg              	0x06    
#define MFRC_Status1Reg            	0x07    
#define MFRC_Status2Reg            	0x08    
#define MFRC_FIFODataReg           	0x09
#define MFRC_FIFOLevelReg          	0x0A
#define MFRC_WaterLevelReg         	0x0B
#define MFRC_ControlReg            	0x0C
#define MFRC_BitFramingReg         	0x0D
#define MFRC_CollReg               	0x0E
#define MFRC_RFU0F                 	0x0F
//PAGE1     
#define MFRC_RFU10                 	0x10
#define MFRC_ModeReg               	0x11
#define MFRC_TxModeReg             	0x12
#define MFRC_RxModeReg             	0x13
#define MFRC_TxControlReg          	0x14
#define MFRC_TxAutoReg             	0x15 //中文手册有误
#define MFRC_TxSelReg              	0x16
#define MFRC_RxSelReg              	0x17
#define MFRC_RxThresholdReg        	0x18
#define MFRC_DemodReg              	0x19
#define MFRC_RFU1A                 	0x1A
#define MFRC_RFU1B                 	0x1B
#define MFRC_MifareReg             	0x1C
#define MFRC_RFU1D                 	0x1D
#define MFRC_RFU1E                 	0x1E
#define MFRC_SerialSpeedReg        	0x1F
//PAGE2    
#define MFRC_RFU20                 	0x20  
#define MFRC_CRCResultRegM         	0x21
#define MFRC_CRCResultRegL         	0x22
#define MFRC_RFU23                 	0x23
#define MFRC_ModWidthReg           	0x24
#define MFRC_RFU25                 	0x25
#define MFRC_RFCfgReg              	0x26
#define MFRC_GsNReg                	0x27
#define MFRC_CWGsCfgReg            	0x28
#define MFRC_ModGsCfgReg           	0x29
#define MFRC_TModeReg              	0x2A
#define MFRC_TPrescalerReg         	0x2B
#define MFRC_TReloadRegH           	0x2C
#define MFRC_TReloadRegL           	0x2D
#define MFRC_TCounterValueRegH     	0x2E
#define MFRC_TCounterValueRegL     	0x2F
//PAGE3      
#define MFRC_RFU30                 	0x30
#define MFRC_TestSel1Reg           	0x31
#define MFRC_TestSel2Reg           	0x32
#define MFRC_TestPinEnReg          	0x33
#define MFRC_TestPinValueReg       	0x34
#define MFRC_TestBusReg            	0x35
#define MFRC_AutoTestReg           	0x36
#define MFRC_VersionReg            	0x37
#define MFRC_AnalogTestReg         	0x38
#define MFRC_TestDAC1Reg           	0x39  
#define MFRC_TestDAC2Reg           	0x3A   
#define MFRC_TestADCReg            	0x3B   
#define MFRC_RFU3C                 	0x3C   
#define MFRC_RFU3D                 	0x3D   
#define MFRC_RFU3E                 	0x3E   
#define MFRC_RFU3F                 	0x3F

/*MFRC522的FIFO长度定义*/
#define MFRC_FIFO_LENGTH       		64 

/*MFRC522传输的帧长定义*/
#define MFRC_MAXRLEN                18                

/*MFRC522命令集,中文手册P59*/
#define MFRC_IDLE              		0x00	//取消当前命令的执行
#define MFRC_CALCCRC           		0x03    //激活CRC计算
#define MFRC_TRANSMIT          		0x04    //发送FIFO缓冲区内容
#define MFRC_NOCMDCHANGE            0x07	//无命令改变
#define MFRC_RECEIVE           		0x08    //激活接收器接收数据
#define MFRC_TRANSCEIVE        		0x0C    //发送并接收数据
#define MFRC_AUTHENT           		0x0E    //执行Mifare认证(验证密钥)
#define MFRC_RESETPHASE        		0x0F    //复位MFRC522

/*MFRC522通讯时返回的错误代码*/
#define MFRC_OK                 	(char)(0)
#define MFRC_NOTAGERR            	(char)(-1)
#define MFRC_ERR                	(char)(-2)

/*MFRC522函数声明*/
void MFRC_Init(void);
void MFRC_WriteReg(uint8_t addr, uint8_t data);
uint8_t MFRC_ReadReg(uint8_t addr);
void MFRC_SetBitMask(uint8_t addr, uint8_t mask);
void MFRC_ClrBitMask(uint8_t addr, uint8_t mask);
void MFRC_CalulateCRC(uint8_t *pInData, uint8_t len, uint8_t *pOutData);
char MFRC_CmdFrame(uint8_t cmd, uint8_t *pInData, uint8_t InLenByte, uint8_t *pOutData, uint16_t *pOutLenBit);
//********************************************************************

//MFRC552与MF1卡通讯接口程序
//*********************************************************************
/*Mifare1卡片命令字*/
#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_TRANSFER         	0xB0               	//转存(传送)
#define PICC_RESTORE          	0xC2               	//恢复(重储)
#define PICC_HALT             	0x50               	//休眠

/*PCD通讯时返回的错误代码*/
#define PCD_OK                 	(char)0				//成功
#define PCD_NOTAGERR            (char)(-1)			//无卡
#define PCD_ERR                	(char)(-2)			//出错

/*PCD函数声明*/
void PCD_Init(void);//读写器初始化
void PCD_Reset(void);
void PCD_AntennaOn(void);
void PCD_AntennaOff(void);
char PCD_Request(uint8_t RequestMode, uint8_t *pCardType);  //寻卡,并返回卡的类型
char PCD_Anticoll(uint8_t *pSnr);                           //防冲突,返回卡号
char PCD_Select(uint8_t *pSnr);                             //选卡
char PCD_AuthState(uint8_t AuthMode, uint8_t BlockAddr, uint8_t *pKey, uint8_t *pSnr); //验证密码(密码A和密码B)   
char PCD_WriteBlock(uint8_t BlockAddr, uint8_t *pData);   //写数据
char PCD_ReadBlock(uint8_t BlockAddr, uint8_t *pData);    //读数据
char PCD_Value(uint8_t mode, uint8_t BlockAddr, uint8_t *pValue);   
char PCD_BakValue(uint8_t sourceBlockAddr, uint8_t goalBlockAddr);                                 
char PCD_Halt(void);
//******************************************************************************************

#endif


三、主函数调用

void Rc522Contrl(void)
{
	static char flag_lock=0,flag_numb=0;
	
	flag_numb++;
	
	//¿ªÃźó2Ãëºó¹Ø±Õ
	if(flag_lock==1 && flag_numb==4) 
	{
		contrlJdq(GPIO_PIN_RESET);
		flag_lock=0;
	}
	
	//Ñ°¿¨
	if (PCD_Request(PICC_REQALL, RxBuffer)!=0)//·µ»ØֵΪ0£¬´ú±íÑ°¿¨³É¹¦£»²¢°Ñ¿¨ÀàÐÍ´æÈëRxBufferÖÐ)
	{
		/*¹ûÈ»ÕâÀïÒªÇå¿Õһϲ»È»¾Í»áÂÒ£¬»áÓÐһЩRxBufferûÓõÄÔÚÄÇÀïռλ*/
		memset(RxBuffer, 0, sizeof(RxBuffer));//Çå¿Õ×Ö·û´®
		return;//Èç¹û²»¼ÓÕâ¸öÅжϵĻ°£¬Ôò»áÎÞÂÛÑ°¿¨ÊÇ·ñ³É¹¦¶¼»áÓÐÖµ000
	}
	//·À³åײ
	
	if (PCD_Anticoll(RxBuffer)!=0)//·À³åײ£¬Íê³ÉÕⲿ¾Í¿ÉÒÔ¼òµ¥µØ ¶ÁÈ¡¿¨ºÅ
	{
		memset(RxBuffer, 0, sizeof(RxBuffer));//Çå¿Õ×Ö·û´®
		return;//Èç¹û²»¼ÓÕâ¸öÅжϵĻ°£¬Ôò»áÎÞÂÛÑ°¿¨ÊÇ·ñ³É¹¦¶¼»áÈÅÂÒ¿¨ºÅ
	}
	//´¦Àí¿¨ºÅÊý¾Ý
	sprintf(Card_ID,"%x%x%x%x",RxBuffer[0],RxBuffer[1],RxBuffer[2],RxBuffer[3]);
	
	//¶Ô¿¨ºÅ½øÐÐȨÏÞµÄÅжÏ
	/*
	*/
	if(strcmp(Card_ID,"23688e50")==0)//Âô¼ÒÅäµÄ¿¨
    {
		//DoorControl(1);//¿ªÃÅ
		printf("%s \r\n ",Card_ID);
		
		soundsContrl(welcomehome);
		contrlJdq(GPIO_PIN_SET);
		
		flag_lock=1;
		flag_numb=0;
		memset(RxBuffer, 0, sizeof(RxBuffer));//Çå¿Õ×Ö·û´®,ÕâÀïÒªÇå³ýRxBuffer²ÅÐУ¬·ñÔòCard_IDÓֻᱻ×éÆðÀ´	
    }
    HAL_Delay(500);
		return;
	
}

四、移值攻略

  1. 需要修改SPI的引脚、片选、RES引脚;
    在这里插入图片描述
  2. 刷卡成功需要做的事放在这里
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/336798.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣:珠玑妙算(详解)

前言&#xff1a;内容包括四大模块&#xff1a;题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读 题目&#xff1a; 珠玑妙算游戏&#xff08;the game of master mind&#xff09;的玩法如下。 计算机有4个槽&#xff0c;每个槽放一个球&#xff0c;颜色可…

电力系统网架规划MATLAB程序分享

网架数据展示&#xff1a;完整程序&#xff1a;close all;clear all;clc;warning off; % 去除警告 tic; % tic用来保存当前时间&#xff0c;而后使用toc来记录程序完成时间%% 基本参数T12; % 典型日 8-19h % 8-19h 负荷各时段负荷总量total_P_LOAD[828,1001,1105,1105,994,1105…

STM32CubeMX+SPI+FATFS读写SD卡

一、软件硬件说明软件&#xff1a;STM32CubeMX V6.6.1 /KEIL5 V5.29硬件&#xff1a;正点原子mini开发板&#xff0c;SD卡,通过SPI方式驱动SD卡&#xff0c;用的是SPI1接口以上内容来源于正点原子mini开发板手册&#xff0c;SD卡的详细介绍也可以去查阅这个手册。二、STM32Cube…

Ethercat系列(3)TWCat3下抓包实例分析

简介研究Ethercat协议&#xff0c;必须知道数据包格式&#xff0c;以及其真实含义。以一个真实的数据包来学习是最有效的。Twcat3下用wireshark抓包&#xff0c;需要设置一下混杂模式&#xff0c;否则不能直接抓到Ethercat数据包。Twcat抓包设置在正确加载驱动器配置文件后&…

可深度二次开发的智能插座 工业化物联网多场景的高定系统服务商

物联网时代&#xff0c;各类物联网需求越来越迫切。物联网设备呈现出爆发式增长。同时近年来国家不断出台相关的法规政策&#xff0c;为物联网行业发展创造机遇&#xff0c;三大运营商积极部署NB-IOT网络建设&#xff0c;建成90万NB-IoT基站。据统计2012-2022年期间&#xff0c…

缺省参数+函数重载+构造函数

目录 一、缺省参数 &#xff08;一&#xff09;缺省参数概念 &#xff08;二&#xff09;缺省参数分类 1. 全缺省参数 2. 半缺省参数&#xff08;缺省部分参数&#xff09; 3. 注意 二、函数重载 &#xff08;一&#xff09;基本概念 &#xff08;二&#xff09;举例 …

“算丰AI视界”人工智能技术内容征集活动正式开启!

2023年2月8日&#xff0c;首届“算丰AI视界”人工智能技术内容征集活动正式拉开帷幕&#xff01;本次活动主要征集AI、CV、TPU-MLIR、RISC-V等方向的代表性视频和文章&#xff0c;面向国内外的企业、高校和科研院所的优秀开发者。 活动紧扣人工智能行业相关AI视觉技术&#xff…

申请苹果开发者账号的方法

1、打开苹果id注册地址&#xff0c;输入相关信息注册&#xff0c;如果已经有苹果账号了看第二步&#xff0c; https://appleid.apple.com/account?localangzh_CN 2、注册成功了&#xff0c;或者有苹果账号了&#xff0c;登录苹果开发者中心 https://developer.apple.com/acc…

LearnOpenGL 笔记 - 入门 04 你好,三角形

系列文章目录 LearnOpenGL 笔记 - 入门 01 OpenGLLearnOpenGL 笔记 - 入门 02 创建窗口LearnOpenGL 笔记 - 入门 03 你好&#xff0c;窗口 文章目录系列文章目录前言你好&#xff0c;三角形顶点输入顶点着色器&#xff08;Vertex Shader&#xff09;编译着色器片段着色器&…

SpringBoot集成Flink-CDC 采集PostgreSQL变更数据发布到Kafka

一、业务价值 监听数据变化&#xff0c;进行异步通知&#xff0c;做系统内异步任务。 架构方案&#xff08;懒得写了&#xff0c;看图吧&#xff09;&#xff1a; 二、修改数据库配置 2.1、更改配置文件postgresql.conf # 更改wal日志方式为logical&#xff08;必须&#xf…

PCB设计是不是该去除孤铜

你知道PCB设计是不是该去除孤铜? PCB设计的技巧需要注意很多问题&#xff0c;各个器件的兼容问题&#xff0c;以及成品问题等等都是需要考虑的重要因素。 我们今天的主题是PCB设计的时候是不是该去除孤铜的问题?有人说应该除去&#xff0c;原因大概是&#xff1a; 会造成EMI问…

学习深入理解JVM虚拟机及JavaGuide后的学习笔记

JVM虚拟机 一、JVM组成部分&#xff1a; 1.程序计数器 作用&#xff0c;是记住下一条JVM指令的内存地址&#xff1b;1.多线程情况下&#xff0c;程序计数器用于记录当前线程执行的位置&#xff0c;从而线程切换回来的时候能够知道线程上次运行到哪儿了。2.字节码解释器通过改变…

6 前缀、中缀、后缀表达式

文章目录1 前缀表达式 1. 1 缀表达式的计算机求值 2 中缀表达式3 后缀表达式 3. 1 后缀表达式的计算机求值 3. 2 中缀表达式转换为后缀表达式1 前缀表达式 前缀表达式又称波兰式&#xff0c;前缀表达式的运算符位于操作数之前 举例说明&#xff1a; (34)5-6 对应的前缀表达式就…

Orin + SC16IS752+SP3072 SPI转串口485

文章目录 1.前言2.修改过程2.1 sc16is752 芯片2.1.1引脚说明2.1.2 设备树配置2.2.1 源码分析3 调试1.前言 Orin 有四路串口,对于多数设备来说已经够用。 通过SPI 转串口再转RS485在Orin平台应该属于极个例,所以记录一下。 串口扩展芯片: SC16IS752RS485收发器: SP3072通信…

初次尝试-注册openai并使用chatGPT

1 环境 本次我打算在win11虚拟机下进行(不打算动真机的时区啦)。 2 科学上网 这里就不多介绍了&#xff0c;使用科学上网工具连接外网即可。由于软件可连接限制&#xff0c;我这里选择美国网络。 3 更改时区 这里的时区最好和上述的所连接的地区一致。 3 登录网站 1、…

HOMER docker版本安装详细流程

概述 HOMER是一款100%开源的针对SIP/VOIP/RTC的抓包工具和监控工具。 HOMER是一款强大的、运营商级、可扩展的数据包和事件捕获系统&#xff0c;是基于HEP/EEP协议的VoIP/RTC监控应用程序&#xff0c;并可以使用即时搜索、处理和存储大量的信令、RTC事件、日志和统计信息。 …

Word控件Spire.Doc 【Table】教程(13): 如何在 C# 中向现有的 word 表添加一行

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

LwIP系列--软件定时器(超时处理)详解

一、目的在TCP/IP协议栈中ARP缓存的更新、IP数据包的重组、TCP的连接超时和超时重传等都需要超时处理模块&#xff08;软件定时器&#xff09;的参与。本篇主要介绍LwIP中超时处理的实现细节。上图为超时定时器链表&#xff0c;升序排序&#xff0c;其中next_timeout为链表头&a…

pyLoad远程代码执行漏洞(CVE-2023-0297)复现以及原理流量特征分析

声明&#xff1a; 请勿用于非法入侵&#xff0c;仅供学习。传送门 -》中华人民共和国网络安全法 文章目录声明&#xff1a;pyLoad介绍漏洞介绍影响版本不受影响版本漏洞原理漏洞环境搭建以及复现流量特征分析pyLoad介绍 pyLoad是一个用 Python 编写的免费和开源下载管理器&am…

计算GPS两个点之间的距离

参考&#xff1a;Https://blog.csdn.net/u011339749/article/details/125048180任意两点对应的经纬度A(lat0,long0),B(lat1,long1)则C(lat1,long0),D(lat0,long1)。通过A、B、C、D四个点可以确定一个四边形平面。同一纬度相互平行&#xff0c;可知连接ACBD四点构成了一个等腰梯…