1. 前言(包括一些个人理解)
(2021/11/1编辑) 在项目需要做一个NFC门禁功能的时候,突然发现有个RC522丢在我的桌面,甚至不知道它上面的引脚什么意思(还不会SPI通讯),搜索关键词“RC522”去看博客搜索资料,发现了很多都在说扇区,块,S50(M1)卡,然后就给代码,一开始我还以为S50是内嵌在这个模块里面的一个存储器,然后越看越怪,后面去淘宝搜索S50,才发现S50其实是我们的门禁卡,RC522是用来感应和判断的。 (2021/11/5编辑)
- PCD是接近式卡。PICC是接近式耦合设备。
- 在通信过程中实际上是使用PCD命令控制RC522发出PICC命令与卡进行交互。
2. RC522门禁工作过程
#define MFRC_IDLE 0x00
#define MFRC_TRANSMIT 0x04
#define MFRC_RECEIVE 0x08
#define MFRC_TRANSCEIVE 0x0C
#define MFRC_AUTHENT 0x0E
#define MFRC_RESETPHASE 0x0F
#define MFRC_CALCCRC 0x03
#define MFRC_NOCMDCHANGE 0x07
#define PICC_REQIDL 0x26
#define PICC_REQALL 0x52
#define PICC_ANTICOLL1 0x93
#define PICC_ANTICOLL2 0x95
#define PICC_AUTHENT1A 0x60
#define PICC_AUTHENT1B 0x61
#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
3. CubeMx配置
3.1 SPI通讯的配置
打开SPI模式设置为:Full-Duplex Master(全双工主机模式)
- 分频设置为8~256都行,这样随之波特率也会改变,波特率越小通信速度越快
- Clock Phase (CPHA) 设置为第一个上升沿这里一定要1Edge
- 不开启CRC检测
3.2 SDA和REST引脚的配置
随后再定义两个普通的OUTPUT输出的引脚作为复位和使能引脚
4. 外设代码函数编写
4.2 主函数能调用的接口函数
void PCD_Init(void)
{
MFRC_Init();
PCD_Reset();
PCD_AntennaOff();
PCD_AntennaOn();
PCD_Reset();
}
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);
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;
}
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;
}
4.2 二级内部调用函数
#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
void MFRC_Init(void)
{
RS522_NSS(1);
RS522_RST(1);
}
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);
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);
PCD_AntennaOff();
osDelay(2);
PCD_AntennaOn();
}
void PCD_AntennaOn(void)
{
uint8_t temp;
temp = MFRC_ReadReg(MFRC_TxControlReg);
if (!(temp & 0x03))
{
MFRC_SetBitMask(MFRC_TxControlReg, 0x03);
}
}
void PCD_AntennaOff(void)
{
MFRC_ClrBitMask(MFRC_TxControlReg, 0x03);
}
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:
irqEn = 0x12;
waitFor = 0x10;
break;
case MFRC_TRANSCEIVE:
irqEn = 0x77;
waitFor = 0x30;
break;
}
MFRC_WriteReg(MFRC_ComIEnReg, irqEn | 0x80);
MFRC_ClrBitMask(MFRC_ComIrqReg, 0x80);
MFRC_WriteReg(MFRC_CommandReg, MFRC_IDLE);
MFRC_SetBitMask(MFRC_FIFOLevelReg, 0x80);
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;
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;
}
4.3 第三级最底层函数
uint8_t MFRC_ReadReg(uint8_t addr)
{
uint8_t AddrByte, data;
AddrByte = ((addr << 1 ) & 0x7E ) | 0x80;
RS522_NSS(0);
SPI2_RW_Byte(AddrByte);
data = SPI2_RW_Byte(0x00);
RS522_NSS(1);
return data;
}
void MFRC_SetBitMask(uint8_t addr, uint8_t mask)
{
uint8_t temp;
temp = MFRC_ReadReg(addr);
MFRC_WriteReg(addr, temp | mask);
}
void MFRC_ClrBitMask(uint8_t addr, uint8_t mask)
{
uint8_t temp;
temp = MFRC_ReadReg(addr);
MFRC_WriteReg(addr, temp & ~mask);
}
5. 使用教程
PCD_Init();
void NFC(void)
{
if (PCD_Request(PICC_REQALL, RxBuffer)!=0)
{
memset(RxBuffer, 0, sizeof(RxBuffer));
return;
}
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);
memset(RxBuffer, 0, sizeof(RxBuffer));
}
else if(strcmp(Card_ID,"e1eff3cc")==0)
{
DoorControl(1);
HAL_TIM_Base_Start_IT(&htim5);
memset(RxBuffer, 0, sizeof(RxBuffer));
}
else
{
DoorControl(1);
HAL_TIM_Base_Start_IT(&htim5);
memset(RxBuffer, 0, sizeof(RxBuffer));
}
HAL_Delay(100);
return;
}
|