赞
踩
(2021/11/1编辑)
在项目需要做一个NFC门禁功能的时候,突然发现有个RC522丢在我的桌面,甚至不知道它上面的引脚什么意思(还不会SPI通讯),搜索关键词“RC522”去看博客搜索资料,发现了很多都在说扇区,块,S50(M1)卡,然后就给代码,一开始我还以为S50是内嵌在这个模块里面的一个存储器,然后越看越怪,后面去淘宝搜索S50,才发现S50其实是我们的门禁卡,RC522是用来感应和判断的。
(2021/11/5编辑)
/*MFRC522命令集,中文手册P59*/
#define MFRC_IDLE 0x00 //取消当前命令的执行
#define MFRC_TRANSMIT 0x04 //发送FIFO缓冲区内容
#define MFRC_RECEIVE 0x08 //激活接收器接收数据
#define MFRC_TRANSCEIVE 0x0C //发送并接收数据
#define MFRC_AUTHENT 0x0E //执行Mifare认证(验证密钥)
#define MFRC_RESETPHASE 0x0F //复位MFRC522
#define MFRC_CALCCRC 0x03 //激活CRC计算
#define MFRC_NOCMDCHANGE 0x07 //无命令改变
/*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 //休眠
打开SPI模式设置为:Full-Duplex Master(全双工主机模式)
随后再定义两个普通的OUTPUT输出的引脚作为复位和使能引脚
/*************************************************************************************** * 函数名称: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("寻卡OK\r\n");break; case PCD_ERR: printf("寻卡ERROR\r\n");break; case PCD_NOTAGERR: printf("无卡\r\n");break; } MFRC_SetBitMask(MFRC_CollReg, 0x80); return status; }
//三目运算符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);
}
/************************************************************************************** * 函数名称: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);
}
/************************************************************************************** * 函数名称: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; }
/************************************************************************************** * 函数名称: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); //处理过的数据再写入寄存器
}
#ifndef _RC522_H #define _RC522_H //头文件 //************************************************ #include "gpio.h"//要一些引脚上的宏定义 #include "spi.h"//硬件SPI的定义 #include "printf.h" #include "main.h"//Laber User上的宏定义 //************************************************ //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
//先用CubeMx初始化 PCD_Init();//RC522初始化 /* * 函数功能:验证刷卡人,以及发送上位机刷卡人身份 * 参 数:无 * 返 回 值:无 * 注 意:无 * 作 者:苏释州 */ void NFC(void) { //寻卡 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,"b59dfcaa")==0)//卖家配的卡 { DoorControl(1);//开门 HAL_TIM_Base_Start_IT(&htim5);//开门的时候开启定时器5的中断,进入关门计时 memset(RxBuffer, 0, sizeof(RxBuffer));//清空字符串,这里要清除RxBuffer才行,否则Card_ID又会被组起来 } else if(strcmp(Card_ID,"e1eff3cc")==0)//刘骏帆手机本科生证 { DoorControl(1);//开门 HAL_TIM_Base_Start_IT(&htim5);//开启定时器5的中断 memset(RxBuffer, 0, sizeof(RxBuffer));//清空字符串,这里要清除RxBuffer才行,否则Card_ID又会被组起来 } else { DoorControl(1);//开门 HAL_TIM_Base_Start_IT(&htim5);//开启定时器5的中断 memset(RxBuffer, 0, sizeof(RxBuffer));//清空字符串 } HAL_Delay(100); return; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。