基于STM32G070RBT6模拟SPI的RC522驱动移植

本例程使用环境如下:

芯片:STM32G070RBT6

RFID模块:RC522

软件:STM32CubeMX、keil

工程链接:

链接:https://pan.baidu.com/s/1QnMhPtPyV-y3J9uGa7GqvA?pwd=AAAA 
提取码:AAAA 

工程配置:

使用STM32CubeMX配置芯片的主频为64MHz(需启用外部晶振)、启用USART.

移植RC522驱动:

找到生成工程的根目录,新建名为User的文件夹并将RC522s.h和RC522.c复制进去

RC522s.h

#ifndef RFID_RC522S_H
#define RFID_RC522S_H

#include "main.h" 
 
#define DelayMs(n) HAL_Delay(n)
/*
RC522射频模块外部的接口:
*1--SDA <----->PA4--片选脚
*2--SCK <----->PA5--时钟线
*3--MOSI<----->PA7--输出
*4--MISO<----->PA6--输入
*5--悬空
*6--GND <----->GND
*7--RST <----->PA11--复位脚
*8--VCC <----->VCC
*/
 
 
//MF522命令字
#define PCD_IDLE              0x00               //取消当前命令
#define PCD_AUTHENT           0x0E               //验证密钥
#define PCD_RECEIVE           0x08               //接收数据
#define PCD_TRANSMIT          0x04               //发送数据
#define PCD_TRANSCEIVE        0x0C               //发送并接收数据
#define PCD_RESETPHASE        0x0F               //复位
#define PCD_CALCCRC           0x03               //CRC计算
 
 
//Mifare_One卡片命令字
#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_RESTORE          0xC2               //调块数据到缓冲区
#define PICC_TRANSFER         0xB0               //保存缓冲区中数据
#define PICC_HALT             0x50               //休眠
 
//MF522 FIFO长度定义
#define DEF_FIFO_LENGTH       64                 //FIFO size=64byte
#define MAXRLEN  18
 
 
//MF522寄存器定义
// PAGE 0
#define     RFU00                 0x00    
#define     CommandReg            0x01    
#define     ComIEnReg             0x02    
#define     DivlEnReg             0x03    
#define     ComIrqReg             0x04    
#define     DivIrqReg             0x05
#define     ErrorReg              0x06    
#define     Status1Reg            0x07    
#define     Status2Reg            0x08    
#define     FIFODataReg           0x09
#define     FIFOLevelReg          0x0A
#define     WaterLevelReg         0x0B
#define     ControlReg            0x0C
#define     BitFramingReg         0x0D
#define     CollReg               0x0E
#define     RFU0F                 0x0F
// PAGE 1     
#define     RFU10                 0x10
#define     ModeReg               0x11
#define     TxModeReg             0x12
#define     RxModeReg             0x13
#define     TxControlReg          0x14
#define     TxAutoReg             0x15
#define     TxSelReg              0x16
#define     RxSelReg              0x17
#define     RxThresholdReg        0x18
#define     DemodReg              0x19
#define     RFU1A                 0x1A
#define     RFU1B                 0x1B
#define     MifareReg             0x1C
#define     RFU1D                 0x1D
#define     RFU1E                 0x1E
#define     SerialSpeedReg        0x1F
// PAGE 2    
#define     RFU20                 0x20  
#define     CRCResultRegM         0x21
#define     CRCResultRegL         0x22
#define     RFU23                 0x23
#define     ModWidthReg           0x24
#define     RFU25                 0x25
#define     RFCfgReg              0x26
#define     GsNReg                0x27
#define     CWGsCfgReg            0x28
#define     ModGsCfgReg           0x29
#define     TModeReg              0x2A
#define     TPrescalerReg         0x2B
#define     TReloadRegH           0x2C
#define     TReloadRegL           0x2D
#define     TCounterValueRegH     0x2E
#define     TCounterValueRegL     0x2F
 
// PAGE 3      
#define     RFU30                 0x30
#define     TestSel1Reg           0x31
#define     TestSel2Reg           0x32
#define     TestPinEnReg          0x33
#define     TestPinValueReg       0x34
#define     TestBusReg            0x35
#define     AutoTestReg           0x36
#define     VersionReg            0x37
#define     AnalogTestReg         0x38
#define     TestDAC1Reg           0x39  
#define     TestDAC2Reg           0x3A   
#define     TestADCReg            0x3B   
#define     RFU3C                 0x3C   
#define     RFU3D                 0x3D   
#define     RFU3E                 0x3E   
#define     RFU3F		  		        0x3F
 
 
//和MF522通讯时返回的错误代码
#define 	MI_OK                 0
#define 	MI_NOTAGERR           1
#define 	MI_ERR                2
 
#define	SHAQU1		0X01
#define	KUAI4			0X04
#define	KUAI7			0X07
#define	REGCARD		0xa1
#define	CONSUME		0xa2
#define READCARD	0xa3
#define ADDMONEY	0xa4
 

/*
    RC522各种驱动函数
*/
void RC522_Init(void);																            		//功    能:RC522射频卡模块初始化
void RC522_ClearBitMask(uint8_t  reg,uint8_t  mask);									//功    能:清RC522寄存器位
void RC522_WriteRawRC(uint8_t  Address, uint8_t  value);					    //功    能:写RC632寄存器
void RC522_SetBitMask(uint8_t  reg,uint8_t  mask);							     	//功    能:置RC522寄存器位
char RC522_PcdComMF522(uint8_t  Command,uint8_t *pIn,uint8_t  InLenByte,uint8_t *pOut,uint8_t *pOutLenBit);	//功能:通过RC522和ISO14443卡通讯
void RC522_CalulateCRC(uint8_t  *pIn,uint8_t  len,uint8_t  *pOut );		//功    能:用MF522计算CRC16函数
uint8_t  RC522_ReadRawRC(uint8_t  Address);													  //功    能:读RC632寄存器
char RC522_PcdReset(void);																						//功    能:复位RC522
char RC522_PcdRequest(unsigned char req_code,unsigned char *pTagType);//功    能:寻卡
void RC522_PcdAntennaOn(void);																				//功    能:开启天线 
void RC522_PcdAntennaOff(void);																				//功    能:关闭天线
char M500PcdConfigISOType(unsigned char type);									      //功    能:设置RC632的工作方式 
char RC522_PcdAnticoll(unsigned char *pSnr);													//功    能:防冲撞
char RC522_PcdSelect(unsigned char *pSnr);														//功    能:选定卡片
char RC522_PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr);//功    能:验证卡片密码
char RC522_PcdWrite(unsigned char addr,unsigned char *pData);					//功    能:写数据到M1卡一块
char RC522_PcdRead(unsigned char addr,unsigned char *pData);					//功    能:读取M1卡一块数据
char RC522_PcdHalt(void);																							//功    能:命令卡片进入休眠状态
void RC522_Reset(void);																					      //功    能:复位RC522
uint8_t  RC522_MFRC522_SelectTag(uint8_t  *serNum);                   //功    能:读取卡存储器容量
uint8_t  RC522_SPI_ReadWriteOneByte(uint8_t  tx_data);								//功    能:SPI读写函数
#endif

RC522s.c

#include "RC522S.h"
#include "string.h"

/*
函数功能:移植接口--SPI时序读写一个字节
函数参数:data:要写入的数据
返 回 值:读到的数据
*/
uint8_t  RC522_SPI_ReadWriteOneByte(uint8_t  tx_data)
{			  	 
	uint8_t  rx_data=0;				 
  uint8_t  i;
  for(i=0;i<8;i++)
	{
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, 0);;  
		if(tx_data&0x80){HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, 1);}
		else {HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, 0);}
		tx_data<<=1;	
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, 1);;
		rx_data<<=1;
		if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6))rx_data|=0x01;
	}
	//检测spi是否接通
//	if(rx_data != 0) {
//		printf("rx_data != 0\r\n");
//	} else {
//		printf("rx_data = 0\r\n");
//	}
	return rx_data; 
}
 
 
/*
函数功能:初始化RC522的IO口	 
*1--SDA <----->PA4--片选脚
*2--SCK <----->PA5--时钟线
*3--MOSI<----->PA7--输出
*4--MISO<----->PA6--输入
*5--悬空
*6--GND <----->GND
*7--RST <----->PA11--复位脚
*8--VCC <----->VCC
*/
void RC522_IO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7|GPIO_PIN_11, GPIO_PIN_SET);

  /*Configure GPIO pins : PA4 PA5 PA7 PA11 */
  GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7|GPIO_PIN_11;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PA6 */
  GPIO_InitStruct.Pin = GPIO_PIN_6;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}	
 
 
/*
功能描述:选卡读取卡存储器容量
输入参数:serNum 传入卡序列号
返 回 值:成功返回卡容量
*/
uint8_t  RC522_MFRC522_SelectTag(uint8_t  *serNum) //读取卡存储器容量
{     
	uint8_t  i;     
	uint8_t  status;     
	uint8_t  size;     
	uint8_t  recvBits;     
	uint8_t  buffer[9];
	     
	buffer[0]=PICC_ANTICOLL1;	  //防撞码1     
	buffer[1]=0x70;
	buffer[6]=0x00;						     
	for(i=0;i<4;i++)					
	{
		buffer[i+2]=*(serNum+i);	//buffer[2]-buffer[5]为卡序列号
		buffer[6]^=*(serNum+i);	  //卡校验码
	}
	
	RC522_CalulateCRC(buffer,7,&buffer[7]);	//buffer[7]-buffer[8]为RCR校验码
	RC522_ClearBitMask(Status2Reg,0x08);
	status=RC522_PcdComMF522(PCD_TRANSCEIVE,buffer,9,buffer,&recvBits);
	
	if((status==MI_OK)&&(recvBits==0x18))    
		size=buffer[0];     
	else    
		size=0;
	
	return size; 
}
 
 
/*
延时函数,纳秒级
*/
void RC522_Delay(uint32_t  ns)
{
  uint32_t  i;
  for(i=0;i<ns;i++)
  {
    __nop();
    __nop();
    __nop();
  }
}
 
 
/*
函数功能:RC522芯片初始化
*/
void RC522_Init(void)
{
  RC522_IO_Init();	//RC522初始化
  RC522_PcdReset();  			//复位RC522 
  RC522_PcdAntennaOff();	//关闭天线
  DelayMs(2);  		  //延时2毫秒
  RC522_PcdAntennaOn();		//开启天线
  M500PcdConfigISOType('A'); //设置RC632的工作方式
}
 
 
/*
函数功能:复位RC522
*/
void RC522_Reset(void)
{
  RC522_PcdReset();				//复位RC522
  RC522_PcdAntennaOff();	//关闭天线
  DelayMs(2);  		  //延时2毫秒
  RC522_PcdAntennaOn();		//开启天线  	
}     
 
 
/*
功    能: 寻卡
参数说明: req_code[IN]:寻卡方式
                0x52   = 寻感应区内所有符合14443A标准的卡
                0x26   = 寻未进入休眠状态的卡
          			pTagType[OUT]:卡片类型代码
                0x4400 = Mifare_UltraLight
                0x0400 = Mifare_One(S50)
                0x0200 = Mifare_One(S70)
                0x0800 = Mifare_Pro(X)
                0x4403 = Mifare_DESFire
返 回 值: 成功返回MI_OK
*/
char RC522_PcdRequest(uint8_t  req_code,uint8_t  *pTagType)
{
	char status;  
	uint8_t  unLen;
	uint8_t  ucComMF522Buf[MAXRLEN];  	   // MAXRLEN  18
 
	RC522_ClearBitMask(Status2Reg,0x08);	//清RC522寄存器位,/接收数据命令
	RC522_WriteRawRC(BitFramingReg,0x07); //写RC632寄存器
	RC522_SetBitMask(TxControlReg,0x03);  //置RC522寄存器位
 
	ucComMF522Buf[0]=req_code; 	    //寻卡方式
	
	status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen); //通过RC522和ISO14443卡通讯
	
	if((status==MI_OK)&&(unLen==0x10))
	{    
		*pTagType=ucComMF522Buf[0];
		*(pTagType+1)=ucComMF522Buf[1];
	}
	else
	{
	  status = MI_ERR;
	}  
	return status;
}
 
 
/*
功    能: 防冲撞
参数说明: pSnr[OUT]:卡片序列号,4字节
返    回: 成功返回MI_OK
*/
char RC522_PcdAnticoll(uint8_t  *pSnr)
{
    char status;
    uint8_t  i,snr_check=0;
    uint8_t  unLen;
    uint8_t  ucComMF522Buf[MAXRLEN]; 
    
    RC522_ClearBitMask(Status2Reg,0x08);  //清RC522寄存器位 
    RC522_WriteRawRC(BitFramingReg,0x00); //写
    RC522_ClearBitMask(CollReg,0x80);     //清
 
    ucComMF522Buf[0]=PICC_ANTICOLL1;   //PICC_ANTICOLL1 = 0x93
    ucComMF522Buf[1]=0x20;
	
    status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen); //0x0c,通过RC522和ISO14443卡通讯
											 //PCD_TRANSCEIVE =发送并接收数据
											 //2:写入卡里的数据字节长度
											 //ucComMF522Buf:存放数据的地址
											 //unLen:从卡里读出的数据长度
    if(status==MI_OK)
    {
    	 for(i=0;i<4;i++)
			 {   
					 *(pSnr+i)=ucComMF522Buf[i];  //把读到的卡号赋值给pSnr
					 snr_check^=ucComMF522Buf[i];
			 }
			 if(snr_check!=ucComMF522Buf[i])
			 {
					status = MI_ERR;
			 }
    }   
    RC522_SetBitMask(CollReg,0x80);
    return status;
}
 
 
/*
功    能:选定卡片
参数说明:pSnr[IN]:卡片序列号,4字节
返    回:成功返回MI_OK
*/
char RC522_PcdSelect(uint8_t  *pSnr)
{
    char status;
    uint8_t  i;
    uint8_t  unLen;
    uint8_t  ucComMF522Buf[MAXRLEN]; 
    
    ucComMF522Buf[0]=PICC_ANTICOLL1;
    ucComMF522Buf[1]=0x70;
    ucComMF522Buf[6]=0;
	
    for(i=0;i<4;i++)
    {
    	ucComMF522Buf[i+2]=*(pSnr+i);
    	ucComMF522Buf[6]^=*(pSnr+i);
    }
		
    RC522_CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]); //用MF522计算CRC16函数,校验数据
    RC522_ClearBitMask(Status2Reg,0x08);	                //清RC522寄存器位
    status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);
    if((status==MI_OK)&&(unLen==0x18))status=MI_OK;
    else status=MI_ERR;
		
    return status;
}
 
 
/*
功    能:验证卡片密码
参数说明:auth_mode[IN]: 密码验证模式
                 0x60 = 验证A密钥
                 0x61 = 验证B密钥 
          addr[IN]:块地址
          pKey[IN]:扇区密码
          pSnr[IN]:卡片序列号,4字节
返    回:成功返回MI_OK
*/               
char RC522_PcdAuthState(uint8_t  auth_mode,uint8_t  addr,uint8_t  *pKey,uint8_t  *pSnr)
{
    char status;
    uint8_t  unLen;
    uint8_t  ucComMF522Buf[MAXRLEN];  //MAXRLEN  18(数组的大小)
	  
	  //验证模式+块地址+扇区密码+卡序列号   
    ucComMF522Buf[0]=auth_mode;		
    ucComMF522Buf[1]=addr;				
    memcpy(&ucComMF522Buf[2],pKey,6); //拷贝,复制
    memcpy(&ucComMF522Buf[8],pSnr,4); 
	 
    status=RC522_PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen);
    if((status!= MI_OK)||(!(RC522_ReadRawRC(Status2Reg)&0x08)))status = MI_ERR;
    return status;
}
 
 
/*
功    能:读取M1卡一块数据
参数说明: 
					addr:块地址
          p   :读出的块数据,16字节
返    回:成功返回MI_OK
*/ 
char RC522_PcdRead(uint8_t  addr,uint8_t  *p)
{
    char status;
    uint8_t  unLen;
    uint8_t  i,ucComMF522Buf[MAXRLEN]; //18
 
    ucComMF522Buf[0]=PICC_READ;
    ucComMF522Buf[1]=addr;
    RC522_CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
    status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);//通过RC522和ISO14443卡通讯
    if((status==MI_OK&&(unLen==0x90)))
    {
        for(i=0;i<16;i++)
				{
						*(p +i)=ucComMF522Buf[i];
				}
    }
    else
    {   
			status=MI_ERR;
		}
    return status;
}
 
 
/*
功    能:写数据到M1卡指定块
参数说明:addr:块地址
          p   :向块写入的数据,16字节
返    回:成功返回MI_OK
*/                  
char RC522_PcdWrite(uint8_t  addr,uint8_t  *p)
{
    char status;
    uint8_t  unLen;
    uint8_t  i,ucComMF522Buf[MAXRLEN]; 
    
    ucComMF522Buf[0]=PICC_WRITE;// 0xA0 //写块
    ucComMF522Buf[1]=addr;      //块地址
    RC522_CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
 
    status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
 
    if((status!= MI_OK)||(unLen != 4)||((ucComMF522Buf[0]&0x0F)!=0x0A))
    {
				status = MI_ERR;
		}
		
    if(status==MI_OK)
    {
        for(i=0;i<16;i++)//向FIFO写16Byte数据 
        {    
        	ucComMF522Buf[i]=*(p +i);   
        }
        RC522_CalulateCRC(ucComMF522Buf,16,&ucComMF522Buf[16]);
        status = RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,18,ucComMF522Buf,&unLen);
        if((status != MI_OK)||(unLen != 4)||((ucComMF522Buf[0]&0x0F)!=0x0A))
        {   
					status = MI_ERR;   
				}
    }
    return status;
}
 
 
/*
功    能:命令卡片进入休眠状态
返    回:成功返回MI_OK
*/
char RC522_PcdHalt(void)
{
    uint8_t  status;
    uint8_t  unLen;
    uint8_t  ucComMF522Buf[MAXRLEN]; //MAXRLEN==18
	  status=status;
    ucComMF522Buf[0]=PICC_HALT;
    ucComMF522Buf[1]=0;
    RC522_CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
    status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
    return MI_OK;
}
 
 
/*
功    能:用MF522计算CRC16函数
参    数:
				*pIn :要读数CRC的数据
				len:-数据长度
				*pOut:计算的CRC结果
*/
void RC522_CalulateCRC(uint8_t  *pIn ,uint8_t  len,uint8_t  *pOut )
{
    uint8_t  i,n;
    RC522_ClearBitMask(DivIrqReg,0x04);  //CRCIrq = 0  
    RC522_WriteRawRC(CommandReg,PCD_IDLE);
    RC522_SetBitMask(FIFOLevelReg,0x80); //清FIFO指针
    
	  //向FIFO中写入数据  
		for(i=0;i<len;i++)
    {  
			RC522_WriteRawRC(FIFODataReg,*(pIn +i));  //开始RCR计算
		}
		
		RC522_WriteRawRC(CommandReg,PCD_CALCCRC);   //等待CRC计算完成 
		i=0xFF;
    do 
    {
        n=RC522_ReadRawRC(DivIrqReg);
        i--;
    }
    while((i!=0)&&!(n&0x04));//CRCIrq = 1
	  
		//读取CRC计算结果 
		pOut[0]=RC522_ReadRawRC(CRCResultRegL);
    pOut[1]=RC522_ReadRawRC(CRCResultRegM);
}
 
 
/*
功    能:复位RC522
返    回:成功返回MI_OK
*/
char RC522_PcdReset(void)
{
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, 1);;   //PF1写1
    RC522_Delay(10);
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, 0);;   //PF1清0
    RC522_Delay(10);
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, 1);;	 //PF1写1
    RC522_Delay(10);
    RC522_WriteRawRC(CommandReg,PCD_RESETPHASE);  //写RC632寄存器,复位
	  RC522_WriteRawRC(CommandReg,PCD_RESETPHASE);	//写RC632寄存器,复位
    RC522_Delay(10);
    
    RC522_WriteRawRC(ModeReg,0x3D);             //和Mifare卡通讯,CRC初始值0x6363
    RC522_WriteRawRC(TReloadRegL,30);           //写RC632寄存器   
    RC522_WriteRawRC(TReloadRegH,0);
    RC522_WriteRawRC(TModeReg,0x8D);
    RC522_WriteRawRC(TPrescalerReg,0x3E);
	
	  RC522_WriteRawRC(TxAutoReg,0x40);//必须要
    return MI_OK;
}
 
 
/*
函数功能:设置RC632的工作方式 
*/
char M500PcdConfigISOType(uint8_t  type)
{
   if(type=='A')                        //ISO14443_A
   { 
		 RC522_ClearBitMask(Status2Reg,0x08);     //清RC522寄存器位
		 RC522_WriteRawRC(ModeReg,0x3D);          //3F//CRC初始值0x6363
		 RC522_WriteRawRC(RxSelReg,0x86);         //84
		 RC522_WriteRawRC(RFCfgReg,0x7F);         //4F  //调整卡的感应距离//RxGain = 48dB调节卡感应距离  
		 RC522_WriteRawRC(TReloadRegL,30);        //tmoLength);// TReloadVal = 'h6a =tmoLength(dec) 
	   RC522_WriteRawRC(TReloadRegH,0);
		 RC522_WriteRawRC(TModeReg,0x8D);
	   RC522_WriteRawRC(TPrescalerReg,0x3E);
	   RC522_Delay(1000);
     RC522_PcdAntennaOn();		//开启天线 
   }
   else return 1;       //失败,返回1
   return MI_OK;				//成功返回0
}
 
 
/*
功    能:读RC632寄存器
参数说明:Address[IN]:寄存器地址
返    回:读出的值
*/
uint8_t  RC522_ReadRawRC(uint8_t  Address)
{
    uint8_t  ucAddr;
    uint8_t  ucResult=0;		
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, 0);;						//片选选中RC522
    ucAddr=((Address<<1)&0x7E)|0x80;
		RC522_SPI_ReadWriteOneByte(ucAddr);		  //发送命令
		ucResult=RC522_SPI_ReadWriteOneByte(0); //读取RC522返回的数据
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, 1);;						   //释放片选线(PF0)
		return ucResult;         //返回读到的数据
}
 
 
/*
功    能:写RC632寄存器
参数说明:Address[IN]:寄存器地址
          value[IN] :写入的值
*/
void RC522_WriteRawRC(uint8_t  Address,uint8_t  value)
{  
  uint8_t  ucAddr;
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, 0);; //PF0写 0 (SDA)(SPI1片选线,低电平有效)
  ucAddr=((Address<<1)&0x7E); 
	RC522_SPI_ReadWriteOneByte(ucAddr); //SPI1发送一个字节
	RC522_SPI_ReadWriteOneByte(value);  //SPI1发送一个字节
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, 1);;										      //PF1写1(SDA)(SPI1片选线)
}
 
 
/*
功    能:置RC522寄存器位
参数说明:reg[IN]:寄存器地址
          mask[IN]:置位值
*/
void RC522_SetBitMask(uint8_t  reg,uint8_t  mask)  
{
    char tmp=0x0;
    tmp=RC522_ReadRawRC(reg);					//读RC632寄存器
    RC522_WriteRawRC(reg,tmp|mask);   //写RC632寄存器
}
 
 
/*
功    能:清RC522寄存器位
参数说明:reg[IN]:寄存器地址
         mask[IN]:清位值
*/
void RC522_ClearBitMask(uint8_t  reg,uint8_t  mask)  
{
    char tmp=0x0;
    tmp=RC522_ReadRawRC(reg);        //读RC632寄存器
    RC522_WriteRawRC(reg,tmp&~mask); // clear bit mask
} 
 
 
/*
功    能:通过RC522和ISO14443卡通讯
参数说明:Command[IN]:RC522命令字
          pIn [IN]:通过RC522发送到卡片的数据
          InLenByte[IN]:发送数据的字节长度
          pOut [OUT]:接收到的卡片返回数据
          *pOutLenBit[OUT]:返回数据的位长度
*/
char RC522_PcdComMF522(uint8_t  Command,uint8_t  *pIn,uint8_t  InLenByte,uint8_t  *pOut,uint8_t  *pOutLenBit)
{
    char status=MI_ERR;
    uint8_t  irqEn=0x00;
    uint8_t  waitFor=0x00;
    uint8_t  lastBits;
    uint8_t  n;
    uint16_t i;
	
    switch(Command)
    {
			case PCD_AUTHENT:    //验证密钥
					 irqEn=0x12;
					 waitFor=0x10;
					 break;
			case PCD_TRANSCEIVE: //发送并接收数据
					 irqEn=0x77;
					 waitFor=0x30;
					 break;
			default:
					 break;
    }
    RC522_WriteRawRC(ComIEnReg,irqEn|0x80);	
    RC522_ClearBitMask(ComIrqReg,0x80);			//清所有中断位
    RC522_WriteRawRC(CommandReg,PCD_IDLE);	
    RC522_SetBitMask(FIFOLevelReg,0x80);	 	//清FIFO缓存
    
    for(i=0;i<InLenByte;i++)
    {   
				RC522_WriteRawRC(FIFODataReg,pIn[i]);
		}
		
		RC522_WriteRawRC(CommandReg,Command);	 
		if(Command==PCD_TRANSCEIVE)
		{  
			RC522_SetBitMask(BitFramingReg,0x80);	 //开始传送
		}
    
		//有问题,下面的循环
    //i = 600;//根据时钟频率调整,操作M1卡最大等待时间25ms
		  i=2000;
			do 
			{
				n=RC522_ReadRawRC(ComIrqReg);
				i--;
			}
			while((i!=0)&&!(n&0x01)&&!(n&waitFor));
				
			RC522_ClearBitMask(BitFramingReg,0x80);
			if(i!=0)
			{    
        if(!(RC522_ReadRawRC(ErrorReg)&0x1B))
        {
            status=MI_OK;
            if(n&irqEn&0x01)
            {
							status=MI_NOTAGERR;
						}
            if(Command==PCD_TRANSCEIVE)
            {
               	n=RC522_ReadRawRC(FIFOLevelReg);
              	lastBits=RC522_ReadRawRC(ControlReg)&0x07;
                if(lastBits)
                {
									*pOutLenBit=(n-1)*8+lastBits;
								}
                else
                {   
									*pOutLenBit=n*8;   
								}
								
                if(n==0)n=1;
                if(n>MAXRLEN)n=MAXRLEN;
                for(i=0; i<n; i++)
                {   
									pOut[i]=RC522_ReadRawRC(FIFODataReg);    
								}
            }
        }
        else
        {   
					status=MI_ERR;   
				}
    }
    RC522_SetBitMask(ControlReg,0x80);// stop timer now
    RC522_WriteRawRC(CommandReg,PCD_IDLE); 
    return status;
}
 
 
/*
函数功能:开启天线  
参    数:每次启动或关闭天险发射之间应至少有1ms的间隔
*/
void RC522_PcdAntennaOn(void)
{
    uint8_t  i;
    i=RC522_ReadRawRC(TxControlReg);
    if(!(i&0x03))
    {
        RC522_SetBitMask(TxControlReg,0x03);
    }
}
 
 
/*
函数功能:关闭天线  
参    数:每次启动或关闭天险发射之间应至少有1ms的间隔
*/
void RC522_PcdAntennaOff(void)
{
	RC522_ClearBitMask(TxControlReg,0x03); //清RC522寄存器位
}
 

打开Keil文件进入配置界面添加User文件夹的地址

添加RC522s.c文件

在main.h里面引用RC522s.h

串口初始化:

在main.h里面引用stdio.h,并在main.c里面添加fput和fget函数,同时不要忘记在配置页面勾选上“USB MicroLib”选项哦!

引脚连接:

RC522
STM32G070RBT6
SDAPA4
SCKPA5
MOSIPA7
MISOPA6
IRQ置空
GNDGND
RSTPA11
3.3V

3.3V(VCC)

测试运行:

将测试代码写入main.c中:

main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @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 "main.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "RC522s.h"
/* 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 */
uint8_t Card_Type1[2];
uint8_t Card_ID[4];
uint8_t Card_KEY[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; //{0x11,0x11,0x11,0x11,0x11,0x11};   //密码
uint8_t Card_Data[16];
uint8_t status;
/* 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 */

  /* 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_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	uint8_t i;
	Card_Type1[0] = 0x04;
	Card_Type1[1] = 0x00;
	RC522_Init();
	printf("---------------------------------------\r\n");
	printf("-----------G070RBT6_RFID_Test----------\r\n");
	printf("---------------------------------------\r\n");
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
        HAL_Delay(10);
        if (MI_OK == RC522_PcdRequest(0x26, Card_Type1)) //寻卡函数,如果成功返回MI_OK   打印1次
				{
            uint16_t cardType = (Card_Type1[0] << 8) | Card_Type1[1]; //读不同卡的类型
            printf("卡类型:(0x%04X)\r\n", cardType);       
            switch (cardType)
            {
            case 0x4400:
                printf("Mifare UltraLight\r\n");
                break;
            case 0x0400:
                printf("Mifare One(S50)\r\n");
                break;
            case 0x0200:
                printf("Mifare One(S70)\r\n");
                break;
            case 0x0800:
                printf("Mifare Pro(X)\r\n");
                break;
            case 0x4403:
                printf("Mifare DESFire\r\n");
                break;
            default:
                printf("Unknown Card\r\n");
                break;
            }

						status = RC522_PcdAnticoll(Card_ID); //防冲撞 如果成功返回MI_OK
            if (status != MI_OK)
            {
                printf("Anticoll Error\r\n");
            }
            else
            {
                printf("Serial Number:%02X%02X%02X%02X\r\n", Card_ID[0], Card_ID[1], Card_ID[2], Card_ID[3]);
            }
            //status = PcdSelect(Card_ID);  //选卡 如果成功返回MI_OK
            status = RC522_PcdSelect(Card_ID);  //选卡 如果成功返回MI_OK
            if(status != MI_OK)
            {
            	printf("Select Card Error\r\n");
            }
            else
            	printf("Select Card OK\r\n");

			//status = PcdAuthState(PICC_AUTHENT1A, 5, Card_KEY, Card_ID);     //验证卡片密码
			status = RC522_PcdAuthState(PICC_AUTHENT1A, 5, Card_KEY, Card_ID); //验证卡片密码
			if (status != MI_OK) {
				printf("Auth State Error\r\n");
				continue;
			}

			memset(Card_ID, 1, 4);
			memset(Card_Data, 1, 16);
			Card_Data[0] = 0xaa;
			
			//status = PcdWrite(6, Card_Data); //写入数据			
			status = RC522_PcdWrite(6, Card_Data); //写入数据
			
			if (status != MI_OK) {
				printf("Card Write Error\r\n");
				continue;
			}
			memset(Card_Data, 0, 16); //清零
			//delay_us(8);
			HAL_Delay(8);
			//status = PcdRead(6, Card_Data); //读取我们写入的数据
			status = RC522_PcdRead(6, Card_Data); //读取我们写入的数据
			if (status != MI_OK) {
				printf("Card Read Error\r\n");
				continue;
			} else {
				for (i = 0; i < 16; i++) {
					printf("%02X ", Card_Data[i]);
				}
				printf("\r\n");
			}

            memset(Card_Data, 0, 16);
            //PcdHalt(); //卡片进入休眠
            RC522_PcdHalt(); //卡片进入休眠
            //status = PcdHalt(); //卡片进入休眠状态		
            status = RC522_PcdHalt(); //卡片进入休眠状态
            if (status != MI_OK)
            {
                printf("PcdHalt Error\r\n");
            }
            else
            {
                printf("PcdHalt OK\r\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};

  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
  RCC_OscInitStruct.PLL.PLLN = 8;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  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_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
int fgetc(FILE *f){
	int ch;
	HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
	return ch;
}
int fputc(int ch, FILE *f) {
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
	return ch;
}


/* 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 */

效果演示:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值