【STM32】最后一刷-江科大Flash闪存-学习笔记
FLASH简介
- STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程,(系统存储器用于存储原厂写入的BootLoader程序,用于串口下载,不允许我们修改)
- 读写FLASH的用途:
- 利用程序存储器的剩余空间来保存掉电不丢失的用户数据
- 通过在程序中编程(IAP),实现程序的自我更新
在线编程(In-Circuit Programming – ICP)用于更新程序存储器的全部内容,它通过JTAG、SWD协议或系统加载程序(Bootloader)下载程序
在程序中编程(In-Application Programming – IAP)可以使用微控制器支持的任一种通信接口下载程序
存储器映像参考这篇:【江协科技STM32】DMA直接存储器存储-学习笔记_江科 stm32 dma-CSDN博客
闪存模块组织
对应主存储器,进行了分页,分页是为了更好地管理闪存,擦除和写保护都是以页为单位的,这一点和之前的W25Q64的闪存一样,写入前必须擦除等等。具体参考Flash操作注意事项:【STM32】SPI通信协议&W25Q64Flash存储器芯片(学习笔记)_spi存储芯片-CSDN博客
FLASH基本结构
FLASH解锁(解除闪存锁)
FPEC共有三个键值:
- RDPRT键 = 0x000000A5(解除读保护密钥)
- KEY1 = 0x45670123
- KEY2 = 0xCDEF89AB
- 解锁:
- 复位后,FPEC被保护,不能写入FLASH_CR
- 在FLASH_KEYR先写入KEY1,再写入KEY2,解锁
- 错误的操作序列会在下次复位前锁死FPEC和FLASH_CR
加锁:
- 置FLASH_CR中的LOCK位锁住FPEC和FLASH_CR
使用指针访问存储器
uint16_t Data = *((__IO uint16_t *)(0x08000000));
这行代码是在 C 语言中用于从特定内存地址读取数据,并将其赋值给变量Data
。解释如下:
uint16_t
是一种无符号 16 位整数类型,定义在<stdint.h>
头文件中,确保了数据类型的宽度为 16 位,可表示的范围是 0 到 65535。Data
是定义的一个uint16_t
类型的变量,用于存储从特定内存地址读取的数据。(__IO uint16_t *)(0x08000000)
:这部分是一个强制类型转换。(__IO uint16_t *)
将0x08000000
这个地址值转换为指向__IO uint16_t
类型的指针。其中__IO
通常是由编译器定义的宏,可能表示该内存地址是可读写(volatile
)的,防止编译器对该地址的访问进行优化,确保每次访问都是真实地从该内存地址读写数据。0x08000000
是一个十六进制表示的内存地址。*((__IO uint16_t *)(0x08000000))
:这部分通过指针解引用操作,从0x08000000
这个内存地址读取一个uint16_t
类型的数据。- 最后,将从指定内存地址读取的数据赋值给
Data
变量。
*((__IO uint16_t *)(0x08000000)) = 0x1234;
- 指针类型强制转换
(__IO uint16_t *)(0x08000000)
这部分代码将地址值0x08000000
强制转换为一个指向__IO uint16_t
类型的指针。其中__IO
可能是一个特定的修饰符,通常用于表示该内存位置具有特殊的读写属性(例如可能是与外设寄存器相关,允许读写操作),uint16_t
表示无符号 16 位整数类型。通过这种强制类型转换,告诉编译器把0x08000000
这个地址当作是一个__IO uint16_t
类型数据的起始地址。 - 赋值操作
在完成指针类型强制转换后,使用*
运算符对这个指针进行解引用,然后将值0x1234
赋给该指针所指向的内存位置。也就是将0x1234
这个 16 位无符号整数值写入到了内存地址0x08000000
开始的两个字节(因为uint16_t
是 16 位,占两个字节)。
实例
指定地址下读:
/*** 函 数:FLASH读取一个32位的字* 参 数:Address 要读取数据的字地址* 返 回 值:指定地址下的数据*/
uint32_t HerFlash_ReadWord(uint32_t Address)
{return *((__IO uint32_t *)(Address)); //使用指针访问指定地址下的数据并返回
}/*** 函 数:FLASH读取一个16位的半字* 参 数:Address 要读取数据的半字地址* 返 回 值:指定地址下的数据*/
uint16_t HerFlash_ReadHalfWord(uint32_t Address)
{return *((__IO uint16_t *)(Address)); //使用指针访问指定地址下的数据并返回
}/*** 函 数:FLASH读取一个8位的字节* 参 数:Address 要读取数据的字节地址* 返 回 值:指定地址下的数据*/
uint8_t HerFlash_ReadByte(uint32_t Address)
{return *((__IO uint8_t *)(Address));//使用指针访问指定地址下的数据并返回
}
程序存储器全擦除
-
第一步:读 FLASH_CR 的 LOCK 位
- 理由:LOCK 位用于锁定闪存控制寄存器(FLASH_CR),在对闪存进行擦除等操作前,需要先了解其锁定状态。如果 LOCK 位 = 1,表示闪存处于锁定状态,不能直接进行后续的擦除操作,需要先执行解锁过程;若 LOCK 位 = 0,则可跳过解锁过程直接进行擦除设置。
- 操作及结果:读取该位,得到 LOCK 位 = 1,说明闪存处于锁定状态。
-
第二步:执行解锁过程
- 理由:因为第一步检测到 LOCK 位为 1,闪存锁定,所以必须执行解锁过程才能对闪存控制寄存器进行操作,以实现擦除等功能。
- 操作及结果:执行解锁过程后,将 LOCK 位置为 0,此时闪存解锁,可以对相关寄存器进行设置。
-
第三步:置 FLASH_CR 的 MER = 1
- 理由:MER(Mass Erase)位用于选择是否进行全擦除操作。将 MER 位置 1,表示要进行闪存全擦除操作。
- 操作及结果:将 MER 位置 1,准备执行全擦除。
-
第四步:置 FLASH_CR 的 STRT = 1
- 理由:STRT(Start)位用于启动闪存擦除操作。当 MER 位已置 1 准备好全擦除,再将 STRT 位置 1,就可以正式启动全擦除过程。
- 操作及结果:将 STRT 位置 1,闪存全擦除操作开始执行。
-
第五步:关注 FLASH_SR 的 BSY 位
- 理由:BSY(Busy)位用于指示闪存操作是否正在进行。在全擦除操作启动后,需要监测该位来判断擦除操作是否完成。当 BSY = 1 时,表示闪存操作正在进行中;当 BSY = 0 时,表示闪存操作已完成。
- 操作及结果:在全擦除操作执行过程中,BSY 位会变为 1,表示操作正在进行。等待一段时间后,当 BSY 位变为 0,说明全擦除操作完成。
-
第六步:读出并验证所有页的数据
- 理由:全擦除操作完成后,需要验证是否所有页的数据都已被正确擦除。通过读出所有页的数据,并与预期的擦除后数据(一般为全 1 或特定的擦除后状态)进行比较,来验证擦除操作的正确性。
- 操作及结果:读出所有页的数据,与预期的擦除后数据进行对比,若完全一致,则说明全擦除操作成功;若有不一致的地方,则说明擦除操作可能存在问题。
实例
/*** 函 数:FLASH全擦除* 参 数:无* 返 回 值:无* 说 明:调用此函数后,FLASH的所有页都会被擦除,包括程序文件本身,擦除后,程序将不复存在*/
void HerFlash_EraseAllPages(void)
{FLASH_Unlock(); //解锁FLASH_EraseAllPages(); //全擦除FLASH_Lock(); //加锁
}
void FLASH_Unlock(void)//解锁FLASH程序擦除控制器(解锁)
void FLASH_Lock(void)//锁定FLASH程序擦除控制器
FLASH_Status FLASH_EraseAllPages(void)//擦除所有FLASH页面
注意:以上功能可用于所有STM32F10x器件
程序存储器页擦除
- 读取锁定状态:首先读取闪存控制寄存器(
FLASH_CR
)的LOCK
位,判断闪存是否处于锁定状态。 - 解锁操作(若需):若
LOCK
位为1
(锁定状态),执行解锁过程;若为0
,跳过解锁。 - 配置擦除参数:
- 置
FLASH_CR
的PER
(Page Erase,页擦除使能)位为1
; - 在
FLASH_AR
(地址寄存器)中选择要擦除的闪存页; - 置
FLASH_CR
的STRT
(Start,启动)位为1
,启动页擦除操作。
- 置
- 等待擦除完成:监测闪存状态寄存器(
FLASH_SR
)的BSY
(Busy,忙)位。若BSY=1
,表示擦除仍在进行,需持续等待;若BSY=0
,表示擦除完成。 - 验证擦除结果:擦除完成后,读出并验证被擦除页的数据,确保擦除操作成功。
实例
/*** 函 数:FLASH页擦除* 参 数:PageAddress 要擦除页的页地址* 返 回 值:无*/
void HerFlash_ErasePage(uint32_t PageAddress)
{FLASH_Unlock();FLASH_ErasePage(PageAddress);FLASH_Lock();
}
FLASH_Status FLASH_ErasePage(uint32_t Page_Address)//擦除指定的FLASH页面
注意:此功能可用于所有STM32F10x器件
程序存储器编程
注意:这种模式下CPU以标准的写半字的方式烧写闪存, FLASH_CR寄存器的PG位必须置’1’。 FPEC先读出指定地址的内容并检查它是否被擦除,如未被擦除则不执行编程并在FLASH_SR寄存器的PGERR位提出警告(唯一的例外是当要烧写的数值是0x0000时, 0x0000可被正确烧入且PGERR位不被置位);如果指定的地址在FLASH_WRPR中设定为写保护,则不执行编程并在FLASH_SR寄存器的WRPRTERR位置’1’提出警告。 FLASH_SR寄存器的EOP为’1’时表示编程结束。
编程过程讲解:
- 读取锁定状态:首先读取闪存控制寄存器(
FLASH_CR
)的LOCK
位,判断闪存是否处于锁定状态。 - 解锁操作(若需):若
LOCK
位为1
(锁定状态),执行解锁序列;若为0
,直接进入下一步。 - 使能编程模式:将
FLASH_CR
寄存器的PG
位(Program,编程使能)置为1
,开启编程功能。 - 写入数据:在指定的闪存地址中写入半字(16 位)数据。用到这句代码 *((__IO uint16_t *)(0x08000000)) = 0x1234;
- 等待操作完成:监测闪存状态寄存器(
FLASH_SR
)的BSY
(Busy,忙)位。若BSY=1
,表示编程操作仍在进行,需持续等待;若BSY=0
,表示编程操作完成。 - 验证数据:读取编程地址中的数据,检查写入的数据是否正确,确保编程操作成功。
实例
/*** 函 数:FLASH编程字* 参 数:Address 要写入数据的字地址* 参 数:Data 要写入的32位数据* 返 回 值:无*/
void HerFLASH_ProgramWord(uint32_t Address, uint32_t Data)
{FLASH_Unlock();FLASH_ProgramWord(Address, Data);FLASH_Lock();
}/*** 函 数:FLASH编程字* 参 数:Address 要写入数据的半字地址* 参 数:Data 要写入的16位数据* 返 回 值:无*/
void HerFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{FLASH_Unlock();FLASH_ProgramHalfWord(Address, Data);FLASH_Lock();
}
FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data)//在指定地址编程一个字
注意:以上功能可用于所有STM32F10x器件
参数 | 说明 |
Address | 指定要编程的地址 |
Data | 指定要编程的数据 |
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)//在指定地址上编程半个字
参数 | 说明 |
Address | 指定要编程的地址 |
Data | 指定要编程的数据 |
注意:以上功能可用于所有STM32F10x器件
选择字节说明
- RDP:写入RDPRT键(0x000000A5)后解除读保护
- USER:配置硬件看门狗和进入停机/待机模式是否产生复位
- Data0/1:用户可自定义使用
- WRP0/1/2/3:配置写保护,每一个位对应保护4个存储页(中容量)
选项字节擦除
- 检查FLASH_SR的BSY位,以确认没有其他正在进行的闪存操作
- 解锁FLASH_CR的OPTWRE位
- 设置FLASH_CR的OPTER位为1
- 设置FLASH_CR的STRT位为1
- 等待BSY位变为0
- 读出被擦除的选择字节并做验证
选项字节编程
- 检查FLASH_SR的BSY位,以确认没有其他正在进行的编程操作
- 解锁FLASH_CR的OPTWRE位
- 设置FLASH_CR的OPTPG位为1
- 写入要编程的半字到指定的地址
- 等待BSY位变为0
- 读出写入的地址并验证数据
读取内部FLASH闪存
要实现数据掉电不丢失的存储,那就要基于底层代码,再建一个模块Store,在Store模块我们要用SRAM缓存数组来管理FLASH闪存的最后一页,实现参数的任意读写和保存。因为闪存每次都是擦除,再写入,擦除之后,还容易丢失数据,所以要想灵活管理数据,还是得靠SRAM数组,需要备份的时候,我们再统一转到闪存里。所以在Store模块里要先定义一个Store_数组,用于存放备份数据。
参数存储模块初始化
#define STORE_START_ADDRESS 0x0800FC00
#define STORE_DATA 512uint16_t Store_Data[STORE_DATA]; //定义SRAM数字,512个数据,每个数据16位,2字节,刚好对应闪存一页1024字节void Store_Init(void)
{/*判断是不是第一次使用*/if(HerFlash_ReadHalfWord(STORE_START_ADDRESS) != 0xA8A8){HerFlash_ErasePage(STORE_START_ADDRESS);HerFLASH_ProgramHalfWord(STORE_START_ADDRESS, 0xA8A8);//在第一个半字写入自己规定的标志位,用于判断是不是第一次使用for(uint16_t i =1; i < STORE_DATA; i ++) //循环STORE_COUNT次,除了第一个标志位{HerFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2,0x0000);//除了标志位的有效数据全部清0}}/*上电时,将闪存数据加载回SRAM数组,实现SRAM数组的掉电不丢失*/for(uint16_t i =0;i < STORE_DATA; i ++){Store_Data[i] = HerFlash_ReadHalfWord(STORE_START_ADDRESS + i * 2);//将闪存的数据加载回SRAM数组}
}
参数存储模块保存数据到闪存
/*** 函 数:参数存储模块保存数据到闪存* 参 数:无* 返 回 值:无*/
void Store_Save(void)
{HerFlash_ErasePage(STORE_START_ADDRESS);for(uint16_t i = 0;i < STORE_DATA;i ++) //循环STORE_COUNT次,包括第一个标志位{HerFLASH_ProgramHalfWord(STORE_START_ADDRESS +i*2, Store_Data[i]);//将SRAM数组的数据备份保存到闪存}
}
参数存储模块将所有有效数据清0
/*** 函 数:参数存储模块将所有有效数据清0* 参 数:无* 返 回 值:无*/
void Store_Clear(void)
{for(uint16_t i = 1;i < STORE_DATA;i ++){Store_Data[i] = 0x0000; //SRAM数组有效数据清0} Store_Save(); //保存数据到闪存
}
最终梳理思路:梳理思路
其实就是,在主函数对SRAM数组Store_Data进行修改,然后在放到闪存,防止SRAM掉电丢失,然后在上电初始化的时候在把闪存的数据再读取到SRAMStore_Data数组,实现SRAM掉电不丢失
main函数
#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] = 0x1234; //变换测试数据,断电丢失Store_Data[2] = 0xABCD;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);OLED_ShowHexNum(4, 1, Store_Data[3], 4);OLED_ShowHexNum(4, 6, Store_Data[4], 4);}
}
结果
注意一个问题:程序文件大小和用户数据大小的冲突
程序占用空间大小
器件电子签名&读取芯片ID
电子签名存放在闪存存储器模块的系统存储区域,包含的芯片识别信息在出厂时编写,不可更改,使用指针读指定地址下的存储器可获取电子签名
闪存容量寄存器:
- 基地址:0x1FFF F7E0
- 大小:16位
产品唯一身份标识寄存器:
- 基地址: 0x1FFF F7E8
- 大小:96位
int main(void)
{OLED_Init(); 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);OLED_ShowHexNum(3, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x04)), 8);OLED_ShowHexNum(4, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x08)), 8);while (1){}
}
结果
最后记得看数据手册,这东西是真的能看懂 学会 学到知识!!!!
相关文章:
【STM32】最后一刷-江科大Flash闪存-学习笔记
FLASH简介 STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程,(系统存储器用于存储原厂写入的BootLoader程序,用于串口…...
Dify 深度集成 MCP实现灾害应急响应
一、架构设计 1.1 分层架构 #mermaid-svg-5dVNjmixTX17cCfg {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-5dVNjmixTX17cCfg .error-icon{fill:#552222;}#mermaid-svg-5dVNjmixTX17cCfg .error-text{fill:#552222…...
2025 年上半年软考信息系统项目管理师备考计划
2025 年上半年软考信息系统项目管理师备考计划 2025 年上半年软考信息系统项目管理师考试时间为 5 月 24 日 - 27 日,从现在开始备考,需合理规划,高效学习。以下为详细备考计划: 一、基础学习阶段(现在 - 4 月上…...
Scikit-learn使用指南
1. Scikit-learn 简介 定义: Scikit-learn(简称 sklearn)是基于 Python 的开源机器学习库,提供了一系列算法和工具,用于数据挖掘、数据预处理、分类、回归、聚类、模型评估等任务。特点: 基于 NumPy、SciP…...
学习大模型需要具备哪些技术、知识和基础
数学基础 概率论与数理统计:用于理解模型中的不确定性、概率分布,以及进行数据的统计分析、评估模型的性能等。例如,通过概率分布来描述模型预测结果的可信度,利用统计方法对数据进行抽样、估计模型的参数等。线性代数࿱…...
十五届蓝桥杯省赛Java B组(持续更新..)
目录 十五届蓝桥杯省赛Java B组第一题:报数第二题:类斐波那契数第三题:分布式队列第四题:食堂第五题:最优分组第六题:星际旅行第七题:LITS游戏第八题:拼十字 十五届蓝桥杯省赛Java B…...
Flink SQL Client bug ---datagen connector
原始sql语句如下 CREATE TABLE test_source (event_time TIMESTAMP(3), -- 事件时间(精确到毫秒)click INT, -- 随机数值字段WATERMARK FOR event_time AS event_time - INTERVAL 5 SECOND WITH (connector datagen, …...
股指期货的多头套期保值是什么意思?
多头套期保值,又叫“买入套期保值”,听起来很复杂,其实很简单。它的核心就是“提前锁定价格,防止未来价格上涨”。 举个例子,假设你是一家工厂的老板,过几个月要买一批原材料。现在原材料的价格是100元/吨…...
hadoop集群配置-scp命令
scp 命令用于在不同主机之间复制文件或目录,在Hadoop集群配置中常用于将配置文件或相关资源分发到各个节点。以下是 scp 命令的基本用法和在Hadoop集群配置中的示例: 基本语法 scp [-r] [源文件或目录] [目标用户目标主机:目标路径] - -r :…...
Redis 源码硬核解析系列专题 - 结语:从源码看Redis的设计哲学
1. 引言 通过前七篇的源码解析,我们从Redis的整体架构、核心数据结构、事件驱动模型,到内存管理、持久化、主从复制与集群模式,逐步揭开了Redis高性能与简洁性的秘密。本篇将总结这些技术细节,提炼Redis的设计哲学,并探讨如何将源码学习成果应用到实际开发中。 2. Redis的…...
解决QSharedPointer栈变量的崩溃问题
目录 参考崩溃代码现象 解决 参考 QSharedPointer的陷阱 qt中的共享指针,QSharedPointer类 崩溃 代码 #include <QtCore/QCoreApplication> #include <QDebug> #include <QSharedPointer>class MyClass { public:void doSomething() {qDebug…...
Lambda 表达式是什么以及如何使用
目录 📌 Kotlin 的 Lambda 表达式详解 🎯 什么是 Lambda 表达式? 🔥 1. Lambda 表达式的基本语法 ✅ 示例 1:Lambda 基本写法 ✅ 示例 2:使用 it 关键字(单参数简化) ✅ 示例 3…...
C++自定义迭代器
实现自己的迭代器 最近在写数据结构,使用类模板实现,碰到了一些问题,其中有一个就是遍历的问题,查阅资料最后实现了自己的迭代器,让我实现的数据结构能像STL一样进行for循环遍历。 类的构成 #include <stdexcept…...
PWA 中的 Service Worker:如何实现应用离线功能
前言 在当今快速发展的互联网时代,Progressive Web App (PWA) 正在逐步成为现代 Web 开发的主流选择。PWA 将 Web 应用和原生应用的最佳特性相结合,提供了丰富的用户体验。而在 PWA 的众多技术中,Service Worker 无疑是其核心组件之一。 作…...
dockerfile制作镜像
1.docker pull centos:centos7 2.dockerfile内容 FROM centos:centos7 #指定镜像维护的作者和邮箱 MAINTAINER csdn< **********qq.com #设置环境变量mypath ENV MYPATH /usr/local #设置进入容器的默认目录是/usr/local WORKDIR $MYPATH # 下载并替换 CentOS 镜像源 RUN …...
网络空间安全(46)DevSecOps概述
一、定义与核心理念 DevSecOps是“开发(Development)、安全(Security)和运营(Operations)”的结合,它将安全实践融入软件开发生命周期的每个阶段,从需求、设计、开发、测试到部署和运…...
LeetCode 211
实现支持通配符的字典树(Trie):解决单词匹配问题 一、问题描述 我们需要设计一个数据结构,支持以下功能: 添加新单词搜索字符串是否与任何已添加的单词匹配,其中搜索字符串可能包含通配符 .(…...
Docker Compose 启动jar包项目
参考文章安装Docker和Docker Compose 点击跳转 配置 创建一个文件夹存放项目例如mydata mkdir /mydata上传jar包 假设我的jar包名称为goudan.jar 编写dockerfile文件 vim app-dockerfile按键盘上的i进行编辑 # 使用jdk8 FROM openjdk:8-jre# 设置时区 上海 ENV TZAsia/Sh…...
利用deepseek直接调用其他文生图网站生成图片
这次deepseek输入中文后,其实翻译英文后,是可以丢到比如pollinations.这个网站,来生成图片,用法如下: 你是一个图像生成助手,请根据我的简单描述,想象并详细描述一幅完整的画面。 然后将你的详…...
远程装个Jupyter-AI协作笔记本,Jupyter容器镜像版本怎么选?安装部署教程
通过Docker下载Jupyter镜像部署,输入jupyter会发现 有几个版本,不知道怎么选?这几个版本有什么差别? 常见版本有: jupyter/base-notebookjupyter/minimal-notebookjupyter/scipy-notebookjupyter/datascience-notebo…...
11. 盛最多水的容器
leetcode Hot 100系列 文章目录 一、核心操作二、外层配合操作三、核心模式代码总结 一、核心操作 最左右两边逐步往中间走,每次在左右中选取小的一个或–记录最大面积 提示:小白个人理解,如有错误敬请谅解! 二、外层配合操作…...
Selenium Web自动化如何快速又准确的定位元素路径,强调一遍是元素路径
如果文章对你有用,请给个赞! 匹配的ChromeDriver和浏览器版本是更好完成自动化的基础,可以从这里去下载驱动程序: 最全ChromeDriver下载含win linux mac 最新版本134.0.6998.165 持续更新..._chromedriver 134-CSDN博客 如果你问…...
Kotlin 基础语法解析
详细的 Kotlin 基础语法解析,结合概念说明和实用场景: --- ### **一、变量与常量** #### **1. 变量类型** - **val**(不可变变量):声明后不可重新赋值,类似 Java 的 final。 kotlin val name "Kotl…...
html 列表循环滚动,动态初始化字段数据
html <div class"layui-row"><div class"layui-col-md4"><div class"boxall"><div class"alltitle">超时菜品排行</div><div class"marquee-container"><div class"scroll-…...
【大模型基础_毛玉仁】5.4 定位编辑法:ROME
目录 5.4 定位编辑法:ROME5.4.1 知识存储位置1)因果跟踪实验2)阻断实验 5.4.2 知识存储机制5.4.3 精准知识编辑1)确定键向量2)优化值向量3)插入知识 5.4 定位编辑法:ROME 定位编辑:…...
Using SAP an introduction for beginners and business users
Using SAP an introduction for beginners and business users...
Android学习总结之RecyclerView补充篇
在 Android 开发中,列表数据更新的性能一直是关键痛点。传统的 notifyDataSetChanged() 会触发全量刷新,导致不必要的界面重绘。而 DiffUtil 作为 Android 提供的高效差异计算工具,能精准识别数据变化,实现局部更新,成…...
mapbox基础,使用geojson加载cluster聚合图层
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️circle点图层样式二、🍀使用geojson加…...
函数:static和extern
0.前言 在正式开始之前先说作用域和生命周期 作用域: 作用域有分为局部变量和全局变量 局部变量:一个变量仅在其中一段代码内起作用 全局变量:所有的代码都可以使用这个变量 生命周期: 生命周期是一个代码从运行开始到结束…...
【QT】练习1
1、设计一个颜色选择器,可以输入RGB的颜色值,点击确认,可以把主界面的背景颜色改成设置的颜色 修改背景颜色:setStyleSheet(“background-color 红绿蓝颜色值”); // mainwindow.cpp #include "mainwindow.h" #include…...
GreenPlum学习
简介 Greenplum是一个面向数据仓库应用的关系型数据库,因为有良好的体系结构,所以在数据存储、高并发、高可用、线性扩展、反应速度、易用性和性价比等方面有非常明显的优势。Greenplum是一种基于PostgreSQL的分布式数据库,其采用sharednothi…...
张量-pytroch基础(2)
张量-pytroch网站-笔记 张量是一种特殊的数据结构,跟数组(array)和矩阵(matrix)非常相似。 张量和 NumPy 中的 ndarray 很像,不过张量可以在 GPU 或其他硬件加速器上运行。 事实上,张量和 Nu…...
Linux多线程编程的艺术:封装线程、锁、条件变量和信号量的工程实践
目录 📌这篇博客能带给你什么? 🔥为什么需要封装这些组件? 一、线程封装 框架设计 构造与析构 1.线程创建 2.线程分离 3.线程取消 4.线程等待 二、锁封装 框架设计 构造与析构 1.加锁 2.解锁 3.RAII模式 三、条件…...
2025年智慧能源与控制工程国际学术会议(SECE 2025)
官网:www.ic-sece.com 简介 2025年智慧能源与控制工程国际学术会议(SECE 2025)将于2025年4月18日线上会议形式召开,这是一个集中探讨全球智慧能源和控制工程领域创新和挑战的国际学术平台。旨在汇集全球领域内的学者、研究人员、…...
Android 16开发实战指南|锁屏交互+Vulkan优化全解析
一、环境搭建与项目初始化 1. 安装Android Studio Ladybug 下载地址:Android Studio官网关键配置: # 安装后立即更新SDK SDK Manager → SDK Platforms → 安装Android 16 (Preview) SDK Manager → SDK Tools → 更新Android SDK Build-Tools至34.0.0 # 通过命令行安装SDK组…...
sscanf() 用法详解
sscanf() 是 scanf() 的变体,它用于从字符串中提取格式化数据,常用于解析输入字符串。 1️⃣ sscanf() 语法 int sscanf(const char *str, const char *format, ...); str:要解析的字符串(必须是 const char*,可以用…...
0基础入门scrapy 框架,获取豆瓣top250存入mysql
一、基础教程 创建项目命令 scrapy startproject mySpider --项目名称 创建爬虫文件 scrapy genspider itcast "itcast.cn" --自动生成 itcast.py 文件 爬虫名称 爬虫网址 运行爬虫 scrapy crawl baidu(爬虫名) 使用终端运行太麻烦了,而且…...
Linux常见操作命令(2)
(一)复制和移动 复制和移动都分为文件和文件夹,具体的命令是cp和mv。 1.复制文件(复制的文件要是已创建) 格式:cp 源文件 目标文件。 示例:把filel.txt复制一份得到file2.txt。 那么对应的命令就是&#x…...
谷歌将 Android OS 完全转变为 “内部开发”
2025 年 3 月 27 日,据 Android Authority 报道,谷歌证实将从下周开始完全在内部分支机构闭门开发安卓操作系统。相关信息如下: 背景:多年来,谷歌同时维护着两大安卓主要分支,一是面向公众开放的 “安卓开源…...
移动端六大语言速记:第2部分 - 控制结构
移动端六大语言速记:第2部分 - 控制结构 本文继续对比Java、Kotlin、Flutter(Dart)、Python、ArkTS和Swift这六种移动端开发语言的控制结构,帮助开发者快速掌握各语言的语法差异。 2. 控制结构 2.1 条件语句 各语言条件语句的语法对比: …...
【 Vue 2 中的 Mixins 模式】
Vue 2 中的 Mixins 模式 在 Vue 2 里,mixins 是一种灵活的复用代码的方式,它能让你在多个组件间共享代码。借助 mixins,你可以把一些通用的选项(像 data、methods、computed 等)封装到一个对象里,然后在多…...
STM32F103_LL库+寄存器学习笔记13 - 梳理外设CAN与如何发送CAN报文(串行发送)
导言 CAN总线因其高速稳定的数据传输与卓越抗干扰性能,在汽车、机器人及工业自动化中被广泛应用。它采用分布式网络结构,实现多节点间实时通信,确保各控制模块精准协同。在汽车领域,CAN总线连接发动机、制动、车身系统,…...
DataPlatter:利用最少成本数据提升机器人操控的泛化能力
25年3月来自中科院计算所的论文“DataPlatter: Boosting Robotic Manipulation Generalization with Minimal Costly Data”。 视觉-语言-动作 (VLA) 模型在具身人工智能中的应用日益广泛,这加剧对多样化操作演示的需求。然而,数据收集的高成本往往导致…...
受控组件和非受控组件的区别
在 React 中,受控组件(Controlled Components) 和 非受控组件(Uncontrolled Components) 是处理表单元素的两种不同方式,它们的核心区别在于 数据管理的方式 和 与 React 的交互模式。 受控组件…...
Mhand Pro 多节点动作捕捉手套:一副手套多场景应用
随着动作捕捉技术的发展,动捕手套的出现为虚拟现实交互、VR游戏开发、机器臂/灵巧手遥操作等方面带来了更加便捷可行的方案。 广州虚拟动力作为一家在动作捕捉领域深耕多年的公司,基于传感器技术而研发的多节点惯性动作捕捉手套,兼具VR交互与…...
Kafka消息丢失全解析!原因、预防与解决方案
作为一名高并发系统开发工程师,在使用消息中间件的过程中,无法避免遇到系统中消息丢失的问题,而Kafka作为主流的消息队列系统,消息丢失问题尤为常见。 在这篇文章中,将深入浅出地分析Kafka消息丢失的各种情况…...
BERT与Transformer到底选哪个-上部
一、先理清「技术家谱」:BERT和Transformer是啥关系? 就像「包子」和「面食」的关系——BERT是「Transformer家族」的「明星成员」,而GPT、Qwen、DeepSeek这些大模型则是「Transformer家族」的「超级后辈」。 1.1 BERT:Transfor…...
【Unity】记录TMPro使用过程踩的一些坑
1、打包到webgl无法输入中文,编辑器模式可以,但是webgl不行,试过网上的脚本,还是不行 解决方法:暂时没找到 2、针对字体asset是中文时,overflow的效果模式处理奇怪,它会出现除了overflow模式以…...
数据处理的两种范式:深入解析OLTP与OLAP系统
目录 前言1. OLTP:业务运作的基石1.1 OLTP的核心定义与价值1.2 OLTP的技术架构特点1.3 OLTP的典型应用场景 2. OLAP:决策支持的大脑2.1 OLAP的基本概念与作用2.2 OLAP的技术实现方式2.3 OLAP的应用实践 3. OLTP与OLAP的对比与融合3.1 核心差异的深度解析…...
本地飞牛NAS快速部署WordPress个人网站并一键上线公网远程访问
文章目录 前言1. Docker下载源设置2. Docker下载WordPress3. Docker部署Mysql数据库4. WordPress 参数设置5. 飞牛云安装Cpolar工具6. 固定Cpolar公网地址7. 修改WordPress配置文件8. 公网域名访问WordPress 推荐 前些天发现了一个巨牛的人工智能学习网站,通俗…...