江科大—读写内部闪存FLASH读取芯片ID

news2024/11/18 14:32:10

读写内部闪存FLASH

右下角是OLED,然后左上角在PB1和PB11两个引脚,插上两个按键用于控制。下一个代码读取芯片ID,这个也是接上一个OLED,能显示测试数据就可以了。
在这里插入图片描述

STM32-STLINK Utility

在这里插入图片描述
本节的代码调试,使用辅助软件STM32-STLINK Utility,在使用之前我们需要用stink把STM32连接好,然后我们点击这个按钮连接,可以看到下面这个窗口里显示的,就是闪存里面存储的数据了。这个软件可以直接修改闪存里的数据,可以修改选项字节数据,不用写任何代码,非常方便。

Address:可以指定想要查看的起始地址,目前是0x0800 0000,也就是整个闪存的起始地址。
Size:就是从起始地址开始,总共查看多少个字节,目前0x10000,就是查看64KB的字节数
Data Width:数据宽度,可以指定以32位/16位/8位的形式显示,分别对应,字/半字/字节。

16位
在这里插入图片描述
8位
在这里插入图片描述
闪存的操作:

第一步,读取数据,直接封装一下uint16_t Data = *((__IO uint16_t *)(0x08000000));
第二步,擦除:全擦除或页擦除,这两个功能分别对应一个库函数。执行之前,手动调用,解锁;执行之后,在加锁。
第三步,编程,有对应库函数直接调用。执行之前,手动调用,解锁;执行之后,在加锁。

选项字节的擦除和编成与主闪存的擦除和编程类似,有对应的函数。

在这里插入图片描述

用代码配置读写保护,容易造成芯片自锁,如把闪存写保护了,但程序里并没有预留解除写保护的代码,这样锁住之后,芯片就没法下载程序。但还可以再软件里自救,在这个选项字节配置里,把读写保护去掉,再Apply就能救活芯片了。

flash.h库函数

在这里插入图片描述

在这里插入图片描述
FLASH_Status返回值,是这个操作的完成状态,函数返回状态功能:返回第一个,表示芯片当前忙;返回第二个,表示编程错误;返回第三个,表示写保护错误;返回第四个,表示返回完成;返回第五个,表示等待超时。

//这三个是内核相关,不用过多了解与调用
void FLASH_SetLatency(uint32_t FLASH_Latency);
void FLASH_HalfCycleAccessCmd(uint32_t FLASH_HalfCycleAccess);
void FLASH_PrefetchBufferCmd(uint32_t FLASH_PrefetchBuffer);
//加锁解锁
void FLASH_Unlock(void);//解锁
void FLASH_Lock(void);//加锁,把CR寄存器LOCK位置1
//主闪存
FLASH_Status FLASH_ErasePage(uint32_t Page_Address); //闪存擦除某一页
FLASH_Status FLASH_EraseAllPages(void);//全擦除
FLASH_Status FLASH_EraseOptionBytes(void);//擦除选项字节

FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);//在指定地址,写入字
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);//在指定地址,写入半字

//选项字节的写入
FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);//自定义的Data0和Data1
FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages);//写保护
FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState);//读保护
FLASH_Status FLASH_UserOptionByteConfig(uint16_t OB_IWDG, uint16_t OB_STOP, uint16_t OB_STDBY);//用户选项的3个配置位

//获取选项字节当前状态
uint32_t FLASH_GetUserOptionByte(void);//获取用户选项的三个配置位
uint32_t FLASH_GetWriteProtectionOptionByte(void);//获取写保护状态
FlagStatus FLASH_GetReadOutProtectionStatus(void);//获取读保护状态  
............................//获取自定义的Data0和Data1没有给现成函数,直接指针访问就可以了。

FlagStatus FLASH_GetPrefetchBufferStatus(void);//获取预取缓冲区状态 不用了解
void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState);//中断使能
FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG);//获取标志位
void FLASH_ClearFlag(uint32_t FLASH_FLAG);//清除标志位
FLASH_Status FLASH_GetStatus(void);//获取状态
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);//等待上一次操作 等待忙等待BSY为0(上面主闪存这些函数内部已经实现等待忙操作了,此函数不用我们单独调用)

注意:使用完STLINK这个软件,要及时断开连接,要不然设备占用,keil下载出错。

在Store模块,要有SRAM缓存数组来管理FLASH的最后一页,实现参数任意读写和保存

MyFLASH.c

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:FLASH读取一个32位的字
  * 参    数:Address 要读取数据的字地址
  * 返 回 值:指定地址下的数据
  */
uint32_t MyFLASH_ReadWord(uint32_t Address)
{
	return *((__IO uint32_t *)(Address));	//使用指针访问指定地址下的数据并返回
}

/**
  * 函    数:FLASH读取一个16位的半字
  * 参    数:Address 要读取数据的半字地址
  * 返 回 值:指定地址下的数据
  */
uint16_t MyFLASH_ReadHalfWord(uint32_t Address)
{
	return *((__IO uint16_t *)(Address));	//使用指针访问指定地址下的数据并返回
}

/**
  * 函    数:FLASH读取一个8位的字节
  * 参    数:Address 要读取数据的字节地址
  * 返 回 值:指定地址下的数据
  */
uint8_t MyFLASH_ReadByte(uint32_t Address)
{
	return *((__IO uint8_t *)(Address));	//使用指针访问指定地址下的数据并返回
}

/**
  * 函    数:FLASH全擦除
  * 参    数:无
  * 返 回 值:无
  * 说    明:调用此函数后,FLASH的所有页都会被擦除,包括程序文件本身,擦除后,程序将不复存在
  */
void MyFLASH_EraseAllPages(void)
{
	FLASH_Unlock();					//解锁
	FLASH_EraseAllPages();			//全擦除
	FLASH_Lock();					//加锁
}

/**
  * 函    数:FLASH页擦除
  * 参    数:PageAddress 要擦除页的页地址
  * 返 回 值:无
  */
void MyFLASH_ErasePage(uint32_t PageAddress)
{
	FLASH_Unlock();					//解锁
	FLASH_ErasePage(PageAddress);	//页擦除
	FLASH_Lock();					//加锁
}

/**
  * 函    数:FLASH编程字
  * 参    数:Address 要写入数据的字地址
  * 参    数:Data 要写入的32位数据
  * 返 回 值:无
  */
void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data)
{
	FLASH_Unlock();							//解锁
	FLASH_ProgramWord(Address, Data);		//编程字
	FLASH_Lock();							//加锁
}

/**
  * 函    数:FLASH编程半字
  * 参    数:Address 要写入数据的半字地址
  * 参    数:Data 要写入的16位数据
  * 返 回 值:无
  */
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{
	FLASH_Unlock();							//解锁
	FLASH_ProgramHalfWord(Address, Data);	//编程半字
	FLASH_Lock();							//加锁
}

MyFLASH.h

#ifndef __MYFLASH_H
#define __MYFLASH_H

uint32_t MyFLASH_ReadWord(uint32_t Address);
uint16_t MyFLASH_ReadHalfWord(uint32_t Address);
uint8_t MyFLASH_ReadByte(uint32_t Address);

void MyFLASH_EraseAllPages(void);
void MyFLASH_ErasePage(uint32_t PageAddress);

void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data);
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);

#endif

Store.c

#include "stm32f10x.h"                  // Device header
#include "MyFLASH.h"

#define STORE_START_ADDRESS		0x0800FC00		//宏定义,存储的起始地址  (闪存的最后一页)
#define STORE_COUNT				512				//宏定义,存储数据的个数

uint16_t Store_Data[STORE_COUNT];				//定义SRAM数组

/**
  * 函    数:参数存储模块初始化    
  * 参    数:无
  * 返 回 值:无
  */
  void Store_Init(void)      //第一大步,第一次使用的时候,对闪存进行初始化
{
	/*判断是不是第一次使用*/
	if (MyFLASH_ReadHalfWord(STORE_START_ADDRESS) != 0xA5A5)	//读取第一个半字的标志位,if成立,则执行第一次使用的初始化
	{
		MyFLASH_ErasePage(STORE_START_ADDRESS);					//擦除指定页
		MyFLASH_ProgramHalfWord(STORE_START_ADDRESS, 0xA5A5);	//在第一个半字写入自己规定的标志位,用于判断是不是第一次使用
		
		//把剩余的存储空间,全都置为默认值0
		for (uint16_t i = 1; i < STORE_COUNT; i ++)				//循环STORE_COUNT次,除了第一个标志位。注意;要从1开始,而不是0,因为第一个半字是标志位,剩下的才是有效数据
		{
			MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, 0x0000);		//除了标志位的有效数据全部清0。注:因为一个半字要占用两个地址,所以i要乘2
		}
	}
	
	/*第2大步,上电时,将闪存数据加载回SRAM数组,就是上电时恢复数据,实现SRAM数组的掉电不丢失*/
	for (uint16_t i = 0; i < STORE_COUNT; i ++)					//循环STORE_COUNT次,包括第一个标志位
	{
		Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS + i * 2);		//将闪存的数据加载回SRAM数组
	}
}

/**
  * 函    数:参数存储模块保存数据到闪存
  * 参    数:无
  * 返 回 值:无
  */
void Store_Save(void)  //备份保存
{
	MyFLASH_ErasePage(STORE_START_ADDRESS);				//擦除指定页
	for (uint16_t i = 0; i < STORE_COUNT; i ++)			//循环STORE_COUNT次,包括第一个标志位
	{
		MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, Store_Data[i]);	//将SRAM数组的数据,备份保存到闪存
	}
}

/**
  * 函    数:参数存储模块将所有有效数据清0
  * 参    数:无
  * 返 回 值:无
  */
void Store_Clear(void)
{
	for (uint16_t i = 1; i < STORE_COUNT; i ++)			//循环STORE_COUNT次,除了第一个标志位。注:i要从1开始,不用把标志位清0
	{
		Store_Data[i] = 0x0000;							//SRAM数组有效数据清0
	}
	Store_Save();										//更新保存数据到闪存。每次修改完数组后,都要Store_Save();保证数值和闪存数据一样;如果不Save,那下次上电,加载的是以前保存的数据
}

Store.h

#ifndef __STORE_H
#define __STORE_H

extern uint16_t Store_Data[];

void Store_Init(void);
void Store_Save(void);
void Store_Clear(void);

#endif

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Store.h"
#include "Key.h"

uint8_t KeyNum;					//定义用于接收按键键码的变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();				//OLED初始化
	Key_Init();					//按键初始化
	Store_Init();				//参数存储模块初始化,在上电的时候将闪存的数据加载回Store_Data,实现掉电不丢失
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "Flag:");
	OLED_ShowString(2, 1, "Data:");
	
	while (1)
	{
		KeyNum = Key_GetNum();		//获取按键键码
		
		if (KeyNum == 1)			//按键1按下
		{
			Store_Data[1] ++;		//变换测试数据
			Store_Data[2] += 2;
			Store_Data[3] += 3;
			Store_Data[4] += 4;
			Store_Save();			//将Store_Data的数据备份保存到闪存,实现掉电不丢失
		}
		
		if (KeyNum == 2)			//按键2按下
		{
			Store_Clear();			//将Store_Data的数据全部清0
		}
		
		OLED_ShowHexNum(1, 6, Store_Data[0], 4);	//显示Store_Data的第一位标志位
		OLED_ShowHexNum(3, 1, Store_Data[1], 4);	//显示Store_Data的有效存储数据
		OLED_ShowHexNum(3, 6, Store_Data[2], 4);    //3行6列显示Store_Data[2],长度为4
		OLED_ShowHexNum(4, 1, Store_Data[3], 4);
		OLED_ShowHexNum(4, 6, Store_Data[4], 4);
	}
}

程序现象
Flag显示标志位:A5A5,这是之前保存的。按下Key2,可以去清0所以参数;按下Key1,可以变换测试数据,之后断定在重新上电,数据保持原样,按复位键,数据也不会丢失。
在这里插入图片描述
按下Key2,可以去清0所以参数
在这里插入图片描述
按下Key1,可以变换测试数据
在这里插入图片描述

前面一部分存储的是程序文件,最后一页存储的是用户数据,目前我们的假设是程序文件比较小,最后一页肯定是没有用到的,所以我们放心的使用最后一页,但是如果程序比较大,触及到了最后一页,那程序和用户数据存储的位置就冲突了,或者说如果你参数非常多,最后10页很大一部分都是留着存储用户数据的,这样如果前面的程序文件长一些,那样非常容易和用户数据冲突,并且这种冲突如果没发现,就会产生非常隐蔽的bug,那如何解决这个问题呢,这时我们可以给程序文件限定一个存储范围,不让它分配到后面我们用户数据的空间来。

在这里插入图片描述

这就是编译器,给各个数据分配的空间地址和范围了。如,片上的ROM,起始地址是0800 0000,注意,最高位的0省略了。它的Size:是0x10000,默认全部的64k闪存,都是程序代码分配的空间 ,

如果你想把闪存的尾部空间留着自己用,那可以把这个程序空间的size改小点,比如我们改成0XFC00,这样编译后的代码,无论如何也不会分配到最后一页了。如果Size过小,那编译的时候也会报错。

所以如果你计划把闪存尾部的很多空间都留着自己用,那就把这个程序代码的空间改小点,以免冲突。然后这个下载程序的起始地址也可以改,比如你想写个BOOTLOADER程序放在闪存尾部,那可以在这里修改下载到闪存的起始位置。

在这里插入图片描述

最右边这里是片上RAM的起始地址和大小,2000开始大小5000对应就是20K。

在这里插入图片描述

这里debug, settings,Flash download,在这里是配置下载选项,其中这个选项我们要选择第二个,擦除扇区,也就是页擦除。
第一个是,每次下载代码都全擦除再下载。
第二个是用到多少页,就擦多少页这个下载速度更快一些,如果你想在闪存尾部存储数据,那也最好选择页擦除的下载,要不然每次下载程序芯片都全擦除了。

在这里插入图片描述

程序编译之后,到底占用了多大的空间,我们可以全部编一下,在下面有一行信息就显示了Program Size,程序大小,其中有四个数,这四个数分别是什么意思,感兴趣的话可以网上搜索。
这里只需要记住,前三个数相加,得到的就是程序占用闪存的大小,后两个数相加,得到的是占用SRAM的大小。

在这里插入图片描述

这个程序大小,也可以在Target1这里(工程目录最上面)双击,会打开一个.map文件,这就是详细的编译信息。这个.map文件看完就删掉,要不然每次编译后,都会弹出窗口问你是不是要重新加载。

我们看最后面这里也有写程序的大小,并且有计算结果:
倒数第二行,是占用SRAM的大小,这里结果是2664字节,2.6kb,最后一行,是占用闪存的大小,这里是4576字节,4.47kb。

在这里插入图片描述

下载到STM32里,验证一下。可以看到,程序在0x0800 11E0地址终止,用计算机转换:16进制 11E0就是10进制的4576。观察的数据和编译的结果相符,没问题。

读取芯片ID

复制OLED的工程。

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"

int main(void)
{
	OLED_Init();						//OLED初始化
	
	OLED_ShowString(1, 1, "F_SIZE:");	//显示静态字符串
	OLED_ShowHexNum(1, 8, *((__IO uint16_t *)(0x1FFFF7E0)), 4);		//使用指针读取指定地址下的闪存容量寄存器
	
	OLED_ShowString(2, 1, "U_ID:");		//显示静态字符串
	OLED_ShowHexNum(2, 6, *((__IO uint16_t *)(0x1FFFF7E8)), 4);		//使用指针读取指定地址下的产品唯一身份标识寄存器
	OLED_ShowHexNum(2, 11, *((__IO uint16_t *)(0x1FFFF7E8 + 0x02)), 4);  //第2次读是,基地址+0x02地址偏移
	OLED_ShowHexNum(3, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x04)), 8);
	OLED_ShowHexNum(4, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x08)), 8);
	
	while (1)
	{
		
	}
}

程序现象
在这里插入图片描述
ID号对不对,可以用软件来验证。

在这里插入图片描述

手册

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

Sparse4Dv2

Sparse4D: Multi-view 3D Object Detection with Sparse Spatial-Temporal Fusion 相关内容&#xff1a;总览&#xff0c;Sparse4D v1&#xff0c;Sparse4D v3&#xff0c; 单位&#xff1a;地平线(Sparse4D v1 原班人马) GitHub&#xff1a;https://github.com/HorizonRobo…

计算机网络之数据通信原理(中)

上节内容传送口&#xff1a;数据通信原理基础 1.数据传输方式 1.1并行传输 并行传输: 字符编码的各个比特同时传输 特点&#xff1a; 一个比特时间内可传输一个字符&#xff0c;传输速度快&#xff0c;每个比特传输要求一个单独的信道支持&#xff0c;通信成本高&#xf…

基于单片机和 Arduino 平台的六自由度可控机械手臂

摘 要 : 为了降低机械手臂的设计开发难度 &#xff0c; 并使之尽早地投入应用 &#xff0c; 设计一种基于单片机和 Arduino 平台的六自由度可控机械手臂 。提出六自由度可控机械手臂的控制方案&#xff0c; 给出机械手臂控制系统的结构框图 。 详细设计六自由度可控机械手臂…

《UDS协议从入门到精通》系列——图解0x35:请求上传

《UDS协议从入门到精通》系列——图解0x35&#xff1a;请求上传 一、简介二、数据包格式2.1 服务请求格式2.2 服务响应格式2.2.1 肯定响应2.2.2 否定响应 三、通信示例 Tip&#x1f4cc;&#xff1a;本文描述中但凡涉及到其他UDS服务的&#xff0c;将陆续提供链接跳转方式以便快…

Power BI可视化表格矩阵如何保持样式导出数据?

故事背景&#xff1a; 有朋友留言询问&#xff1a;自己从Power BI可视化矩阵表格中导出数据时&#xff0c;导出的表格样式会发生改变&#xff0c;需要线下再手动调整&#xff0c;重新进行透视组合成自己想要的格式。 有没有什么办法让表格导出来跟可视化一样&#xff1f; Po…

pd虚拟机 Parallels Desktop 19 for Mac 破解版小白安装使用指南

Parallels Desktop 19 for Mac 乃是一款适配于 Mac 的虚拟化软件。它能让您在 Mac 计算机上同时运行多个操作系统。您可借此创建虚拟机&#xff0c;并于其中装设不同的操作系统&#xff0c;如 Windows、Linux 或 macOS。使用 Parallels Desktop 19 mac 版时&#xff0c;您可在 …

编译正则表达式模式re.compile

【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 编译正则表达式模式 re.compile [太阳]选择题 根据给定的Python代码&#xff0c;哪个选项是正确的&#xff1f; import re pattern re.compile(r\d) print(f"【显示】pattern{patter…

eBPF 如何塑造 Linux 和平台工程的未来

当Docker 于 2013 年突然出现时&#xff0c;Linux 容器似乎一夜成名。但容器&#xff08;以及微服务和Kubernetes&#xff09;的演变实际上是基于 Linux 操作系统中的内核原语而进行的&#xff0c;历时数十年。 Docker 使用这些原语&#xff08;即 cgroups 和命名空间&#xf…

前端框架中的前端安全性(Front-end Security)

聚沙成塔每天进步一点点 本文回顾 ⭐ 专栏简介前端框架中的前端安全性&#xff08;Front-end Security&#xff09;1. 引言2. 常见的前端安全威胁2.1 跨站脚本攻击&#xff08;XSS&#xff09;2.1.1 防御措施 2.2 跨站请求伪造&#xff08;CSRF&#xff09;2.2.1 防御措施 2.3 …

YOLOv8改进 | 添加注意力篇 | 结合Mamba注意力机制MLLA助力YOLOv8有效涨点(全网独家首发)

一、本文介绍 本文给大家带来的改进机制是结合号称超越Transformer架构的Mamba架构的最新注意力机制MLLA&#xff0c;本文将其和我们YOLOv8进行结合&#xff0c;MLLA&#xff08;Mamba-Like Linear Attention&#xff09;的原理是通过将Mamba模型的一些核心设计融入线性注意力…

【毛毛虫案例-拖拽 Objective-C语言】

一、这个毛毛虫案例啊,是这个样子的, 1.首先,你这个脑袋,这个蓝色的脑袋,它是可以拽起来的, 下面的红色球,一个一个中心点之间,相互去附着, 其他的红色球,是拖不起来的, 只有这个蓝色的东西,可以拽起来,这个蓝色的View,还有重力, 这个蓝色的View,我在拖动它…

Spring底层原理之proxyBeanMenthod实例 动态代理 反射 Bean的拦截

proxyBeanMenthod 假设我们要进行一个系统的二次开发 然后第一次开发我们实用的是XML声明bean 二次开发的时候要用注解 我们如何把bean都加载上来呢 我们首先创建一个全新的配置类 package com.bigdata1421.config;public class SpringConfig32 { } 我们创建一个APP 加载…

R语言数据分析案例37-旅游景点聚类分析

一、研究背景 近年来&#xff0c;随着旅游业的迅猛发展&#xff0c;旅游景点的竞争日益激烈。如何在众多景点中脱颖而出&#xff0c;吸引更多游客&#xff0c;成为各大景点管理者关注的焦点。通过对旅游景点进行深入的数据分析&#xff0c;可以帮助管理者更好地了解景点的优势…

HashMap第5讲——resize方法扩容源码分析及细节

put方法的源码和相关的细节已经介绍完了&#xff0c;下面我们进入扩容功能的讲解。 一、为什么需要扩容 这个也比较好理解。假设现在HashMap里的元素已经很多了&#xff0c;但是链化比较严重&#xff0c;即便树化了&#xff0c;查询效率也是O(logN)&#xff0c;肯定没有O(1)好…

最新MDYS14源码影视视频网站模板/苹果CMS系统/附搭建教程

最新MDYS14源码影视视频网站模板/苹果CMS系统/附搭建教程 基本介绍&#xff1a; 1、后台增加自定义参数&#xff0c;对应会员升级页面&#xff0c;以及积分充值 2、视频&#xff0c;演员&#xff0c;专题&#xff0c;收藏&#xff0c;会员系统模块齐全&#xff0c;支持子分类…

本地读取classNames txt文件

通过本地读取classNames,来减少程序修改代码,提高了程序的拓展性和自定义化。 步骤: 1、输入本地路径,分割字符串。 2、将className按顺序放入vector容器中。 3、将vector赋值给classNmaes;获取classNames.size(),赋值给CLASSES;这样,类别个数和类别都已经赋值完成。…

阀门盘根的介绍

盘根&#xff08;编制盘根&#xff09;&#xff08;packing&#xff09;也叫密封填料&#xff0c;通常由较柔软的线状物编织而成&#xff0c;通常截面积是正方形或长方形、圆形的条状物填充在密封腔体内,从而实现密封。填料密封最早是以棉麻等纤维塞在泄漏通道内来阻止液流泄漏…

牛客挑战赛75 D. 不存在的玩家(sg图dp)

题目 思路来源 灵茶山群群友 https://blog.csdn.net/Code92007/article/details/110354429 题解 其实想了想&#xff0c;和20年小米邀请赛决赛这个G题的dp思路是一样的&#xff0c;姑且称为sg图dp吧 按sg值从大到小dp&#xff0c;每次补上全局sg值-1的这些点&#xff0c; …

XML简介XML 使用教程XML的基本结构XML的使用场景

学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把手教你开发炫酷的vbs脚本制作(完善中……&#xff09; 4、牛逼哄哄的 IDEA编程利器技巧(编写中……&#xff09; 5、面经吐血整理的 面试技…

VCS编译bug汇总

‘typedef’ is not expected to be used in this contex 注册前少了分号。 Scope resolution error resolution : 声明指针时 不能与类名同名&#xff0c;即 不能声明为adapter. cannot find member "type_id" 忘记注册了 拼接运算符使用 关键要加上1b&#xff0…