RC522模块学习

2023-05-16

目录

1.原理简介

2.SPI通信

3.获取卡号实验

3.驱动函数


参考:

https://www.cnblogs.com/ivantang/p/3904025.html

https://xiaolong.blog.csdn.net/article/details/117075834?spm=1001.2014.3001.5506

https://blog.csdn.net/weixin_47316662/article/details/124555292?spm=1001.2014.3001.5506

https://blog.csdn.net/qq_40574123/article/details/116722010?spm=1001.2014.3001.5506
https://yourcee.blog.csdn.net/article/details/107832198?spm=1001.2014.3001.5506


 

1.原理简介

       RC522 是一种非接触式读写卡芯片,底层采用SPI模拟时序,可以应用于校园一卡通、水卡充值消费、公交卡充值消费设计、门禁卡等。

       有两个部分,射频读写器和IC卡。射频读写器向IC卡发一组固定频率的电磁波,卡片内有一个LC串联谐振电路,其频率与读写器发射的频率相同,这样在电磁波激励下,LC谐振电路产生共振,从而使电容内有了电荷;在这个电荷的另一端,接有一个单向导通的电子泵,将电容内的电荷送到另一个电容内存储,当所积累的电荷达到2V时,此电容可作为电源为其它电路提供工作电压,将卡内数据发射出去或接受读写器的数据。

      非接触性IC卡与读卡器之间通过无线电波来完成读写操作。二者之间的通讯频率为13.56MHZ。非接触性IC卡本身是无源卡,当读写器对卡进行读写操作时,读写器发出的信号由两部分叠加组成:一部分是电源信号,该信号由卡接收后,与本身的L/C产生一个瞬间能量来供给芯片工作。另一部分则是指令和数据信号,指挥芯片完成数据的读取、修改、储存等,并返回信号给读写器,完成一次读写操作。

流程:

复位应答:M1射频卡的通讯协议和通讯波特率是定义好的,当有卡片进入读写器的操作范围时,读写器以特定的协议与它通讯,从而确定该卡是否为M1射频卡,即验证卡片的卡型。

防冲突机制:当有多张卡进入读写器操作范围时,防冲突机制会从其中选择一张进行操作,未选中的则处于空闲模式等待下一次选卡,该过程会返回被选卡的序列号。

选择卡片:选择被选中的卡的序列号,并同时返回卡的容量代码。

三次互相确认:选定要处理的卡片之后,读写器就确定要访问的扇区号,并对该扇区密码进行密码校验,在三次相互认证之后就可以通过加密流进行通讯。(在选择另一扇区时,则必须进行另一扇区密码校验。)

如果概括来说的话,主要也就四部分:开关连接、寻卡、验证密码、读取。

2.SPI通信

数据由MISO端口到RC52寄存器,RC522寄存器MOSI端口

软件SPI通过控制MISO引脚和MOSI端口引脚的高低电平来控制数据的进出,下面读取和写入寄存器的函数都是靠这两个函数来接收和发送数据与外界

 RC552采用模式3,上图为模式3的时序图,根据时序图写发送数据,共有8个时钟周期,所以循环8次, 按位查询需要发送的数据的高低电平,0MOSI引输出低电平,1MOSI输出高电平,然后调SCK时钟引脚,使时钟引脚输出低电平(默认状态高电平),延时一会,输出高电平。

void SPI_RC522_SendByte ( uint8_t byte )
{
  uint8_t counter;
 
  for(counter=0;counter<8;counter++)
  {     
    if ( byte & 0x80 )
      RC522_MOSI_1 ();
    else 
      RC522_MOSI_0 ();
    
    RC522_DELAY();
    RC522_SCK_0 ();
    
    RC522_DELAY();
    RC522_SCK_1();
    
    RC522_DELAY();
    byte <<= 1; 
  } 	
}
 
 
/**
  * @brief  从RC522发送1 Byte 数据
  * @param  无
  * @retval RC522返回的数据
  */
uint8_t SPI_RC522_ReadByte ( void )
{
  uint8_t counter;
  uint8_t SPI_Data;
 
  for(counter=0;counter<8;counter++)
  {
    SPI_Data <<= 1;
    RC522_SCK_0 ();
   
    RC522_DELAY();
    if ( RC522_MISO_GET() == 1)
     SPI_Data |= 0x01;
    
    RC522_DELAY();
    RC522_SCK_1 ();
    
    RC522_DELAY();
  }
  return SPI_Data;
	
}

3.获取卡号实验

假设我们写522代码的目的是为了设计一个门禁系统,那有个问题是:我们需要从ic中读出什么数据?什么数据又是正确的数据?

卡片内部有块地址,它用于存放厂商代码,已经固化,不可更改。这样一个东西,叫做UID,这是一个存储在ic中的不可更改的数据,他是一个4字节16进制数,所以我们将他作为我们的判断依据。

开发板采用正点原子mini板,主控芯片为stm32F103RCT6

stm使用引脚

引脚名称使用功能定义
PB0普通的GPIO口,用于复位RC522
PA6SPI1的MISO
PA7SPI1的MOSI
PA5SPI1的SCK
PA4普通的GPIO口,用于RC522的片选端口

RC522使用引脚说明

引脚名称功能
3.3V电源正
RST复位引脚,高电平有效
GND地,电源负
IRQ中断引脚,悬空不使用
MISOSPI协议数据线
MOSISPI协议数据线
SCKSPI时钟线
SDASPI片选端口

接线说明

STM32F103RC522
3V33.3V
PB0RST
GNDGND
不接IRQ
PA6MISO
PA7MOSI
PA5SCK
PA4SDA

最后接好线烧录程序后,利用串口助手即可查看ic卡的uid,试了一下自己的校园卡也是可以刷出来的。主函数main.c

void IC_test ( void )
{
	char cStr [ 30 ];
  u8 ucArray_ID [ 4 ];        
	u8 ucStatusReturn;           
  static u8 ucLineCount = 0; 
	
  while ( 1 )
  { 
		if ( ( ucStatusReturn = PcdRequest ( PICC_REQALL, ucArray_ID ) ) != MI_OK )   
		{
				ucStatusReturn = PcdRequest ( PICC_REQALL, ucArray_ID );		
		}
		if ( ucStatusReturn == MI_OK  )
		{
			if ( PcdAnticoll ( ucArray_ID ) == MI_OK ) 
			{
				sprintf ( cStr, "The Card ID is: %02X%02X%02X%02X", ucArray_ID [ 0 ], ucArray_ID [ 1 ], ucArray_ID [ 2 ], ucArray_ID [ 3 ] );
				printf ( "%s\r\n",cStr ); 
				if ( ucLineCount == 0 )
				ucLineCount ++;
				if ( ucLineCount == 17 ) ucLineCount = 0;
			}	
		}	
  }
}

3.驱动函数rcc.c


/*
 * 函数名:SPI_RC522_SendByte
 * 描述  :向RC522发送1 Byte 数据
 * 输入  :byte,要发送的数据
 * 返回  : RC522返回的数据
 * 调用  :内部调用
 */
void SPI_RC522_SendByte ( u8 byte )
{
    u8 counter;
	
	
    for(counter=0;counter<8;counter++)
    {     
			if ( byte & 0x80 )
					macRC522_MOSI_1 ();
			else 
					macRC522_MOSI_0 ();

//			Delay_us ( 3 );
			macRC522_DELAY();
		
			macRC522_SCK_0 ();

//			Delay_us ( 1 );
//			Delay_us ( 3 );
			macRC522_DELAY();
			 
			macRC522_SCK_1();

//			Delay_us ( 3 );
			macRC522_DELAY();
			 
			byte <<= 1; 
			
    } 
	
}


/*
 * 函数名:SPI_RC522_ReadByte
 * 描述  :从RC522发送1 Byte 数据
 * 输入  :无
 * 返回  : RC522返回的数据
 * 调用  :内部调用
 */
u8 SPI_RC522_ReadByte ( void )
{
	u8 counter;
	u8 SPI_Data;


	for(counter=0;counter<8;counter++)
	{
			SPI_Data <<= 1;
	 
			macRC522_SCK_0 ();

//			Delay_us ( 3 );
		macRC522_DELAY();
		
			if ( macRC522_MISO_GET() == 1)
					SPI_Data |= 0x01;

//			Delay_us ( 2 );
//			Delay_us ( 3 );
			macRC522_DELAY();

			macRC522_SCK_1 ();
	
//			Delay_us ( 3 );
			macRC522_DELAY();
			
	}
	
	return SPI_Data;
	
}


/*
 * 函数名:ReadRawRC
 * 描述  :读RC522寄存器
 * 输入  :ucAddress,寄存器地址
 * 返回  : 寄存器的当前值
 * 调用  :内部调用
 */
u8 ReadRawRC ( u8 ucAddress )
{
	u8 ucAddr, ucReturn;
	
	
	ucAddr = ( ( ucAddress << 1 ) & 0x7E ) | 0x80;
	
	macRC522_CS_Enable();
	
	SPI_RC522_SendByte ( ucAddr );
	
	ucReturn = SPI_RC522_ReadByte ();
	
	macRC522_CS_Disable();
	
	
	return ucReturn;
	
	
}


/*
 * 函数名:WriteRawRC
 * 描述  :写RC522寄存器
 * 输入  :ucAddress,寄存器地址
 *         ucValue,写入寄存器的值
 * 返回  : 无
 * 调用  :内部调用
 */
void WriteRawRC ( u8 ucAddress, u8 ucValue )
{  
	u8 ucAddr;
	
	
	ucAddr = ( ucAddress << 1 ) & 0x7E;
	
	macRC522_CS_Enable();
	
	SPI_RC522_SendByte ( ucAddr );
	
	SPI_RC522_SendByte ( ucValue );
	
	macRC522_CS_Disable();	

	
}


/*
 * 函数名:SetBitMask
 * 描述  :对RC522寄存器置位
 * 输入  :ucReg,寄存器地址
 *         ucMask,置位值
 * 返回  : 无
 * 调用  :内部调用
 */
void SetBitMask ( u8 ucReg, u8 ucMask )  
{
    u8 ucTemp;
	
	
    ucTemp = ReadRawRC ( ucReg );
	
    WriteRawRC ( ucReg, ucTemp | ucMask );         // set bit mask
	
	
}


/*
 * 函数名:ClearBitMask
 * 描述  :对RC522寄存器清位
 * 输入  :ucReg,寄存器地址
 *         ucMask,清位值
 * 返回  : 无
 * 调用  :内部调用
 */
void ClearBitMask ( u8 ucReg, u8 ucMask )  
{
    u8 ucTemp;
	
	
    ucTemp = ReadRawRC ( ucReg );
	
    WriteRawRC ( ucReg, ucTemp & ( ~ ucMask) );  // clear bit mask
	
	
}


/*
 * 函数名:PcdAntennaOn
 * 描述  :开启天线 
 * 输入  :无
 * 返回  : 无
 * 调用  :内部调用
 */
void PcdAntennaOn ( void )
{
    u8 uc;
	
	
    uc = ReadRawRC ( TxControlReg );
	
    if ( ! ( uc & 0x03 ) )
			SetBitMask(TxControlReg, 0x03);

		
}


/*
 * 函数名:PcdAntennaOff
 * 描述  :开启天线 
 * 输入  :无
 * 返回  : 无
 * 调用  :内部调用
 */
void PcdAntennaOff ( void )
{
  ClearBitMask ( TxControlReg, 0x03 );
	
	
}


/*
 * 函数名:PcdRese
 * 描述  :复位RC522 
 * 输入  :无
 * 返回  : 无
 * 调用  :外部调用
 */
void PcdReset ( void )
{
	macRC522_Reset_Disable();
	
	Delay_us ( 1 );
	
	macRC522_Reset_Enable();
	
	Delay_us ( 1 );
	
	macRC522_Reset_Disable();
	
	Delay_us ( 1 );
	
	WriteRawRC ( CommandReg, 0x0f );
	
	while ( ReadRawRC ( CommandReg ) & 0x10 );
	
	Delay_us ( 1 );
	
  WriteRawRC ( ModeReg, 0x3D );            //定义发送和接收常用模式 和Mifare卡通讯,CRC初始值0x6363
	
  WriteRawRC ( TReloadRegL, 30 );          //16位定时器低位    
	WriteRawRC ( TReloadRegH, 0 );			     //16位定时器高位
	
  WriteRawRC ( TModeReg, 0x8D );				   //定义内部定时器的设置
	
  WriteRawRC ( TPrescalerReg, 0x3E );			 //设置定时器分频系数
	
	WriteRawRC ( TxAutoReg, 0x40 );				   //调制发送信号为100%ASK	
	

}


/*
 * 函数名:M500PcdConfigISOType
 * 描述  :设置RC522的工作方式
 * 输入  :ucType,工作方式
 * 返回  : 无
 * 调用  :外部调用
 */
void M500PcdConfigISOType ( u8 ucType )
{
	if ( ucType == 'A')                     //ISO14443_A
  {
		ClearBitMask ( Status2Reg, 0x08 );
		
    WriteRawRC ( ModeReg, 0x3D );//3F
		
		WriteRawRC ( RxSelReg, 0x86 );//84
		
		WriteRawRC( RFCfgReg, 0x7F );   //4F
		
		WriteRawRC( TReloadRegL, 30 );//tmoLength);// TReloadVal = 'h6a =tmoLength(dec) 
		
		WriteRawRC ( TReloadRegH, 0 );
		
		WriteRawRC ( TModeReg, 0x8D );
		
		WriteRawRC ( TPrescalerReg, 0x3E );
		
		Delay_us ( 2 );
		
		PcdAntennaOn ();//开天线
		
   }

	 
}


/*
 * 函数名:PcdComMF522
 * 描述  :通过RC522和ISO14443卡通讯
 * 输入  :ucCommand,RC522命令字
 *         pInData,通过RC522发送到卡片的数据
 *         ucInLenByte,发送数据的字节长度
 *         pOutData,接收到的卡片返回数据
 *         pOutLenBit,返回数据的位长度
 * 返回  : 状态值
 *         = MI_OK,成功
 * 调用  :内部调用
 */
char PcdComMF522 ( u8 ucCommand, u8 * pInData, u8 ucInLenByte, u8 * pOutData, u32 * pOutLenBit )		
{
    char cStatus = MI_ERR;
    u8 ucIrqEn   = 0x00;
    u8 ucWaitFor = 0x00;
    u8 ucLastBits;
    u8 ucN;
    u32 ul;
	
	
    switch ( ucCommand )
    {
       case PCD_AUTHENT:		//Mifare认证
          ucIrqEn   = 0x12;		//允许错误中断请求ErrIEn  允许空闲中断IdleIEn
          ucWaitFor = 0x10;		//认证寻卡等待时候 查询空闲中断标志位
          break;
			 
       case PCD_TRANSCEIVE:		//接收发送 发送接收
          ucIrqEn   = 0x77;		//允许TxIEn RxIEn IdleIEn LoAlertIEn ErrIEn TimerIEn
          ucWaitFor = 0x30;		//寻卡等待时候 查询接收中断标志位与 空闲中断标志位
          break;
			 
       default:
         break;
			 
    }
   
    WriteRawRC ( ComIEnReg, ucIrqEn | 0x80 );		//IRqInv置位管脚IRQ与Status1Reg的IRq位的值相反 
    ClearBitMask ( ComIrqReg, 0x80 );			//Set1该位清零时,CommIRqReg的屏蔽位清零
    WriteRawRC ( CommandReg, PCD_IDLE );		//写空闲命令
    SetBitMask ( FIFOLevelReg, 0x80 );			//置位FlushBuffer清除内部FIFO的读和写指针以及ErrReg的BufferOvfl标志位被清除
    
    for ( ul = 0; ul < ucInLenByte; ul ++ )
		  WriteRawRC ( FIFODataReg, pInData [ ul ] );    		//写数据进FIFOdata
			
    WriteRawRC ( CommandReg, ucCommand );					//写命令
   
    
    if ( ucCommand == PCD_TRANSCEIVE )
			SetBitMask(BitFramingReg,0x80);  				//StartSend置位启动数据发送 该位与收发命令使用时才有效
    
    ul = 1000;//根据时钟频率调整,操作M1卡最大等待时间25ms
		
    do 														//认证 与寻卡等待时间	
    {
         ucN = ReadRawRC ( ComIrqReg );							//查询事件中断
         ul --;
    } while ( ( ul != 0 ) && ( ! ( ucN & 0x01 ) ) && ( ! ( ucN & ucWaitFor ) ) );		//退出条件i=0,定时器中断,与写空闲命令
		
    ClearBitMask ( BitFramingReg, 0x80 );					//清理允许StartSend位
		
    if ( ul != 0 )
    {
			if ( ! ( ReadRawRC ( ErrorReg ) & 0x1B ) )			//读错误标志寄存器BufferOfI CollErr ParityErr ProtocolErr
			{
				cStatus = MI_OK;
				
				if ( ucN & ucIrqEn & 0x01 )					//是否发生定时器中断
				  cStatus = MI_NOTAGERR;   
					
				if ( ucCommand == PCD_TRANSCEIVE )
				{
					ucN = ReadRawRC ( FIFOLevelReg );			//读FIFO中保存的字节数
					
					ucLastBits = ReadRawRC ( ControlReg ) & 0x07;	//最后接收到得字节的有效位数
					
					if ( ucLastBits )
						* pOutLenBit = ( ucN - 1 ) * 8 + ucLastBits;   	//N个字节数减去1(最后一个字节)+最后一位的位数 读取到的数据总位数
					else
						* pOutLenBit = ucN * 8;   					//最后接收到的字节整个字节有效
					
					if ( ucN == 0 )		
            ucN = 1;    
					
					if ( ucN > MAXRLEN )
						ucN = MAXRLEN;   
					
					for ( ul = 0; ul < ucN; ul ++ )
					  pOutData [ ul ] = ReadRawRC ( FIFODataReg );   
					
					}
					
      }
			
			else
				cStatus = MI_ERR;   
			
    }
   
   SetBitMask ( ControlReg, 0x80 );           // stop timer now
   WriteRawRC ( CommandReg, PCD_IDLE ); 
		 
		
   return cStatus;
		
		
}


/*
 * 函数名:PcdRequest
 * 描述  :寻卡
 * 输入  :ucReq_code,寻卡方式
 *                     = 0x52,寻感应区内所有符合14443A标准的卡
 *                     = 0x26,寻未进入休眠状态的卡
 *         pTagType,卡片类型代码
 *                   = 0x4400,Mifare_UltraLight
 *                   = 0x0400,Mifare_One(S50)
 *                   = 0x0200,Mifare_One(S70)
 *                   = 0x0800,Mifare_Pro(X))
 *                   = 0x4403,Mifare_DESFire
 * 返回  : 状态值
 *         = MI_OK,成功
 * 调用  :外部调用
 */
char PcdRequest ( u8 ucReq_code, u8 * pTagType )
{
   char cStatus;  
	 u8 ucComMF522Buf [ MAXRLEN ]; 
   u32 ulLen;
	

   ClearBitMask ( Status2Reg, 0x08 );	//清理指示MIFARECyptol单元接通以及所有卡的数据通信被加密的情况
   WriteRawRC ( BitFramingReg, 0x07 );	//	发送的最后一个字节的 七位
   SetBitMask ( TxControlReg, 0x03 );	//TX1,TX2管脚的输出信号传递经发送调制的13.56的能量载波信号

   ucComMF522Buf [ 0 ] = ucReq_code;		//存入 卡片命令字

   cStatus = PcdComMF522 ( PCD_TRANSCEIVE,	ucComMF522Buf, 1, ucComMF522Buf, & ulLen );	//寻卡  
  
   if ( ( cStatus == MI_OK ) && ( ulLen == 0x10 ) )	//寻卡成功返回卡类型 
   {    
       * pTagType = ucComMF522Buf [ 0 ];
       * ( pTagType + 1 ) = ucComMF522Buf [ 1 ];
   }
	 
   else
     cStatus = MI_ERR;

   
   return cStatus;
	 
	 
}


/*
 * 函数名:PcdAnticoll
 * 描述  :防冲撞
 * 输入  :pSnr,卡片序列号,4字节
 * 返回  : 状态值
 *         = MI_OK,成功
 * 调用  :外部调用
 */
char PcdAnticoll ( u8 * pSnr )
{
    char cStatus;
    u8 uc, ucSnr_check = 0;
    u8 ucComMF522Buf [ MAXRLEN ]; 
	  u32 ulLen;
    

    ClearBitMask ( Status2Reg, 0x08 );		//清MFCryptol On位 只有成功执行MFAuthent命令后,该位才能置位
    WriteRawRC ( BitFramingReg, 0x00);		//清理寄存器 停止收发
    ClearBitMask ( CollReg, 0x80 );			//清ValuesAfterColl所有接收的位在冲突后被清除
   
    ucComMF522Buf [ 0 ] = 0x93;	//卡片防冲突命令
    ucComMF522Buf [ 1 ] = 0x20;
   
    cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 2, ucComMF522Buf, & ulLen);//与卡片通信
	
    if ( cStatus == MI_OK)		//通信成功
    {
			for ( uc = 0; uc < 4; uc ++ )
			{
         * ( pSnr + uc )  = ucComMF522Buf [ uc ];			//读出UID
         ucSnr_check ^= ucComMF522Buf [ uc ];
      }
			
      if ( ucSnr_check != ucComMF522Buf [ uc ] )
				cStatus = MI_ERR;    
				 
    }
    
    SetBitMask ( CollReg, 0x80 );
		
		
    return cStatus;
		
		
}


/*
 * 函数名:CalulateCRC
 * 描述  :用RC522计算CRC16
 * 输入  :pIndata,计算CRC16的数组
 *         ucLen,计算CRC16的数组字节长度
 *         pOutData,存放计算结果存放的首地址
 * 返回  : 无
 * 调用  :内部调用
 */
void CalulateCRC ( u8 * pIndata, u8 ucLen, u8 * pOutData )
{
    u8 uc, ucN;
	
	
    ClearBitMask(DivIrqReg,0x04);
	
    WriteRawRC(CommandReg,PCD_IDLE);
	
    SetBitMask(FIFOLevelReg,0x80);
	
    for ( uc = 0; uc < ucLen; uc ++)
	    WriteRawRC ( FIFODataReg, * ( pIndata + uc ) );   

    WriteRawRC ( CommandReg, PCD_CALCCRC );
	
    uc = 0xFF;
	
    do 
    {
        ucN = ReadRawRC ( DivIrqReg );
        uc --;
    } while ( ( uc != 0 ) && ! ( ucN & 0x04 ) );
		
    pOutData [ 0 ] = ReadRawRC ( CRCResultRegL );
    pOutData [ 1 ] = ReadRawRC ( CRCResultRegM );
		
		
}


/*
 * 函数名:PcdSelect
 * 描述  :选定卡片
 * 输入  :pSnr,卡片序列号,4字节
 * 返回  : 状态值
 *         = MI_OK,成功
 * 调用  :外部调用
 */
char PcdSelect ( u8 * pSnr )
{
    char ucN;
    u8 uc;
	  u8 ucComMF522Buf [ MAXRLEN ]; 
    u32  ulLen;
    
    
    ucComMF522Buf [ 0 ] = PICC_ANTICOLL1;
    ucComMF522Buf [ 1 ] = 0x70;
    ucComMF522Buf [ 6 ] = 0;
	
    for ( uc = 0; uc < 4; uc ++ )
    {
    	ucComMF522Buf [ uc + 2 ] = * ( pSnr + uc );
    	ucComMF522Buf [ 6 ] ^= * ( pSnr + uc );
    }
		
    CalulateCRC ( ucComMF522Buf, 7, & ucComMF522Buf [ 7 ] );
  
    ClearBitMask ( Status2Reg, 0x08 );

    ucN = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 9, ucComMF522Buf, & ulLen );
    
    if ( ( ucN == MI_OK ) && ( ulLen == 0x18 ) )
      ucN = MI_OK;  
    else
      ucN = MI_ERR;    

		
    return ucN;
		
		
}


/*
 * 函数名:PcdAuthState
 * 描述  :验证卡片密码
 * 输入  :ucAuth_mode,密码验证模式
 *                     = 0x60,验证A密钥
 *                     = 0x61,验证B密钥
 *         u8 ucAddr,块地址
 *         pKey,密码
 *         pSnr,卡片序列号,4字节
 * 返回  : 状态值
 *         = MI_OK,成功
 * 调用  :外部调用
 */
char PcdAuthState ( u8 ucAuth_mode, u8 ucAddr, u8 * pKey, u8 * pSnr )
{
    char cStatus;
	  u8 uc, ucComMF522Buf [ MAXRLEN ];
    u32 ulLen;
    
	
    ucComMF522Buf [ 0 ] = ucAuth_mode;
    ucComMF522Buf [ 1 ] = ucAddr;
	
    for ( uc = 0; uc < 6; uc ++ )
	    ucComMF522Buf [ uc + 2 ] = * ( pKey + uc );   
	
    for ( uc = 0; uc < 6; uc ++ )
	    ucComMF522Buf [ uc + 8 ] = * ( pSnr + uc );   

    cStatus = PcdComMF522 ( PCD_AUTHENT, ucComMF522Buf, 12, ucComMF522Buf, & ulLen );
	
    if ( ( cStatus != MI_OK ) || ( ! ( ReadRawRC ( Status2Reg ) & 0x08 ) ) )
      cStatus = MI_ERR;   
    
		
    return cStatus;
		
		
}


/*
 * 函数名:PcdWrite
 * 描述  :写数据到M1卡一块
 * 输入  :u8 ucAddr,块地址
 *         pData,写入的数据,16字节
 * 返回  : 状态值
 *         = MI_OK,成功
 * 调用  :外部调用
 */
char PcdWrite ( u8 ucAddr, u8 * pData )
{
    char cStatus;
	  u8 uc, ucComMF522Buf [ MAXRLEN ];
    u32 ulLen;
     
    
    ucComMF522Buf [ 0 ] = PICC_WRITE;
    ucComMF522Buf [ 1 ] = ucAddr;
	
    CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );
 
    cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );

    if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )
      cStatus = MI_ERR;   
        
    if ( cStatus == MI_OK )
    {
			//memcpy(ucComMF522Buf, pData, 16);
      for ( uc = 0; uc < 16; uc ++ )
			  ucComMF522Buf [ uc ] = * ( pData + uc );  
			
      CalulateCRC ( ucComMF522Buf, 16, & ucComMF522Buf [ 16 ] );

      cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 18, ucComMF522Buf, & ulLen );
			
			if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )
        cStatus = MI_ERR;   
			
    } 
		
		
    return cStatus;
		
		
}


/*
 * 函数名:PcdRead
 * 描述  :读取M1卡一块数据
 * 输入  :u8 ucAddr,块地址
 *         pData,读出的数据,16字节
 * 返回  : 状态值
 *         = MI_OK,成功
 * 调用  :外部调用
 */
char PcdRead ( u8 ucAddr, u8 * pData )
{
    char cStatus;
	  u8 uc, ucComMF522Buf [ MAXRLEN ]; 
    u32 ulLen;
    

    ucComMF522Buf [ 0 ] = PICC_READ;
    ucComMF522Buf [ 1 ] = ucAddr;
	
    CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );
   
    cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );
	
    if ( ( cStatus == MI_OK ) && ( ulLen == 0x90 ) )
    {
			for ( uc = 0; uc < 16; uc ++ )
        * ( pData + uc ) = ucComMF522Buf [ uc ];   
    }
		
    else
      cStatus = MI_ERR;   
    
		
    return cStatus;
		
		
}


/*
 * 函数名:PcdHalt
 * 描述  :命令卡片进入休眠状态
 * 输入  :无
 * 返回  : 状态值
 *         = MI_OK,成功
 * 调用  :外部调用
 */
char PcdHalt( void )
{
	u8 ucComMF522Buf [ MAXRLEN ]; 
	u32  ulLen;
  

  ucComMF522Buf [ 0 ] = PICC_HALT;
  ucComMF522Buf [ 1 ] = 0;
	
  CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );
 	PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );

  return MI_OK;
	
}


void IC_CMT ( u8 * UID, u8 * KEY, u8 RW, u8 * Dat )
{
  u8 ucArray_ID [ 4 ] = { 0 };//先后存放IC卡的类型和UID(IC卡序列号)
  
	
  PcdRequest ( 0x52, ucArray_ID );//寻卡

  PcdAnticoll ( ucArray_ID );//防冲撞
  
  PcdSelect ( UID );//选定卡
  
  PcdAuthState ( 0x60, 0x10, KEY, UID );//校验
	

	if ( RW )//读写选择,1是读,0是写
    PcdRead ( 0x10, Dat );
   
   else 
     PcdWrite ( 0x10, Dat );
   
	 
   PcdHalt ();
	 
	 
}

rcc.h文件

#ifndef __RC52_H
#define __RC52_H
#include "sys.h"
#include "stm32f10x.h"


 
/*********************************** RC522 引脚定义 *********************************************/
#define               macRC522_GPIO_CS_CLK_FUN                  RCC_APB2PeriphClockCmd
#define               macRC522_GPIO_CS_CLK                      RCC_APB2Periph_GPIOA
#define               macRC522_GPIO_CS_PORT    	                GPIOA			   
#define               macRC522_GPIO_CS_PIN		                  GPIO_Pin_4
#define               macRC522_GPIO_CS_Mode		                  GPIO_Mode_Out_PP

#define               macRC522_GPIO_SCK_CLK_FUN                 RCC_APB2PeriphClockCmd
#define               macRC522_GPIO_SCK_CLK                     RCC_APB2Periph_GPIOA
#define               macRC522_GPIO_SCK_PORT    	              GPIOA			   
#define               macRC522_GPIO_SCK_PIN		                  GPIO_Pin_5
#define               macRC522_GPIO_SCK_Mode		                GPIO_Mode_Out_PP

#define               macRC522_GPIO_MOSI_CLK_FUN                RCC_APB2PeriphClockCmd
#define               macRC522_GPIO_MOSI_CLK                    RCC_APB2Periph_GPIOA
#define               macRC522_GPIO_MOSI_PORT    	              GPIOA			   
#define               macRC522_GPIO_MOSI_PIN		                GPIO_Pin_7
#define               macRC522_GPIO_MOSI_Mode		                GPIO_Mode_Out_PP

#define               macRC522_GPIO_MISO_CLK_FUN                RCC_APB2PeriphClockCmd
#define               macRC522_GPIO_MISO_CLK                    RCC_APB2Periph_GPIOA
#define               macRC522_GPIO_MISO_PORT    	              GPIOA			   
#define               macRC522_GPIO_MISO_PIN		                GPIO_Pin_6
#define               macRC522_GPIO_MISO_Mode		                GPIO_Mode_IN_FLOATING

#define               macRC522_GPIO_RST_CLK_FUN                 RCC_APB2PeriphClockCmd
#define               macRC522_GPIO_RST_CLK                     RCC_APB2Periph_GPIOB
#define               macRC522_GPIO_RST_PORT    	              GPIOB		   
#define               macRC522_GPIO_RST_PIN		                  GPIO_Pin_0
#define               macRC522_GPIO_RST_Mode		                GPIO_Mode_Out_PP

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

//
//#define  spi_cs 1;
//sbit  spi_ck=P0^6;
//sbit  spi_mosi=P0^7;
//sbit  spi_miso=P4^1;
//sbit  spi_rst=P2^7;
#define SPIReadByte()	SPIWriteByte(0)
u8 SPIWriteByte(u8 byte);
void SPI1_Init(void);
//void SPI2_Init(void);

#define SET_SPI_CS  (GPIOA->BSRR=0X01)
#define CLR_SPI_CS  (GPIOA->BRR=0X01)



#define SET_RC522RST  GPIOA->BSRR=0X02
#define CLR_RC522RST  GPIOA->BRR=0X02


/***********************RC522 函数宏定义**********************/
#define          RC522_CS_Enable()         GPIO_ResetBits ( GPIOA, GPIO_Pin_4 )
#define          RC522_CS_Disable()        GPIO_SetBits ( GPIOA, GPIO_Pin_4 )

#define          RC522_Reset_Enable()      GPIO_ResetBits( GPIOB, GPIO_Pin_0 )
#define          RC522_Reset_Disable()     GPIO_SetBits ( GPIOB, GPIO_Pin_0)

#define          RC522_SCK_0()             GPIO_ResetBits( GPIOA, GPIO_Pin_5 )
#define          RC522_SCK_1()             GPIO_SetBits ( GPIOA, GPIO_Pin_5)

#define          RC522_MOSI_0()            GPIO_ResetBits( GPIOA, GPIO_Pin_7 )
#define          RC522_MOSI_1()            GPIO_SetBits ( GPIOA, GPIO_Pin_7 )

#define          RC522_MISO_GET()          GPIO_ReadInputDataBit ( GPIOA, GPIO_Pin_6 )

void             RC522_Handel               (void);
void             RC522_Init                 ( void );                       //初始化
void             PcdReset                   ( void );                       //复位
void             M500PcdConfigISOType       ( u8 type );                    //工作方式
char             PcdRequest                 ( u8 req_code, u8 * pTagType ); //寻卡
char             PcdAnticoll                ( u8 * pSnr);                   //读卡号

char             PcdSelect                  ( u8 * pSnr );
char             PcdAuthState               ( u8 ucAuth_mode, u8 ucAddr, u8 * pKey, u8 * pSnr );
char             PcdWrite                   ( u8 ucAddr, u8 * pData );
char             PcdRead                    ( u8 ucAddr, u8 * pData );
void ShowID(u8 *p);	 //显示卡的卡号,以十六进制显示

extern char* POINT_LNG;
extern char* POINT_LAT;
extern char* POINT_LNG_ON;
extern char* POINT_LAT_ON;
extern char* POINT_LNG_OFF;
extern char* POINT_LAT_OFF;

u8 shibieka(void);


#endif

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RC522模块学习 的相关文章

  • 第12章 项目沟通管理和干系人管理

    文章目录 沟通渠道计算 xff08 M 61 n n 1 2 xff09 12 1 2 沟通的方式沟通管理计划的编制过程12 2 2 制订沟通管理计划的工具4 沟通方法 xff08 交互式 推式 拉式 xff09 12 3 2 管理沟通的工
  • 第13章 项目合同管理

    文章目录 13 2 1 按信息系统 范围 划分的合同分类1 总承包合同2 单项工程承包合同3 分包合同 13 2 2 按项目 付款方式 划分的合同分类1 总价合同2 成本补偿合同 xff08 卖方有利 xff09 3 工料合同 13 3 1
  • FS-Cli常用命令简介

    目录 退出操作 日志与显示操作 全局变量 fsctl xff1a 发送控制信息 通话相关命令简介 show xff1a 显示信息 fs cli是FreeSWITCH的一个客户端连接程序 xff0c 可以方便地查看运行情况 xff0c 并对其
  • 第14章 项目采购管理

    文章目录 采购管理包括如下几个过程14 2 编制采购计划编制采购计划的输出1 xff09 采购管理计划2 xff09 采购工作说明书3 xff09 采购文件 14 2 3 工作说明书 xff08 SOW xff09 14 3 实施采购14
  • 第15章 信息(文档)和配置管理

    文章目录 软件文档的分类 xff08 1 xff09 开发文档 xff1a 描述开发过程 本身 xff08 2 xff09 产品文档 xff1a 描述开发过程的 产物 xff08 3 xff09 管理文档 xff1a 记录项目管理的信息 文
  • 第16章 变更管理

    文章目录 16 1 项目变更的基本概念16 1 1 项目变更的含义16 1 2 项目变更的分类16 1 3 项目变更产生的原因 16 2 变更管理的基本原则16 3 变更管理角色职责与工作程序16 3 1 角色职责16 3 2 工作程序 1
  • 第17章 信息系统安全管理

    文章目录 信息安全属性及目标 xff08 1 xff09 保密性 xff08 Confidentiality xff09 xff08 2 xff09 完整性 xff08 Integrity xff09 xff08 3 xff09 可用性 x
  • 第18章 项目风险管理

    文章目录 18 1 2 风险的分类按照性质划分 xff08 纯粹 投机 xff09 按照产生原因 xff08 自然 社会 政治 经济 技术 xff09 18 1 3 风险的性质 xff08 客观 偶然 相对 社会 不确定 xff09 项目风
  • 第19章 项目收尾管理

    文章目录 19 1 项目验收 xff08 1 xff09 验收测试 xff08 2 xff09 系统试运行 xff08 3 xff09 系统文档验收 xff08 4 xff09 项目终验 19 2 项目总结 xff08 属于项目收尾的 管理
  • 第20章 知识产权管理、第21章 法律法规和标准规范

    文章目录 20 1 2 知识产权的特性 58420 2 1 著作权及邻接权 58520 2 2 专利权 58920 2 3 商标权 59221 3 诉讼时效 59921 6 3 标准分级与标准类型 60321 7 2 信息系统集成项目管理常
  • 系统集成项目管理工程师 下午 真题 及考点(2022年四套卷)

    文章目录 2022年下半年试题一 xff1a 第10章 项目质量管理 xff0c 流程图 核查表 帕累托图 xff0c 7种质量工具 xff0c 一致性成本和非一致性成本 xff0c 质量保证和质量控制试题二 xff1a 第8章 项目进度管
  • 系统集成项目管理工程师 下午 真题 及考点(2021年上下半年)

    文章目录 2021年下半年试题一 xff1a 第18章 项目风险管理 xff0c 风险应对策略 xff0c 风险的性质 xff08 客观 偶然 相对 社会 不确定 xff09 试题二 xff1a 第9章 项目成本管理 xff0c 执行绩效
  • 系统集成项目管理工程师 下午 真题 及考点(2020年下半年)

    文章目录 2020年下半年试题一 xff1a 第10章 项目质量管理 xff0c 规划质量管理过程的输入试题二 xff1a 第9章 项目成本管理 xff0c 典型 xff1a EAC 61 AC 43 ETC 61 AC 43 xff08
  • FreeSWITCH之lua脚本事件订阅

    目录 相关接口简要说明 Even EventConsumer pop获取事件 bind订阅 代码示例 事件创建 事件订阅 FreeSWITCH中通过订阅事件 xff0c 我们能获取到各种实时信息 xff0c 进而可以对通话进行精确的控制 在

随机推荐

  • 超级基础A*寻路教程

    download code resource 学习了一下A 算法 xff0c 但是天生对算法无奈 xff0c 还好一不小心找到下面这篇文章 如果你苦于无法理解网上各大牛人的巅峰讨论以及他们火星文般的源代码 xff0c 那么这篇文章实在是太适
  • Cannot find module ‘body-parser‘

    node modules下模块缺失 解决方案 xff1a npm install span class token operator span save body span class token operator span parser
  • C#中struct和class的区别

    本文详细分析了C 中struct和class的区别 xff0c 对于C 初学者来说是有必要加以了解并掌握的 简单来说 xff0c struct是值类型 xff0c 创建一个struct类型的实例被分配在栈上 class是引用类型 xff0c
  • 沁恒MCU串口使用指南

    转载注明出处 沁恒MCU串口使用指南 xff1a 适用于WCH的32位MCU和CH559 558单片机 只描述TTL电平的TX 43 RX形式的常规串口 xff0c 流控 xff0c RS232 RS485不在文章涉及范围之内 大部分8位机
  • ubuntu安装网络调试助手

    下载mNetAssist安装包 链接 https pan baidu com s 1eHalZSnsVKXRERmIOCfj0w 提取码 bhxs新建终端并切换到安装包所在目录sudo dpkg i mNetAssist release a
  • .s19 文件转换为 .hex 和 .bin文件的方法

    使用STVD开发时 xff0c 编译后产生的是 s19 文件 xff0c 与Keil 和 IAR常见的 hex bin文件不同 xff0c 那么如何将 s19文件转换为常见的文件格式呢 xff1f 一 获取工具 burner 下载链接 xf
  • VS Code中C/C++ 无法跳转到定义的解决办法

    VS code的跳转功能一直很迷 xff0c 时好时坏 xff0c 有些新的工程环境干脆用不了 经过一遍遍的baidu加上自己的摸索 xff0c 总结出一套经验 xff0c 应该可以解决大部分的情况了 一 首先 xff0c 当然是安装插件了
  • 使用void*强转函数指针(编辑中)

    别把函数名当成函数 xff0c just a 变量 typedef void AirCb void 空回调函数 typedef int aimFunction int para1 char para2 int para3 要传递的目标函数
  • KoroFileHeader 配置

    一 安装插件 二 Github 地址 https github com OBKoro1 koro1FileHeader 三 快速上手 https github com OBKoro1 koro1FileHeader wiki E5 AE 8
  • 网络接入与身份认证简介

    目录 1 认证简介 2 常见认证机制 基于口令的身份认证机制 挑战 响应认证机制 EAP认证机制 3 公钥认证机制 4 使用认证机制的认证协议 RADIUS认证协议 TACACS 43 认证协议 Kerberos认证协议 LDAP协议 5
  • VS Code常见问题

    1 更改自动补全 xff08 联想 xff09 快捷键的方法 文件 gt 首选项 gt 键盘快捷方式 搜索trigger 找到该选项 xff0c 更改快捷键 2 当鼠标悬停在枚举值上 xff0c 不能显示当前序号 a 打开setting j
  • 用Keil编译C51和ARM时,分别生成.Bin文件的方法

    一 C51 1 使用srec cat exe a Keil工程需生成 hex文件 b 将srec cat exe放在工程路径中任意文件夹下 c 新建一个文本文档 xff0c 之后填写如下内容 xff0c 保存后更名为 1 bat xff08
  • Keil新建Stm32标准工程中 Preprocessor Symbols的作用

    xff08 转自正点原子的回复 xff09 标准的工程新建办法 是要添加 34 USE STDPERIPH DRIVER STM32F10X HD的 USE STDPERIPH DRIVER 是告诉编译器 我们需要使用标准库了 实际上是 c
  • 单片机中利用Union联合体打印输出浮点数(小数)

    方法一 xff1a 指针 UART串口有一个缺点 xff0c 就是发送和接受是一个字节一个字节的接收 xff0c 如果发送的浮点数那可怎么办啊 xff1f 有人会说 xff0c 那就一个字节一个字节发送啊 那么 xff0c 我先定义一个do
  • 用 IAR 开发 STM8 时,简单软件延时不起作用的原因

    近期有幸接手了前任工程师遗留的项目 xff0c MCU 选择的是 STM8L151XX xff0c 开发工具使用的是 IAR 打开祖传代码后 xff0c 通读了一遍 xff0c 就用ST Link烧录进去跑程序 xff0c 结果发现和预想的
  • 基于SX1276芯片的 LORA 技术开发详解

    一 简介 LORA xff0c 是 Long Range 的简称 LORA 技术 xff0c 源自于美国的升特公司 xff08 Semtech xff09 xff0c 是一种用于中 长距离传输的技术 xff0c 相关信息主要从升特公司官网获
  • Linux下用C语言将一个字符串格式(char*)的MAC地址转换为十六进制数组

    include lt stdio h gt include lt stdlib h gt unsigned char a2x const char c switch c case 39 0 39 39 9 39 return unsigne
  • 超声波换能器的主要参数解读,全!

    1 导纳是阻抗的倒数 xff0c 也就是一个代表困难程度的量 xff0c G为电导 xff0c B为电纳 导纳Y是一个复数 xff0c Y 61 G 43 jB xff1b 实部为电导 xff0c 虚部为电纳 G越大 xff0c 说明电荷越
  • 温度对超声波换能器的影响

    我们都知道超声波换能器的主要参数有 xff1a 谐振频率 反谐振频率 谐振阻抗 反谐振阻抗 输出幅值 静态电容等 在平时使用换能器的时候 xff0c 除了超声波换能器有自身损耗的影响外 xff0c 很可能使用场合出现在室内或室外 xff0c
  • RC522模块学习

    目录 1 原理简介 2 SPI通信 3 获取卡号实验 3 驱动函数 参考 xff1a https www cnblogs com ivantang p 3904025 html https xiaolong blog csdn net ar