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

news2024/9/20 5:28:55

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–

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/165819.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

es官网翻译之Exploring Your Cluster

Exploring Your Cluster 探索你的集群 The rest api rest 风格的 api Now that we have our node (and cluster) up and running, the next step is to understand how to 现在 我们已经将我们自己的节点(和集群) 启动并运行着, 下一个步骤是知道如何 communicate with it…

Java面试题每日10问(12)

1. What is String Pool? String pool is the space reserved in the heap memory that can be used to store the strings.The main advantage of using the String pool is whenever we create a string literal; the JVM checks the “string constant pool” first.If th…

速度为单GPU1.6倍,kaggle双GPU(ddp模式)加速pytorch攻略

accelerate 是huggingface开源的一个方便将pytorch模型迁移到 GPU/multi-GPUs/TPU/fp16 模式下训练的小巧工具。和标准的 pytorch 方法相比&#xff0c;使用accelerate 进行多GPU DDP模式/TPU/fp16 训练你的模型变得非常简单(只需要在标准的pytorch训练代码中改动不几行代码就可…

linux基功系列之man帮助命令实战

文章目录前言一、man命令介绍二、常用参数2.1 语法2.2 常用参数2.3 man页面的操作命令man命令使用案例1. 直接查看手册2. -aw 参数找到可以被查询的章节2.3 一次性查阅所有章节2.4 搜索手册页2.5 -L 设置查询语言总结前言 linux系统中的命令数量有上千的&#xff0c;即使是常用…

前端——周总结系列二

1 JS数组排序sort()方法 不传参数排序&#xff0c;默认根据Unicode排序 附录 传参数&#xff0c;使用比较函数&#xff0c;自己定义比较规则 简单数组排序 // 升序 function ascSort(a, b) {return a - b; } // 降序 function ascSort(a, b) {return b - a; }数组对象排序…

算法leetcode|31. 下一个排列(rust重拳出击)

文章目录31. 下一个排列&#xff1a;样例 1&#xff1a;样例 2&#xff1a;样例 3&#xff1a;提示&#xff1a;分析&#xff1a;题解&#xff1a;rustgoccpythonjava31. 下一个排列&#xff1a; 整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。 例如&#xff0…

ROS2机器人编程简述humble-第二章-First Steps with ROS2 .1

ROS2机器人编程简述新书推荐-A Concise Introduction to Robot Programming with ROS2学习笔记流水账-推荐阅读原书。第二章主要就是一些ROS的基本概念&#xff0c;其实ROS1和ROS2的基本概念很多都是类似的。ROS2机器人个人教程博客汇总&#xff08;2021共6套&#xff09;如何更…

Linux chgrp 命令

Linux chgrp&#xff08;英文全拼&#xff1a;change group&#xff09;命令用于变更文件或目录的所属群组。与 chown 命令不同&#xff0c;chgrp 允许普通用户改变文件所属的组&#xff0c;只要该用户是该组的一员。在 UNIX 系统家族里&#xff0c;文件或目录权限的掌控以拥有…

(一)Jenkins部署、基础配置

目录 1、前言 1.1、Jenkins是什么 1.2、jenkins有什么用 2、 Jenkins安装 2.1、jdk安装 2.2、安装Jenkins 3、Jenkins配置 3.1、解锁Jenkins 3.2、插件安装 3.3、创建管理员 3.4、实例配置 4、汉化 4.1、下载Locale插件 4.2、设置为中文 5、设置中文失效解决步骤 1…

U-Boot 之零 源码文件、启动阶段(TPL、SPL)、FALCON、设备树

最近&#xff0c;工作重心要从裸机开发转移到嵌入式 Linux 系统开发&#xff0c;在之前的博文 Linux 之八 完整嵌入式 Linux 环境、&#xff08;交叉&#xff09;编译工具链、CPU 体系架构、嵌入式系统构建工具 中详细介绍了嵌入式 Linux 环境&#xff0c;接下来就是重点学习一…

【Spring6源码・AOP】代理对象的创建

前三篇Spring IOC的源码解析与这一章的AOP是紧密相连的&#xff1a; 【Spring6源码・IOC】BeanDefinition的加载 【Spring6源码・IOC】Bean的实例化 【Spring6源码・IOC】Bean的初始化 - 终结篇 首先介绍我们本章的demo&#xff1a; 一个接口&#xff0c;一个实现&#xf…

【论文速递】ECCV2022 - 开销聚合与四维卷积Swin Transformer_小样本分割

【论文速递】ECCV2022 - 开销聚合与四维卷积Swin Transformer_小样本分割 【论文原文】&#xff1a;Cost Aggregation with 4D Convolutional Swin Transformer for Few-Shot Segmentation 获取地址&#xff1a;https://arxiv.org/pdf/2207.10866.pdf博主关键词&#xff1a; …

紧聚焦涡旋光束app设计-VVB2.0

紧聚焦涡旋光束app设计-VVB2.0前言界面预览功能演示写在最后前言 时隔几个月&#xff0c;花了点时间&#xff0c;将之前用matlab设计的app紧聚焦涡旋光束matlab gui设计进行一次修改&#xff0c;这次发布2.0版本&#xff0c;本次修改的范围主要是将原来的界面进行重做&#xf…

软件设计师中级复习小总结

软件设计师中级复习小总结 计算机与体系结构 K 1024 k 1000 B 字节 b 位 1字节 8位 8bit(位)1Byte(字节) 1024Byte(字节)1KB KB&#xff0c;MB&#xff0c;GB之间的换算关系是&#xff1a;1024KB1MB&#xff0c;1024MB1GB&#xff0c;1024GB1TB K&#xff0c;M&#x…

DevOps 实战概述

一、背景越来越多的团队使用DevOps&#xff0c;个人觉得原因有二&#xff0c;其一市场需求&#xff0c;从瀑布到敏捷的过程能看出市场就是需要团队响应快&#xff0c;小步快跑&#xff0c;风险低效率高&#xff0c;但是敏捷只解决了开发团队的问题并没有解决运维团队的问题&…

16、Javaweb_ajax的JSjQuery实现方式JSON_Java对象互转用户校验案例

AJAX&#xff1a; 1. 概念&#xff1a; ASynchronous JavaScript And XML 异步的JavaScript 和 XML 1. 异步和同步&#xff1a;客户端和服务器端相互通信的基础上 * 客户端必须等待服务器端的响应。在等待的期间客户端不能做其他操作。 * 客户端不需要…

[LeetCode周赛复盘] 第 328 场周赛20230115

[LeetCode周赛复盘] 第 328 场周赛20230115 一、本周周赛总结二、 [Easy] 6291. 数组元素和与数字和的绝对差1. 题目描述2. 思路分析3. 代码实现三、[Medium] 6292. 子矩阵元素加 11. 题目描述2. 思路分析3. 代码实现四、[Medium] 6293. 统计好子数组的数目1. 题目描述2. 思路分…

文献阅读总结--合成生物学工程促进大肠杆菌中莽草酸的高水平积累

题目&#xff1a;Systems engineering of Escherichia coli for high-level shikimate production (ME 2022) 0 前言 本版块内容为记录阅读的文献内容总结经典方法手段。本文内容来自相关文献&#xff0c;在文末做来源进行详细说明对文献中内容不做真实性评价。 1 具体内容 …

标准化和归一化概念澄清与梳理

标准化和归一化是特征缩放(feature scalingscaling)的主要手段&#xff0c;其核心原理可以简单地理解为&#xff1a;让所有元素先减去同一个数&#xff0c;然后再除以另一个数&#xff0c;在数轴上的效果就是&#xff1a;先将数据集整体平移到有某个位置&#xff0c;然后按比例…

【C进阶】动态内存管理

家人们欢迎来到小姜的世界&#xff0c;<<点此>>传送门 这里有详细的关于C/C/Linux等的解析课程&#xff0c;家人们赶紧冲鸭&#xff01;&#xff01;&#xff01; 客官&#xff0c;码字不易&#xff0c;来个三连支持一下吧&#xff01;&#xff01;&#xff01;关注…