RFID-RC522模块的使用(标准库)
1. SPI模块的使用
RC522模块与主机的通需要使用SPI通信
1.1初始化SPI相关配置看引脚图)这里是SPI1
/*
*GPIO_Pin_5是时钟引脚
*GPIO_Pin_6是MISO
*GPIO_Pin_7是MOSI
*/
void SPI_Init(void)
{
GPIO_InitTypedef GPIO_InitStructure;
//初始化时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//初始化引脚
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
//用来作为SPI的片选引脚(这里是低电平有效)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_SetBits(GPIOA,GPIO_Pin_4);
//初始化SPI外设本身
SPI_InitTypeDef SPI_InitStruct;
//初始化时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
//本身初始化
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;//时钟分频,决定了传输速率
SPI_InitStruct.SPI_Direction= SPI_Direction_2Lines_FullDuplex;//全双工模式
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;//主机模式
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;//按照每次一个字节传送
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;//相位
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;//极性
SPI_InitStruct.SPI_NSS = SPI_NSS_Hard;//片选由硬件决定
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;//数据从高位开始发送
SPI_InitStruct.SPI_CRCPolynomial = 7;//一般值就是7
SPI_Init(SPIx, &SPI_InitStruct);
//外设使能
SPI_Cmd(SPIx, ENABLE); //使能模块
SPI_SSOutputCmd(SPIx, ENABLE);//硬件自动管理NSS信号(片选信号,需要我们控制硬件的输出来完成片选)
}
1.2SPI的写函数和读函数
/*
*SPI是全双工的,所以可以同时进行读和写,但是是读还是写取决与你的需求,但是函数可以是同一个函数
*一般先要完成一个字节的数据的读写
*/
//一个字节的读
uint8_t SPI_ReadByte(uint8_t data)
{
//阻塞等待缓冲区可以发送数据
while((SPI1->SR & SPI_I2S_FLAG_TXE)==0);
//如果缓冲区可可用
SPI1->DR=0xff;//有的的时候如果是发送一些其他数据可能会引起问题,但是原则上是不必关系发送的数据,毕竟也不接收
//等待缓冲区可以读数据
while((SPI1->SR & SPI_I2S_FLAG_RXNE)==0);
return SPI->DR; //返回读到的数据
}
uint8_t SPI_WriteByte(uint8_t data)
{
//阻塞等待缓冲区可以发送数据
while((SPI1->SR & SPI_I2S_FLAG_TXE)==0);
//如果缓冲区可可用
SPI1->DR=data;//有的的时候如果是发送一些其他数据可能会引起问题,但是原则上是不必关系发送的数据,毕竟也不接收
//等待缓冲区可以读数据
while((SPI1->SR & SPI_I2S_FLAG_RXNE)==0);
SPI->DR;//这里是为了读走脏数据
return 0;
}
//多个字节的读
void SPI_ReadNByte(uint8_t *Rx_data,uint8_t len)
{
while(len--)
{
//等待缓冲区可写
while((SPI1->SR & SPI_I2S_FLAG_TXE)==0);
SPI1->DR=0xff;
while((SPI1->SR & SPI_I2S_FLAG_RXNE)==0);
*Rx_data++=SPI1->DR;
}
}
//多个字节的写
void SPI_WriteNByte(uint8_t *Tx_data,uint8_t len)
{
while(len--)
{
//等待缓冲区可写
while((SPI1->SR & SPI_I2S_FLAG_TXE)==0);
SPI1->DR=*Tx_data++;
while((SPI1->SR & SPI_I2S_FLAG_RXNE)==0);
SPI1->DR;
}
}
2. RC522模块的使用
2.1、RC522模块的寄存器了解
以下是RC522(MFRC522)在使用中必须使用到的一些关键寄存器、其地址及功能说明的表格:
寄存器名称 | 地址 | 功能说明 |
---|---|---|
CommandReg | 0x01 | 命令寄存器 |
ComIEnReg | 0x02 | 中断使能标志位 |
DivIEnReg | 0x03 | 控制Rc522上IRQ引脚的输出 |
ComIrqReg | 0x04 | 中断请求标志 |
DivIrqReg | 0x05 | 包含其他类型中断请求标志。 |
ErrorReg | 0x06 | 错误标志,指示执行的上个命令的错误状态,例如CRC错误、奇偶校验错误等。 |
Status1Reg | 0x07 | 包含中断、CRC、FIFO的一些状态 |
Status2Reg | 0x08 | 包含接收器和发送器的状态标志,以及定时器状态等。 |
FIFODataReg | 0x09 | FIFO数据寄存器 |
FIFOLevelReg | 0x0A | FIFO寄存器的清除控制以及FIFO中字节数的信息 |
WaterLevelReg | 0x0B | FIFO中剩下的空间如果小于level会对status1REG中警告位进行设置 |
ControlReg | 0x0C | 控制定时器启动停止,以及上一个接受字节的有效位数,0表示整个字节都有效 |
BitFramingReg | 0x0D | 配置传输的帧的格式 |
CollReg | 0x0E | 防冲突控制寄存器,用于控制防冲突机制的相关参数。 |
ModeReg | 0x11 | 定义发送和接收的常用模式,例如设置调制深度、信号极性等。 |
TxModeReg | 0x12 | 定义发送过程中的数据传输速率等参数。 |
RxModeReg | 0x13 | 定义接收过程中的数据传输速率等参数。 |
TxControlReg | 0x14 | 控制天线驱动器管脚TX1和TX2的逻辑特性,例如开启或关闭天线驱动器。 |
TModeReg | 0x2A | 定义内部定时器的设置,例如定时器的工作模式等。 |
TPrescalerReg | 0x2B | 定时器预分频器寄存器,用于设置定时器的预分频值。 |
TReloadRegH | 0x2C | 定时器重载值高字节寄存器,与TReloadRegL 一起设置定时器的重载值。 |
TReloadRegL | 0x2D | 定时器重载值低字节寄存器。 |
TxASKReg | 0x15 | 控制发送器的ASK调制参数。 |
TxSelReg | 0x16 | 选择天线驱动器的内部源。 |
RxSelReg | 0x17 | 选择内部的接收器设置。 |
RxThresholdReg | 0x18 | 设置接收器的阈值。 |
DemodReg | 0x19 | 定义解调器的设置,例如解调模式等。 |
MIFAREReg | 0x1C | 用于与MIFARE卡通信的特殊寄存器,包含一些与MIFARE卡操作相关的控制位。 |
SerialSpeedReg | 0x1F | 选择串行UART接口的速率。 |
CRCResultRegM | 0x21 | 显示CRC计算的实际MSB值。 |
CRCResultRegL | 0x22 | 显示CRC计算的实际LSB值。 |
ModWidthReg | 0x24 | 配置调制宽度。 |
RFCfgReg | 0x26 | 配置接收器增益等RF相关参数。 |
GsNReg | 0x27 | 选择天线驱动器管脚TX1和TX2的N驱动器的电导。 |
CWGsPReg | 0x28 | 定义P驱动器的电导。 |
ModGsPReg | 0x29 | 定义驱动器P输出电导,便于时间的调制。 |
TCounterValueRegH | 0x2E | 定时器当前计数值高字节寄存器,与TCounterValueRegL 一起表示定时器当前计数值。 |
TCounterValueRegL | 0x2F | 定时器当前计数值低字节寄存器。 |
2.2、向寄存器写入、或者读取的函数
- 在RC522中,实际的地址是1-6位来表示,而0位是一个预留位0,7位如果是0表示写操作,如果是1表示读操作,所以我们应该将原来的地址先向左移动一位并根据读写进行相应变换
/*
*先发地址,再发数据
*/
//写入
void WriteToRC(uint8_t address,uint8_t value)
{
//首先要写入地址
uint8_t data[2]={0};
data[0]=(address<<1)&0x7e;
data[1]=value;
//发送数据
//发送的时候要打开片选
RC522_ENABLE;//这是一个宏函数,打开片选引脚
SPI_WriteNByte(data,2);//不关心返回的数据
//关闭片选
RC522_DISABLE;
}
//读取
uint8_t ReadForRC(uint8_t address)
{
//打开片选
RC522_ENABLE;
uint*_t data=0;
//只需要发送一个字节地址
data=SPI_ReadByte(((address<<1)&0x7e)|0x80);//这里是读最高位应该是1
//取消片选
RC522_DISABLE;
return data;
}
2.3 设置寄存器某一位或者清除某一位的函数
- 有的时候不需要设置寄存器中所有的位而是只需要设置或者清除其中某几位,下面是对应的函数
//设置寄存器中的位
void SetBitMask(uint8_t address,uint8_t mask)
{
//用于接收读取的数值
uint8_t tmp=ReadForRC(address);
//再重新写入
WriteToRC(address,tmp|mask);
}
//清除寄存器中的位
void ClearBitMask(uint8_t address,uint8_t mask)
{
//用于接收读取的数值
uint8_t tmp=ReadForRC(address);
//再重新写入
WriteToRC(address,tmp&(~mask));
}
2.4、RC522模块的基本常用指令
以下是将这些常用指令及其作用整理成表格的形式:
指令宏 | 指令值 (十六进制) | 作用描述 |
---|---|---|
PCD_IDLE | 0x00 | 将 MFRC522 设置为空闲状态,准备进行其他操作。 |
PCD_AUTHENT | 0x0E | 执行密钥认证(Authentication),用于与卡片进行安全通信。 |
PCD_RECEIVE | 0x08 | 接收来自卡片的数据,通常在认证成功后使用。 |
PCD_TRANSMIT | 0x04 | 向卡片发送数据,例如写入数据或发送命令。 |
PCD_TRANSCEIVE | 0x0C | 同时发送和接收数据(Transceive),用于与卡片进行双向通信。 |
PCD_RESETPHASE | 0x0F | 重置 MFRC522 的通信相位,通常在通信错误后使用。 |
PCD_CALCCRC | 0x03 | 计算 CRC(循环冗余校验)值,用于校验数据的完整性。 |
发送PCD和PICC之间相关指令的函数
/*
*第四个参数outLenBit指的是返回的数据的比特数,不是字节数
*/
uint8_t PCDConPICC(uint8_t commond,uint8_t *pInData,uint8_t inLen,uint8_t pOutData,uint8_t outLenBit)
{
uint8_t status=MI_ERR;
uint8_t irqEn=0x00;
uint8_t waitFor=0x00;
uint8_t temp;//用来做一些零时变量
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);
/*发送指令之前设置成空闲模式防止其他的任务干扰,并清空FIFO*/
WriteRawRC(CommandReg,PCD_IDLE);
SetBitMask(FIFOLevelReg,0x80);
/*准备执行命令的参数和命令*/
for (i=0; i<InLenByte; i++)
{ WriteRawRC(FIFODataReg, pInData[i]); }
WriteRawRC(CommandReg, Command);
//如果是PCD_TRANSCEIVE,开启向PICC发送数据帧
if (Command == PCD_TRANSCEIVE)
{ SetBitMask(BitFramingReg,0x80); }//执行命令
i = 800 ; //尝试次数
do
{
n = ReadRawRC(ComIrqReg);//获取中断状态寄存器
i--;
}
while ((i!=0) && !(n&0x01) && !(n&waitFor));//没有尝试完,没有发生定时器中断,没有发生等待的中断
ClearBitMask(BitFramingReg,0x80);//停止通过天线向PICC发送数据
if (i!=0) //没有超过尝试次数
{
if(!(ReadRawRC(ErrorReg)&0x1B)) //检测没有碰撞、奇偶校验错误以及协议错误
{
status = MI_OK;
if (n & irqEn & 0x01) //判断无卡状态
{ status = MI_NOTAGERR; }
if (Command == PCD_TRANSCEIVE)
{
n = ReadRawRC(FIFOLevelReg);//返回FIFO中的字节数,最高位不设置的时候都会默认是0
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 now
WriteRawRC(CommandReg,PCD_IDLE);
return status;
}
正式进入RC522的功能实现模块!!!
正式进入RC522的功能实现模块!!!
正式进入RC522的功能实现模块!!!
3、RC522功能函数
3.1、寻求PICC卡-寻卡函数
寻卡指令0x52
uint8_t PcdRequest(unsigned char req_code,unsigned char *pTagType)
{
char status;
unsigned int unLen;
unsigned char buffer[MAXRLEN]; //接收卡片通信返回的卡片数据
//清除卡片通信加密功能位,只有在认证成功之后才能开启
ClearBitMask(Status2Reg,0x08);
//设置定向帧有效数据位数
WriteRawRC(BitFramingReg,0x07);
//启动天线两个引脚的传输功能
SetBitMask(TxControlReg,0x03);
buffer[0] = req_code;
status=PcdComMF522(PCD_TRANSCEIVE,buffer,1,buffer,&unLen);
//寻求成功会返回2个字节的信息
if ((status == MI_OK) && (unLen == 0x10))
{
*pTagType = buffer[0];
*(pTagType+1) = buffer[1];
}
else
{ status = MI_ERR; }
return status;
}
3.2、防碰撞操作函数
uid异或操作
uid长度
/*
*4个字节的uid最后一个字节低4位是检验位
*/
uint8_t PcdAnticoll(uint8_t *pSnr)
{
uint8_t status;
uint8_t i,snr_check=0;
uint8_t unLen;
uint8_t buffer[MAXRLEN];
uint8_t rcv_crc=0;
//清除卡片通信加密功能位,只有在认证成功之后才能开启
ClearBitMask(Status2Reg,0x08);
//设置定向帧数据的有效位数,如果是0,就是全部有效8位(这里定向帧是指最后传输的最后一个字节中的有效位数)
WriteRawRC(BitFramingReg,0x00);
//设置成0就是为了检测到碰撞,则所有接收位清零(相当于开启开启碰撞检测)
ClearBitMask(CollReg,0x80);
ucComMF522Buf[0] = PICC_ANTICOLL1;//防碰撞第一个阶段,读取卡片前4个字节的uid或者部分uid
//第二个参数代表要读取uid的长度
ucComMF522Buf[1] = 0x20;
status = PCDConPICC(PCD_TRANSCEIVE,buffer,2,buffer,&unLen);
if (status == MI_OK) //接收数据成功
{
for (i=0; i<4; i++)
{
*(pSnr+i) = buffer[i];
snr_check ^= buffer[i];
}
//进行异或操作
rcv_crc=buffer[4]|(buffer[5]<<4);//CRC校验值一般会被放在后面两个字节
if (snr_check != rcv_crc) //这里好像是获取低4位
{ status = MI_ERR; }
}
SetBitMask(CollReg,0x80); //关闭碰撞检测
return status;
}
注意:用来存储CRC校验值的变量一般是要初始化,否则很可能会有其他未知值
3.3 选卡
- CRC校验
CRC处理完成标志
进入空闲
清空FIFO
CRC校验结果寄存器
/*
*pIndata是选卡中的指令数组,长度是7(防碰撞指令+选卡固定参数+4个字节的uid+校验位)
*/
void CalulateCRC(unsigned char *pIndata,unsigned char len,unsigned char *pOutData)
{
unsigned char i,n;
ClearBitMask(DivIrqReg,0x04);//清除CRC数据处理完成标志
WriteRawRC(CommandReg,PCD_IDLE);//进入空闲状态,为CRC计算做准备
SetBitMask(FIFOLevelReg,0x80);//清空FIFO
for (i=0; i<len; i++)
{ WriteRawRC(FIFODataReg, *(pIndata+i)); }
WriteRawRC(CommandReg, PCD_CALCCRC); //启动CRC指令
i = 0xFF;
do
{
n = ReadRawRC(DivIrqReg);
i--;
}
while ((i!=0) && !(n&0x04));//看是否超时或者CRC计算完成
//获取CRC的校验结果
pOutData[0] = ReadRawRC(CRCResultRegL);
pOutData[1] = ReadRawRC(CRCResultRegM);
}
- 选卡
选卡固定参数
CRC校验
向卡片发送信息
/*
*参数pSnr是在防碰撞止之后获取到的4个字节的uid
*/
char PcdSelect(unsigned char *pSnr)
{
char status;
unsigned char i;
unsigned int unLen;
unsigned char buffer[MAXRLEN];
buffer[0] = PICC_ANTICOLL1;
buffer[1] = 0x70; //这是在选卡的时候的固定参数
buffer[6] = 0;//用于存放uid的异或检验的值
for (i=0; i<4; i++)
{
buffer[i+2] = *(pSnr+i);
buffer[6] ^= *(pSnr+i);
}
//进行CRC校验
CalulateCRC(buffer,7,&buffer[7]);
ClearBitMask(Status2Reg,0x08);//只有认证之后才能被设置成1
//向卡发送指令
status = PCDConPICC(PCD_TRANSCEIVE,buffer,9,buffer,&unLen);
//选卡成功之后会返回24个字节的信息
if ((status == MI_OK) && (unLen == 0x18))
{ status = MI_OK; }
else
{ status = MI_ERR; }
return status;
}
3.4 卡片认证
认证方式
扇区
密钥
uid
加密通信被设置
/*
*auth_mode是PICC_AUTHENT1A或者PICC_AUTHENT1B认证
*addr 指的是卡片的扇区号
*pKey指的就是扇区的密钥(6个字节)
*pSnr 指的是uid(4个字节)
*/
uint8_t PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr)
{
char status;
unsigned int unLen;
unsigned char i,buffer[MAXRLEN];
buffer[0] = auth_mode;//认证方式
buffer[1] = addr;//扇区地址
//密钥
for (i=0; i<6; i++)
{ buffer[i+2] = *(pKey+i); }
//uid
for (i=0; i<4; i++)
{ buffer[i+8] = *(pSnr+i); }
//认证
status = PCDConPICC(PCD_AUTHENT,buffer,12,buffer,&unLen);
if ((status != MI_OK) || (!(ReadRawRC(Status2Reg) & 0x08))) //没有成功发送或者加密通信没有成功
{ status = MI_ERR; }
return status;
}
3.5 、读取卡片的块内容
只能读取被认证的扇区中的快
PICC_READ
扇区编号
CRC校验
返回18个字节
/*
*第一个参数addr表示的是块的编号,如果有16个扇区,那么范围就是0-64
*返回的数据
*/
uint8_t PcdRead(unsigned char addr,unsigned char *pData)
{
char status;
unsigned int unLen;
unsigned char i,buffer[MAXRLEN];
buffer[0] = PICC_READ;
buffer[1] = addr;
CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
status = PCDConPICC(PCD_TRANSCEIVE,buffer,4,buffer,&unLen);
//返回18字节的数据,但是只有16位是有效的,后面的两个字节是CRC校验
if ((status == MI_OK) && (unLen == 0x90))
{
for (i=0; i<16; i++)
{ *(pData+i) = ucComMF522Buf[i]; }
}
else
{ status = MI_ERR; }
return status;
}
3.6、写卡片快内容
PICC_WRITE
写成功返回4个比特0xa
/*
*@addr 要写入的块的编号
*@aData 要写入的数据(16个字节)
*/
uint8_t PcdWrite(unsigned uint8_t addr,unsigned uint8_t *pData)
{
char status;//标志
unsigned uint8_t unLen;//数据长度
unsigned uint8_t i,buffer[MAXRLEN];
buffer[0] = PICC_WRITE;
buffer[1] = addr;
//校验
CalulateCRC(buffer,2,&buffer[2]);
status = PCDConPICC(PCD_TRANSCEIVE,buffer,4,buffer,&unLen);
if ((status != MI_OK) || (unLen != 4) || ((buffer[0] & 0x0F) != 0x0A))
{ status = MI_ERR; }
if (status == MI_OK)
{
for (i=0; i<16; i++)
{ buffer[i] = *(pData+i); }
CalulateCRC(buffer,16,&buffer[16]);
status =PCDConPICC(PCD_TRANSCEIVE,buffer,18,buffer,&unLen);
if ((status != MI_OK) || (unLen != 4) || ((buffer[0] & 0x0F) != 0x0A))
{ status = MI_ERR; }
}
return status;
}
3.7、卡片的值操作
卡片的值操作包括通常用于实现电子钱包功能,支持加值、减值和传输等操作。
值操作必须要通过PICC_TRANSFER命令才能真正生效
/*
*@dd_mode指的是值操作的模式,Increment或者Decrement
*/
uint8_t PcdValue(unsigned char dd_mode,unsigned char addr,unsigned char *pValue)
{
char status;
unsigned int unLen;
unsigned char i,buffer[MAXRLEN];
buffer[0] = dd_mode;
buffer[1] = addr;
//校验
CalulateCRC(buffer,2,&buffer[2]);
//发送之操作信息
status =PCDConPICC(PCD_TRANSCEIVE,buffer,4,buffer,&unLen);
if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
{ status = MI_ERR; }
if (status == MI_OK)
{
for (i=0; i<4; i++)
{ buffer[i] = *(pValue+i); }
CalulateCRC(buffer,4,&ubuffer[4]);
unLen = 0;
status = PCDConPICC(PCD_TRANSCEIVE,buffer,6,buffer,&unLen);
if (status != MI_ERR)
{ status = MI_OK; }
}
//传送操作,让值的操作生效
if (status == MI_OK)
{
buffer[0] = PICC_TRANSFER;
buffer[1] = addr;
CalulateCRC(buffer,2,&buffer[2]);
status = PCDConPICC(PCD_TRANSCEIVE,buffer,4,buffer,&unLen);
if ((status != MI_OK) || (unLen != 4) || ((buffer[0] & 0x0F) != 0x0A))
{ status = MI_ERR; }
}
return status;
}
3.8、备份值操作 (就是备份一个块的值到另一个块中)
空数据帧表示确认操作,通知卡片进行下一个操作
PICC_RESTORE
/*
*@sourceaddr 就是原来的块的地址
*@goaladdr 就是备份地址
*/
uint8_t PcdBakValue(unsigned char sourceaddr, unsigned char goaladdr)
{
char status;
unsigned int unLen;
unsigned char buffer[MAXRLEN];
buffer[0] = PICC_RESTORE;
buffer[1] = sourceaddr;
CalulateCRC(buffer,2,&buffer[2]);
status = PCDConPICC(PCD_TRANSCEIVE,buffer,4,buffer,&unLen);
if ((status != MI_OK) || (unLen != 4) || ((buffer[0] & 0x0F) != 0x0A))
{ status = MI_ERR; }
if (status == MI_OK)
{
buffer[0] = 0;
buffer[1] = 0;
buffer[2] = 0;
buffer[3] = 0;
CalulateCRC(buffer,4,&buffer[4]);
status = PCDConPICC(PCD_TRANSCEIVE,buffer,6,buffer,&unLen);
if (status != MI_ERR)
{ status = MI_OK; }
}
if (status != MI_OK)
{ return MI_ERR; }
buffer[0] = PICC_TRANSFER;
buffer[1] = goaladdr;
CalulateCRC(buffer,2,&buffer[2]);
status = PcdComMF522(PCD_TRANSCEIVE,buffer,4,buffer,&unLen);
if ((status != MI_OK) || (unLen != 4) || ((buffer[0] & 0x0F) != 0x0A))
{ status = MI_ERR; }
return status;
}
3.9、卡片休眠操作
uint8_t PcdHalt(void)
{
uint8_t status=MI_ERR;
unsigned uint8_t unLen;
unsigned uint8_t buffer[MAXRLEN];
buffer[0] = PICC_HALT;
buffer[1] = 0;
CalulateCRC(buffer,2,&buffer[2]);
//status =
PCDConPICC(PCD_TRANSCEIVE,buffer,4,buffer,&unLen);
if(buffer[0]&0x0f==0x0a){
status=MI_OK;
}
return MI_OK;
}
4、模块初始化
4.1、天线的打开和关闭
//打开
void PcdAntennaOn(void)
{
unsigned char i;
i = ReadRawRC(TxControlReg);
if (!(i & 0x03))
{
SetBitMask(TxControlReg, 0x03);
}
}
//关闭
void PcdAntennaOff(void)
{
ClearBitMask(TxControlReg, 0x03);
}
4.2、初始化
char PcdReset(void)
{
//通过硬件复位RC522,(低电平有效)这里先拉高
RC522_RESET_SET();
delay_us(10);
//开始复位
RC522_RESET_RESET();
delay_ms(60);
RC522_RESET_SET(); //停止复位
delay_us(500); //_NOP();_NOP();
WriteRawRC(CommandReg,PCD_RESETPHASE); //软件复位
delay_ms(2);
//设置RC522的基本模式
WriteRawRC(ModeReg,0x3D);
//设置自动装载低位
WriteRawRC(TReloadRegL,30);
//设置自动装载高位
WriteRawRC(TReloadRegH,0);
//设置定时器的工作模式
WriteRawRC(TModeReg,0x8D);
//设置分屏
WriteRawRC(TPrescalerReg,0x3E);
//设置传输调制设置
WriteRawRC(TxAutoReg,0x40);
//关闭用于调试的引脚功能,避免发生干扰
ClearBitMask(TestPinEnReg, 0x80);//off MX and DTRQ out
WriteRawRC(TxAutoReg,0x40);
return MI_OK;
}