该例程参考自:从0开始设计_基于STM32F1的RC522读写卡-OpenEdv-开源电子网
STM32 (基于HAL库)MFRC-522 无线射频IC卡驱动教程(RFID)mfrc522如何与stm32开发嵌入式lover的博客-CSDN博客
首先准备好需要使用的硬件设备:正点原子MiniSTM32开发板一块,MiniRFID-RC522模块一个,杜邦线七条,miniUSB线一条,ST_Link一个(ST_Link是需要一根miniUSB线与20pin接口线的,也可采用4条杜邦线连接;也可换为J_Link),M1白卡一张,
如图
STM32 Cobe MX配置
代码部分:
rc522.c
/*************笔记**************** 1、接线方式: STM32 RFID PA4 -> SDA PA5 -> SCK PA7 -> MOSI PA6 -> MISO 悬空 -> IKQ GND -> GND PA3 -> RST 3.3V -> 3.3V 2、应用函数 MFRC_Init();//初始化 PCD_Reset();//器件复位 PCD_Request(PICC_REQALL, RxBuffer);//返回值为0,代表寻卡成功;并把卡类型存入RxBuffer中 PCD_Anticoll(RxBuffer); //把(十六进制)的4个字节卡号存储在数组RxBuffer中 ***********************************/ #include "rc522.h" #include "usart.h" extern SPI_HandleTypeDef hspi1; /************************************************************************************** * 函数名称: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(&hspi1, &byte, &ret, 1, 10);//把byte 写入,并读出一个值,把它存入ret return ret;//入口是byte 的地址,读取时用的也是ret地址,一次只写入一个值10 } /************************************************************************************** * 函数名称: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) { //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(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_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 <stdint.h> /******************************************************************************* * rc522.c文件宏定义 * *********************************************************************************/ #define RC522_CS_GPIO_Port GPIOA #define RC522_CS_Pin GPIO_PIN_4//cs nss sda是一个东西 #define RC522_RST_GPIO_Port GPIOA #define RC522_RST_Pin GPIO_PIN_3 #define osDelay HAL_Delay #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) /*********************************************************************************** * 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);//初始化RC522 void MFRC_WriteReg(uint8_t addr, uint8_t data);//向RC522写寄存器 uint8_t MFRC_ReadReg(uint8_t addr);//读RC522寄存器 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);//用MFRC计算CRC结果 char MFRC_CmdFrame(uint8_t cmd, uint8_t *pInData, uint8_t InLenByte, uint8_t *pOutData, uint16_t *pOutLenBit);//MFRC522和ISO14443A卡通讯的命令帧函数 /*********************************************************************************** * 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);//初始化PCD void PCD_Reset(void);//复位PCD 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);//启动ID卡任务 #endif
rfid.c
#include "rfid.h" #include "rc522.h" #include <ctype.h> #include <stdio.h> #include <string.h> int RFID_WritFlag = 0;//写RFID标志位 char RFID_FLAG = PCD_ERR;//RFID状态 uint8_t RFID_WriteData[16] = "1234567890ABCDEF";//需要写入IC卡内的数据 uint8_t key_A[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};//密钥A uint8_t key_B[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};//密钥B /******************************************************************************* *函数名 :RFID_Handl RFID处理 *补充 :此函数只做RFID逻辑处理 *作者 :Li Xunjiu *********************************************************************************/ void RFID_Handl(void) { uint8_t CardType[4];//卡类型 uint8_t Card_ID[4];//卡ID char RFID_ReadData[16];//读取卡内的数据 RFID_FLAG = PCD_Request(PICC_REQIDL, CardType);//返回值为0,代表寻卡成功;并把卡类型存入CardType中 if(RFID_FLAG == PCD_OK) { RFID_FLAG = PCD_ERR; AntiCollision(Card_ID);//进行防冲撞及获取ID SIM_Card(Card_ID);//选卡 Key_Verification(PICC_AUTHENT1A,7,key_A,Card_ID);//验证 WriteCard(6,RFID_WriteData);//写卡 ReadCard(6,(uint8_t *)RFID_ReadData);//读卡 PCD_Halt();//RFID进入休眠 memset(Card_ID, 0, sizeof(Card_ID));//清空字符串 memset(RFID_WriteData, 0, sizeof(RFID_WriteData));//清空字符串 memset(RFID_ReadData, 0, sizeof(RFID_ReadData));//清空字符串 HAL_Delay(1000); } HAL_Delay(100); return; } /******************************************************************************* * 函数名 :convertToUpper *函数参数 :str ->需要更改大小写的数组 *补充 :将数组内的元素大写 *作者 :Li Xunjiu *********************************************************************************/ void convertToUpper(uint8_t *str) { int i = 0; while (str[i]) { str[i] = toupper(str[i]); i++; } } /******************************************************************************* * 函数名 :SIM_Card 选择卡 *函数参数 :cardID ->卡号ID *作者 :Li Xunjiu *********************************************************************************/ void SIM_Card(uint8_t * cardID) { RFID_FLAG = PCD_Select(cardID);//选卡 if(RFID_FLAG == PCD_OK) { RFID_FLAG = PCD_ERR; printf("选卡成功\r\n"); return; } else { printf("选卡失败\r\n"); return; } } /******************************************************************************* * 函数名 :AntiCollision 防冲撞并获取卡ID *函数参数 :readUid 读取RFID的卡号 *作者 :Li Xunjiu *********************************************************************************/ void AntiCollision(uint8_t * cardID) { RFID_FLAG = PCD_Anticoll(cardID); //防冲撞,完成这步就可以简单地读取卡号,本次不涉及更高层次应用 if(RFID_FLAG == PCD_OK) { char CardTem[4]; RFID_FLAG = PCD_ERR; sprintf(CardTem,"%x%x%x%x",cardID[0],cardID[1],cardID[2],cardID[3]); convertToUpper((uint8_t *) CardTem); printf("ID=%s\r\n",(uint8_t *)CardTem); return; } } /******************************************************************************* * 函数名 :Key_Verification 密钥验证 *函数参数 :authmode ->密钥验证模式(A或是B) * addr ->密钥验证地址(每个扇区的区块3) * key ->验证的密钥值 * UID ->卡的序列号(4位) *作者 :Li Xunjiu *********************************************************************************/ void Key_Verification(uint8_t authmode,uint8_t addr,uint8_t * key,uint8_t * UID) { RFID_FLAG = PCD_AuthState(authmode, addr, key, UID);//解密 if(RFID_FLAG == PCD_OK) { RFID_FLAG = PCD_ERR; printf("密钥验证成功\r\n"); return; } else { printf("密钥验证成功\r\n"); return; } } /******************************************************************************* * 函数名 :WriteCard 向IC卡内写数据 *函数参数 :addr ->需要写入数据的区块地址 * RFID_WriteData ->需要写入的数据 *作者 :Li Xunjiu *********************************************************************************/ void WriteCard(uint8_t addr,uint8_t *RFID_WriteData) { if(RFID_WritFlag == 1) { uint8_t EmptyStr[16] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; PCD_WriteBlock(addr,(uint8_t *)EmptyStr); printf("数据块已清空,开始写入新数据!\r\n"); RFID_FLAG = PCD_WriteBlock(addr, (uint8_t *)RFID_WriteData);//写卡 if(RFID_FLAG == PCD_OK) { RFID_FLAG = PCD_ERR; printf("写卡成功\r\n"); RFID_WritFlag = 0; return; } else { printf("写卡失败:%d\r\n",RFID_FLAG); RFID_WritFlag = 0; return; } } else printf("未开启RFID写标志!\r\n"); RFID_WritFlag = 0; return; } /******************************************************************************* * 函数名 :ReadCard 读取卡的数据 *函数参数 :addr ->需要读的区块地址0~15(8扇区每个扇区4个数据块一个数代表一个数据块) * RFID_ReadData ->卡内读出的数据 *作者 :Li Xunjiu *********************************************************************************/ void ReadCard(uint8_t addr,uint8_t *RFID_ReadData) { char RFID_FLAG = PCD_ERR; RFID_FLAG = PCD_ReadBlock(addr, RFID_ReadData);//读卡 if(RFID_FLAG == PCD_OK) { RFID_FLAG = PCD_ERR; printf("读卡成功:%s\r\n",(char *) RFID_ReadData);//这里输出的数据后面后跟所读数据的卡号 HAL_Delay(500); return; } else { printf("读卡失败:%d\r\n",RFID_FLAG); return; } }
rfid.h
#ifndef _RFID_H #define _RFID_H #include "main.h" extern int RFID_WritFlag; extern char RFID_FLAG; extern uint8_t key_A[6]; extern uint8_t key_B[6]; extern uint8_t RFID_WriteData[16]; void RFID_Handl(void);//RFID处理函数 void convertToUpper(uint8_t *str); //将字符格式标注仅大写 void SIM_Card(uint8_t * cardID);//选卡 void AntiCollision(uint8_t * cardID);//防冲撞及获取ID void Key_Verification(uint8_t authmode,uint8_t addr,uint8_t * key,uint8_t * UID);//验证密钥 void WriteCard(uint8_t addr,uint8_t *RFID_WriteData);//向卡内写入数据 void ReadCard(uint8_t addr,uint8_t *RFID_ReadData);//读卡数据 uint8_t RFIDReadCard(uint8_t *readUid, uint8_t *cardID); #endif
usart.c
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file usart.c * @brief This file provides code for the configuration * of the USART instances. ****************************************************************************** * @attention * * Copyright (c) 2023 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 "usart.h" /* USER CODE BEGIN 0 */ #include "rfid.h" int UartDataReceived = 0;//串口开启标志位 int UartFalg = 0;//串口接收数据标志 int UartRxLen =0;//串口接收数据长度 uint8_t Uart_Rx_Buf[1];//串口接收缓冲 uint8_t UartData[300];//串口数据 /* USER CODE END 0 */ UART_HandleTypeDef huart1; /* USART1 init function */ void MX_USART1_UART_Init(void) { /* USER CODE BEGIN USART1_Init 0 */ /* USER CODE END USART1_Init 0 */ /* USER CODE BEGIN USART1_Init 1 */ /* USER CODE END USART1_Init 1 */ huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN USART1_Init 2 */ __enable_irq();//使能串口中断 HAL_UART_Receive_IT(&huart1, (uint8_t *)Uart_Rx_Buf, 1); /* USER CODE END USART1_Init 2 */ } void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(uartHandle->Instance==USART1) { /* USER CODE BEGIN USART1_MspInit 0 */ /* USER CODE END USART1_MspInit 0 */ /* USART1 clock enable */ __HAL_RCC_USART1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ GPIO_InitStruct.Pin = GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USART1 interrupt Init */ HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USART1_IRQn); /* USER CODE BEGIN USART1_MspInit 1 */ /* USER CODE END USART1_MspInit 1 */ } } void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle) { if(uartHandle->Instance==USART1) { /* USER CODE BEGIN USART1_MspDeInit 0 */ /* USER CODE END USART1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_USART1_CLK_DISABLE(); /**USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10); /* USART1 interrupt Deinit */ HAL_NVIC_DisableIRQ(USART1_IRQn); /* USER CODE BEGIN USART1_MspDeInit 1 */ /* USER CODE END USART1_MspDeInit 1 */ } } /* USER CODE BEGIN 1 */ /******************************************************************************* * 函数名 :printf *功能描述:输出函数 *函数参数:ch,*p * 返回值 :ch *补充说明:该函数是标准库stdio.h内的输出函数,在这只是重定向其输出方向 *作者 :Li Xunjiu *********************************************************************************/ int fputc(int ch,FILE *p) { char c = ch; HAL_UART_Transmit(&huart1,(unsigned char *)&c, 1, 50); return ch; } /******************************************************************************* * 函数名 :HAL_UART_RxCpltCallback *功能描述:串口回调函数 *函数参数: * 返回值 :无 *补充说明:该函数是HAL库内的函数,只是在这重写了 *作者 :Li Xunjiu *********************************************************************************/ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { uint8_t Uart_Data_Buf[300];//串口数据缓冲 if (huart == &huart1) // 处理串口1的数据 { UartDataReceived = 1;//开启串标志位 UartFalg++; //每接收到一个数据,进入回调数据长度加1 Uart_Data_Buf[UartFalg-1] = Uart_Rx_Buf[0]; //把每次接收到的数据保存到缓存数组 if (Uart_Data_Buf[UartFalg-1]== ';')//接收结束标志判断 { memcpy(UartData, Uart_Data_Buf, UartFalg * sizeof(uint8_t)); //将数组Uart_Data_Buf中的数据转交给Uart_Data memset(Uart_Data_Buf, 0, sizeof(Uart_Data_Buf)); //清空缓存数组 UartRxLen = UartFalg; //将UartFalg的值赋给UartRxLen UartFalg = 0; //清空接收标志 } Uart_Rx_Buf[0] = 0; //重置接收缓冲 // 每接收一个数据,打开一次串口中断接收,否则只会接收一个数据就停止接收 HAL_UART_Receive_IT(&huart1, (uint8_t *)Uart_Rx_Buf, 1); } } /******************************************************************************* * 函数名 :USART_Handl *功能描述:串口数据处理 *函数参数:无 * 返回值 :无 *补充说明:该函数只做接收的的函数处理,所有串口数据皆在该函数内进行,外部只需调用即可 *作者 :Li Xunjiu *********************************************************************************/ void USART_Handl(void) { if(UartDataReceived == 0)//串口标志未开启 { HAL_UART_Receive_IT(&huart1, (uint8_t *)Uart_Rx_Buf, 1); } if(UartDataReceived == 1)//串口标志已开启 { printf("串口开启接收数据成功!\r\n"); if(memcmp(UartData, "Set_CardData:", 13) == 0) { if(UartRxLen-14<=16) { RFID_WritFlag = 1;//开启RFID写标志 for(int i = 0;i<UartRxLen-14;i++) { RFID_WriteData[i]=UartData[i+13]; } printf("数据获取完成开始写数据:%s\r\n",RFID_WriteData); RFID_Handl(); } else printf("只支持16位数据修改,您的数据不合法!\n\r"); } UartDataReceived = 0; } return; } /* USER CODE END 1 */
main.c(注意:main.c这个文件因为cobe生成的代码太多部分以删除)
/* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "spi.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "rc522.h" #include "rfid.h" /* USER CODE END Includes */ int main(void) { /* USER CODE BEGIN 1 */ /* 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 */ PCD_Init();//初始化RC522 /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_SPI1_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ LED0 = 0; LED1 = 1; printf("初始化完成,程序开始运行中...\r\n"); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { //USART_Handl();//串口处理函数 RFID_Handl();//RFID处理函数 /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }
最终实验现象