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进行连接。
这里采用STM32F103C6T6作为控制芯片,首先建立基本工程并设置时钟系统:
STM32F103C6T6支持USB接口,这里采用USB和UART双通讯输出接口,配置USB接口为虚拟串口:
配置UART接口:
选择5个管脚与RC522连接实现模拟SPI协议访问,STM32的管脚安排如下:
保存并生成初始工程文件:
代码微秒级的时序控制,采用的微秒延时函数参考: STM32 HAL us delay(微秒延时)的指令延时实现方式及优化
STM32虚拟串口的设置可以参考: STM32 USB VCOM和HID的区别,配置及Echo功能实现(HAL)
编译时需要采用节省存储的编译方式,参考: STM32 region `FLASH‘ overflowed by xxx bytes 问题解决
功能逻辑设计为:
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 */
}
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(); //片选选中RC522ucAddr=((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 = 0RC522_WriteRawRC(CommandReg,PCD_IDLE);RC522_SetBitMask(FIFOLevelReg,0x80); //清FIFO指针//向FIFO中写入数据for(i=0;iRC522_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;iRC522_WriteRawRC(FIFODataReg,pIn[i]);}RC522_WriteRawRC(CommandReg,Command);if(Command==PCD_TRANSCEIVE){RC522_SetBitMask(BitFramingReg,0x80); //开始传送}i=25; //操作M1卡最大等待时间25msdo{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; ipOut[i]=RC522_ReadRawRC(FIFODataReg);}}}else{status=MI_ERR;}}RC522_SetBitMask(ControlReg,0x80);// stop timer nowRC522_WriteRawRC(CommandReg,PCD_IDLE);return status;
}/*
函数功能:复位RC522
*/
void RC522_Reset(void)
{RC522_PcdReset(); //复位RC522RC522_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初始值0x6363RC522_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初始值0x6363RC522_WriteRawRC(RxSelReg,0x86); //84RC522_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; //失败,返回1return MI_OK; //成功返回0
}/*
函数功能:RC522芯片初始化
*/
void RC522_Init(void)
{RC522_PcdReset(); //复位RC522M500PcdConfigISOType('A'); //设置RC522的工作方式
}/*功 能: 寻卡
参数说明: req_code[IN]:寻卡方式0x52 = 寻感应区内所有符合14443A标准的卡0x26 = 寻未进入休眠状态的卡pTagType[OUT]:卡片类型代码0x4400 = Mifare_UltraLight0x0400 = 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 18RC522_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 = 0x93ucComMF522Buf[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]; //把读到的卡号赋值给pSnrsnr_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]; //18ucComMF522Buf[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==18ucComMF522Buf[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 changeif((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 volumeif(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 volumeif(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 volumeif(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–