不同的stm32单片机的flash大小不同,这个需要查阅芯片手册或者查看STM32CubeMX软件。

stm32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实际的flash大小,要操作flash时注意不要超出此范围。

Flash中的内容一般用来存储代码和一些定义为const的数据,和一些用户自定义的保存数据,它断电不丢失。

不同型号的单片机对flash的操作方式略有不同。下面我以自己用到的STML4R9VIT6为例贴上代码。

STM32的内部 FLASH 包含主存储器、系统存储器、 OTP 区域以及选项字节区域,具体分部查看响应的数据手册。

flash的写机制,只能将存储区域的1改为0,从0改为1只能选择擦除(页擦除或者扇区擦除),一次性擦除多个字节。

flash的读机制,只需要从flash的地址中读取数据就行了,可以字节读取,也可以按字读取。具体操作看代码。

首先需要说明的是,stm32内部flash空间包含多个用途,在保存自定义的数据时,千万不要去操作正在使用的区域。

其次,stm32是小端模式,数据的高字节保存在内存的高地址中, 而数据的低字节保存在内存的低地址中, 这种存储模式将地址的高低和数据位权有效地结合起来, 高地址部分权值高,低地址部分权值低。

//针对STM32L4R9VIT6单片机,通过地址获取所在页的函数如下

uint32_t getPage(uint32_t Address)//获取地址所在的

{

uint32_t page = 0;

if (Address < (FLASH_BASE + FLASH_BANK_SIZE))

page = (Address - FLASH_BASE) / FLASH_PAGE_SIZE;

else

page = (Address - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE;

return page;

}

//这是获取bank的代码

uint32_t GetBank(uint32_t Addr)

{

uint32_t bank = 0;

if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0)

{

if (Addr < (FLASH_BASE + FLASH_BANK_SIZE))/* No Bank swap */

bank = FLASH_BANK_1;

else

bank = FLASH_BANK_2;

}

else

{

if (Addr < (FLASH_BASE + FLASH_BANK_SIZE))/* Bank swap */

bank = FLASH_BANK_2;

else

bank = FLASH_BANK_1;

}

return bank;

}

//这是擦除函数,stm32在写数据之前,都需要先把地址中的数据擦除成0xFF,然后才能写数据

FLASH_EraseInitTypeDef EraseInitStruct;

uint8_t eraseFlash(uint32_t start_addr,uint32_t end_addr)//擦除flash

{

uint32_t BANK;

uint32_t FirstPages = 0,LastPages = 0, NbPages = 0;

uint32_t pageError = 0;

HAL_FLASH_Unlock(); //首先解锁flash

FirstPages = getPage(start_addr); //获取要擦除的第一个页

LastPages = getPage(end_addr);

NbPages = LastPages - FirstPages + 1; //获取擦除的页数量

BANK = GetBank(start_addr);//判断地址的Banks是1还是2

/* Fill EraseInit structure*/

EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;//页擦除

EraseInitStruct.Banks = BANK;

EraseInitStruct.Page = FirstPages;

EraseInitStruct.NbPages = NbPages;

if(HAL_FLASHEx_Erase(&EraseInitStruct, &pageError) != HAL_OK)

{

HAL_FLASH_Lock(); //上锁

return 2;//擦除有错误,返回2

}

//下面这些是清除标志位

__HAL_FLASH_DATA_CACHE_DISABLE();

__HAL_FLASH_INSTRUCTION_CACHE_DISABLE();

__HAL_FLASH_DATA_CACHE_RESET();

__HAL_FLASH_INSTRUCTION_CACHE_RESET();

__HAL_FLASH_INSTRUCTION_CACHE_ENABLE();

__HAL_FLASH_DATA_CACHE_ENABLE();

HAL_FLASH_Lock(); //上锁

return 0;

}

其中有个重要的东西是FLASH_EraseInitTypeDef结构体

typedef struct

{

uint32_t TypeErase; //页擦除和块擦除

uint32_t Banks; //选择擦除的bank区域

uint32_t Page; //擦除的起始页

uint32_t NbPages; //要擦除的页数

} FLASH_EraseInitTypeDef;

然后下面是写flash操作

__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);//清除flash标志位

eraseFlash(ADDR_FLASH_START,ADDR_FLASH_END);//擦除要写入的flash地址的数据

HAL_FLASH_Unlock();//解锁flash

HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, ADDR_FLASH_START, (uint64_t)data);//写数据

HAL_FLASH_Lock();//上锁

这里详细解说一下HAL_FLASH_Program()函数,函数原型如下

HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data);

/*

返回值类型如下

typedef enum

{

HAL_OK = 0x00,

HAL_ERROR = 0x01,

HAL_BUSY = 0x02,

HAL_TIMEOUT = 0x03

} HAL_StatusTypeDef;

可以用返回值是否等于HAL_OK来判断是否写入成功.

参数TypeProgram是按什么类型写入数据,不同的stm32支持的数据类型不尽相同,需要自己查看程序定义,

支持的数据类型有按字节/半字/字/双字.

参数Address是要写的flash地址,这里需要注意的是,如果要写入两次数据,第二次写入时地址需要做偏移.一个地址对应一个字节.见如下实例.

*/

//如果是按字节写入(stm32L4R9VIT6不支持这种方式)

uint8_t a=1;

uint8_t b=2;

HAL_FLASH_Program(FLASH_TYPEPROGRAMDATA_BYTE, addr, a);//第一次写数据

HAL_FLASH_Program(FLASH_TYPEPROGRAMDATA_BYTE, addr+1, b);//第二次写数据,需要地址偏1

//如果是按双字写入(stm32L4R9VIT6支持)

uint64_t a=0x12345678;

uint64_t b=0x87654321;

HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr, a);//第一次写数据

HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr+8, b);//第二次写数据,需要地址偏8

//这里不同的是,按字节写入,占用一个地址的数据,所以偏移1,按双字写入,占用8个地址的数据,所以偏移8

读数据就很简单了

//读取操作中不需要加锁和解锁,直接一句代码即可完成一次数据的读取操作

//按字节读取

uint8_t a = 0;

a = *(__IO uint8_t*)(start_addr);

//按双字读取

uint64_t a = 0;

a = *(__IO uint64_t*)(start_addr);

//这里依然要注意读取多个数据时地址偏移量的问题,字节偏移1,半字偏移2,字偏移4,双字偏移8

另外,一个比较方便的操作,是读写结构体。这种操作可以很容易的获取和保存多个数据,从而不需要数组赋值

比如我们要保存如下结构体

typedef struct _userinfo//保存的信息

{

uint8_t id;

uint8_t ip[16];//ip

uint16_t port;//端口

}USERINFO;

USERINFO User_Info = {1,"192.168.0.1",8808};

__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);

eraseFlash(ADDR_FLASH_USER_START,ADDR_FLASH_USER_END);

HAL_FLASH_Unlock();

for(uint8_t i = 0;i < sizeof(USERINFO);i+=8)

{

if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, ADDR_FLASH_USER_START+i,*((__IO uint64_t*)(&userinfo->id+i)))!= HAL_OK)//这里的数据由于是结构体,需要从里面取值,一定要以第一个成员的地址开始偏移,不能使用结构体自身的地址来偏移,否则数据会出错

{

HAL_FLASH_Lock();

return 1;

}

}

HAL_FLASH_Lock();

//为了避免数据出错,读操作一定要和写操作对应,写是按双字写,读就要按双字读,否则就需要解决大小端的问题

for(uint8_t i = 0;iid+i)) = *(__IO uint64_t*)(ADDR_FLASH_USER_START + i);//注意赋值的左边,必须要用结构体第一个成员的地址来偏移,双字偏移量是8

}

//这样获取的结构体内容,可以直接通过结构体变量或者结构体指针来访问了.

c语言 将结构体放在flash,stm32的内部flash读写操作(含结构体的保存)相关推荐

  1. 一.stm32的内部flash操作笔记

    一.在文件stm32f4xx_hal_flash_ex.h中有对应的文件标号定义如下: /*--------------------------------------- STM32F40xxx/ST ...

  2. STM32之内部FLASH例程

    #include "stm32f10x.h" #include <string.h>/* STM32 内部 FLASH 配置 */ #define STM32_FLAS ...

  3. STM32之内部FLASH原理

    不同型号的 STM32,其 FLASH 容量也有所不同,最小的只有 16K 字节,最大的则达到了 1024K 字节.市面上 STM32F1 开发板使用的芯片是 STM32F103系列,其 FLASH ...

  4. STM32系列内部Flash擦写程序

    stm32内部Flash擦写流程,对于FLash必须按页擦写,不同型号的flash页大小不同,需要根据实际修改 #define FLASH_PAGE_SIZE 2048 //定义Flash页大小,RC ...

  5. STM32 --- 使用内部FLASH存储数据

    本文记录了对一些知识点的理解.操作方法,如有错误,请务必批评指正!! 最终的测试截图: 目录​ 一.内部FLASH要点 关于地址: 关于解锁: 关于擦除: 关于写入: 二.读取数据 三.存储数据 四. ...

  6. STM32单片机内部FLASH使用注意事项

    目录 1.前言 2.STM32 F1.F4.L1系列内部FLASH分区及大小 1.STM32F1系列 2.STM32F4系列 3.STM32L1系列 3.STM32 F1.F4.L1系列内部FLASH ...

  7. STM32的内部Flash读写

    内部Flash官方手册介绍 STM官方关于stm32F103系列的芯片有一个专门介绍flash读写的手册.STM32F100xx超值型产品闪存编程手册 通过J-Link查看自己的芯片内部的flash大 ...

  8. Flash之SM25QH128M、JFM25F32A读写操作FPGA Verilog实现

    JFM25F32A Flash写操作流程如图1所示,对于Flash类型的存储器,向已经存在数据的单元写入数据时,直接写入是无法写入的,在写入之前必须先执行擦除命令,再进行写入即可:如果待写入的单元为新 ...

  9. STM32 使用内部FLASH存储读取数据

    /*FLASH读写程序*/ #define ADDR_USER_DATA 0x0801F800 //要写入地址 void Flash_RW(void) {uint32_t data = 0; uint ...

最新文章

  1. java自学入门心得体会 0.1
  2. matlab柱状图加阴影,matlab 绘制 阴影 柱状图 条形图
  3. 有驾照不等于会开车,教你开车技巧27招
  4. Mac查看Python安装路径和版本
  5. javascript实战pdf_web前端入门到实战:10分钟入门 CSS3 Animation
  6. 网易云音乐ncm文件格式转mp3格式教程
  7. Bootstrap系列---按钮
  8. 115网盘资源下载到群晖
  9. Windows查看所有的端口
  10. 收集一张英语试卷的所有单词
  11. KOOK使用过程有杂音如何解决
  12. iphone文件连接smb服务器,实用!三种iPhone与Windows电脑互传文件操作技巧,建议收藏...
  13. 手持两把锟斤拷,口中疾呼烫烫烫。脚踏千朵屯屯屯,笑看万物锘锘锘。
  14. cogs1487. 麻球繁衍
  15. 2021年全球CAN按键面板行业调研及趋势分析报告
  16. 广义表和二叉树的转换
  17. Git和SVN的区别与联系
  18. JS----hover时间延迟设置
  19. PBA简介 全称PMI-PBA
  20. 【JavaScript】JS基础学习

热门文章

  1. 联合搜索:搜索中的所有需求
  2. 智能工厂在智能制造企业中的实践应用-东杰智能
  3. Matlab fplot函数详解
  4. xxl-job任务详解
  5. GDI基础(1):绘制线条和图形
  6. OC get set 方法理解 get set方法不能同时重写
  7. JAVA基础作业练习—自定义异常之模拟ATM
  8. 3000字/16张炫酷动态图,推荐一款好用到爆的Python可视化利器
  9. 互联网晚报 | 12月8日 星期三 | 淘宝购物车上线“好友买单”功能;英超联赛正式入驻视频号;中国联通成立5G消息生态联盟...
  10. 6、13iOS项目代码例子微博、地图、淘宝、豆瓣、指南针