当前位置: 首页 > news >正文

STM32模拟SPI总线读写RFID模块RC522

STM32模拟SPI总线读写RFID模块RC522

RC522是一款NXP 公司的支持ISO14443A协议的高频(13.56MHz)RFID射频芯片。RFID有ID和IC两种卡应用类型,RC522属于IC卡的应用类型。NFC则属于增强的IC卡类型,支持双向通信和更多类型的协议。

ID卡在制卡时写入一次后,以后只能读取不能写入,常见的Mango卡工作频率为125KHz,所以也叫低频卡,支持ISO 18000-2协议。常见的ID卡右下角有一串打印数字(由ID前十位和ID后八位组成):
在这里插入图片描述

IC卡在发卡时写入信息后,以后通过密码可以读取也可以写入。市面上有比较丰富的RC522可用模块:
在这里插入图片描述
卡的内型有标准卡/方形卡和异形卡(水滴形钥匙扣等)。RFID卡通过近距离接收读卡器发送的射频功率用作感应能量来源,以及信号解析密码验证后将卡内的信息发出给读卡器。Mifare卡是市面上最常用,最廉价的RFID卡之一。Mifare卡分为MF0, MF1, MF2, MF3这么几种类型,MF0不带密码控制,使用很少;最常用的是MF1,这种卡带密码控制,分为S50和S70,S50拥有1K存储空间,S70拥有4K存储空间。

关于RC522与卡之间的通讯协议,这里不做仔细介绍,可以参考这几篇介绍:
参考1
参考2
参考3

这里移植参考代码,进行修改优化,实现STM32控制RC522模块读写Mifare卡,执行卡类型识别,卡ID识别,卡存储空间识别,验证密码,写数据,读数据,改变钱包值,备份钱包值。代码基于STM32CUBEIDE开发环境和HAL库。模块采用3.3V供电,可以直接和STM32进行连接。

STM32工程配置

这里采用STM32F103C6T6作为控制芯片,首先建立基本工程并设置时钟系统:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
STM32F103C6T6支持USB接口,这里采用USB和UART双通讯输出接口,配置USB接口为虚拟串口:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
配置UART接口:
在这里插入图片描述
选择5个管脚与RC522连接实现模拟SPI协议访问,STM32的管脚安排如下:
在这里插入图片描述
在这里插入图片描述

保存并生成初始工程文件:
在这里插入图片描述

STM32工程代码

代码微秒级的时序控制,采用的微秒延时函数参考: STM32 HAL us delay(微秒延时)的指令延时实现方式及优化
STM32虚拟串口的设置可以参考: STM32 USB VCOM和HID的区别,配置及Echo功能实现(HAL)
编译时需要采用节省存储的编译方式,参考: STM32 region `FLASH‘ overflowed by xxx bytes 问题解决

功能逻辑设计为:

  1. UART1为默认数据输出接口
  2. USB接口收到用户发来的任何数据,才开启USB输出数据
    在这里插入图片描述
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  /* USER CODE BEGIN 6 */
  extern uint8_t USB_Status;
  USB_Status = 1;

  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  return (USBD_OK);
  /* USER CODE END 6 */
}
  1. 循环进行卡类型识别,卡ID识别,卡存储空间识别,验证密码,写数据,读数据,改变钱包值,备份钱包值

main.h文件代码:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.h
  * @brief          : Header for main.c file.
  *                   This file contains the common defines of the application.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 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 */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/*
RC522 module connection to STM32:
*1--SDA/CS <-----> PA4
*2--SCK    <-----> PA5
*3--MOSI   <-----> PA7
*4--MISO   <-----> PA6
*5--IRQ    <-----> floating/unused
*6--GND    <-----> GND
*7--RST    <-----> PB0
*8--VCC    <-----> 3.3V
*/
#define   RC522_CS_0()              HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET)
#define   RC522_CS_1()              HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)

#define   RC522_Reset_0()           HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET)
#define   RC522_Reset_1()           HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET)

#define   RC522_SCK_0()             HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET)
#define   RC522_SCK_1()             HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET)

#define   RC522_MOSI_0()            HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET)
#define   RC522_MOSI_1()            HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET)

#define   RC522_MISO_GET()          HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6)


//MF522 Command
#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 Card Command
#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各种驱动函数
*/
uint8_t RC522_SPI_ReadWriteOneByte(uint8_t tx_data);
void RC522_IO_Init(void);
uint8_t RC522_Pcd_SelectTag(uint8_t *pSnr);
void RC522_Init(void);
void RC522_Reset(void);
char RC522_PcdRequest(uint8_t req_code,uint8_t *pTagType);
char RC522_PcdAnticoll(uint8_t *pSnr);
char RC522_PcdSelect(uint8_t *pSnr);
char RC522_PcdAuthState(uint8_t auth_mode,uint8_t addr,uint8_t *pKey,uint8_t *pSnr);
char RC522_PcdRead(uint8_t addr,uint8_t *p);
char RC522_PcdWrite(uint8_t addr,uint8_t *p);
char RC522_PcdHalt(void);
void RC522_CalulateCRC(uint8_t *pIn ,uint8_t len,uint8_t *pOut );
char RC522_PcdReset(void);
char M500PcdConfigISOType(uint8_t type);
char M500PcdConfigISOType(uint8_t type);
uint8_t RC522_ReadRawRC(uint8_t Address);
void RC522_WriteRawRC(uint8_t Address,uint8_t value);
void RC522_SetBitMask(uint8_t reg,uint8_t mask) ;
void RC522_ClearBitMask(uint8_t reg,uint8_t mask);
char RC522_PcdComMF522(uint8_t Command,uint8_t *pIn,uint8_t InLenByte,uint8_t *pOut,uint8_t *pOutLenBit);
void RC522_PcdAntennaOn(void);
void RC522_PcdAntennaOff(void);
char RC522_PcdValue(uint8_t dd_mode,uint8_t addr,uint8_t *pValue);
char RC522_PcdBakValue(uint8_t sourceaddr, uint8_t goaladdr);


/*
复位操作:
开启天线
关闭天线
复位RC522
设置RC522工作方式

通讯操作:
寻卡,通过RC522和M1卡通讯(数据的双向传输,从而确定卡片的卡型。)
防冲突(当有多张卡片进入读写器操作范围时,会从中选择一张卡片进行操作,并返回选中卡片的序列号。)
选定卡片(用RC522计算CRC16(循环冗余校验))
校验卡片密码(三次相互确认)
在M1卡的指定块地址写入指定数据(M1卡分为16个扇区,每个扇区有4块,实际操作时,将16个扇区分为64个块,按绝对地址编号0-63)
读取M1卡的指定块地址的数据
让卡片进入休眠模式

S50(M1)卡基础知识:
1.每张卡有唯一的序列号共32位
2.卡的容量为8Kbit的EEPROM
3.分为16个扇区,每个扇区分为4块,每块16个字节,以块为存取单元
4.每个扇区都有独立的一组密码和访问控制

扇区0的块0用来固化厂商代码
每个扇区的块3作为控制块,存放:密码A(6字节), 存取控制(4字节), 密码B(6字节)
每个扇区的块0,1,2作为数据块,其作用如下:
1.作为数据存储,可以对其中的数据进行写卡,读卡
2.用作钱包数据值,可以进行写卡,读卡,加值,减值

对数据块的操作类型:
读(Read):读一个块的数据
写(Write):在一个块中写数据
加(Increment):对数据块中的数据进行加值(充款)
减(Decrement):对数据块中的数值进行减值(扣款)
传输(Transfer):将数据寄存器中的内容写入数据块中
中止(Halt):暂停卡片的工作

要设置一个块为数值块,它的格式是非常严格的,必须按照数据块的格式去写,才能调用充值和扣款的功能:
|字节0|字节1|字节2|字节3|字节4|字节5|字节6|字节7|字节8|字节9|字节10|字节11|字节12|字节13|字节14|字节15|
|      钱包值           |     钱包值反值       |         钱包值          |地址  |地址反|地址  |地址反|

Mifare S50在出厂时,每一个控制块的密码A和密码B都为FF FF FF FF FF FF
 */


/* USER CODE END ET */

/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */

/* USER CODE END EC */

/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */

/* USER CODE END EM */

/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);

/* USER CODE BEGIN EFP */

/* USER CODE END EFP */

/* Private defines -----------------------------------------------------------*/
/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

#ifdef __cplusplus
}
#endif

#endif /* __MAIN_H */

main.c文件代码:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 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.
  *
  ******************************************************************************
  //Written by Pegasus Yu in 2022
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usb_device.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

//Protocol Reference: https://blog.csdn.net/qq_43743762/article/details/104207730
//Protocol Reference: https://xiaolong.blog.csdn.net/article/details/117075834
//Protocol Reference: https://javaforall.cn/192001.html

#include "string.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
uint8_t USB_Status = 0;
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
__IO float usDelayBase;
void PY_usDelayTest(void)
{
  __IO uint32_t firstms, secondms;
  __IO uint32_t counter = 0;

  firstms = HAL_GetTick()+1;
  secondms = firstms+1;

  while(uwTick!=firstms) ;

  while(uwTick!=secondms) counter++;

  usDelayBase = ((float)counter)/1000;
}

void PY_Delay_us_t(uint32_t Delay)
{
  __IO uint32_t delayReg;
  __IO uint32_t usNum = (uint32_t)(Delay*usDelayBase);

  delayReg = 0;
  while(delayReg!=usNum) delayReg++;
}

void PY_usDelayOptimize(void)
{
  __IO uint32_t firstms, secondms;
  __IO float coe = 1.0;

  firstms = HAL_GetTick();
  PY_Delay_us_t(1000000) ;
  secondms = HAL_GetTick();

  coe = ((float)1000)/(secondms-firstms);
  usDelayBase = coe*usDelayBase;
}

void PY_Delay_us(uint32_t Delay)
{
  __IO uint32_t delayReg;

  __IO uint32_t msNum = Delay/1000;
  __IO uint32_t usNum = (uint32_t)((Delay%1000)*usDelayBase);

  if(msNum>0) HAL_Delay(msNum);

  delayReg = 0;
  while(delayReg!=usNum) delayReg++;
}
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/*
函数功能:移植接口--SPI时序读写一个字节
函数参数:data:要写入的数据
返 回 值:读到的数据
*/
uint8_t RC522_SPI_ReadWriteOneByte(uint8_t tx_data)
{
  uint8_t rx_data=0;
  for(uint8_t i=0;i<8;i++)
	{
		RC522_SCK_0();
		if(tx_data&0x80){RC522_MOSI_1();}
		else {RC522_MOSI_0();}
		tx_data<<=1;
		PY_Delay_us_t(1);
		RC522_SCK_1();
		rx_data<<=1;
		if(RC522_MISO_GET())rx_data|=0x01;
		PY_Delay_us_t(1);
	}
	return rx_data;
}


/*
功    能:读RC522寄存器
参数说明:Address[IN]:寄存器地址
返    回:读出的值
*/
uint8_t RC522_ReadRawRC(uint8_t Address)
{
    uint8_t ucAddr;
    uint8_t ucResult=0;

    RC522_CS_0();						      //片选选中RC522
    ucAddr=((Address<<1)&0x7E)|0x80;
    RC522_SPI_ReadWriteOneByte(ucAddr);		  //发送命令
    ucResult=RC522_SPI_ReadWriteOneByte(0);   //读取RC522返回的数据
    RC522_CS_1();						      //释放片选线
    return ucResult;                          //返回读到的数据
}


/*
功    能:写RC522寄存器
参数说明:Address[IN]:寄存器地址
          value[IN] :写入的值
*/
void RC522_WriteRawRC(uint8_t Address,uint8_t value)
{
  uint8_t ucAddr;

  RC522_CS_0();                                           //SPI1片选线,低电平有效
  ucAddr=((Address<<1)&0x7E);
  RC522_SPI_ReadWriteOneByte(ucAddr);                     //SPI1发送一个字节
  RC522_SPI_ReadWriteOneByte(value);                      //SPI1发送一个字节
  RC522_CS_1();										      //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
}

/*
功    能:用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));  //开始CRC计算
		}

		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和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=25; //操作M1卡最大等待时间25ms
			do
			{
				n=RC522_ReadRawRC(ComIrqReg);
				i--;
				PY_Delay_us_t(1000); //1ms delay
			}
			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;
}

/*
函数功能:复位RC522
*/
void RC522_Reset(void)
{
  RC522_PcdReset();				//复位RC522
  RC522_PcdAntennaOff();	    //关闭天线
  PY_Delay_us_t(2000);          //延时2毫秒
  RC522_PcdAntennaOn();		    //开启天线
}

/*
函数功能:开启天线
参    数:每次启动或关闭天险发射之间应至少有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寄存器位
}

/*
功    能:复位RC522
返    回:成功返回MI_OK
*/
char RC522_PcdReset(void)
{
	RC522_Reset_1();
    PY_Delay_us_t(10);
	RC522_Reset_0();
    PY_Delay_us_t(10);
	RC522_Reset_1();
    PY_Delay_us_t(10);

    RC522_WriteRawRC(CommandReg,PCD_RESETPHASE);    //写RC522寄存器,复位
	RC522_WriteRawRC(CommandReg,PCD_RESETPHASE);	//写RC522寄存器,复位
    PY_Delay_us_t(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);
	     PY_Delay_us_t(1000);
         RC522_PcdAntennaOn();		               //开启天线
   }
   else return 1;                                  //失败,返回1
   return MI_OK;				                   //成功返回0
}

/*
函数功能:RC522芯片初始化
*/
void RC522_Init(void)
{
  RC522_PcdReset();  			//复位RC522
  M500PcdConfigISOType('A');    //设置RC522的工作方式
}


/*

功    能: 寻卡
参数说明: 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);   //写RC522寄存器
	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)) return MI_OK;
    else return MI_ERR;

}

/*
功能描述:选卡读取卡存储器容量
输入参数:serNum 传入卡序列号
返    回:成功返回卡容量
*/
uint8_t RC522_Pcd_SelectTag(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)) return ucComMF522Buf[0] ;
    else return 0;
}


/*
功    能:验证卡片密码
参数说明: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;
}

//******************************************************************/
//功    能:扣款和充值
//参数说明: dd_mode[IN]:命令字
//               0xC0 = 扣款
//               0xC1 = 充值
//          addr[IN]:钱包地址
//          pValue[IN]:4字节充/扣值,低位在前
//返    回: 成功返回MI_OK
//******************************************************************/
char RC522_PcdValue(uint8_t dd_mode,uint8_t addr,uint8_t *pValue)
{
    char status;
    uint8_t  unLen;
    uint8_t i,ucComMF522Buf[MAXRLEN];

    ucComMF522Buf[0] = dd_mode;
    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++)
        {    ucComMF522Buf[i] = *(pValue+i);   }
        RC522_CalulateCRC(ucComMF522Buf,4,&ucComMF522Buf[4]);
        unLen = 0;
        status = RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,6,ucComMF522Buf,&unLen);
        if (status != MI_ERR)
        {    status = MI_OK;    }
    }

    if (status == MI_OK)
    {
        ucComMF522Buf[0] = PICC_TRANSFER;
        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;   }
    }
    return status;
}


//******************************************************************/
//功    能:备份钱包
//参数说明: sourceaddr[IN]:源地址(源块地址)
//          goaladdr[IN]:目标地址(目的块地址)
//返    回: 成功返回MI_OK
//******************************************************************/
char RC522_PcdBakValue(uint8_t sourceaddr, uint8_t goaladdr)
{
    char status;
    uint8_t  unLen;
    uint8_t ucComMF522Buf[MAXRLEN];

    ucComMF522Buf[0] = PICC_RESTORE;
    ucComMF522Buf[1] = sourceaddr;
    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)
    {
        ucComMF522Buf[0] = 0;
        ucComMF522Buf[1] = 0;
        ucComMF522Buf[2] = 0;
        ucComMF522Buf[3] = 0;
        RC522_CalulateCRC(ucComMF522Buf,4,&ucComMF522Buf[4]);

        status = RC522_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;

    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;   }

    return status;
}


/*
功    能:命令卡片进入休眠状态
返    回:成功返回MI_OK
*/
char RC522_PcdHalt(void)
{
    uint8_t status;
    uint8_t unLen;
    uint8_t ucComMF522Buf[MAXRLEN]; //MAXRLEN==18

    ucComMF522Buf[0]=PICC_HALT;
    ucComMF522Buf[1]=0;
    RC522_CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
    status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
    return status;
}

/*参考密码*/
uint8_t KEY[14][6]={
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5},
{0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5},
{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
{0x4D, 0x3A, 0x99, 0xC3, 0x51, 0xDD},
{0x1A, 0x98, 0x2C, 0x7E, 0x45, 0x9A},
{0x71, 0x4C, 0x5C, 0x88, 0x6E, 0x97},
{0x58, 0x7E, 0xE5, 0xF9, 0x35, 0x0F},
{0xA0, 0x47, 0x8C, 0xC3, 0x90, 0x91},
{0x53, 0x3C, 0xB6, 0xC7, 0x23, 0xf6},
{0x8F, 0xD0, 0xA4, 0xF2, 0x56, 0xE9},
{0x66, 0x55, 0x44, 0x11, 0x22, 0x33},
{0x66, 0x55, 0x44, 0x33, 0x22, 0x11}
};
/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(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 */
  uint8_t temp = 0;
  uint8_t td[128];
  char cStr[64];

  uint8_t demotype = 0;
  uint8_t wallet_demo[16] = {255,0,0,0, 0,255,255,255, 255,0,0,0, 0x08, 0xf7, 0x08, 0xf7};
  uint32_t wvalue = 0x00000001;

  /* 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_USB_DEVICE_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  PY_usDelayTest();
  PY_usDelayOptimize();

  RC522_Init();

  PY_Delay_us_t(10000000); //Waiting for possible USB_Status change

  if((RC522_ReadRawRC(VersionReg)&0xf0)==0x90) //Read version register
  {
	  HAL_UART_Transmit(&huart1, "SPI communication verification OK!\r\n", strlen("SPI communication verification OK!\r\n"), 2700);
	  if(USB_Status==1)
	  {
		  while(CDC_Transmit_FS("SPI communication verification OK!\r\n", strlen("SPI communication verification OK!\r\n"))!=0) ;

	  }
  }
  else
  {
	  while(1)
	  {
		  HAL_UART_Transmit(&huart1, "SPI communication verification failure!\r\n", strlen("SPI communication verification failure!\r\n"), 2700);
		  if(USB_Status==1)
		  {
			  while(CDC_Transmit_FS("SPI communication verification failure!\r\n", strlen("SPI communication verification failure!\r\n"))!=0) ;

		  }
	  }
  }

  /* USER CODE END 2 */

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

	  temp = RC522_PcdRequest(PICC_REQALL, td);
      if(temp!=MI_OK) temp = RC522_PcdRequest(PICC_REQALL, td);

      if(demotype%3==0)  //Write and read test
      {
    	  demotype++;
          if(temp==MI_OK)
          {
    		  sprintf (cStr, "\r\nCard Type got: 0x%02x%02x\r\n", td[0],td[1]);
    		  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
    		  if(USB_Status==1)
    		  {
    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
    		  }
    		  sprintf (cStr, "0x4400 = Mifare_UltraLight\r\n0x0400 = Mifare_One(S50)\r\n0x0200 = Mifare_One(S70)\r\n0x0800 = Mifare_Pro(X)\r\n0x4403 = Mifare_DESFire\r\n");
    		  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
    		  if(USB_Status==1)
    		  {
    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
    		  }

        	  if(RC522_PcdAnticoll(td)==MI_OK) //Get card ID
        	  {
        			  temp = RC522_Pcd_SelectTag(td); //Select card and get volume
        			  if(temp==0)
        			  {
            			  sprintf(cStr, "Card selected failure!\r\n");
            			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                		  if(USB_Status==1)
                		  {
                			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                		  }

        			  }
        			  else
        			  {
            			  sprintf(cStr, "Card selected OK and size got: %d Kbit for ID: 0x%02x%02x%02x%02x\r\n", temp, td[0], td[1], td[2], td[3]);
            			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                		  if(USB_Status==1)
                		  {
                			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                		  }

                		  if(RC522_PcdAuthState(0x60, 0x04, KEY[0], td)!=MI_OK) //验证A密钥:�?4(扇区1的块0)的密码验证,用默认密码尝试
                		  {
                			  sprintf(cStr, "Password verification failure!\r\n");
                			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                    		  if(USB_Status==1)
                    		  {
                    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                    		  }

                		  }
                		  else
                		  {
                			  sprintf(cStr, "Password verification OK!\r\n");
                			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                    		  if(USB_Status==1)
                    		  {
                    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                    		  }

                    		  for(uint8_t i=0;i<16;i++) td[i]=i;

                    		  if(RC522_PcdWrite(0x04, td)!=MI_OK) //测试写卡�?4(扇区1的块0)
                    		  {
                    			  sprintf(cStr, "Block(0x04) writing failure!\r\n");
                    			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                        		  if(USB_Status==1)
                        		  {
                        			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                        		  }

                    		  }
                    		  else
                    		  {
                    			  sprintf(cStr, "Block(0x04) writing(0x000102030405060708090A0B0C0D0E0F) OK!\r\n");
                    			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                        		  if(USB_Status==1)
                        		  {
                        			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                        		  }

                        		  for(uint8_t i=0;i<16;i++) td[i]=0;
                        		  PY_Delay_us_t(100000);

                        		  if(RC522_PcdRead(0x04, td) != MI_OK) //测试读卡�?4(扇区1的块0)
                        		  {
                        			  sprintf(cStr, "Block(0x04) read failure!\r\n");
                        			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                            		  if(USB_Status==1)
                            		  {
                            			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                            		  }

                        		  }
                        		  else
                        		  {
                        			  sprintf(cStr, "Block(0x04) read ok: 0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\r\n", td[0], td[1], td[2], td[3], td[4], td[5], td[6], td[7], td[8], td[9], td[10], td[11], td[12], td[13], td[14], td[15]);
                        			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                            		  if(USB_Status==1)
                            		  {
                            			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                            		  }

                        		  }

                    		  }



                		  }


        			  }

                  }

              }
      }
      else if(demotype%3==1) //Wallet change
      {
    	  demotype++;
          if(temp==MI_OK)
          {
    		  sprintf (cStr, "\r\nCard Type got: 0x%02x%02x\r\n", td[0],td[1]);
    		  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
    		  if(USB_Status==1)
    		  {
    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
    		  }
    		  sprintf (cStr, "0x4400 = Mifare_UltraLight\r\n0x0400 = Mifare_One(S50)\r\n0x0200 = Mifare_One(S70)\r\n0x0800 = Mifare_Pro(X)\r\n0x4403 = Mifare_DESFire\r\n");
    		  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
    		  if(USB_Status==1)
    		  {
    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
    		  }

        	  if(RC522_PcdAnticoll(td)==MI_OK) //Get card ID
        	  {
        			  temp = RC522_Pcd_SelectTag(td); //Select card and get volume
        			  if(temp==0)
        			  {
            			  sprintf(cStr, "Card selected failure!\r\n");
            			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                		  if(USB_Status==1)
                		  {
                			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                		  }

        			  }
        			  else
        			  {
        				  sprintf(cStr, "Card selected OK and size got: %d Kbit for ID: 0x%02x%02x%02x%02x\r\n", temp, td[0], td[1], td[2], td[3]);
            			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                		  if(USB_Status==1)
                		  {
                			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                		  }

                		  if(RC522_PcdAuthState(0x60, 0x08, KEY[0], td)!=MI_OK) //验证A密钥:�?8(扇区2的块0)的密码验证,用默认密码尝试
                		  {
                			  sprintf(cStr, "Password verification failure!\r\n");
                			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                    		  if(USB_Status==1)
                    		  {
                    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                    		  }

                		  }
                		  else
                		  {
                			  sprintf(cStr, "Password verification OK!\r\n");
                			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                    		  if(USB_Status==1)
                    		  {
                    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                    		  }

                    		  for(uint8_t i=0;i<16;i++) td[i]=wallet_demo[i];

                    		  if(RC522_PcdWrite(0x08, td)!=MI_OK) //测试写卡�?8(扇区2的块0)
                    		  {
                    			  sprintf(cStr, "Block(0x08) writing failure!\r\n");
                    			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                        		  if(USB_Status==1)
                        		  {
                        			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                        		  }

                    		  }
                    		  else
                    		  {
                    			  sprintf(cStr, "Block(0x08) writing(0xFF00000000FFFFFFFF00000008F708F7) OK!\r\n");
                    			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                        		  if(USB_Status==1)
                        		  {
                        			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                        		  }

                        		  for(uint8_t i=0;i<16;i++) td[i]=0;
                        		  PY_Delay_us_t(100000);

                        		  if(RC522_PcdRead(0x08, td) != MI_OK) //测试读卡�?8(扇区2的块0)
                        		  {
                        			  sprintf(cStr, "Block(0x08) read failure!\r\n");
                        			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                            		  if(USB_Status==1)
                            		  {
                            			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                            		  }

                        		  }
                        		  else
                        		  {
                        			  sprintf(cStr, "Block(0x08) read ok: 0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\r\n", td[0], td[1], td[2], td[3], td[4], td[5], td[6], td[7], td[8], td[9], td[10], td[11], td[12], td[13], td[14], td[15]);
                        			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                            		  if(USB_Status==1)
                            		  {
                            			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                            		  }

                            		  PY_Delay_us_t(100000);

                            		  if(RC522_PcdValue(0xC1, 0x08, (uint8_t *)&wvalue) != MI_OK)
                            		  {
                            			  sprintf(cStr, "Block(0x08) wallet change operation failure!\r\n");
                            			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                                		  if(USB_Status==1)
                                		  {
                                			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                                		  }

                            		  }
                            		  else
                            		  {

                            			  sprintf(cStr, "Block(0x08) wallet change operation OK!\r\n");
                            			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                                		  if(USB_Status==1)
                                		  {
                                			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                                		  }

                                		  PY_Delay_us_t(100000);

                                		  if(RC522_PcdRead(0x08, td) != MI_OK) //测试读卡�?8(扇区2的块0)
                                		  {
                                			  sprintf(cStr, "Block(0x08) read failure!\r\n");
                                			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                                    		  if(USB_Status==1)
                                    		  {
                                    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                                    		  }

                                		  }
                                		  else
                                		  {
                                			  sprintf(cStr, "Block(0x08) read ok: 0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\r\n", td[0], td[1], td[2], td[3], td[4], td[5], td[6], td[7], td[8], td[9], td[10], td[11], td[12], td[13], td[14], td[15]);
                                			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                                    		  if(USB_Status==1)
                                    		  {
                                    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                                    		  }

                                		  }


                            		  }

                        		  }

                    		  }



                		  }


        			  }

                  }

              }

      }
      else //wallet backup test
      {
    	  demotype++;
          if(temp==MI_OK)
          {
    		  sprintf (cStr, "\r\nCard Type got: 0x%02x%02x\r\n", td[0],td[1]);
    		  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
    		  if(USB_Status==1)
    		  {
    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
    		  }
    		  sprintf (cStr, "0x4400 = Mifare_UltraLight\r\n0x0400 = Mifare_One(S50)\r\n0x0200 = Mifare_One(S70)\r\n0x0800 = Mifare_Pro(X)\r\n0x4403 = Mifare_DESFire\r\n");
    		  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
    		  if(USB_Status==1)
    		  {
    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
    		  }

        	  if(RC522_PcdAnticoll(td)==MI_OK) //Get card ID
        	  {
        			  temp = RC522_Pcd_SelectTag(td); //Select card and get volume
        			  if(temp==0)
        			  {
            			  sprintf(cStr, "Card selected failure!\r\n");
            			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                		  if(USB_Status==1)
                		  {
                			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                		  }

        			  }
        			  else
        			  {
        				  sprintf(cStr, "Card selected OK and size got: %d Kbit for ID: 0x%02x%02x%02x%02x\r\n", temp, td[0], td[1], td[2], td[3]);
            			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                		  if(USB_Status==1)
                		  {
                			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                		  }

                		  if(RC522_PcdAuthState(0x60, 0x08, KEY[0], td)!=MI_OK) //验证A密钥: �?8(扇区2的块0)的密码验证,用默认密码尝试
                		  {
                			  sprintf(cStr, "Password verification failure!\r\n");
                			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                    		  if(USB_Status==1)
                    		  {
                    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                    		  }

                		  }
                		  else
                		  {
                			  sprintf(cStr, "Password verification OK!\r\n");
                			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                    		  if(USB_Status==1)
                    		  {
                    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                    		  }

                    		  for(uint8_t i=0;i<16;i++) td[i]=wallet_demo[i];

                    		  if(RC522_PcdWrite(0x08, td)!=MI_OK) //测试写卡�?8(扇区2的块0)钱包数据
                    		  {
                    			  sprintf(cStr, "Block(0x08) writing failure!\r\n");
                    			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                        		  if(USB_Status==1)
                        		  {
                        			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                        		  }

                    		  }
                    		  else
                    		  {
                    			  sprintf(cStr, "Block(0x08) writing(0xFF00000000FFFFFFFF00000008F708F7) OK!\r\n");
                    			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                        		  if(USB_Status==1)
                        		  {
                        			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                        		  }

                        		  for(uint8_t i=0;i<16;i++) td[i]=0;
                        		  PY_Delay_us_t(100000);

                        		  if(RC522_PcdRead(0x08, td) != MI_OK) //测试读卡�?8(扇区2的块0)
                        		  {
                        			  sprintf(cStr, "Block(0x08) read failure!\r\n");
                        			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                            		  if(USB_Status==1)
                            		  {
                            			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                            		  }

                        		  }
                        		  else
                        		  {
                        			  sprintf(cStr, "Block(0x08) read ok: 0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\r\n", td[0], td[1], td[2], td[3], td[4], td[5], td[6], td[7], td[8], td[9], td[10], td[11], td[12], td[13], td[14], td[15]);
                        			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                            		  if(USB_Status==1)
                            		  {
                            			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                            		  }

                            		  PY_Delay_us_t(100000);

                            		  if(RC522_PcdBakValue(0x08, 0x09) != MI_OK)  //备份�?8数据到块9
                            		  {
                            			  sprintf(cStr, "Block(0x08) wallet backup operation failure!\r\n");
                            			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                                		  if(USB_Status==1)
                                		  {
                                			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                                		  }

                            		  }
                            		  else
                            		  {

                            			  sprintf(cStr, "Block(0x08) wallet backup operation OK!\r\n");
                            			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                                		  if(USB_Status==1)
                                		  {
                                			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                                		  }

                                		  PY_Delay_us_t(100000);

                                		  if(RC522_PcdRead(0x09, td) != MI_OK) //测试读卡�?9(扇区2的块1)
                                		  {
                                			  sprintf(cStr, "Block(0x09) read failure!\r\n");
                                			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                                    		  if(USB_Status==1)
                                    		  {
                                    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                                    		  }

                                		  }
                                		  else
                                		  {
                                			  sprintf(cStr, "Block(0x09) read ok: 0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\r\n", td[0], td[1], td[2], td[3], td[4], td[5], td[6], td[7], td[8], td[9], td[10], td[11], td[12], td[13], td[14], td[15]);
                                			  HAL_UART_Transmit(&huart1, cStr, strlen(cStr), 2700);
                                    		  if(USB_Status==1)
                                    		  {
                                    			  while(CDC_Transmit_FS(cStr, strlen(cStr))!=0) ;
                                    		  }

                                		  }






                            		  }

                        		  }

                    		  }



                		  }


        			  }

                  }

              }

      }



	  PY_Delay_us_t(500000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  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_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
  PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOD_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_SET);

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

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);

  /*Configure GPIO pins : PA4 PA5 PA7 */
  GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  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);

  /*Configure GPIO pin : PB0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

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

测试效果

上电后通过串口观察输出数据,将RFID卡靠近RC522模块天线:
在这里插入图片描述

例程下载

STM32F103C6T6读写RC522模块完整例程(STM32CUBEIDE开发环境HAL库工程)

–End–

相关文章:

  • 中小企业网络构建/手机优化大师
  • 如何在百度上做公司网站/网络营销策划书800字
  • wordpress对接公众号开发者/拉新工作室在哪里接项目
  • 网站建设毕业设计心得/搜索引擎优化举例说明
  • 网站设计师的工作环境/自己动手建立个人网站
  • wordpress 文件夹权限/营销技巧和营销方法心得
  • 历史最全事件抽取任务分类、经典论文、模型及数据集整理分享
  • 读写锁RWLock简单实现研究
  • 软件测试技术之利用 Jest 为 React 组件编写单元测试
  • JS入门到精通详解(9)
  • 【C语言进阶】自定义类型之结构体
  • mysql新建分区设置阈值(less than)引发的问题
  • 2.1总线概述
  • Android/Linux 子系统Graphics图形栈入门普法介绍
  • LocalDate方法使用总结
  • Open3D 点云投影至指定平面(Python版本)
  • 基于深度学习神经网络的农业病虫害识别(完整代码+数据)
  • Redis序列化、乱码问题