STM32学习笔记13-FLASH闪存
FLASH简介
- STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程
- 读写FLASH的用途:
利用程序存储器的剩余空间来保存掉电不丢失的用户数据
通过在程序中编程(IAP),实现程序的自我更新
- 在线编程(In-Circuit Programming – ICP)用于更新程序存储器的全部内容,它通过JTAG、SWD协议或系统加载程序(Bootloader)下载程序
- 在程序中编程(In-Application Programming – IAP)可以使用微控制器支持的任一种通信接口下载程序
闪存模块组织
FLASH基本结构
FLASH解锁
FPEC共有三个键值:
- 1)RDPRT键 = 0x000000A5
- 2)KEY1 = 0x45670123
- 3)KEY2 = 0xCDEF89AB
- 解锁的方式:
-
复位后,FPEC被保护,不能写入FLASH_CR,也就是复位后FLASH默认是锁着的,然后在FLASH_KEYR先写入KEY1,再写入KEY2,解锁。错误的操作序列会在下次复位前锁死FPEC和FLASH_CR。
-
解锁之后如何加锁呢?我们操作完成之后要尽快把FLASH重新加锁,以防止意外情况。
-
加锁:
-
设置FLASH_CR中的LOCK位锁住FPEC和FLASH_CR。
-
接下来看一下如何使用C语言指针访问存储器:
程序存储器全擦除
程序存储器擦除
程序存储器编程
擦除之后我们就可以执行写入的流程了,STM32的闪存在写入之前会检查指定地址有没有擦除,如果没有擦除就写入STM32则不执行写入操作,除非写入的全是0,这一个数据是个例外。
选项字节
简单介绍一下,了解即可。
- RDP:写入RDPRT键(0x000000A5)后解除读保护
- USER:配置硬件看门狗和进入停机/待机模式是否产生复位
- Data0/1:用户可自定义使用
- WRP0/1/2/3:配置写保护,每一个位对应保护4个存储页(中容量)
选项字节编程
- 检查FLASH_SR的BSY位,以确认没有其他正在进行的编程操作
- 解锁FLASH_CR的OPTWRE位
- 设置FLASH_CR的OPTPG位为1
- 写入要编程的半字到指定的地址
- 等待BSY位变为0
- 读出写入的地址并验证数据
选项字节擦除
- 检查FLASH_SR的BSY位,以确认没有其他正在进行的闪存操作
- 解锁FLASH_CR的OPTWRE位
- 设置FLASH_CR的OPTER位为1
- 设置FLASH_CR的STRT位为1
- 等待BSY位变为0
- 读出被擦除的选择字节并做验证
器件电子签名
电子签名存放在闪存存储器模块的系统存储区域,包含的芯片识别信息在出厂时编写,不可更改,使用指针读指定地址下的存储器可获取电子签名。
1)闪存容量寄存器:
基地址:0x1FFF F7E0
大小:16位
2)产品唯一身份标识寄存器:
基地址: 0x1FFF F7E8
大小:96位
FLASH应用
读写内部FLASH
代码整体规划如下:
接下来看一下库函数:
void FLASH_Unlock(void);//用来解锁
void FLASH_Lock(void);//加锁
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);//指定地址写入半字
完整代码:
MyFLASH.c:
#include "stm32f10x.h" // Device header/*读取字(32位)
*/
uint32_t MyFLASH_ReadWord(uint32_t Address)
{return *((__IO uint32_t *)(Address));
}/*读取半字(16位)
*/
uint16_t MyFLASH_ReadHalfWord(uint32_t Address)
{return *((__IO uint16_t *)(Address));
}/*读取字节(8位)
*/
uint8_t MyFLASH_ReadByte(uint32_t Address)
{return *((__IO uint8_t *)(Address));
}/*全擦除
*/
void MyFLASH_EraseAllPages(void)
{FLASH_Unlock();//第一步对FLASH解锁FLASH_EraseAllPages();//第二步直接调库函数FLASH_Lock();//第三步锁上FLASH
}/*页擦除
* 参数 PageAddress:要擦除的页地址
*/
void MyFLASH_ErasePage(uint32_t PageAddress)
{FLASH_Unlock();//第一步对FLASH解锁FLASH_ErasePage(PageAddress);//第二步直接调库函数FLASH_Lock();//第三步锁上FLASH
}/*编程,写入一个字
* 参数1 Address:要写入的地址
* 参数2 Data:32位的数据
*/
void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data)
{FLASH_Unlock();//第一步对FLASH解锁FLASH_ProgramWord(Address, Data);//第二步直接调库函数FLASH_Lock();//第三步锁上FLASH
}/*编程,写入半字
* 参数1 Address:要写入的地址
* 参数2 Data:16位的数据
*/
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{FLASH_Unlock();//第一步对FLASH解锁FLASH_ProgramHalfWord(Address, Data);//第二步直接调库函数FLASH_Lock();//第三步锁上FLASH
}
Store.c:
#include "stm32f10x.h" // Device header
#include "MyFLASH.h"#define STORE_START_ADDRESS 0x0800FC00
#define STORE_COUNT 512uint16_t Store_Data[STORE_COUNT];void Store_Init(void)
{/* 初始化闪存,最后一页第一个半字是标志位A5A5,剩下数据全是0 *///0xA5A5是随便定义的标志位,如果第一个半字不是A5A5就说明是第一次使用if(MyFLASH_ReadHalfWord(0x08000000) != 0xA5A5){MyFLASH_ErasePage(STORE_START_ADDRESS);//擦除最后一页MyFLASH_ProgramHalfWord(STORE_START_ADDRESS, 0xA5A5);//在第一个半字的位置写入规定的标志位for(uint16_t i = 1;i < STORE_COUNT;i++)//把剩余的存储空间全都置为默认值0{MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i*2, 0x0000);}}/* 上电时把闪存数据转存到SRAM数组 */for(uint16_t i = 0;i < STORE_COUNT;i++){Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS + i*2);}
}/*SRAM数组备份保存到闪存
*/
void Stort_Save(void)
{/* 第一步擦除最后一页 */MyFLASH_ErasePage(STORE_START_ADDRESS);/* 第二步把数组完全备份保存到闪存最后一页 */for(uint16_t i = 0;i < STORE_COUNT;i++){MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i*2, Store_Data[i]);}
}/*数据清零
*/
void Store_Clear(void)
{for(uint16_t i = 1;i < STORE_COUNT;i++){Store_Data[i] = 0x0000;}Stort_Save();//把更改更新到闪存
}
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();Key_Init();Store_Init();//第一次使用的时候初始化闪存,把闪存备份的数据加载回SRAM数组OLED_ShowString(1, 1, "Flag:");OLED_ShowString(2, 1, "Data:");while(1){KeyNum = Key_GetNum();if(KeyNum == 1){Store_Data[1] ++;//第0个位置是标志位,不能用Store_Data[2] += 2;Store_Data[3] += 3;Store_Data[4] += 4;Stort_Save();//把SRAM数组备份到闪存}if(KeyNum == 2){Store_Clear();}OLED_ShowHexNum(1, 6, Store_Data[0], 4);//显示标志位OLED_ShowHexNum(3, 1, Store_Data[1], 4);OLED_ShowHexNum(3, 6, Store_Data[2], 4);OLED_ShowHexNum(4, 1, Store_Data[3], 4);OLED_ShowHexNum(4, 6, Store_Data[4], 4);}
}
相关文章:

STM32学习笔记13-FLASH闪存
FLASH简介 STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程读写FLASH的用途: 利用程序存储器的剩余空间来保存掉电不丢失的用户数据 通过在…...

UIButton的UIEdgeInsetsMake属性(setTitleEdgeInsets,setImageEdgeInsets)
一.UIEdgeInsetsMake的四个属性 UIEdgeInsetsMake 有四个属性,依次是 Top,left,bottom,right [Btn setTitleEdgeInsets:UIEdgeInsetsMake( top, left, bottom, right)]; 四个属性的默认值为0,拿其中一个left属性来聊, 你可以理解为文字距离Btn左边界的“位移”是0, 如果…...

子网掩码是什么?
子网掩码(Subnet Mask)是用于划分网络的一个32位的二进制数,用于指示IP地址中哪些位用于网络标识,哪些位用于主机标识。 在IPv4网络中,IP地址由32位二进制数组成,通常表示为四个十进制数,每个数…...

SQLALchemy 数据的 CRUD 操作
SQLALchemy 数据的 CRUD 操作 导入必要的模块创建数据库引擎创建会话CRUD 操作创建(Create)读取(Read)更新(Update)删除(Delete)过滤条件使用 `filter` 方法使用 `filter_by` 方法总结聚合函数使用ORM接口使用SQL表达式语言注意关闭会话注意事项SQLAlchemy 是一个流行的…...

reactFiberLane
Lane (车道模型) 英文单词lane翻译成中文表示"车道, 航道"的意思, 所以很多文章都将Lanes模型称为车道模型 Lane模型的源码在ReactFiberLane.js, 源码中大量使用了位运算(有关位运算的讲解, 首先引入作者对Lane的解释(相应的 pr), 这里简单概括如下: Lane类型被定义…...

Hackademic.RTB1靶场实战【超详细】
靶机下载链接:https://download.vulnhub.com/hackademic/Hackademic.RTB1.zip 一、主机探测和端口扫描 nmap 192.168.121.0/24 ip:192.168.121.196 端口:22、80 二、访问80端口 发现target可点击 点击后跳转,页面提示目标是读取到 key.txt 文件 fin…...

让3岁小孩都能理解LeetCode每日一题_3148.矩阵中的最大得分
解释说明: 上面的内容的意思是为了有只移动一次的情况,而后面的grid(i,j)-grid(i,k)由于j严格大于k,所以至少移动了一次,前面可以保持不移动,不移动就是选择0。 class Solution {public int maxScore(List<List&l…...

8.15日学习打卡---Spring Cloud Alibaba(三)
8.15日学习打卡 目录: 8.15日学习打卡为什么需要服务网关Higress是什么安装DockerCompose部署Higress创建网关微服务模块Higress路由配置Higress策略配置-跨域配置Higress解决如何允许跨域Higress策略配置之什么是HTTP认证Higress策略配置-Basic 认证什么是JWT认证J…...

2024下半年EI学术会议一览表
2024下半年将举办多个重要的EI学术会议,涵盖了从机器视觉、图像处理与影像技术到感知技术、绿色通信、计算机、大数据与人工智能等多个领域。 2024下半年EI学术会议一览表 第二届机器视觉、图像处理与影像技术国际会议(MVIPIT 2024)将于2024…...

【海奇HC-RTOS平台E100-问题点】
海奇HC-RTOS平台E100-问题点 ■ btn 没有添加到group中 ,怎么实现的事件的■ 屏幕是1280*720, UI是1024*600,是否修改UI■ hc15xx-db-e100-v10-hcdemo.dtb 找不到■ 触摸屏驱动 能否给个实例■ 按键驱动■ __initcall(projector_auto_start)■ source insigt4.0 #if…...

性能测试之Mysql数据库调优
一、前言 性能调优前提:无监控不调优,对于mysql性能的监控前几天有文章提到过,有兴趣的朋友可以去看一下 二、Mysql性能指标及问题分析和定位 1、我们在监控图表中关注的性能指标大概有这么几个:CPU、内存、连接数、io读写时间…...

使用 RestHighLevelClient 进行 Elasticsearch 高亮查询及解析
在搜索引擎中,高亮显示查询关键字是一个提升用户体验的功能,它可以帮助用户更快地定位到相关信息。Elasticsearch 支持在搜索结果中对匹配的文本进行高亮显示。本文将介绍如何在 Java 应用程序中使用 Elasticsearch 的 RestHighLevelClient 执行高亮查询…...

Java基础入门15:算法、正则表达式、异常
算法(选择排序、冒泡排序、二分查找) 选择排序 每轮选择当前位置,开始找出后面的较小值与该位置交换。 选择排序的关键: 确定总共需要选择几轮:数组的长度-1。 控制每轮从以前位置为基准,与后面元素选择…...

SpringBoot响应式编程 WebFlux入门教程
🍁 作者:知识浅谈,CSDN签约讲师,CSDN博客专家,华为云云享专家,阿里云专家博主 📌 擅长领域:全栈工程师、爬虫、ACM算法 🔥 微信:zsqtcyw 联系我领取学习资料 …...

LeetCode 383. 赎金信
题目 给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以,返回 true ;否则返回 false 。 magazine 中的每个字符只能在 ransomNote 中使用一次。 示例 1: 输入&…...

python绘制电路图
要在 Python 中实现电路图,你可以使用一些专门的库来创建和可视化电路图。一个常用的库是 schemdraw,它可以用来绘制电路图,并支持多种电气组件和符号。 下面是一个使用 schemdraw 库绘制简单电路图的示例: 安装 schemdraw 库&am…...

Vue3 Suspense 和 defineAsyncComponent 结合使用方法
Suspense:用于协调对组件树中嵌套的异步依赖的处理。 defineAsyncComponent:定义一个异步组件,它在运行时是懒加载的。参数可以是一个异步加载函数,或是对加载行为进行更具体定制的一个选项对象。 异步组件的好处:使…...

GitHub中Codespace怎么使用;LLM模拟初始化;MLP:全连接神经网络的并行执行
目录 PyUnit unittest是什么 unittest怎么使用 GitHub中Codespace怎么使用 测试常用功能 LLM模拟初始化 参数解释 类属性设置 总结 MLP:全连接神经网络的并行执行 假设 代码解释 注意事项 PyUnit unittest是什么 unittest是Python的内置单元测试框架,原名PyUn…...

【rh】rh项目部署
【fastadmin】 1、项目先clone到本地,其中web为h5前端使用(gitclone后,把web内容放进去再提交),其余为项目后端使用 2、安装本地环境,项目跑起来,步骤如下: 1)查春.git 和 composer,json 版本信…...

VoxelNet: End-to-End Learning for Point Cloud Based 3D Object Detection
VoxelNet: End-to-End Learning for Point Cloud Based 3D Object Detection Abstract 摘要部分,作者首先指出了3D点云中目标检测的重要性,在自动驾驶导航、家政机器人以及增强现实和虚拟现实等多个领域有重要的作用。然后,提到了现有方法的…...

结构开发笔记(三):solidworks软件(二):小试牛刀,绘制一个立方体
若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/141122350 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV…...

LLM 量化算法AutoRound 0.3 发布及原理浅析
这里写自定义目录标题 AutoRound V0.3 特性原理浅析其他工作AutoRound 原理 AutoRound(https://github.com/intel/auto-round)在Llama3.1-8B-Instruct上效果明显优于AWQ/GPTQ等方法,在10个任务的平均准确率上我们以63.93%由于AWQ的63.15%和GP…...

汽车免拆诊断案例 | 2013款北京现代悦动车发动机偶尔无法起动
故障现象 一辆2013款北京现代悦动车,搭载G4FC发动机,累计行驶里程约为13.9万km。车主反映,发动机偶尔无法起动着机,断开点火开关,等待一会儿又可以起动着机。 故障诊断 接车后反复试车,当发动机无法起动着…...

React、AntD,封装动态表单
在React中使用Ant Design(简称AntD)来封装动态表单是一个常见的需求,特别是在需要灵活配置表单字段的场景下。以下是一个基本的步骤和示例代码,展示如何使用React和AntD来封装一个动态表单。 步骤 1: 安装必要的库 首先,确保你的项目中已经安装了react和antd。如果还没有…...

【Linux基础】Linux中的开发工具(3)--make/makefile和git的使用
目录 前言一,Linux项目自动化构建工具-make/makefile1. 背景2. 依赖关系和依赖方法3. 项目清理4. 使用方法和原理5. .PHONY的作用6. makefile中符号的使用 二,进度条的实现1. 理解回车换行2. 理解行缓冲区3. 版本14. 版本2 三,Linux上git的使…...

过滤了字母、数字、_、$的webshell命令执行技巧
目录 对于php5以上首先要解决的问题有 解决技巧 1.code长度小于35位 2.没有字母、数字、_ 、$ 3.怎么把文件放进服务器 4.怎么执行文件里面的内容 1.执行Linux命令 2.执行文件里面的shell命令 5.构造完整的code参数 6.我们还可以通过修改文件里面shell命令,…...

python-A+B again
[题目描述] 小理有一个非常简单的问题给你,给你两个整数 A 和 B,你的任务是计算 AB。输入格式: 输入共 2∗T1 行。 输入的第一行包含一个整数 T 表示测试实例的个数,然后 2∗T 行,分别表示 A 和 B 两个正整数。注意整数…...

C语言—函数递归
一、递归概念 递归其实是⼀种解决问题的⽅法,在C语⾔中,递归就是函数⾃⼰调⽤⾃⼰。下面举一个例子: 上述就是⼀个简单的递归程序,只不过上⾯的递归只是为了演⽰递归的基本形式,不是为了解决问题,代码最终…...

结构开发笔记(四):solidworks软件(三):绘制36x36方块摄像头示意体
若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/141187797 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV…...

【机器学习】Caltech-101的基本概念和使用方法以及Caltech-101和ImageNet的联系和区别
引言 Caltech-101数据集是一个广泛用于对象识别任务的数据库,它包含了大约9,000张图像,这些图像来自101个不同的对象类别。每个类别包含的图像数量大约在40到800张之间,大多数类别大约有50张图像。图像的分辨率大致为300200像素 文章目录 引言…...