STM32操作FLASH

以下将为你详细介绍 STM32 的 Flash 操作相关知识,包含基本原理、操作步骤,并给出具体的代码示例。

1. STM32 Flash 基本原理

1.1 Flash 存储器结构

STM32 的 Flash 存储器用于存储程序代码和一些需要掉电保存的数据。它通常被划分为多个扇区,每个扇区有固定的大小。不同系列的 STM32 芯片,其 Flash 扇区大小和数量可能不同。例如,STM32F103 系列的 Flash 扇区大小有 1KB、2KB、4KB、16KB、64KB 和 128KB 等。

1.2 Flash 操作限制
  • 写操作:在进行写操作之前,必须先擦除相应的扇区。因为 Flash 的写操作只能将 “1” 变为 “0”,而擦除操作会将整个扇区的数据都变为 “1”。
  • 擦除操作:擦除操作是以扇区为单位进行的,不能只擦除一个字节或一个字。
  • 保护机制:为了防止误操作或恶意修改,STM32 的 Flash 提供了写保护和读保护机制。

2. STM32 Flash 操作步骤

2.1 解锁 Flash

在进行写或擦除操作之前,需要先解锁 Flash。因为 Flash 默认是处于锁定状态的,以防止误操作。

2.2 擦除扇区

如果要写入新的数据,需要先擦除相应的扇区。可以选择擦除单个扇区或多个扇区。

2.3 写入数据

在扇区擦除完成后,就可以向 Flash 中写入数据了。写入数据时需要注意数据的对齐方式,通常是以半字(16 位)或字(32 位)为单位进行写入。

2.4 锁定 Flash

在完成写或擦除操作后,需要锁定 Flash,以保护数据安全。

3. 代码示例(以 STM32F103 为例)

#include "stm32f10x.h"// 解锁Flash
void FLASH_Unlock(void)
{if ((FLASH->CR & FLASH_CR_LOCK) != 0){FLASH->KEYR = FLASH_KEY1;FLASH->KEYR = FLASH_KEY2;}
}// 锁定Flash
void FLASH_Lock(void)
{FLASH->CR |= FLASH_CR_LOCK;
}// 擦除指定扇区
uint8_t FLASH_EraseSector(uint32_t Sector)
{uint32_t timeout = 0xFFFF;FLASH_Unlock();FLASH->CR |= FLASH_CR_PER;FLASH->AR = Sector;FLASH->CR |= FLASH_CR_STRT;while ((FLASH->SR & FLASH_SR_BSY) != 0){if (timeout-- == 0){FLASH->CR &= ~FLASH_CR_PER;FLASH_Lock();return 1; // 擦除超时}}if ((FLASH->SR & FLASH_SR_EOP) != 0){FLASH->SR |= FLASH_SR_EOP;}FLASH->CR &= ~FLASH_CR_PER;FLASH_Lock();return 0; // 擦除成功
}// 写入半字数据到指定地址
uint8_t FLASH_WriteHalfWord(uint32_t Address, uint16_t Data)
{uint32_t timeout = 0xFFFF;FLASH_Unlock();FLASH->CR |= FLASH_CR_PG;*(__IO uint16_t*)Address = Data;while ((FLASH->SR & FLASH_SR_BSY) != 0){if (timeout-- == 0){FLASH->CR &= ~FLASH_CR_PG;FLASH_Lock();return 1; // 写入超时}}if ((FLASH->SR & FLASH_SR_EOP) != 0){FLASH->SR |= FLASH_SR_EOP;}FLASH->CR &= ~FLASH_CR_PG;FLASH_Lock();return 0; // 写入成功
}// 从指定地址读取半字数据
uint16_t FLASH_ReadHalfWord(uint32_t Address)
{return *(__IO uint16_t*)Address;
}int main(void)
{uint32_t SectorAddress = 0x08004000; // 假设要操作的扇区地址uint16_t WriteData = 0x1234;uint16_t ReadData;// 擦除扇区if (FLASH_EraseSector(SectorAddress) == 0){// 写入数据if (FLASH_WriteHalfWord(SectorAddress, WriteData) == 0){// 读取数据ReadData = FLASH_ReadHalfWord(SectorAddress);// 这里可以根据读取的数据进行相应的处理}}while (1){// 主循环}
}

4. 代码解释

  • FLASH_Unlock():用于解锁 Flash,通过向FLASH->KEYR寄存器写入特定的解锁密钥来实现。
  • FLASH_Lock():用于锁定 Flash,将FLASH->CR寄存器的LOCK位置 1。
  • FLASH_EraseSector():擦除指定扇区。首先解锁 Flash,然后设置擦除标志位,启动擦除操作,等待擦除完成,最后清除擦除标志位并锁定 Flash。
  • FLASH_WriteHalfWord():向指定地址写入半字数据。首先解锁 Flash,然后设置写入标志位,写入数据,等待写入完成,最后清除写入标志位并锁定 Flash。
  • FLASH_ReadHalfWord():从指定地址读取半字数据。

5. 注意事项

  • 地址选择:在选择 Flash 地址时,要确保该地址不会影响到程序代码的正常运行。
  • 擦除操作:擦除操作会将整个扇区的数据都清除,所以在擦除之前要确保该扇区的数据已经备份或不再需要。
  • 数据对齐:写入数据时要注意数据的对齐方式,通常是以半字或字为单位进行写入。

当不使用寄存器直接操作时,我们可以利用 STM32 HAL 库来进行 Flash 操作。HAL(Hardware Abstraction Layer)库是 ST 公司提供的硬件抽象层,它对底层寄存器操作进行了封装,使得代码的编写更加简洁和易于理解。以下是一个使用 STM32 HAL 库进行 Flash 操作的示例,以 STM32F4 系列为例:

1. 代码示例

#include "stm32f4xx_hal.h"// 定义要操作的扇区和地址
#define FLASH_USER_START_ADDR   ADDR_FLASH_SECTOR_6   // 假设使用扇区6
#define FLASH_USER_END_ADDR     ADDR_FLASH_SECTOR_7 - 1// 解锁Flash
void Flash_Unlock(void) {HAL_FLASH_Unlock();
}// 锁定Flash
void Flash_Lock(void) {HAL_FLASH_Lock();
}// 擦除指定扇区
uint8_t Flash_EraseSector(uint32_t Sector) {FLASH_EraseInitTypeDef EraseInitStruct;uint32_t SectorError;EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;EraseInitStruct.Sector = Sector;EraseInitStruct.NbSectors = 1;if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {return 1; // 擦除失败}return 0; // 擦除成功
}// 写入32位数据到指定地址
uint8_t Flash_WriteWord(uint32_t Address, uint32_t Data) {if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, Data) != HAL_OK) {return 1; // 写入失败}return 0; // 写入成功
}// 从指定地址读取32位数据
uint32_t Flash_ReadWord(uint32_t Address) {return *(__IO uint32_t*)Address;
}int main(void) {HAL_Init();uint32_t WriteData = 0xABCD1234;uint32_t ReadData;// 解锁FlashFlash_Unlock();// 擦除扇区if (Flash_EraseSector(FLASH_SECTOR_6) == 0) {// 写入数据if (Flash_WriteWord(FLASH_USER_START_ADDR, WriteData) == 0) {// 读取数据ReadData = Flash_ReadWord(FLASH_USER_START_ADDR);// 这里可以根据读取的数据进行相应的处理}}// 锁定FlashFlash_Lock();while (1) {// 主循环}
}

2. 代码解释

2.1 头文件和宏定义
#include "stm32f4xx_hal.h"
#define FLASH_USER_START_ADDR   ADDR_FLASH_SECTOR_6
#define FLASH_USER_END_ADDR     ADDR_FLASH_SECTOR_7 - 1
  • #include "stm32f4xx_hal.h":包含 STM32F4 系列的 HAL 库头文件。
  • FLASH_USER_START_ADDRFLASH_USER_END_ADDR:定义了要操作的 Flash 扇区的起始和结束地址。
2.2 解锁和锁定 Flash
void Flash_Unlock(void) {HAL_FLASH_Unlock();
}void Flash_Lock(void) {HAL_FLASH_Lock();
}
  • HAL_FLASH_Unlock():调用 HAL 库函数解锁 Flash。
  • HAL_FLASH_Lock():调用 HAL 库函数锁定 Flash。
2.3 擦除指定扇区
uint8_t Flash_EraseSector(uint32_t Sector) {FLASH_EraseInitTypeDef EraseInitStruct;uint32_t SectorError;EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;EraseInitStruct.Sector = Sector;EraseInitStruct.NbSectors = 1;if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {return 1; // 擦除失败}return 0; // 擦除成功
}
  • FLASH_EraseInitTypeDef:定义一个 Flash 擦除初始化结构体,用于配置擦除操作的参数。
  • HAL_FLASHEx_Erase():调用 HAL 库函数进行扇区擦除操作。
2.4 写入 32 位数据到指定地址
uint8_t Flash_WriteWord(uint32_t Address, uint32_t Data) {if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, Data) != HAL_OK) {return 1; // 写入失败}return 0; // 写入成功
}
  • HAL_FLASH_Program():调用 HAL 库函数向指定地址写入 32 位数据。
2.5 从指定地址读取 32 位数据
uint32_t Flash_ReadWord(uint32_t Address) {return *(__IO uint32_t*)Address;
}
  • 直接从指定地址读取 32 位数据。

3. 注意事项

  • 扇区选择:要根据实际需求选择合适的 Flash 扇区,避免影响程序代码的正常运行。
  • 初始化:在使用 HAL 库之前,需要调用HAL_Init()函数进行初始化。
  • 错误处理:在进行 Flash 操作时,要注意检查函数的返回值,以便及时处理可能出现的错误。

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

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

相关文章

算法之 跳跃游戏

文章目录 55.跳跃游戏思路参考:56.合并区间 55.跳跃游戏 55.跳跃游戏 灵神思路 思路分析: 两种思路,思路1是我们可以直接维护当前到达i的时候所能到达的最右的边界mr,如果i>mr就说明无法到达i,否则就是可以到达;…

Ubuntu22.04通过Docker部署Jeecgboot

程序发布环境包括docker、mysql、redis、maven、nodejs、npm等。 一、安装docker 1、用如下命令卸载旧Docker: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done 2、安装APT环境依赖包…

STM32 ADC介绍(硬件原理篇)

目录 背景 AD转换器 采样与保持 量化 编码 AD转换器转换原理 DA转换原理 AD转换原理 1.逐次逼近型AD转换器 2.并联比较型AD转换器 编码器 同步D触发器和边沿D触发器 基本RS触发器 同步RS触发器 同步D触发器 边沿型D触发器(维持-阻塞D触发器&#xff…

DeepSeek4j 已开源,支持思维链,自定义参数,Spring Boot Starter 轻松集成,快速入门!建议收藏

DeepSeek4j Spring Boot Starter 快速入门 简介 DeepSeek4j 是一个专为 Spring Boot 设计的 AI 能力集成启动器,可快速接入 DeepSeek 大模型服务。通过简洁的配置和易用的 API,开发者可轻松实现对话交互功能。 环境要求 JDK 8Spring Boot 2.7Maven/Gr…

编程技巧:VUE 实现接口返回数据的流式处理

一、写在前面 ChatGPT 的问答响应界面相信大家都见过,内容是一点一点追加式的显示。不是等好了一起发给你,然后一次性展示出来。这种效果和我们平常开发的展示渲染模式有点区别。可能有的同学会说,前端拿到报文后,我们做成这样的…

Django 创建表 choices的妙用:get_<field_name>_display()

1.定义choices 我在创建表时,对于性别这个字段,定义了choices 选项,1代表男,2代表女 mysql中表的数据如下,里面存储的是1或2 如果我们在网页上展示的时候,想展示“男”或“女”,而不是数字1或2…

Mac安装JD-GUI

Mac安装反编译工具步骤如下: 打开官网https://java-decompiler.github.io/ 选择下载mac的安装包解压下载好的压缩包,点击JD-GUI安装 有可能会遇到如下错误。请先检查是否安装JDK,通过java -version命令查看是否是1.8版本的jdk如果jdk没问题&…

[免费]Springboot+Vue医疗(医院)挂号管理系统【论文+源码+SQL脚本】

大家好,我是java1234_小锋老师,看到一个不错的SpringbootVue医疗(医院)挂号管理系统,分享下哈。 项目视频演示 【免费】SpringBootVue医疗(医院)挂号管理系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 在如今社会上,关于信息上…

链表(典型算法思想)—— OJ例题算法解析思路

目录 一、2. 两数相加 - 力扣(LeetCode) 算法代码: 1. 初始化 2. 遍历链表并相加 3. 返回结果 举例说明 二、24. 两两交换链表中的节点 - 力扣(LeetCode) 算法代码: 代码思路 举例说明 初始状…

twisted实现MMORPG 游戏数据库操作封装设计与实现

在设计 MMORPG(大规模多人在线角色扮演游戏)时,数据库系统是游戏架构中至关重要的一部分。数据库不仅承担了游戏中各种数据(如玩家数据、物品数据、游戏世界状态等)的存储和管理任务,还必须高效地支持并发访…

lvsDR模式实现

LVS DR模式与NAT模式的优缺点: NAT:优点:配置简单,所需网络环境简单,访问流量的出入都经过LVS服务器,控制流量简单, 缺点:由于访问流量的出入都会经过LVS服务器,所以LVS…

闭源大语言模型的怎么增强:提示工程 检索增强生成 智能体

闭源大语言模型的怎么增强 提示工程 检索增强生成 智能体 核心原理 提示工程:通过设计和优化提示词,引导大语言模型进行上下文学习和分解式思考,激发模型自身的思维和推理能力,使模型更好地理解和生成文本,增强其泛用性和解决问题的能力。检索增强生成:结合检索的准确…

【快速幂算法】快速幂算法讲解及C语言实现(递归实现和非递归实现,附代码)

快速幂算法 快速幂算法可用分治法实现 不难看出,对任意实数a和非负整数n,有: a n { 1 , n 0 , a ≠ 0 0 , a 0 ( a n 2 ) 2 , n > 0 , n 为偶数 ( a n 2 ) 2 ∗ a , n > 0 , n 为奇数 a^n \begin{cases} 1, & n 0, a\neq 0…

大数据SQL调优专题——Hive执行原理

引入 Apache Hive 是基于Hadoop的数据仓库工具,它可以使用SQL来读取、写入和管理存在分布式文件系统中的海量数据。在Hive中,HQL默认转换成MapReduce程序运行到Yarn集群中,大大降低了非Java开发者数据分析的门槛,并且Hive提供命令…

30天开发操作系统 第 20 天 -- API

前言 大家早上好,今天我们继续努力哦。 昨天我们已经实现了应用程序的运行, 今天我们来实现由应用程序对操作系统功能的调用(即API, 也叫系统调用)。 为什么这样的功能称为“系统调用”(system call)呢?因为它是由应用程序来调用(操作)系统中的功能来完…

UE5.2后 Bake Out Materials失效

这个问题出现在5.3,5.4,5.5没有测试 烘焙贴图后会找不到贴图位置, 这个是5.2的正常状态 默认是生成在模型当前目录里,包括新的材质 但是这个bug会让材质和贴图都消失,无法定位 暂时没有办法解决,等官方 …

macOS部署DeepSeek-r1

好奇,跟着网友们的操作试了一下 网上方案很多,主要参考的是这篇 DeepSeek 接入 PyCharm,轻松助力编程_pycharm deepseek-CSDN博客 方案是:PyCharm CodeGPT插件 DeepSeek-r1:1.5b 假设已经安装好了PyCharm PyCharm: the Pyth…

架构设计系列(二):CI/CD

一、概述 CI/CD 是 持续集成(Continuous Integration) 和 持续交付/持续部署(Continuous Delivery/Continuous Deployment) 的缩写,是现代软件开发中的一套核心实践和工具链,旨在提高软件交付的效率、质量…

Windows 11 搭建私有知识库(docker、dify、deepseek、ollama)

一、操作系统信息 版本 Windows 11 家庭中文版 版本号 23H2 安装日期 ‎2023/‎8/‎21 操作系统版本 22631.4460二、搭建思路 ollama拉取deepseek、bge-m3模型docker拉取dify的镜像dify链接ollama使用模型,并上传文件搭建知识库,创建应用 三、搭建步骤…

本地部署DeepSeek摆脱服务器繁忙

由于图片和格式解析问题,可前往 阅读原文 最近DeepSeek简直太火了,频频霸榜热搜打破春节的平静,大模型直接开源让全球科技圈都为之震撼!再次证明了中国AI的换道超车与崛起 DeepSeek已经成了全民ai,使用量也迅速上去了…