STM32G070CBT6读写FLASH中的数据

news2025/3/18 12:22:05

向FLASH中写入数据函数

/*
    函数说明:向FLASH中写数据
    形参:addr-要写入数据的起始地址 data-准备写入数据  len-数据大小
    返回值:1-成功,0-失败
*/
uint8_t FlashWriteData(uint64_t addr,uint8_t data[],size_t len)
{
    uint32_t FirstPage = 0, NbOfPages = 0;      //FirstPage:第一页,NbOfPages:Number of pages to be erased,需要被擦除的页数
    uint32_t Address = 0, PageError = 0;    //Address:要写入FLASH的地址
    
    
    //FLASH解锁
    HAL_FLASH_Unlock(); //FLASH解锁
    
    //获取要擦除的第一页
    FirstPage = GetPage(FLASH_USER_START_ADDR); //获取要擦除的第一页
    
    //设置要擦除多少页
    NbOfPages = 1;  //1页,擦除一页
    
    //对要擦除结构体中的内容赋值
    EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;    //仅擦除页面
    EraseInitStruct.Page        = FirstPage;    //要擦除的起始页面
    EraseInitStruct.NbPages     = NbOfPages;    //需要擦除的页数
    
    //擦除FLASH
    if(HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)//擦除FLASH
    {
        while (1)
        {
            
        }
    }
    
    if(PageError != 0xFFFFFFFF)
    {
        return FLASH_WRITE_FAIL;
    }
    
    //对要写入FLASH的初始地址赋值
    Address = addr;  //初始地址赋值
    
    //写入数据到FLASH中
    for(int i = 0 ; i < len;i ++ ,Address+=8) 
    {
        //写入数据,写入位置Address+=8,每次+8是因为存储的类型是uint64_t,占用64bit,8字节
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, data[i]);
    }
    HAL_FLASH_Lock(); //FLASH上锁
    return FLASH_READ_SUCCESS;
}

/**
  * @brief  Gets the page of a given address 获取给定地址的页面
  * @param  Addr: Address of the FLASH Memory   FLASH中的地址
  * @retval The page of a given address
  */
static uint32_t GetPage(uint32_t Addr)  
{
  return (Addr - FLASH_BASE) / FLASH_PAGE_SIZE;
}

读取FLASH中数据函数

/*
    函数说明:读取FLASH中的数据
    形参:addr-要读取数据的起始地址 data-读出数据存放的地址  len-数据大小
    
*/
void FalshReadData(uint64_t addr,uint8_t *data,size_t len)
{
    uint32_t Address = 0;   //要读取数据的地址
    Address = addr;  //起始地址
    for(int i = 0; i < len; i++, Address+=8)
    {
        data[i] = *(__IO uint32_t*)(Address);
    }
    
}

程序汇总在一起,.c和.h文件如下:

hal_falsh.c文件

#include "hal_flash.h"


static uint32_t GetPage(uint32_t Address);

static FLASH_EraseInitTypeDef EraseInitStruct;  //FLASH擦除结构体

/*
    函数说明:向FLASH中写数据
    形参:addr-要读取数据的起始地址 data-准备写入数据  len-数据大小
    返回值:1-成功,0-失败
*/
uint8_t FlashWriteData(uint64_t addr,uint8_t data[],size_t len)
{
    uint32_t FirstPage = 0, NbOfPages = 0;      //FirstPage:第一页,NbOfPages:Number of pages to be erased,需要被擦除的页数
    uint32_t Address = 0, PageError = 0;    //Address:要写入FLASH的地址
    
    
    //FLASH解锁
    HAL_FLASH_Unlock(); //FLASH解锁
    
    //获取要擦除的第一页
    FirstPage = GetPage(FLASH_USER_START_ADDR); //获取要擦除的第一页
    
    //设置要擦除多少页
    NbOfPages = 1;  //1页,擦除一页
    
    //对要擦除结构体中的内容赋值
    EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;    //仅擦除页面
    EraseInitStruct.Page        = FirstPage;    //要擦除的起始页面
    EraseInitStruct.NbPages     = NbOfPages;    //需要擦除的页数
    
    //擦除FLASH
    if(HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)//擦除FLASH
    {
        while (1)
        {
            
        }
    }
    
    if(PageError != 0xFFFFFFFF)
    {
        return FLASH_WRITE_FAIL;
    }
    
    //对要写入FLASH的初始地址赋值
    Address = addr;  //初始地址赋值
    
    //写入数据到FLASH中
    for(int i = 0 ; i < len;i ++ ,Address+=8) 
    {
        //写入数据,写入位置Address+=8,每次+8是因为存储的类型是uint64_t,占用64bit,8字节
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, data[i]);
    }
    HAL_FLASH_Lock(); //FLASH上锁
    return FLASH_READ_SUCCESS;
}

/*
    函数说明:读取FLASH中的数据
    形参:addr-要读取数据的起始地址 data-读出数据存放的地址  len-数据大小
    
*/
void FalshReadData(uint64_t addr,uint8_t *data,size_t len)
{
    uint32_t Address = 0;   //要读取数据的地址
    Address = addr;  //起始地址
    for(int i = 0; i < len; i++, Address+=8)
    {
        data[i] = *(__IO uint32_t*)(Address);
    }
    
}


/**
  * @brief  Gets the page of a given address 获取给定地址的页面
  * @param  Addr: Address of the FLASH Memory   FLASH中的地址
  * @retval The page of a given address
  */
static uint32_t GetPage(uint32_t Addr)  
{
  return (Addr - FLASH_BASE) / FLASH_PAGE_SIZE;
}

hal_falsh.h文件

#ifndef _HAL_FLASH_H_
#define _HAL_FLASH_H_

#include "stm32g0xx_hal.h"


//FLASH写入状态
typedef enum
{
    FLASH_WRITE_FAIL,   //0,失败
    FLASH_READ_SUCCESS, //1,成功
}FLASH_WRITE_STATE;

uint8_t FlashWriteData(uint64_t addr,uint8_t data[],size_t len);
void FalshReadData(uint64_t addr,uint8_t *data,size_t len);


#endif

在主函数中,需要对FLASH写入或读取数据,直接调用这两个函数即可。

注意:

如果将串口接收到的数据直接通过这个FLASH写函数写入FALSH中的话,会出现每个数据之间间隔8个字节,如下图所示,因为串口是8位数据(1字节),而这个FLASH写函数一次性写入时64位(8字节)。

在读FLASH函数中,也是一次性读取64位(8字节)数据,所以如果串口接收数据不是特别多,间隔八个字节存储在FLASH中可以存储下,那么就可以直接调用上面的写函数和读函数进行数据的读写,最终可以得到正确的结果。

参考文章:

Keil5 HAL库操作 flash 存储数据(stm32f103c6t6),实现断电保存数据 - 耿明岩 - 博客园

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

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

相关文章

AD绘图基本操作

一、基本操作 注意&#xff1a;快捷键都要在英文模式下才能生效 1、移动 按住鼠标右键移动 2、切换桌面栅格距离 G 3、英寸和毫米 尺寸切换 Q 4、元件在3D模式下的移动 3D视角鼠标左键只起到选择元器件并移动之的功能&#xff0c; 单纯鼠标右键只能平移桌面 shift鼠…

dfs(十二)21. 合并两个有序链表 递归解决

21. 合并两个有序链表 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4]示例 2&#xff1a; 输入&#xff1a;l1 [], l2 [] …

51单片机指令系统入门

目录 基本概念讲解 一、机器指令​ 二、汇编指令​ &#xff08;一&#xff09;汇编指令的一般格式 &#xff08;二&#xff09;按字节数分类的指令 三、高级指令 总结​ 基本概念讲解 指令是计算机&#xff08;或单片机&#xff09;中 CPU 能够识别并执行的基本操作命令…

安全无事故连续天数计算,python 时间工具的高效利用

安全天数计算&#xff0c;数据系统时间直取&#xff0c;安全标准高效便捷好用。 笔记模板由python脚本于2025-03-17 23:50:52创建&#xff0c;本篇笔记适合对python时间工具有研究欲的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值&#xff1a;在于输出思考与经验&am…

如何玩DeepSeek!15分钟快速创建GIS动态数据可视化仪表盘

DeepSeek最近火遍全球&#xff0c;大家用的都用的不亦乐乎。国外呢&#xff1f;当然也是&#xff0c;最近一上YouTube、X等都是deepseek的推送。 今天介绍一下&#xff0c;我在YouTube上看到的GIS行业与DeepSeek结合的一个案例&#xff1a; 快速轻松构建交互式地图仪表盘&…

课上测试:MIRACL共享库使用测试

MIRACL(MultiprecisionIntegerandRationalArithmeticC/cLibrary)是著名的密码算法库&#xff0c;设法去官网下载安装MIRACL&#xff0c;提交安装过程截图或过程文本&#xff08;3分&#xff09;. 去github官网下载.zip文件 使用如下命令进行解压 unzip -j -aa -L MIRACL-mast…

网络编程知识预备阶段

1. OSI七层模型 OSI&#xff08;Open System Interconnect&#xff09;七层模型是一种将计算机网络通信协议划分为七个不同层次的标准化框架。每一层都负责不同的功能&#xff0c;从物理连接到应用程序的处理。这种模型有助于不同的系统之间进行通信时&#xff0c;更好地理解和…

STM32微控制器_03_GPIO原理与应用

核心内容 STM32 GPIO基本原理&#xff08;熟悉&#xff09;GPIO输出功能HAL库编程实现的应用&#xff08;重点&#xff09;GPIO输入功能HAL库编程实现的应用&#xff08;重点&#xff09; 一.STM32 GPIO基本原理 1.GPIO简介 STM32的GPIO相当于STM32的四肢&#xff0c;一个S…

零拷贝分析

kafka 零拷贝 请求 - 网口 - socket - 用户态 - 内核缓存区 - 内核态&#xff08;磁盘信息&#xff09; 磁盘 - 内核缓存区 - 用户缓存区 - 网络缓存区 零拷贝&#xff08;Zero-Copy&#xff09; 是一种高效的数据传输技术&#xff0c;旨在减少数据在内存中的拷贝次数&#x…

从Instagram到画廊:社交平台如何改变艺术家的展示方式

从Instagram到画廊&#xff1a;社交平台如何改变艺术家的展示方式 在数字时代&#xff0c;艺术家的展示方式正在经历一场革命。社交平台&#xff0c;尤其是Instagram&#xff0c;已经成为艺术家展示作品、与观众互动和建立品牌的重要渠道。本文将探讨社交平台如何改变艺术家的…

✎ 一次有趣的经历

&#x1f4c6;2025年3月17日 | 周一 | ☀️晴 &#x1f4cd;今天路过学院楼7&#xff0c;见到了满园盛开的花&#x1f33a;&#xff0c;心情瞬间明朗&#xff01; &#x1f4cc;希望接下来的日子也能像这些花一样&#xff0c;充满活力&#x1f525;&#xff01; &#x1…

快!快!快!NDPP时延测试数据公布!

在全方位认识NDPP第3期《NDPP在金融场景的应用》中&#xff0c;我们重点介绍了NDPP的典型应用场景行情解码硬件加速和策略计算加速&#xff0c;并帮助某百亿私募用户基于NDPP实现期货业务加速的案例。 近期&#xff0c;中科驭数凭借低时延产品荣获信创“大比武”行业融合赛道三…

激光雷达“开卷”2.0,头部Tier1入局

高阶智驾的普及&#xff0c;正在催生激光雷达市场的巨大潜在增长空间。 本周&#xff0c;汽车激光雷达主力供应商之一的禾赛科技发布财报&#xff0c;去年第四季度激光雷达总交付量为222,054台&#xff0c;同比增长153.1%&#xff0c;超过2023年全年。2024全年激光雷达总交付量…

力扣No.376.摆动序列

题目&#xff1a; 链接&#xff1a; https://leetcode.cn/problems/wiggle-subsequence/description/ 代码&#xff1a; class Solution {public int wiggleMaxLength(int[] nums) {int nnums.length;//状态表示:int[] fnew int[n];int[] gnew int[n];//初始化:for(int i0;i…

C语言中qsort函数的详解,以及模拟

引言 C语言中qsort函数的详解和模拟实现qsort函数&#xff0c;这里为了使用冒泡排序来模拟qsort函数 一、详解qsort函数 在 C 语言中&#xff0c;qsort 函数是一个标准库函数&#xff0c;用于对数组进行快速排序&#xff08;Quick Sort&#xff09;。它位于 <stdlib.h>…

9、讲一讲你理解的虚拟内存【中高频】

计算机早期&#xff0c;CPU 是直接操作 物理内存&#xff08;Physical Memory&#xff09;的&#xff0c;但这会导致 内存空间无法完全隔离&#xff0c;一个程序修改了另一个程序的地址空间&#xff0c;就会导致程序崩溃&#xff1b;同时物理内存大小有限&#xff0c;一旦超出这…

算法刷题整理合集(四)

本篇博客旨在记录自已的算法刷题练习成长&#xff0c;里面注有详细的代码注释以及和个人的思路想法&#xff0c;希望可以给同道之人些许帮助。本人也是算法小白&#xff0c;水平有限&#xff0c;如果文章中有什么错误或遗漏之处&#xff0c;望各位可以在评论区指正出来&#xf…

高数1.5 极限的运算法则

1. 预备知识 2.四则求极限法则 3.复合运算求极限法则

【鸿蒙开发】Hi3861学习笔记- 定时器中断

00. 目录 文章目录 00. 目录01. 概述02. 定时器相关API2.1 hi_timer_create2.2 hi_timer_start2.3 hi_timer_stop2.4 hi_timer_delete 03. 硬件设计04. 软件设计05. 实验现象06. 附录 01. 概述 定时器&#xff0c;顾名思义就是用来计时的&#xff0c;我们常常会设定计时或闹钟…

Power Apps 技术分享:画布应用使用表单控件

前言 表单控件&#xff0c;是画布应用里一个非常好用的控件&#xff0c;我们今天简单介绍下&#xff0c;如何使用这个控件。 正文 1.首先&#xff0c;我们需要有一个数据源&#xff0c;我们这里用上一篇博客新建的数据源&#xff0c;如下图&#xff1a; 2.新建一个页面&#xf…