STM32CubeMX(13)——SPI时序读写RFID-RC522

article/2025/8/22 23:16:07

SPI时序读写RFID-RC522

目录

STM32 Cubemax(十三) ——SPI时序读写RFID-RC522

前言

一、SPI时序通信

二、模块接线

三.Cubemax配置

 四.核心代码

延时函数

写RC522寄存器

读RC522寄存器

复位RC522

使用代码

1.复位

2.寻卡并得到其序列号

总结





前言

用RFID来学习一下SPI,本次实验使用的是如下这款,在某宝随便搜索RC522即可。

整篇文章较长,手把手从说明书分析代码,要是有说错的,欢迎留言交流!!

这款RC522是支持模拟串口,IIC和SPI的,但本次主要以SPI为主,其他使用方法随缘更新。以下的内容大都基于RC522的官方手册,包括对其读写,寄存器的操作。手册百度网盘的下载地址如下

链接:https://pan.baidu.com/s/1jPve_5UVLLK3ATRKOiEmqw 
提取码:tvx1




一、SPI时序通信

如果不想搞懂代码,这段可以直接跳过,直接从第二部分开始看。

 SPI通信中RC522模块作为从机,SPI时钟SCK由单片机产生,MOSI为单片机发送给RC522信息的引脚,MISO为模块发送给单片机信息的引脚。NSS为片选信号。

注意:在传输过程中MOSI和MISO传输的每个字节都是高位在前,和IIC一样和串口相反。

 这张图熟悉SPI的人应该都很清晰,做一个简单的讲解。

首先如果要对某个SPI外设进行读写,要对这个设备使能,即片选功能,在这里RC522片选端为低电平即为选中,如果有多个RC522,要注意,选中某个的时候,其NSS为低电平,其他为高电平。

SPI进行读写的时候,因为是同步通信,所以所需的同步信号需由SCK时钟线提供,简单的说就是SCK高低电平的转换。

传送数据时:在SCK在上升沿或下降沿时发送器MOSI发送数据,在紧接着下降沿或上升沿时接收器MISO读取数据,完成一位数据的传送,八个时钟周期完成一个字节的传送。

而要对RC522操作,即是对其上的寄存器地址进行SPI通信,理解下图是关键

举个例子方便理解上图,假如我要读取下图的寄存器

 其地址位0x08=00001000b,根据地址字节的传输格式,第一位读写位,最后一位是规定0位,6-1位为地址,可知实际上通过SPI传输的是1001000

假如我要写入下图的寄存器

 其地址为0x04=00000010,可以知道实际上SPI传输的是00000100




二、模块接线

RFID-RC522STM32
SDAPE2(输出引脚)
SCKPE3(输出引脚)
MOSIPE4(输出引脚)
MISOPE5(输入引脚)
RSTPE6(输出引脚)
GNDGND
3.3V3.3V




三.Cubemax配置

这个配置十分简单,就是按照接线的引脚配置IO输出输入即可

 四.核心代码

整个RFID的功能十分多,包括寻卡,防冲突,写卡等等,但其实核心代码就是对其时序的读写,然后根据寄存器的功能,对每个功能依次配置达到功能即可,我这里就讲解一下最核心的代码。

代码前,先定义一下如寄存器地址,功能码等一些官方给的参数,直接复制粘贴即可,写到.h文件

#ifndef _RC522_H
#define _RC522_H
#include "main.h"
// 注意以下为位带操作定义,根据自己的IO增加或修改
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //??
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //??
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
// 延时晶振注意修改!!!
#define CPU_FREQUENCY_MHZ 168
/
//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/
//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 MF522_NSS PEout(2)	//PE0	 SDA
#define MF522_SCK PEout(3)	//PE1
#define MF522_SI PEout(4)	//PE2	MOSI
#define MF522_SO PEin(5)	//PE3	MISO	
#define MF522_RST PEout(6)	//PE4char PcdReset(void);
void PcdAntennaOn(void);
void PcdAntennaOff(void);
char PcdRequest(unsigned char req_code,unsigned char *pTagType);   
char PcdAnticoll(unsigned char *pSnr);
char PcdSelect(unsigned char *pSnr);         
char PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr);     
char PcdRead(unsigned char addr,unsigned char *pData);     
char PcdWrite(unsigned char addr,unsigned char *pData);    
char PcdValue(unsigned char dd_mode,unsigned char addr,unsigned char *pValue);   
char PcdBakValue(unsigned char sourceaddr, unsigned char goaladdr);                                 
char PcdHalt(void);
char PcdComMF522(unsigned char Command, unsigned char *pInData, unsigned char InLenByte,unsigned char *pOutData, unsigned int  *pOutLenBit);
void CalulateCRC(unsigned char *pIndata,unsigned char len,unsigned char *pOutData);
void WriteRawRC(unsigned char Address,unsigned char value);
unsigned char ReadRawRC(unsigned char Address); 
void SetBitMask(unsigned char reg,unsigned char mask); 
void ClearBitMask(unsigned char reg,unsigned char mask); 
#endif 

延时函数

对于时序读写,一直比较重要的就是延时函数,这个延时函数,我自己在很多地方都是直接拿来用的。

//us级的延时函数, CPU_FREQUENCY_MHZ 为自己单片机的主频,我这里为168
void delay_us(__IO uint32_t delay)
{int last, curr, val;int temp;while (delay != 0){temp = delay > 900 ? 900 : delay;last = SysTick->VAL;curr = last - CPU_FREQUENCY_MHZ * temp;if (curr >= 0){do{val = SysTick->VAL;}while ((val < last) && (val >= curr));}else{curr += CPU_FREQUENCY_MHZ * 1000;do{val = SysTick->VAL;}while ((val <= last) || (val > curr));}delay -= temp;}
}

写RC522寄存器

如果看懂上面的SPI通信那,再看这个代码就能比较理解了。

void WriteRawRC(unsigned char Address, unsigned char value)
{  unsigned char i, ucAddr;MF522_SCK = 0;// 片选MF522_NSS = 0;// 先左移是为了确定地址,与上0x7e即取1到6位ucAddr = ((Address<<1)&0x7E);// 先送地址位for(i=8;i>0;i--){MF522_SI = ((ucAddr&0x80)==0x80);// 时钟线变换MF522_SCK = 1;ucAddr <<= 1;MF522_SCK = 0;delay_us(10);	   }// 再送数据for(i=8;i>0;i--){MF522_SI = ((value&0x80)==0x80);// 时钟线变换MF522_SCK = 1;value <<= 1;MF522_SCK = 0;delay_us(10);	 }MF522_NSS = 1;MF522_SCK = 1;
}

读RC522寄存器

读取RC522寄存器和写很像,其实也就是按要求修改一下地址字节而已,然后从MISO脚读取数据

unsigned char ReadRawRC(unsigned char Address)
{unsigned char i, ucAddr;unsigned char ucResult=0;MF522_SCK = 0;MF522_NSS = 0;// 读取第一位是1,所以或上0x80ucAddr = ((Address<<1)&0x7E)|0x80;for(i=8;i>0;i--){MF522_SI = ((ucAddr&0x80)==0x80);MF522_SCK = 1;ucAddr <<= 1;MF522_SCK = 0;delay_us(10); 	  //STM32需要多加的延时时间。51的不需要加}for(i=8;i>0;i--){MF522_SCK = 1;ucResult <<= 1;ucResult|=MF522_SO;MF522_SCK = 0;delay_us(10);	  //STM32需要多加的延时时间。51的不需要加}MF522_NSS = 1;MF522_SCK = 1;return ucResult;
}

复位RC522

下面以复位RC522这个功能来讲解一下具体对RC522的操作,还有一些功能,官方其实也给我们实现好了,分析原理和下面这个同理。

整个复位的过程其实就是对RC522接收模式,卡片类型和其中的定时器进行设定,这个内部结构就不放出来了。

char PcdReset(void)
{MF522_RST=1;delay_us(10);                  MF522_RST=0;delay_us(10);                   MF522_RST=1;delay_us(10);                 // PCD_RESETPHASE位RC522中的复位字,CommandReg地址用来控制启动或停止命令的执行 // PCD_RESETPHASE = 0x0F  WriteRawRC(CommandReg,PCD_RESETPHASE);delay_us(10);                  // 定义发送和接收的常用模式WriteRawRC(ModeReg,0x3D);  // 重装载值位30WriteRawRC(TReloadRegL,30);    		WriteRawRC(TReloadRegH,0);// 定义内部定时器模式WriteRawRC(TModeReg,0x8D);	// 分频系数,62				WriteRawRC(TPrescalerReg,0x3E);		// 重装载值 64	WriteRawRC(TxAutoReg,0x40);	// 复位成功返回MI_OK = 0		return MI_OK;
}

分析上面的代码只需要看下面几个寄存器的定义。

 向此寄存器写入0x0F表明根据命令代码激活复位RC522

向ModeReg寄存器写Ox3D表明复位的时候定义了我们的RC522和Mifare卡进行通信,因为我们通信的CRC校验码为6363

然后就是定时器的配置,比较简单,不多说。

后面所有的函数方法使用,就是分析这些寄存器写出来的,贴出整个.C文件,比较常用的几个代码。

#include "RC522.h"#define MAXRLEN 18//延迟us函数
void delay_us(__IO uint32_t delay)
{int last, curr, val;int temp;while (delay != 0){temp = delay > 900 ? 900 : delay;last = SysTick->VAL;curr = last - CPU_FREQUENCY_MHZ * temp;if (curr >= 0){do{val = SysTick->VAL;}while ((val < last) && (val >= curr));}else{curr += CPU_FREQUENCY_MHZ * 1000;do{val = SysTick->VAL;}while ((val <= last) || (val > curr));}delay -= temp;}
}/
//功    能:写RC632/RC522寄存器
//参数说明:Address[IN]:寄存器地址
//          value[IN]:写入的值
/
void WriteRawRC(unsigned char Address, unsigned char value)
{  unsigned char i, ucAddr;MF522_SCK = 0;MF522_NSS = 0;ucAddr = ((Address<<1)&0x7E);for(i=8;i>0;i--){MF522_SI = ((ucAddr&0x80)==0x80);MF522_SCK = 1;ucAddr <<= 1;MF522_SCK = 0;delay_us(10);	   //STM32需要多加的延时时间。51的不需要加}for(i=8;i>0;i--){MF522_SI = ((value&0x80)==0x80);MF522_SCK = 1;value <<= 1;MF522_SCK = 0;delay_us(10);	 //STM32需要多加的延时时间。51的不需要加}MF522_NSS = 1;MF522_SCK = 1;
}
/
//功    能:读RC632/RC522寄存器
//参数说明:Address[IN]:寄存器地址
//返    回:读出的值
/
unsigned char ReadRawRC(unsigned char Address)
{unsigned char i, ucAddr;unsigned char ucResult=0;MF522_SCK = 0;MF522_NSS = 0;ucAddr = ((Address<<1)&0x7E)|0x80;for(i=8;i>0;i--){MF522_SI = ((ucAddr&0x80)==0x80);MF522_SCK = 1;ucAddr <<= 1;MF522_SCK = 0;delay_us(10); 	  //STM32需要多加的延时时间。51的不需要加}for(i=8;i>0;i--){MF522_SCK = 1;ucResult <<= 1;ucResult|=MF522_SO;MF522_SCK = 0;delay_us(10);	  //STM32需要多加的延时时间。51的不需要加}MF522_NSS = 1;MF522_SCK = 1;return ucResult;
}
/
//功    能:置RC522寄存器位
//参数说明:reg[IN]:寄存器地址
//          mask[IN]:置位值
/
void SetBitMask(unsigned char reg,unsigned char mask)  
{char tmp = 0x0;tmp = ReadRawRC(reg);WriteRawRC(reg,tmp | mask);  // set bit mask
}/
//功    能:清RC522寄存器位
//参数说明:reg[IN]:寄存器地址
//          mask[IN]:清位值
/
void ClearBitMask(unsigned char reg,unsigned char mask)  
{char tmp = 0x0;tmp = ReadRawRC(reg);WriteRawRC(reg, tmp & ~mask);  // clear bit mask
} /
//功    能:复位RC522
//返    回: 成功返回MI_OK
/
char PcdReset(void)
{//unsigned char i;MF522_RST=1;delay_us(10);                  MF522_RST=0;delay_us(10);                   MF522_RST=1;delay_us(10);                 WriteRawRC(CommandReg,PCD_RESETPHASE);delay_us(10);                  WriteRawRC(ModeReg,0x3D);            //和Mifare卡通讯,CRC初始值0x6363WriteRawRC(TReloadRegL,30);    			 // 重装载值       WriteRawRC(TReloadRegH,0);WriteRawRC(TModeReg,0x8D);					 // 定义内部定时器模式WriteRawRC(TPrescalerReg,0x3E);			 // 分频系数WriteRawRC(TxAutoReg,0x40);					 // 自动重装载值return MI_OK;
}/
//功    能:寻卡
//参数说明: 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 PcdRequest(unsigned char req_code,unsigned char *pTagType)
{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,并且Psnr存储卡片序列号
/  
char PcdAnticoll(unsigned char *pSnr)
{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;
}
/
//功    能:通过RC522和ISO14443卡通讯
//参数说明:Command[IN]:RC522命令字
//          pInData[IN]:通过RC522发送到卡片的数据
//          InLenByte[IN]:发送数据的字节长度
//          pOutData[OUT]:接收到的卡片返回数据
//          *pOutLenBit[OUT]:返回数据的位长度
/
char PcdComMF522(unsigned char Command, unsigned char *pInData, unsigned char InLenByte,unsigned char *pOutData, unsigned int  *pOutLenBit)
{char status = MI_ERR;unsigned char irqEn   = 0x00;unsigned char waitFor = 0x00;unsigned char lastBits;unsigned char n;unsigned int i;switch (Command){case PCD_AUTHENT:irqEn   = 0x12;waitFor = 0x10;break;case PCD_TRANSCEIVE:irqEn   = 0x77;waitFor = 0x30;break;default:break;}WriteRawRC(ComIEnReg,irqEn|0x80);ClearBitMask(ComIrqReg,0x80);WriteRawRC(CommandReg,PCD_IDLE);SetBitMask(FIFOLevelReg,0x80);for (i=0; i<InLenByte; i++){   WriteRawRC(FIFODataReg, pInData[i]);    }WriteRawRC(CommandReg, Command);if (Command == PCD_TRANSCEIVE){    SetBitMask(BitFramingReg,0x80);  }i = 600;//根据时钟频率调整,操作M1卡最大等待时间25msdo {n = ReadRawRC(ComIrqReg);i--;}while ((i!=0) && !(n&0x01) && !(n&waitFor));ClearBitMask(BitFramingReg,0x80);if (i!=0){    if(!(ReadRawRC(ErrorReg)&0x1B)){status = MI_OK;if (n & irqEn & 0x01){   status = MI_NOTAGERR;   }if (Command == PCD_TRANSCEIVE){n = ReadRawRC(FIFOLevelReg);lastBits = 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++){   pOutData[i] = ReadRawRC(FIFODataReg);    }}}else{   status = MI_ERR;   }}SetBitMask(ControlReg,0x80);           // stop timer nowWriteRawRC(CommandReg,PCD_IDLE); return status;
}
/
//功    能:读取M1卡一块数据
//参数说明: addr[IN]:块地址
//          pData[OUT]:读出的数据,16字节
//返    回: 成功返回MI_OK
/ 
char PcdRead(unsigned char addr,unsigned char *pData)
{char status;unsigned int  unLen;unsigned char i,ucComMF522Buf[MAXRLEN]; ucComMF522Buf[0] = PICC_READ;ucComMF522Buf[1] = addr;CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);if ((status == MI_OK) && (unLen == 0x90))//   {   memcpy(pData, ucComMF522Buf, 16);   }{for (i=0; i<16; i++){    *(pData+i) = ucComMF522Buf[i];   }}else{   status = MI_ERR;   }return status;
}/
//功    能:写数据到M1卡一块
//参数说明: addr[IN]:块地址
//          pData[IN]:写入的数据,16字节
//返    回: 成功返回MI_OK
/                  
char PcdWrite(unsigned char addr,unsigned char *pData)
{char status;unsigned int  unLen;unsigned char i,ucComMF522Buf[MAXRLEN]; ucComMF522Buf[0] = PICC_WRITE;ucComMF522Buf[1] = addr;CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A)){   status = MI_ERR;   }if (status == MI_OK){//memcpy(ucComMF522Buf, pData, 16);for (i=0; i<16; i++){    ucComMF522Buf[i] = *(pData+i);   }CalulateCRC(ucComMF522Buf,16,&ucComMF522Buf[16]);status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,18,ucComMF522Buf,&unLen);if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A)){   status = MI_ERR;   }}return status;
}
/
//用MF522计算CRC16函数
/
void CalulateCRC(unsigned char *pIndata,unsigned char len,unsigned char *pOutData)
{unsigned char i,n;ClearBitMask(DivIrqReg,0x04);WriteRawRC(CommandReg,PCD_IDLE);SetBitMask(FIFOLevelReg,0x80);for (i=0; i<len; i++){   WriteRawRC(FIFODataReg, *(pIndata+i));   }WriteRawRC(CommandReg, PCD_CALCCRC);i = 0xFF;do {n = ReadRawRC(DivIrqReg);i--;}while ((i!=0) && !(n&0x04));pOutData[0] = ReadRawRC(CRCResultRegL);pOutData[1] = ReadRawRC(CRCResultRegM);
}
/
//功    能:选定卡片
//参数说明: pSnr[IN]:卡片序列号,4字节
//返    回: 成功返回MI_OK
/
char PcdSelect(unsigned char *pSnr)
{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
/                          
char PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr)
{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;
}
/
//功    能:备份钱包
//参数说明: sourceaddr[IN]:源地址
//          goaladdr[IN]:目标地址
//返    回: 成功返回MI_OK
/
char PcdBakValue(unsigned char sourceaddr, unsigned char goaladdr)
{char status;unsigned int  unLen;unsigned char ucComMF522Buf[MAXRLEN]; ucComMF522Buf[0] = PICC_RESTORE;ucComMF522Buf[1] = sourceaddr;CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A)){   status = MI_ERR;   }if (status == MI_OK){ucComMF522Buf[0] = 0;ucComMF522Buf[1] = 0;ucComMF522Buf[2] = 0;ucComMF522Buf[3] = 0;CalulateCRC(ucComMF522Buf,4,&ucComMF522Buf[4]);status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,6,ucComMF522Buf,&unLen);if (status != MI_ERR){    status = MI_OK;    }}if (status != MI_OK){    return MI_ERR;   }ucComMF522Buf[0] = PICC_TRANSFER;ucComMF522Buf[1] = goaladdr;CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A)){   status = MI_ERR;   }return status;
}/
//关闭天线
/
void PcdAntennaOff()
{ClearBitMask(TxControlReg, 0x03);
}/
//开启天线  
//每次启动或关闭天险发射之间应至少有1ms的间隔
/
void PcdAntennaOn()
{unsigned char i;i = ReadRawRC(TxControlReg);if (!(i & 0x03)){SetBitMask(TxControlReg, 0x03);}
}

使用代码

下面以对一个卡进行读取获取其出厂ID,并获得去出厂的序列号为例,说明如何使用代码(下面的代码放到main中执行或者其他地方执行

1.复位

PcdReset();
PcdAntennaOff(); 	// 关闭天线
HAL_Delay(10);	
PcdAntennaOn();		// 开启天线
HAL_Delay(10);

2.寻卡并得到其序列号

while(1)
{unsigned char g_ucTempbuf[20];char status = PcdRequest(PICC_REQALL, g_ucTempbuf); //寻卡if(status != MI_OK){PcdReset();PcdAntennaOff(); HAL_Delay(1);PcdAntennaOn();continue;}status = PcdAnticoll(g_ucTempbuf); //防冲撞并得到序列号
}

如果要对一个卡的内容进行读取。可以根据以下几步

1.寻卡

2.防冲撞——防止多卡,同时获得序列号

3.选中卡片

4.验证卡片密码

5.写块/读块




总结

文章写的比较长,如果有出错,欢迎交流讨论


http://chatgpt.dhexx.cn/article/JHBCOl3Z.shtml

相关文章

基于STM32+RC522设计的门禁系统

一、项目背景 门禁系统是现代社会中非常重要的安全控制系统之一,其功能是在保障建筑物安全的同时,为合法用户提供便利。当前设计一种基于STM32+RC522的门禁系统设计方案,通过RFID-RC522模块实现了对用户卡的注册、识别及身份验证,通过控制SG90舵机实现门锁的开关,具有较高…

硬件速攻-RC522射频模块

介绍 RC522是一种射频识别&#xff08;RFID&#xff09;模块&#xff0c;用于读取和写入基于ISO/IEC 14443 A/MIFARE协议的13.56MHz RFID标签。该模块可以通过SPI接口与微控制器进行通信&#xff0c;并支持多达25个字节的数据传输。 RC522模块包括一个天线、收发器、调制解调…

基础篇010.3 STM32驱动RC522 RFID模块之三:STM32软件模拟SPI驱动RC522

目录 1. 实验硬件及原理图 2. 利用STM32CubeMX创建MDK工程 2.1 STM32CubeMX工程创建 2.2 配置调试方式 2.3 配置时钟电路 2.4 配置时钟 2.5 配置GPIO 2.6 配置串口 2.7 项目配置 3. MDK工程驱动代码调试 3.1 按键、LED程序 3.2 SPI软件模拟程序 3.3 RC522驱动程序…

[STM32] Stm32f103c8t6+RC522 实现读卡写卡功能(超详细,零基础,小白)

本篇文章内容总结下来就是 读卡 使用默认密码读卡所有扇区所有块的数据写ID 使用默认密码读取卡一的0扇区的第一块数据并写入到卡二的0扇区的第一块里密码读卡 不同厂家的初始密码不同,整理了一些默认密码,如果有收集到新的也可以补充进去写全卡 …

STM32/51单片机实训day4——RFID数据读取|RC522|串口数据收发、可模拟RFID (三) 仿真

目录 1 任务指导 2 实验步骤 3 串口调试 4 USART配置 5 fputs函数重写 内 容&#xff1a;能够读取RFID卡S50的ID——编程实现串口数据收发 学 时&#xff1a;3学时 知识点&#xff1a;电路图设计、USART配置 重点&#xff1a; USART配置 难点&#xff1a;USART配置 时间…

Arduino文档阅读笔记-RFID工作原理及RC522模块介绍

RFID工作原理 RFID&#xff08;Radio Frequency Identification&#xff09;&#xff1a;无线射频识别 RFID由2个部分组成&#xff1a;应答器/标签被贴在某个物体上的东东。无线接收器用于读取应答器/标签上的数据。 读卡器由频射模块及高平磁场组成。Tag/应答器为待感应设备…

Arduino教程 RFID-RC522读IC卡门禁原理及破解防御

【文章特色&#xff1a;1、提出IC卡破解原理和简单有效的防御方法2、网上其他文章对于硬件如何接线说得模糊不清】 1、序言 先说下简单门禁系统的原理&#xff1a; (1)IC卡激活&#xff1a;门禁卡管理员将卡片放到读卡器、这时软件读取到IC卡的UID序列号信息(相当于身份证号…

51单片机驱动RC522模块

最近在某宝上买了一块RC522模块&#xff0c;试玩了下&#xff0c;读写卡正常。想学习使用新的东西时&#xff0c;有必要了解它的工作原理和工作过程&#xff0c;不清楚或者不知道的可以参考相关数据手册和参考文献&#xff0c;在这里为了节省自己的时间&#xff0c;我只对我的5…

基础篇010.1 STM32驱动RC522 RFID模块之一:基础知识

目录 1. RFID概述 1.1 RFID工作原理 1.2 RFID分类 1.3 RFID模块 1.4 RFID卡片 1.5 IC卡和ID卡介绍 1.6 IC卡和ID的区分 2. Mifare卡结构原理 2.1 Mifare卡概述 2.2 Mifare非接触式 IC 卡性能简介&#xff08;M1&#xff09; 2.2.1 Mifare S50与Mifare S70 2.2.2 S5…

RC522

该文为摘抄其他文章内容&#xff0c;主要为RC500书籍.pdf. 1. 通讯标准 1.1 RFID卡标准&#xff1a; 1.2 ISO/IEC 14443通讯标准&#xff1a; 2. 读写器 3. 卡 3.1 mifare 1卡 3.1.1 Mifare 1硬件结构&#xff1a; ① 射频接口&#xff1a;在 RF 射频接口电路中&#xff0c;包…

arduino rc522模块使用

rfid IC卡 先了解IC卡一些前置知识。 首先我们会有一张ic卡&#xff08;M1类型IC卡&#xff0c;一般买到的都是1K存储空间&#xff09;&#xff0c;在rc522代码中会出现这个&#xff0c;就是对IC卡进行检查PICC_TYPE_MIFARE_4K和PICC_TYPE_MIFARE_1K就是一种卡片类型不同大小…

RC522线圈设计及相关参数的选定

RC522线圈设计及相关参数的选定 LC低通滤波电路&#xff08;蓝色区域&#xff09;NFC天线电路(绿色区域)匹配电路(黄色区域)品质因子阻抗匹配 接收电路&#xff08;浅黄色区域&#xff09;TGND的疑问 LC低通滤波电路&#xff08;蓝色区域&#xff09; TX1、TX2为载波发送引脚。…

基础篇010.2 STM32驱动RC522 RFID模块之二:STM32硬件SPI驱动RC522

目录 1. 实验硬件及原理图 1.1 RFID硬件 1.2 硬件原理图 2. 单片机与RFID硬件模块分析 3. 利用STM32CubeMX创建MDK工程 3.1 STM32CubeMX工程创建 3.2 配置调试方式 3.3 配置时钟电路 3.4 配置时钟 3.5 配置GPIO 3.6 配置SPI 3.7 配置串口 3.8 项目配置 4. MDK工程…

STM32—驱动RFID-RC522模块

文章目录 一.S50&#xff08;M1&#xff09;卡介绍1.S50&#xff08;M1&#xff09;卡基础知识2.内部信息3.存取控制4.数据块的存取控制5.控制块的存取控6.工作原理7.M1与读卡器的通信 二.RC522工程代码详解1.RC522与M1通信2.STM32对RC522寄存器的操作3.STM32对RC522的基础通信…

STM32F103+RFID-RC522模块 实现简单读卡写卡demo

目录 前言特别声明:代码下载&#xff1a;功能介绍&#xff1a; 接线STM32STM32F1开发指南(精英版)-库函数版本_V1.2STM32中文参考手册 RFID-RC522RFID射频模块电路原理图 使用图效果图测试程序0 RC522_Handle()最终效果一、先用手机软件NFC Writer读取空卡看看内容1、打开软件和…

使用stm32驱动RC522读取IC卡

stm32驱动RC522 RC522与PN532简介关于STM32驱动方式接线说明程序烧录查看卡号总结 原文链接&#xff1a;https://www.yourcee.com/newsinfo/2924379.html 点击图片购买 RC522与PN532简介 在写这篇文章之前有写过一篇有关于PN532的文章&#xff0c;RC522与PN532在使用上都可以用…

RC522(RFID模块)实践总结

此次使用RC522模块和S50卡实现近场通讯功能&#xff08;开发板与RC522通讯方式为硬件SPI&#xff09;&#xff0c;就实践过程中的一些知识点进行总结&#xff1a; RC522模块和M1卡要点介绍&#xff1b;驱动代码&#xff1b;出现问题及解决方法&#xff1b; 1. RC522模块和M1卡…

RC522应用总结

公司需要做刷卡模块&#xff0c;因此选了RC522做demo程序。下面就RC522知识做简要的总结。 本人使用stm32的硬件spi接口搭建工程&#xff0c;相关的配置如下&#xff1a; spi配置&#xff1a; 引脚配置 SDA -------PA4 SCLK ----PB13 MOSI -------PB15 MISO ------PB14 IRQ —没…

RC522 - NFC刷卡模块

RC522 - NFC刷卡模块 芯片介绍/引脚介绍 MF RC522 是应用于 13.56MHz 非接触式通信中高集成度读写卡系列芯片中的一员。是 NXP 公司针对“三表”应用推出的一款低电压、低成本、体积小的非接触式读写卡芯片&#xff0c;是智能仪表和便携式手持设备研发的较好选择。 非接触式…

STM32--RFID无线射频技术(RC522刷卡模块)

文章目录 1、RFID的概念2、RFID的工作原理&#xff08;1&#xff09;RFID中间件的概念&#xff08;2&#xff09;RFID中间件具有以下特点:&#xff08;3&#xff09;RFID中间件的意义: 3、RFID频率划分&#xff08;1&#xff09;RFID低频特性&#xff08;2&#xff09;RFID高频…