(HAL)STM32F103C8T6——RC522与主机进行SPI通信(RFID门禁系统入门必备)

目录

一、MFRC522简介

二、接线

三、存储结构说明

四、代码解析

1、rc522.h

2、rc522.c

3、spi.h

4、spi.c

5、main.c


一、MFRC522简介

店家提供的资料:
链接: 百度网盘 请输入提取码
提取码:su3m
简言之,MFRCC522是基于SPI通信协议与主机进行通信的模块,可实现RFID无线通信,常用于门禁系统、支付系统等。SPI通信原理细节可看往期笔记。 STM32F4——SPI通信
本篇笔记主要介绍MFRC522模块。

二、接线

STM32
RC522
PB12
SDA
PB13
SCK
PB14
MOSI
PB15
MISO
悬空
IRQ
GND
GND
PB1
RST
VCC
VCC
使用SPI2, 记住主机的MOSI和从机的MOSI相连,不是交叉相连!!!!!!!

三、存储结构说明

利用 软件NFC WRITER对NFC卡扇区内存进行管理,可以查看存储信息,通过串口打印出来的前六个字节000000000000存在错误,应该为FFFFFFFFFFFF。
在网上搜了资料,有些朋友说扇区0是不能够写修改的,由厂家初始化,笔者刚开始也可以读取出来,但由于不熟悉且手贱,刚开始在探究NFC卡扇区的读与写时,错误操作于在扇区0第3区块直接写入六个字节(F1FFFFFFFFFF),之后用软件读取不出扇区的内存信息,怀疑是损坏了或者丢失了。现在密码A仍然可以验证为我写入的F1FFFFFFFFFF,但是密码B不知道是什么,也无法对扇区0内存储信息进行读取。

四、代码解析

1、rc522.h

#ifndef _RC522_H
#define _RC522_H#include "stm32f1xx_hal.h"/* CS/NSS/SDA均表示片选 */
#define RC522_RST_Pin               GPIO_PIN_1
#define RC522_RST_GPIO_Port         GPIOB
#define RC522_CS_Pin                GPIO_PIN_12
#define RC522_CS_GPIO_Port          GPIOB#define osDelay HAL_Delay
#define RS522_RST(x) do{ x ? \HAL_GPIO_WritePin(RC522_RST_GPIO_Port, RC522_RST_Pin, GPIO_PIN_SET) :\HAL_GPIO_WritePin(RC522_RST_GPIO_Port, RC522_RST_Pin, GPIO_PIN_RESET);\}while(0)
#define RS522_NSS(x) do{ x ? \HAL_GPIO_WritePin(RC522_CS_GPIO_Port, RC522_CS_Pin, GPIO_PIN_SET) :\HAL_GPIO_WritePin(RC522_CS_GPIO_Port, RC522_CS_Pin, GPIO_PIN_RESET);\}while(0)
/***********************************************************************************
*								MFRC522驱动程序			        				   *
************************************************************************************/
/*MFRC522寄存器定义*/
//PAGE0
#define MFRC_RFU00              	0x00    
#define MFRC_CommandReg         	0x01    
#define MFRC_ComIEnReg             	0x02    
#define MFRC_DivlEnReg             	0x03    
#define MFRC_ComIrqReg             	0x04    
#define MFRC_DivIrqReg             	0x05
#define MFRC_ErrorReg              	0x06    
#define MFRC_Status1Reg            	0x07    
#define MFRC_Status2Reg            	0x08    
#define MFRC_FIFODataReg           	0x09
#define MFRC_FIFOLevelReg          	0x0A
#define MFRC_WaterLevelReg         	0x0B
#define MFRC_ControlReg            	0x0C
#define MFRC_BitFramingReg         	0x0D
#define MFRC_CollReg               	0x0E
#define MFRC_RFU0F                 	0x0F
//PAGE1     
#define MFRC_RFU10                 	0x10
#define MFRC_ModeReg               	0x11
#define MFRC_TxModeReg             	0x12
#define MFRC_RxModeReg             	0x13
#define MFRC_TxControlReg          	0x14
#define MFRC_TxAutoReg             	0x15 //中文手册有误
#define MFRC_TxSelReg              	0x16
#define MFRC_RxSelReg              	0x17
#define MFRC_RxThresholdReg        	0x18
#define MFRC_DemodReg              	0x19
#define MFRC_RFU1A                 	0x1A
#define MFRC_RFU1B                 	0x1B
#define MFRC_MifareReg             	0x1C
#define MFRC_RFU1D                 	0x1D
#define MFRC_RFU1E                 	0x1E
#define MFRC_SerialSpeedReg        	0x1F
//PAGE2    
#define MFRC_RFU20                 	0x20  
#define MFRC_CRCResultRegM         	0x21
#define MFRC_CRCResultRegL         	0x22
#define MFRC_RFU23                 	0x23
#define MFRC_ModWidthReg           	0x24
#define MFRC_RFU25                 	0x25
#define MFRC_RFCfgReg              	0x26
#define MFRC_GsNReg                	0x27
#define MFRC_CWGsCfgReg            	0x28
#define MFRC_ModGsCfgReg           	0x29
#define MFRC_TModeReg              	0x2A
#define MFRC_TPrescalerReg         	0x2B
#define MFRC_TReloadRegH           	0x2C
#define MFRC_TReloadRegL           	0x2D
#define MFRC_TCounterValueRegH     	0x2E
#define MFRC_TCounterValueRegL     	0x2F
//PAGE3      
#define MFRC_RFU30                 	0x30
#define MFRC_TestSel1Reg           	0x31
#define MFRC_TestSel2Reg           	0x32
#define MFRC_TestPinEnReg          	0x33
#define MFRC_TestPinValueReg       	0x34
#define MFRC_TestBusReg            	0x35
#define MFRC_AutoTestReg           	0x36
#define MFRC_VersionReg            	0x37
#define MFRC_AnalogTestReg         	0x38
#define MFRC_TestDAC1Reg           	0x39  
#define MFRC_TestDAC2Reg           	0x3A   
#define MFRC_TestADCReg            	0x3B   
#define MFRC_RFU3C                 	0x3C   
#define MFRC_RFU3D                 	0x3D   
#define MFRC_RFU3E                 	0x3E   
#define MFRC_RFU3F                 	0x3F/*MFRC522的FIFO长度定义*/
#define MFRC_FIFO_LENGTH       		64 /*MFRC522传输的帧长定义*/
#define MFRC_MAXRLEN                18                /*MFRC522命令集,中文手册P59*/
#define MFRC_IDLE              		0x00	//取消当前命令的执行
#define MFRC_CALCCRC           		0x03    //激活CRC计算
#define MFRC_TRANSMIT          		0x04    //发送FIFO缓冲区内容
#define MFRC_NOCMDCHANGE            0x07	//无命令改变
#define MFRC_RECEIVE           		0x08    //激活接收器接收数据
#define MFRC_TRANSCEIVE        		0x0C    //发送并接收数据
#define MFRC_AUTHENT           		0x0E    //执行Mifare认证(验证密钥)
#define MFRC_RESETPHASE        		0x0F    //复位MFRC522/*MFRC522通讯时返回的错误代码*/
#define MFRC_OK                 	(char)0
#define MFRC_NOTAGERR            	(char)(-1)
#define MFRC_ERR                	(char)(-2)/*MFRC522函数声明*/
void MFRC_Init(void);
void MFRC_WriteReg(uint8_t addr, uint8_t data);
uint8_t MFRC_ReadReg(uint8_t addr);
void MFRC_SetBitMask(uint8_t addr, uint8_t mask);
void MFRC_ClrBitMask(uint8_t addr, uint8_t mask);
void MFRC_CalulateCRC(uint8_t *pInData, uint8_t len, uint8_t *pOutData);
char MFRC_CmdFrame(uint8_t cmd, uint8_t *pInData, uint8_t InLenByte, uint8_t *pOutData, uint16_t *pOutLenBit);/***********************************************************************************
*							MFRC552与MF1卡通讯接口程序	 		     	     	   *
************************************************************************************/
/*Mifare1卡片命令字*/
#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_TRANSFER         	0xB0               	//转存(传送)
#define PICC_RESTORE          	0xC2               	//恢复(重储)
#define PICC_HALT             	0x50               	//休眠/*PCD通讯时返回的错误代码*/
#define PCD_OK                 	(char)0				//成功
#define PCD_NOTAGERR            (char)(-1)			//无卡
#define PCD_ERR                	(char)(-2)			//出错/*PCD函数声明*/
void PCD_Init(void);
void PCD_Reset(void);
void PCD_AntennaOn(void);
void PCD_AntennaOff(void);
char PCD_Request(uint8_t RequestMode, uint8_t *pCardType);  //寻卡,并返回卡的类型
char PCD_Anticoll(uint8_t *pSnr);                           //防冲突,返回卡号
char PCD_Select(uint8_t *pSnr);                             //选卡
char PCD_AuthState(uint8_t AuthMode, uint8_t BlockAddr, uint8_t *pKey, uint8_t *pSnr); //验证密码(密码A和密码B)   
char PCD_WriteBlock(uint8_t BlockAddr, uint8_t *pData);   //写数据
char PCD_ReadBlock(uint8_t BlockAddr, uint8_t *pData);    //读数据
char PCD_Value(uint8_t mode, uint8_t BlockAddr, uint8_t *pValue);   
char PCD_BakValue(uint8_t sourceBlockAddr, uint8_t goalBlockAddr);                                 
char PCD_Halt(void);
void Cardcompare(void);    //自行定义函数#endif

2、rc522.c

#include "stm32f1xx_hal.h"
#include "./BSP/RC522/rc522.h"
#include "stdio.h"
#include "./SYSTEM/usart/usart.h"
#include <string.h>extern SPI_HandleTypeDef hspi2;/**************************************************************************************
* 函数名称:MFRC_Init
* 功能描述:MFRC初始化
* 入口参数:无
* 出口参数:无
* 返 回 值:无
* 说    明:MFRC的SPI接口速率为0~10Mbps
***************************************************************************************/
void MFRC_Init(void)
{RS522_NSS(1);RS522_RST(1);
}/**************************************************************************************
* 函数名称: SPI_RW_Byte
* 功能描述: 模拟SPI读写一个字节
* 入口参数: -byte:要发送的数据
* 出口参数: -byte:接收到的数据
***************************************************************************************/
static uint8_t ret;  //这些函数是HAL与标准库不同的地方【读写函数】
uint8_t SPI2_RW_Byte(uint8_t byte)
{HAL_SPI_TransmitReceive(&hspi2, &byte, &ret, 1, 10);//把byte 写入,并读出一个值,把它存入retreturn   ret;//入口是byte 的地址,读取时用的也是ret地址,一次只写入一个值10
}/**************************************************************************************
* 函数名称:MFRC_WriteReg
* 功能描述:写一个寄存器
* 入口参数:-addr:待写的寄存器地址
*           -data:待写的寄存器数据
* 出口参数:无
* 返 回 值:无
* 说    明:无
***************************************************************************************/
void MFRC_WriteReg(uint8_t addr, uint8_t data)
{uint8_t AddrByte;AddrByte = (addr << 1 ) & 0x7E; //求出地址字节RS522_NSS(0);                   //NSS拉低SPI2_RW_Byte(AddrByte);         //写地址字节SPI2_RW_Byte(data);             //写数据RS522_NSS(1);                   //NSS拉高
}/**************************************************************************************
* 函数名称:MFRC_ReadReg
* 功能描述:读一个寄存器
* 入口参数:-addr:待读的寄存器地址
* 出口参数:无
* 返 回 值:-data:读到寄存器的数据
* 说    明:无
***************************************************************************************/
uint8_t MFRC_ReadReg(uint8_t addr)
{uint8_t AddrByte, data;AddrByte = ((addr << 1 ) & 0x7E ) | 0x80;   //求出地址字节RS522_NSS(0);                               //NSS拉低SPI2_RW_Byte(AddrByte);                     //写地址字节data = SPI2_RW_Byte(0x00);                  //读数据RS522_NSS(1);                               //NSS拉高return data;
}/**************************************************************************************
* 函数名称:MFRC_SetBitMask
* 功能描述:设置寄存器的位
* 入口参数:-addr:待设置的寄存器地址
*           -mask:待设置寄存器的位(可同时设置多个bit)
* 出口参数:无
* 返 回 值:无
* 说    明:无
***************************************************************************************/
void MFRC_SetBitMask(uint8_t addr, uint8_t mask)
{uint8_t temp;temp = MFRC_ReadReg(addr);                  //先读回寄存器的值MFRC_WriteReg(addr, temp | mask);           //处理过的数据再写入寄存器
}/**************************************************************************************
* 函数名称:MFRC_ClrBitMask
* 功能描述:清除寄存器的位
* 入口参数:-addr:待清除的寄存器地址
*           -mask:待清除寄存器的位(可同时清除多个bit)
* 出口参数:无
* 返 回 值:无
* 说    明:无
***************************************************************************************/
void MFRC_ClrBitMask(uint8_t addr, uint8_t mask)
{uint8_t temp;temp = MFRC_ReadReg(addr);                  //先读回寄存器的值MFRC_WriteReg(addr, temp & ~mask);          //处理过的数据再写入寄存器
}/**************************************************************************************
* 函数名称:MFRC_CalulateCRC
* 功能描述:用MFRC计算CRC结果
* 入口参数:-pInData:带进行CRC计算的数据
*           -len:带进行CRC计算的数据长度
*           -pOutData:CRC计算结果
* 出口参数:-pOutData:CRC计算结果
* 返 回 值:无
* 说    明:无
***************************************************************************************/
void MFRC_CalulateCRC(uint8_t *pInData, uint8_t len, uint8_t *pOutData)
{//0xc1 1        2           pInData[2]uint8_t temp;uint32_t i;MFRC_ClrBitMask(MFRC_DivIrqReg, 0x04);                  //使能CRC中断MFRC_WriteReg(MFRC_CommandReg, MFRC_IDLE);              //取消当前命令的执行MFRC_SetBitMask(MFRC_FIFOLevelReg, 0x80);               //清除FIFO及其标志位for(i = 0; i < len; i++)                                //将待CRC计算的数据写入FIFO{MFRC_WriteReg(MFRC_FIFODataReg, *(pInData + i));}MFRC_WriteReg(MFRC_CommandReg, MFRC_CALCCRC);           //执行CRC计算i = 100000;do{temp = MFRC_ReadReg(MFRC_DivIrqReg);                //读取DivIrqReg寄存器的值i--;}while((i != 0) && !(temp & 0x04));                      //等待CRC计算完成pOutData[0] = MFRC_ReadReg(MFRC_CRCResultRegL);         //读取CRC计算结果pOutData[1] = MFRC_ReadReg(MFRC_CRCResultRegM);
}/**************************************************************************************
* 函数名称:MFRC_CmdFrame
* 功能描述:MFRC522和ISO14443A卡通讯的命令帧函数
* 入口参数:-cmd:MFRC522命令字
*           -pIndata:MFRC522发送给MF1卡的数据的缓冲区首地址
*           -InLenByte:发送数据的字节长度
*           -pOutdata:用于接收MF1卡片返回数据的缓冲区首地址
*           -pOutLenBit:MF1卡返回数据的位长度
* 出口参数:-pOutdata:用于接收MF1卡片返回数据的缓冲区首地址
*           -pOutLenBit:用于MF1卡返回数据位长度的首地址
* 返 回 值:-status:错误代码(MFRC_OK、MFRC_NOTAGERR、MFRC_ERR)
* 说    明:无
***************************************************************************************/
char MFRC_CmdFrame(uint8_t cmd, uint8_t *pInData, uint8_t InLenByte, uint8_t *pOutData, uint16_t *pOutLenBit)
{uint8_t lastBits;uint8_t n;uint32_t i;char status = MFRC_ERR;uint8_t irqEn   = 0x00;uint8_t waitFor = 0x00;/*根据命令设置标志位*/switch(cmd){case MFRC_AUTHENT:                  //Mifare认证irqEn = 0x12;waitFor = 0x10;                 //idleIRq中断标志break;case MFRC_TRANSCEIVE:               //发送并接收数据irqEn = 0x77;waitFor = 0x30;                 //RxIRq和idleIRq中断标志break;}/*发送命令帧前准备*/MFRC_WriteReg(MFRC_ComIEnReg, irqEn | 0x80);    //开中断MFRC_ClrBitMask(MFRC_ComIrqReg, 0x80);          //清除中断标志位SET1MFRC_WriteReg(MFRC_CommandReg, MFRC_IDLE);      //取消当前命令的执行MFRC_SetBitMask(MFRC_FIFOLevelReg, 0x80);       //清除FIFO缓冲区及其标志位/*发送命令帧*/for(i = 0; i < InLenByte; i++)                  //写入命令参数{MFRC_WriteReg(MFRC_FIFODataReg, pInData[i]);}MFRC_WriteReg(MFRC_CommandReg, cmd);            //执行命令if(cmd == MFRC_TRANSCEIVE){MFRC_SetBitMask(MFRC_BitFramingReg, 0x80);  //启动发送}i = 300000;                                     //根据时钟频率调整,操作M1卡最大等待时间25msdo{n = MFRC_ReadReg(MFRC_ComIrqReg);i--;}while((i != 0) && !(n & 0x01) && !(n & waitFor));     //等待命令完成MFRC_ClrBitMask(MFRC_BitFramingReg, 0x80);          //停止发送/*处理接收的数据*/if(i != 0){if(!(MFRC_ReadReg(MFRC_ErrorReg) & 0x1B)){status = MFRC_OK;if(n & irqEn & 0x01){status = MFRC_NOTAGERR;}if(cmd == MFRC_TRANSCEIVE){n = MFRC_ReadReg(MFRC_FIFOLevelReg);lastBits = MFRC_ReadReg(MFRC_ControlReg) & 0x07;if (lastBits){*pOutLenBit = (n - 1) * 8 + lastBits;}else{*pOutLenBit = n * 8;}if(n == 0){n = 1;}if(n > MFRC_MAXRLEN){n = MFRC_MAXRLEN;}for(i = 0; i < n; i++){pOutData[i] = MFRC_ReadReg(MFRC_FIFODataReg);}}}else{status = MFRC_ERR;}}MFRC_SetBitMask(MFRC_ControlReg, 0x80);               //停止定时器运行MFRC_WriteReg(MFRC_CommandReg, MFRC_IDLE);            //取消当前命令的执行return status;
}/**************************************************************************************
* 函数名称:PCD_Reset
* 功能描述:PCD复位
* 入口参数:无
* 出口参数:无
* 返 回 值:无
* 说    明:无
***************************************************************************************/
void PCD_Reset(void)
{/*硬复位*/RS522_RST(1);//用到复位引脚osDelay(2);RS522_RST(0);osDelay(2);RS522_RST(1);osDelay(2);/*软复位*/MFRC_WriteReg(MFRC_CommandReg, MFRC_RESETPHASE);osDelay(2);/*复位后的初始化配置*/MFRC_WriteReg(MFRC_ModeReg, 0x3D);              //CRC初始值0x6363MFRC_WriteReg(MFRC_TReloadRegL, 30);            //定时器重装值MFRC_WriteReg(MFRC_TReloadRegH, 0);MFRC_WriteReg(MFRC_TModeReg, 0x8D);             //定时器设置MFRC_WriteReg(MFRC_TPrescalerReg, 0x3E);        //定时器预分频值MFRC_WriteReg(MFRC_TxAutoReg, 0x40);            //100%ASKPCD_AntennaOff();                               //关天线osDelay(2);PCD_AntennaOn();                                //开天线printf("初始化完成\n");}/**************************************************************************************
* 函数名称:PCD_AntennaOn
* 功能描述:开启天线,使能PCD发送能量载波信号
* 入口参数:无
* 出口参数:无
* 返 回 值:无
* 说    明:每次开启或关闭天线之间应至少有1ms的间隔
***************************************************************************************/
void PCD_AntennaOn(void)
{uint8_t temp;temp = MFRC_ReadReg(MFRC_TxControlReg);if (!(temp & 0x03)){MFRC_SetBitMask(MFRC_TxControlReg, 0x03);}
}/**************************************************************************************
* 函数名称:PCD_AntennaOff
* 功能描述:关闭天线,失能PCD发送能量载波信号
* 入口参数:无
* 出口参数:无
* 返 回 值:无
* 说    明:每次开启或关闭天线之间应至少有1ms的间隔
***************************************************************************************/
void PCD_AntennaOff(void)
{MFRC_ClrBitMask(MFRC_TxControlReg, 0x03);
}/***************************************************************************************
* 函数名称:PCD_Init
* 功能描述:读写器初始化
* 入口参数:无
* 出口参数:无
* 返 回 值:无
* 说    明:无
***************************************************************************************/
void PCD_Init(void)
{MFRC_Init();      //MFRC管脚配置PCD_Reset();      //PCD复位  并初始化配置PCD_AntennaOff(); //关闭天线PCD_AntennaOn();   //开启天线
}/***************************************************************************************
* 函数名称:PCD_Request
* 功能描述:寻卡
* 入口参数: -RequestMode:讯卡方式
*                             PICC_REQIDL:寻天线区内未进入休眠状态
*                 PICC_REQALL:寻天线区内全部卡
*               -pCardType:用于保存卡片类型
* 出口参数:-pCardType:卡片类型
*                               0x4400:Mifare_UltraLight
*                       0x0400:Mifare_One(S50)
*                       0x0200:Mifare_One(S70)
*                       0x0800:Mifare_Pro(X)
*                       0x4403:Mifare_DESFire
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:无
***************************************************************************************/
char PCD_Request(uint8_t RequestMode, uint8_t *pCardType)
{int status;uint16_t unLen;uint8_t CmdFrameBuf[MFRC_MAXRLEN];MFRC_ClrBitMask(MFRC_Status2Reg, 0x08);//关内部温度传感器MFRC_WriteReg(MFRC_BitFramingReg, 0x07); //存储模式,发送模式,是否启动发送等MFRC_SetBitMask(MFRC_TxControlReg, 0x03);//配置调制信号13.56MHZCmdFrameBuf[0] = RequestMode;status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 1, CmdFrameBuf, &unLen);if((status == PCD_OK) && (unLen == 0x10)){*pCardType = CmdFrameBuf[0];*(pCardType + 1) = CmdFrameBuf[1];}return status;
}/***************************************************************************************
* 函数名称:PCD_Anticoll
* 功能描述:防冲突,获取卡号
* 入口参数:-pSnr:用于保存卡片序列号,4字节
* 出口参数:-pSnr:卡片序列号,4字节
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:无
***************************************************************************************/
char PCD_Anticoll(uint8_t *pSnr)
{char status;uint8_t i, snr_check = 0;uint16_t  unLen;uint8_t CmdFrameBuf[MFRC_MAXRLEN];MFRC_ClrBitMask(MFRC_Status2Reg, 0x08);MFRC_WriteReg(MFRC_BitFramingReg, 0x00);MFRC_ClrBitMask(MFRC_CollReg, 0x80);CmdFrameBuf[0] = PICC_ANTICOLL1;CmdFrameBuf[1] = 0x20;status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 2, CmdFrameBuf, &unLen);if(status == PCD_OK){for(i = 0; i < 4; i++){*(pSnr + i)  = CmdFrameBuf[i];snr_check ^= CmdFrameBuf[i];}if(snr_check != CmdFrameBuf[i]){status = PCD_ERR;}}MFRC_SetBitMask(MFRC_CollReg, 0x80);return status;
}/***************************************************************************************
* 函数名称:PCD_Select
* 功能描述:选卡
* 入口参数:-pSnr:卡片序列号,4字节
* 出口参数:无
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:无
***************************************************************************************/
char PCD_Select(uint8_t *pSnr)
{char status;uint8_t i;uint16_t unLen;uint8_t CmdFrameBuf[MFRC_MAXRLEN];CmdFrameBuf[0] = PICC_ANTICOLL1;CmdFrameBuf[1] = 0x70;CmdFrameBuf[6] = 0;for(i = 0; i < 4; i++){CmdFrameBuf[i + 2] = *(pSnr + i);CmdFrameBuf[6]  ^= *(pSnr + i);}MFRC_CalulateCRC(CmdFrameBuf, 7, &CmdFrameBuf[7]);MFRC_ClrBitMask(MFRC_Status2Reg, 0x08);status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 9, CmdFrameBuf, &unLen);if((status == PCD_OK) && (unLen == 0x18)){status = PCD_OK;}else{status = PCD_ERR;}return status;
}/***************************************************************************************
* 函数名称:PCD_AuthState
* 功能描述:验证卡片密码
* 入口参数:-AuthMode:验证模式
*                   PICC_AUTHENT1A:验证A密码
*                   PICC_AUTHENT1B:验证B密码
*           -BlockAddr:块地址(0~63)
*           -pKey:密码
*           -pSnr:卡片序列号,4字节
* 出口参数:无
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:验证密码时,以扇区为单位,BlockAddr参数可以是同一个扇区的任意块
***************************************************************************************/
char PCD_AuthState(uint8_t AuthMode, uint8_t BlockAddr, uint8_t *pKey, uint8_t *pSnr)
{char status;uint16_t unLen;uint8_t i, CmdFrameBuf[MFRC_MAXRLEN];CmdFrameBuf[0] = AuthMode;CmdFrameBuf[1] = BlockAddr;for(i = 0; i < 6; i++){CmdFrameBuf[i + 2] = *(pKey + i);}for(i = 0; i < 4; i++){CmdFrameBuf[i + 8] = *(pSnr + i);}status = MFRC_CmdFrame(MFRC_AUTHENT, CmdFrameBuf, 12, CmdFrameBuf, &unLen);if((status != PCD_OK) || (!(MFRC_ReadReg(MFRC_Status2Reg) & 0x08))){status = PCD_ERR;}return status;
}/***************************************************************************************
* 函数名称:PCD_WriteBlock
* 功能描述:读MF1卡数据块
* 入口参数:-BlockAddr:块地址
*           -pData: 用于保存待写入的数据,16字节
* 出口参数:无
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:无
***************************************************************************************/
char PCD_WriteBlock(uint8_t BlockAddr, uint8_t *pData)
{char status;uint16_t unLen;uint8_t i, CmdFrameBuf[MFRC_MAXRLEN];CmdFrameBuf[0] = PICC_WRITE;CmdFrameBuf[1] = BlockAddr;MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);if((status != PCD_OK) || (unLen != 4) || ((CmdFrameBuf[0] & 0x0F) != 0x0A)){status = PCD_ERR;}if(status == PCD_OK){for(i = 0; i < 16; i++){CmdFrameBuf[i] = *(pData + i);}MFRC_CalulateCRC(CmdFrameBuf, 16, &CmdFrameBuf[16]);status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 18, CmdFrameBuf, &unLen);if((status != PCD_OK) || (unLen != 4) || ((CmdFrameBuf[0] & 0x0F) != 0x0A)){status = PCD_ERR;}}return status;
}/***************************************************************************************
* 函数名称:PCD_ReadBlock
* 功能描述:读MF1卡数据块
* 入口参数:-BlockAddr:块地址
*           -pData: 用于保存读出的数据,16字节
* 出口参数:-pData: 用于保存读出的数据,16字节
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:无
***************************************************************************************/
char PCD_ReadBlock(uint8_t BlockAddr, uint8_t *pData)
{char status;uint16_t unLen;uint8_t i, CmdFrameBuf[MFRC_MAXRLEN];CmdFrameBuf[0] = PICC_READ;CmdFrameBuf[1] = BlockAddr;MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);if((status == PCD_OK) && (unLen == 0x90)){for(i = 0; i < 16; i++){*(pData + i) = CmdFrameBuf[i];}}else{status = PCD_ERR;}return status;
}/***************************************************************************************
* 函数名称:PCD_Value
* 功能描述:对MF1卡数据块增减值操作
* 入口参数:
*           -BlockAddr:块地址
*           -pValue:四字节增值的值,低位在前
*           -mode:数值块操作模式
*                  PICC_INCREMENT:增值
*                PICC_DECREMENT:减值
* 出口参数:无
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:无
***************************************************************************************/
char PCD_Value(uint8_t mode, uint8_t BlockAddr, uint8_t *pValue)
{//0XC1        1           Increment[4]={0x03, 0x01, 0x01, 0x01};char status;uint16_t unLen;uint8_t i, CmdFrameBuf[MFRC_MAXRLEN];CmdFrameBuf[0] = mode;CmdFrameBuf[1] = BlockAddr;MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);if((status != PCD_OK) || (unLen != 4) || ((CmdFrameBuf[0] & 0x0F) != 0x0A)){status = PCD_ERR;}if(status == PCD_OK){for(i = 0; i < 16; i++){CmdFrameBuf[i] = *(pValue + i);}MFRC_CalulateCRC(CmdFrameBuf, 4, &CmdFrameBuf[4]);unLen = 0;status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 6, CmdFrameBuf, &unLen);if(status != PCD_ERR){status = PCD_OK;}}if(status == PCD_OK){CmdFrameBuf[0] = PICC_TRANSFER;CmdFrameBuf[1] = BlockAddr;MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);if((status != PCD_OK) || (unLen != 4) || ((CmdFrameBuf[0] & 0x0F) != 0x0A)){status = PCD_ERR;}}return status;
}/***************************************************************************************
* 函数名称:PCD_BakValue
* 功能描述:备份钱包(块转存)
* 入口参数:-sourceBlockAddr:源块地址
*                -goalBlockAddr   :目标块地址
* 出口参数:无
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:只能在同一个扇区内转存
***************************************************************************************/
char PCD_BakValue(uint8_t sourceBlockAddr, uint8_t goalBlockAddr)
{char status;uint16_t  unLen;uint8_t CmdFrameBuf[MFRC_MAXRLEN];CmdFrameBuf[0] = PICC_RESTORE;CmdFrameBuf[1] = sourceBlockAddr;MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);if((status != PCD_OK) || (unLen != 4) || ((CmdFrameBuf[0] & 0x0F) != 0x0A)){status = PCD_ERR;}if(status == PCD_OK){CmdFrameBuf[0] = 0;CmdFrameBuf[1] = 0;CmdFrameBuf[2] = 0;CmdFrameBuf[3] = 0;MFRC_CalulateCRC(CmdFrameBuf, 4, &CmdFrameBuf[4]);status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 6, CmdFrameBuf, &unLen);if(status != PCD_ERR){status = PCD_OK;}}if(status != PCD_OK){return PCD_ERR;}CmdFrameBuf[0] = PICC_TRANSFER;CmdFrameBuf[1] = goalBlockAddr;MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);if((status != PCD_OK) || (unLen != 4) || ((CmdFrameBuf[0] & 0x0F) != 0x0A)){status = PCD_ERR;}return status;
}/***************************************************************************************
* 函数名称:PCD_Halt
* 功能描述:命令卡片进入休眠状态
* 入口参数:无
* 出口参数:无
* 返 回 值:-status:错误代码(PCD_OK、PCD_NOTAGERR、PCD_ERR)
* 说    明:无
***************************************************************************************/
char PCD_Halt(void)
{char status;uint16_t unLen;uint8_t CmdFrameBuf[MFRC_MAXRLEN];CmdFrameBuf[0] = PICC_HALT;CmdFrameBuf[1] = 0;MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);return status;
}uint8_t readUid[5]; //卡号
uint8_t CT[3];         //卡类型
uint8_t DATA[16];    //存放数据uint8_t KEY_A[6]= {0xff,0xff,0xff,0xff,0xff,0xff};
uint8_t KEY_B[6]= {0xff,0xff,0xff,0xff,0xff,0xff};
unsigned char buf[16]={0x01,0x02,0x03,0x04,0x05,0x06,0xff
,0x07,0x80,0x69,0x18,0x17,0x16,0x15,0x14,0x13}; uint8_t status;
uint8_t addr = 0x01*4 + 0x03; // 总共16个扇区。一个扇区4个块,从0开始算,表示第一扇区第三块void Cardcompare(void)
{uint8_t i;//status = PCD_WriteBlock(addr, buf); status = PCD_Request(0x52, CT);             //找到卡返回0if(!status)  //寻卡成功{status = PCD_ERR;status = PCD_Anticoll(readUid);     //防冲撞}if(!status) //防冲撞成功{status = PCD_ERR;printf("卡的类型为:%x%x%x\r\n",CT[0],CT[1],CT[2]);   /* 读取卡的类型 */printf("卡号:%x-%x-%x-%x\r\n",readUid[0],readUid[1],readUid[2],readUid[3]);HAL_Delay(1000);status=PCD_Select(readUid);                          /* 选卡 */}    if(!status) //选卡成功{status = PCD_ERR;// 验证A密钥 块地址 密码 SN status = PCD_AuthState(PICC_AUTHENT1A, addr, KEY_A, readUid);if(status == PCD_OK)//验证A成功{printf("A密钥验证成功\r\n");HAL_Delay(1000);}else{printf("A密钥验证失败\r\n");HAL_Delay(1000);}// 验证B密钥 块地址 密码 SN  status = PCD_AuthState(PICC_AUTHENT1B, addr, KEY_B, readUid);if(status == PCD_OK)//验证B成功{printf("B密钥验证成功\r\n");}else{printf("B密钥验证失败\r\n");                    }HAL_Delay(1000);}    if(status == PCD_OK)//验证密码成功,接着读取3块{status = PCD_ERR;status = PCD_ReadBlock(addr, DATA); if(status == PCD_OK)//读卡成功{        printf("1扇区3块DATA:");for(i = 0; i < 16; i++){printf("%02x", DATA[i]);}printf("\r\n");}else{printf("读卡失败\r\n");}HAL_Delay(1000);}}
常用函数,搞清楚下面这些函数会用即可,刚开始使用时,过于去抠原理,新手很难坚持下来。先从如何使用,实现每个小功能开始,有点成就感,才能学得更好,走得更远。兴趣才是最好的老师。如何通过这些基础函数来进行其他操作,对卡号进行识别、读写扇区存储信息、修改密码A/B等等,可通过另写一个函数实现,本文利用void Cardcompare(void);该函数进行实现。
char PCD_Request(uint8_t RequestMode, uint8_t *pCardType);  //寻卡,并返回卡的类型
char PCD_Anticoll(uint8_t *pSnr);                           //防冲突,返回卡号
char PCD_Select(uint8_t *pSnr);                             //选卡
char PCD_AuthState(uint8_t AuthMode, uint8_t BlockAddr, uint8_t *pKey, uint8_t *pSnr); //验证密码(密码A和密码B)   
char PCD_WriteBlock(uint8_t BlockAddr, uint8_t *pData);   //写数据
char PCD_ReadBlock(uint8_t BlockAddr, uint8_t *pData);    //读数据

3、spi.h

#ifndef __SPI_H
#define __SPI_H#include "stm32f1xx_hal.h"#ifdef __cplusplusextern "C" {
#endifextern SPI_HandleTypeDef hspi2;void MX_SPI2_Init(void);#ifdef __cplusplus
}
#endif
#endif

4、spi.c

#include "./BSP/SPI/spi.h"
#include "main.h"SPI_HandleTypeDef hspi2;/* SPI2 init function */
void MX_SPI2_Init(void)
{hspi2.Instance = SPI2;hspi2.Init.Mode = SPI_MODE_MASTER;hspi2.Init.Direction = SPI_DIRECTION_2LINES;hspi2.Init.DataSize = SPI_DATASIZE_8BIT;hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;hspi2.Init.NSS = SPI_NSS_SOFT;hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;hspi2.Init.TIMode = SPI_TIMODE_DISABLE;hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;hspi2.Init.CRCPolynomial = 10;if (HAL_SPI_Init(&hspi2) != HAL_OK){Error_Handler();}}void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(spiHandle->Instance==SPI2){/* USER CODE BEGIN SPI2_MspInit 0 *//* USER CODE END SPI2_MspInit 0 *//* SPI2 clock enable */__HAL_RCC_SPI2_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/**SPI2 GPIO Configuration    PB13     ------> SPI2_SCKPB14     ------> SPI2_MISOPB15     ------> SPI2_MOSI */GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_15;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_14;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);GPIO_InitTypeDef GPIO_InitStruct = {0};/*PB12为片选引脚(CS/NSS/SDA)PB1为RST引脚*//*Configure GPIO pins : PB12 PB4 */GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_1;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12|GPIO_PIN_1, GPIO_PIN_SET);    /* 必须要拉高 */}
}

5、main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/KEY/key.h"
#include "./BSP/OLED/OLED.h"
#include "./BSP/SPI/spi.h"
#include "./BSP/RC522/rc522.h"
#include "main.h"void SystemClock_Config(void);int main(void)
{SystemClock_Config();                                   /* 系统时钟初始化 */HAL_Init();                                             /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9);                     /* 设置时钟, 72Mhz */delay_init(72);                                         /* 延时初始化 */usart_init(115200);                                     /* 初始化串口 */led_init();                                             /* led初始化 */key_init();                                             /* 按键初始化 */OLED_Init();                                            /* oled显示初始化 */MX_SPI2_Init();                                         /* spi初始化 */MFRC_Init();                                            /* MFRC522初始化 */PCD_Reset();                                            /* MFRC522重置 */while (1){Cardcompare();}}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {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();}
}/* 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 */

至于main.h主要是声明Error_Handler();函数,其他main.c中如系统时钟初始化等函数均是由cumax所自动生成。

有问题的朋友可以在下面留言交流,需要源码的关注并留言自己的邮箱即可获取~

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

命令绕过 [安洵杯 2019]easy_web1

打开题目 打开题目在URL处看到cmd&#xff0c;本能的直接用系统命令ls 发现被过滤了。又注意到imgTXpVek5UTTFNbVUzTURabE5qYz0似乎是一串base64 拿去base64解码 再hex解码一次得到555.png 再将其hex加密 base64加密 反向推出index.php的payload:?imgTmprMlJUWTBOalUzT0RK…

snmp协议开通教程

目录 一、什么是snmp协议&#xff1f; 二、snmp协议可以用来干什么&#xff1f; 三、snmp协议的开通 1、snmpv2协议开通 2、snmpv3协议开通 一、什么是snmp协议&#xff1f; SNMP&#xff08;Simple Network Management Protocol&#xff09;是一种用于网络管理的标准协议&a…

【扩散模型】【网络结构探索】神经网络扩散:Neural Network Diffusion(论文解读)

项目地址&#xff1a;https://github.com/NUS-HPC-AI-Lab/Neural-Network-Diffusion 文章目录 摘要一、前言二、Nerual Network Diffusion &#xff08;神经网络扩散&#xff09;2.1扩散模型&#xff08;预备知识&#xff09;2.2 总览2.3 参数自动编码器2.4 参数生成 三、实验3…

汇编语言movs指令学习

字符串传送指令(Move String Instruction) movs 该指令是把指针DS:SI所指向的字节、字或双字传送给指针ES:DI所指向内存单元&#xff0c;并根据标志位DF对寄存器DI和SI作相应增减。该指令的执行不影响任何标志位。 记不清这指令是8086就有的&#xff0c;还是386以后新加的&…

单片机tsm32城市环境污染监测与实现

国内经济增速的持续保持不但加快了城市化建设的步伐&#xff0c;同时也使得更多的人口聚集到大城市中求发展&#xff0c;大量的人口对衣食住行等方面的需求使得这些城市环境的污染问题逐渐加剧。当前各级政府虽然对城市环境污染问题越来越重视&#xff0c;但是因缺乏监测手段而…

美格智能联合罗德与施瓦茨完成5G RedCap模组SRM813Q验证,推动5G轻量化全面商用

全球5G发展进入下半场&#xff0c;5G RedCap以其低成本、低功耗的特性成为行业焦点。近日&#xff0c;中国移动携手合作伙伴率先完成全球最大规模、最全场景、最全产业的RedCap现网规模试验&#xff0c;推动首批芯片、终端具备商用条件&#xff0c;RedCap端到端产业已全面达到商…

Linux之ACL权限chmod命令

一. chmod命令 chmod命令来自英文词组change mode的缩写&#xff0c;其功能是改变文件或目录权限的命令。默认只有文件的所有者和管理员可以设置文件权限&#xff0c;普通用户只能管理自己文件的权限属性。 设置权限时可以使用数字法&#xff0c;亦可使用字母表达式&#xff0…

Python爬虫技术详解:从基础到高级应用,实战与应对反爬虫策略【第93篇—Python爬虫】

前言 随着互联网的快速发展&#xff0c;网络上的信息爆炸式增长&#xff0c;而爬虫技术成为了获取和处理大量数据的重要手段之一。在Python中&#xff0c;requests模块是一个强大而灵活的工具&#xff0c;用于发送HTTP请求&#xff0c;获取网页内容。本文将介绍requests模块的…

C语言之mkdtemp()特定占位符:XXXXXX 用法实例(八十五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

【力扣hot100】刷题笔记Day11

前言 科研不顺啊......又不想搞了&#xff0c;随便弄弄吧&#xff0c;多花点时间刷题&#xff0c;今天开启二叉树&#xff01; 94. 二叉树的中序遍历 - 力扣&#xff08;LeetCode&#xff09; 递归 # 最简单递归 class Solution:def inorderTraversal(self, root: TreeNode) …

基于ssm框架的高校班级管理系统设计与实现

为解决当前高校班级管理中管理方式落后、手段落后及效率低下等问题而以当前主流的互联网技术设计一款高校班级管理系统。该系统采用B/S模式的设计思路而将前端&#xff08;JSP技术&#xff09;和后端&#xff08;SSM框架MySQL数据库&#xff09;整合于一体并通过Java语言代码编…

华为OD机试真题-虚拟游戏理财-2023年OD统一考试(C卷)---Python3--开源

题目&#xff1a; 考察内容&#xff1a; for if max 代码&#xff1a; """ 题目分析&#xff1a;投资额*回报率投资回报 要在可接受范围内选择最优的投资方式获得最大回报最多投资2个理财产品输入&#xff1a; 产品数int; 总投资额int; 总风险int 产品投资…