NFC RC522开发记录

本文介绍了ID卡与IC卡(M1卡、CPU卡)的区别,强调了CPU卡的安全性。接着详细阐述了RC522模块进行NFC数据读写的操作流程,并提供了RC522与STM32的硬件接线图,以及RC522的相关驱动代码文件(RC522.c、RC522.h、main.c)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、ID卡、IC卡(M1卡、CPU卡)的区别

在这里插入图片描述

  • ID卡 :只存储了ID号,设备识别ID号,没有算法可言,容易复制,安全性低

IC卡包含了M1卡CPU卡

  • M1卡:存储了ID号,可读写数据,M1卡发一个数据到设备,设备再传一个数据给M1卡确认,再进行交易或身份认证,只有一个算法,可在空中盗-取信息,反复计算,算出其中算法,在复制卡,安全性比ID卡高很多,但还是能被破解
  • CPU卡:有操作系统,可存储数据,也有自己的ID号,CPU卡发一串数据给设备,设备与SAM卡进行运算,设备再发一串数据回CPU卡确认,然后进行交易或身份认证;跟M1卡的区别在于一个算法在空中,一个算法在设备里面;无论是卡商,设备商,运营商,都不知道其中的算法,所以这个系统的安全性会高很多

M1卡介绍 :

M1 卡分为 16 个扇区,每个扇区由 4 块(块 0、块 1、块 2、块 3)组成,(我们也将 16 个扇区的 64 个块按绝对地址编号为 0~63,存贮结构(其它扇区依此类推)如下图所示:
在这里插入图片描述

每个扇区的块 0、块 1、块 2 为数据块,可用于存贮数据。数据块可作两种应用:
1、用作一般的数据保存,可以进行读、写操作。
2、用作数据值,可以进行初始化值、加值、减值、读值操作

每个扇区的块 3 为控制块,包括了密码 A、存取控制、密码 B。具体结构如下:
在这里插入图片描述

二、RC522读写操作

1. 数据读写流程

在这里插入图片描述

三、RC522驱动代码

1. RC522 与 STM32 的接线图

硬件平台:正点原子精英开发板 – STM32F103ZET6

*1--SDA <----->PA4--片选脚
*2--SCK <----->PA5--时钟线
*3--MOSI<----->PA7--输出
*4--MISO<----->PA6--输入
*5--悬空
*6--GND <----->GND
*7--RST <----->PA11--复位脚
*8--VCC <----->VCC
2. RC522.c
#include "rc522.h"
#include "string.h"
#include "./SYSTEM/usart/usart.h"

#include "RC522.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,
///////////////////////////////////////////////////////////////////// //功 能:寻卡 //参数说明: 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 ///////////////////////////////////////////////////////////////////// signed char PcdRequest(unsigned char req_code,unsigned char *pTagType) { signed char status; unsigned int unLen; unsigned char ucComMF522Buf[MAXRLEN]; ClearBitMask(Status2Reg,0x08); WriteRawRC(BitFramingReg,0x07); SetBitMask(TxControlReg,0x03); ucComMF522Buf[0] = req_code; status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen;); if ((status == MI_OK) && (unLen == 0x10)) { *pTagType = ucComMF522Buf[0]; *(pTagType+1) = ucComMF522Buf[1]; } else { status = MI_ERR; } return status; } ///////////////////////////////////////////////////////////////////// //功 能:防冲撞 //参数说明: pSnr[OUT]:卡片序列号,4字节 //返 回: 成功返回MI_OK ///////////////////////////////////////////////////////////////////// signed char PcdAnticoll(unsigned char *pSnr) { signed char status; unsigned char i,snr_check=0; unsigned int unLen; unsigned char ucComMF522Buf[MAXRLEN]; ClearBitMask(Status2Reg,0x08); WriteRawRC(BitFramingReg,0x00); ClearBitMask(CollReg,0x80); ucComMF522Buf[0] = PICC_ANTICOLL1; ucComMF522Buf[1] = 0x20; status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen;); if (status == MI_OK) { for (i=0; i<4; i++) { *(pSnr+i) = ucComMF522Buf[i]; snr_check ^= ucComMF522Buf[i]; } if (snr_check != ucComMF522Buf[i]) { status = MI_ERR; } } SetBitMask(CollReg,0x80); return status; } ///////////////////////////////////////////////////////////////////// //功 能:选定卡片 //参数说明: pSnr[IN]:卡片序列号,4字节 //返 回: 成功返回MI_OK ///////////////////////////////////////////////////////////////////// signed char PcdSelect(unsigned char *pSnr) { signed char status; unsigned char i; unsigned int unLen; unsigned char 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); } CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf;[7]); ClearBitMask(Status2Reg,0x08); status = 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 ///////////////////////////////////////////////////////////////////// signed char PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr) { signed char status; unsigned int unLen; unsigned char i,ucComMF522Buf[MAXRLEN]; ucComMF522Buf[0] = auth_mode; ucComMF522Buf[1] = addr; for (i=0; i<6; i++) { ucComMF522Buf[i+2] = *(pKey+i); } for (i=0; i<6; i++) { ucComMF522Buf[i+8] = *(pSnr+i); } // memcpy(&ucComMF522Buf;[2], pKey, 6); // memcpy(&ucComMF522Buf;[8], pSnr, 4); status = PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen;); if ((status != MI_OK) || (!(ReadRawRC(Status2Reg) & 0x08))) { status = MI_ERR; } return status; }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值