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 问题解决
功能逻辑设计为:
- UART1为默认数据输出接口
- 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 */
}
- 循环进行卡类型识别,卡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–