开发板:stm32f103c8t6
开发工具:keil5,stm32cubemx
hal库固件包:STM32Cube_FW_F1_V1.8.0
前言:关于RC522的介绍大家可以在网上随便找到,我这里的RC522板只引出来i2c协议的口。在网上找了半天i2c协议驱动RC522但是找的都是用SPI协议,这里参考了一下该博客的代码,STM32 (基于HAL库)MFRC-522 无线射频IC卡驱动(RFID)_rc522怎么没有片选引脚-CSDN博客
把SPI相关的代码改成了i2c的代码。
我的RC522接线(RST接PB1,SCL和SDA接PB6和PB7):
在stm32cubemx选中stm32f103c8t6芯片。
将PB1引脚改为Output工作模式,我这里将用PB1引脚接入RC522的RST复位引脚。
在RCC中将HSE和LSE改为如下配置:
在SYS中将Debug改为如下配置:
在I2C选项卡中打开I2C
在USART1选项卡中的Mode里选择Asynchronous异步通信
在时钟树中作如下配置分配72MHZ系统时钟
在Project Manager中写上工程名,IDE选择ARM,V5。固件包选择STM32Cube_FW_F1_V1.8.0,最后一行选择固件包的路径。在Code Generator中如图配置。然后点击右上角生成代码并打开文件。
代码部分:
RC522.C
(注意我这里RC522的从机写地址和读地址分别为0x54和0x55,如果地址和我不同。要将MFRC_WriteReg和MFRC_ReadReg中封装的HAL_I2C_Mem_Write和HAL_I2C_Mem_Read函数中的0x54和0x55改为自己的从机地址。)
#include "stm32f1xx_hal.h"
#include "RC522.h"
#include "stdio.h"
#include "usart.h"
#include "string.h"
#include "i2c.h"
#define osDelay HAL_Delay
#define RS522_RST_SET HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET)
#define RS522_RST_RESET HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET)
/**************************************************************************************
* 函数名称:MFRC_Init
* 功能描述:MFRC初始化
* 入口参数:无
* 出口参数:无
* 返 回 值:无
***************************************************************************************/
void MFRC_Init(void)
{
RS522_RST_SET;
}
/**************************************************************************************
* 函数名称:MFRC_WriteReg
* 功能描述:写一个寄存器
* 入口参数:-memaddr:待写的寄存器地址
* -data:待写的寄存器数据
* 出口参数:无
* 返 回 值:无
* 说 明:无
***************************************************************************************/
void MFRC_WriteReg(uint16_t memaddr, uint8_t data)
{
uint8_t *ptr_data = &data;
HAL_I2C_Mem_Write(&hi2c1, 0x54, memaddr, I2C_MEMADD_SIZE_8BIT, ptr_data, sizeof(data), HAL_MAX_DELAY);
}
/**************************************************************************************
* 函数名称:MFRC_ReadReg
* 功能描述:读一个寄存器
* 入口参数:-memaddr:待读的寄存器地址
* 出口参数:无
* 返 回 值:-data:读到寄存器的数据
* 说 明:无
***************************************************************************************/
uint8_t MFRC_ReadReg(uint8_t memaddr)
{
uint8_t data;
uint8_t *ptr_data = &data;
HAL_I2C_Mem_Read(&hi2c1, 0x55, memaddr, I2C_MEMADD_SIZE_8BIT, ptr_data, sizeof(data), HAL_MAX_DELAY);
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)
{
//0xc1 1 2 pInData[2]
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_SET;//用到复位引脚
osDelay(5);
RS522_RST_RESET;
osDelay(5);
RS522_RST_SET;
osDelay(5);
/*软复位*/
MFRC_WriteReg(MFRC_CommandReg, MFRC_RESETPHASE);
osDelay(5);
/*复位后的初始化配置*/
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_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;
}
}
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 "main.h"
#include "stm32f1xx_hal.h"
/***********************************************************************************
* 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(uint16_t memaddr, uint8_t ptr_data);
uint8_t MFRC_ReadReg(uint8_t memaddr);
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);
void StartIDcardTask(void const * argument);
#endif
main.c
(注意在uint8_t UID[5]数组中填入自己的卡号)
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"
#include "RC522.h"
#include "stdio.h"
#include "string.h"
int fputc(int ch, FILE *f)//重定向printf使其向串口打印输出
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);
return ch;
}
uint8_t readCard(uint8_t *readUid,void(*funCallBack)(void))//读卡函数
{
uint8_t Temp[5];
if (PCD_Request(0x52, Temp) == 0)
{
if (PCD_Anticoll(readUid) == 0)
{
if(funCallBack!=NULL)
funCallBack();
return 0;
}
}
return 1;
}
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t readUid[5];
uint8_t UID[5]={0x14,0xCB,0xBA,0x75};//自己的卡号,可以通过串口打印通过下面读取到的打印到上位机,再把那个读取的卡号填入数组
//读取卡号,做数据回填,成功读取到卡号就退出 ,另一个是回调功能函数
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
MFRC_Init();
PCD_Reset();
printf("RC522 chu shi hua wan cheng\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE BEGIN 3 */
if(!readCard(readUid,NULL)){
printf("ka hao:%x-%x-%x-%x\n",readUid[0],readUid[1],readUid[2],readUid[3]);
if(!strncmp((char *)readUid,(char *)UID,4)){
//比对卡号正确要做什么
printf("ka hao zheng que\n");
}
else{
//比对卡号错误要做什么
printf("ka hao cuo wu\n");
}
}
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
完成后将代码编译并下载到单片机
打开串口调试工具(我这里用的sscom V5.13.1),选择单片机接入的端口并打开串口。重新上电并复位单片机,将卡靠近RC522,串口调试工具打印卡号并比较卡号是否与自己预输入的卡号相同。