老板说,单片机,Flash模拟EEPROM,16字节,算法轮询存储给我做到100万次的存储次数

原创 芯片之家 2025-05-07 12:15

在单片机开发中,数据存储是一个绕不开的话题。EEPROM因其非易失性存储特性,常用于保存配置参数等数据。

然而,EEPROM的擦写次数通常有限,以STM32为例,STM32L0、STM32L4自带的EEPROM一般10万次左右,而很多单片机并不内置EEPROM,这时候,利用单片机的FLASH存储器来模拟EEPROM就成为了一个高性价比的解决方案,但,FLASH的擦写次数一般在1万次左右,这个我们可以通过ST的官方数据手册看到:

1万次,在很多场景下并不够。

今天,老宇哥跟大家一起探讨,如何用单片机FLASH模拟EEPROM,并且通过算法优化实现高达100万次以上的存储次数!

我们都知道,独立的EEPROM芯片是可以直接写字节的,即使覆盖写也无须擦除,单片机的FLASH不同,STM32必须按页来擦除

手头刚好有个STM32G071RBT6的开发板,就以这个芯片做测试,后续可以很方便的移植到其它芯片上。

要求是,程序一共有16个字节的内容需要断电保存,每改变其中一个字节就需要保存一次,做到100万次的一个存储次数。

我们的核心存储算法是轮询存储,STM32G071RBT6的FLASH一共128KB,从0x08000000到0x0801FFFF,一共64页,每页2KB。

我们的数据就存储到最后一页,也就是0x0801F800到0x0801FFFF。

Flash主要是擦写次数受限,所以我们的思想是,一共16个字节,第一次就写入前16个字节,然后更新写入地址索引到第17个字节,下一次就写入17到32个字节,继续更新写入地址索引到33,以此类推。

这里还需要做的一个就是重新上电的时候,需要找到最新的索引地址,也就是如果已经写入了两次,需要自动找到索引地址为第33个字节,这个也是核心。

故,一页写满可以存储2048/16=128次,写满一页擦除一次,也就是理论存储次数能达到128 × 1万次/页 = 128万次

下面上代码,头文件flash.h

#ifndef FLASH__H
#define FLASH__H

#include "stm32g0xx_hal.h"
#include

// FLASH配置
#define FLASH_BASE_ADDR 0x0801F800 // FLASH最后一页起始地址 (128KB - 2KB)
#define PAGE_SIZE 2048             // STM32G071页面大小为2KB
#define STATE_SIZE 16             // 结构体大小(填充到24字节)

typedef struct {
    unsigned int  color;                  // 颜色
    unsigned int  seconds;                // 秒数
    unsigned char mode;                   // 模式
    unsigned char number;                 // 序号
    unsigned char padinng[5];             // 预留5
 unsigned char checksum;               // 1字节,校验和
}dataState;

extern dataState old_state;
extern dataState current_state;
void printState(dataState *state);
HAL_StatusTypeDef flash_program(unsigned int addr, unsigned char* data, unsigned int len);
void read_flash(unsigned int addr, unsigned char* data, unsigned int len);
void init_flash_addr(void);
void save_state(dataState* state);
void get_state(dataState* state);
void update_state(dataState* state);

#endif

头文件中定义了一个结构体,简单几个宏定义与函数声明,这里的结构体我们增加了一个字节的校验。

接下来看flash.c

// 初始化:查找最新有效数据
void init_flash_addr(void) {
    dataState temp_state;
    uint32_t addr = FLASH_BASE_ADDR;
    uint32_t last_valid_addr = FLASH_BASE_ADDR;
    int found_valid_data = 0;

    while (addr < FLASH_BASE_ADDR + PAGE_SIZE) {
        read_flash(addr, (uint8_t*)&temp_state, STATE_SIZE);

        // 检查是否全0xFF
        uint8_t all_ff[STATE_SIZE];
        memset(all_ff, 0xFF, STATE_SIZE);
        int is_all_ff = (memcmp(&temp_state, all_ff, STATE_SIZE) == 0);

        if (!is_all_ff && temp_state.checksum == calculate_checksum(&temp_state)) {
            last_valid_addr = addr;
            found_valid_data = 1;
            memcpy(¤t_state, &temp_state, STATE_SIZE);        
        } else {     
          break;
        }
        addr += STATE_SIZE;
    }

    flash_addr = last_valid_addr + (found_valid_data ? STATE_SIZE : 0);

    if(found_valid_data)
       printf("init first,found valid data,last_valid_addr:%X\r\n",last_valid_addr);
    else
       printf("init first,it is all ff,it is the first data\r\n");
     
    if (flash_addr > FLASH_BASE_ADDR + PAGE_SIZE)     {
        printf("init erase page 2KB\r\n");
        erase_page(FLASH_BASE_ADDR);
        flash_addr = FLASH_BASE_ADDR;
    }

    if (!found_valid_data) {
        printf("not found valid data\r\n");
        current_state.color = 100;
        current_state.seconds = 200;
        current_state.mode = 1;
        current_state.number = 1;
        current_state.checksum = calculate_checksum(¤t_state);
        __disable_irq(); 
        flash_program(FLASH_BASE_ADDR, (uint8_t*)¤t_state, STATE_SIZE);
        __enable_irq(); 
        flash_addr = FLASH_BASE_ADDR + STATE_SIZE;       
    }
    printState(¤t_state);
}

第一步,先从第一个地址读取第一个16字节,然后判断是不是全部等于0xFF,如果第一次是就证明是第一次,下一步flash_addr就不需要增加STATE_SIZE,写入地址索引就是FLASH_BASE_ADDR。

第二步,如果不全是0xFF并且校验字节通过,证明这是一组有效数据,我们先将此数据更新到current_state,但是这里还不能证明是最后一组有效数据,因为最后一组有效数据才是我们要找到的数据。

就继续检查下一组数据,直到检查到一组数据是全0xFF,证明上一组数据就是最后一组有效数据,就跳出,此时我们也就找到了最后一组有效数据的起始地址。

接着就此地址增加STATE_SIZE就是最新可以存储数据的地址索引了。

如果flash_addr超出了空间,需要复位擦除一下,正常应该不会到这一步。

第三步,如果没找到有效数据,证明是第一次,就写入默认数值并保存,更新索引。

以上,上电的时候最新的写地址索引就找好了。

接下来是保存数据save_state函数:

// 保存状态到FLASH

void save_state(dataState* state) {
    dataState last_state;

    if (flash_addr > FLASH_BASE_ADDR) {
        read_flash(flash_addr - STATE_SIZE, (uint8_t*)&last_state, STATE_SIZE);
        if (memcmp(&last_state, state, STATE_SIZE) == 0) {
          printf("数据没有变化,直接返回");
          return
        }
    }
     __disable_irq(); 
    if (flash_addr + STATE_SIZE > FLASH_BASE_ADDR + PAGE_SIZE) {
     printf("erase page 2KB\r\n");
        erase_page(FLASH_BASE_ADDR);
        flash_addr = FLASH_BASE_ADDR;   
    }
    
    state->checksum = calculate_checksum(state);
    flash_program(flash_addr, (uint8_t*)state, STATE_SIZE);
    flash_addr += STATE_SIZE; 
     __enable_irq(); 
}

函数就比较简单了,首先将要保存的数据与最新存储的数据做对比,如果没变化,就不操作;如果地址超出范围了,就先擦除整个页,更新写索引到FLASH_BASE_ADDR,接着保存数据到当下最新写地址索引即可。

重要的就是这两个函数了,其它函数都很普通没必要解释。

实际测试数据:

刚下在进去代码,最后一页全部为0XFF,然后按下5次按键,number数据每次加1存储。

下面这张是按了128次,存储了128次的结果,整个页都写满了。

最后一张是写满之后再按一次,Flash进行了擦除,并保存在第一组位置中。

整个代码逻辑有它的应用场景,也可能有一些bug,非常欢迎大家指正,代码整体老宇哥会上传到GitHub,欢迎大家留言Star!

工程源代码地址:

https://github.com/chiphome/flashMultipleErase

现在很多独立的EEPROM芯片都性价比很高了,直接IIC协议进行读写,可以按字节直接修改,轻松达到100W次的擦写次数,具体大家根据项目的应用场景,不同的要求高度进行选择。 

↑↑↑ 点击领取6层板打样券 ↑↑↑ 

往期推荐

电子漫画系列更新...(第22期)

绿米窗帘伴侣拆解,大家评论下还有没有降本空间?

玩转PD步进电机(一)硬件篇

开源一个USB PD诱骗器,基于CH224和CH32V003


评论
  • 在智能制造浪潮席卷全球的今天,MES系统(制造执行系统)作为连接企业管理层与车间生产层的“神经中枢”,其重要性日益凸显。它能有效打通信息孤岛,实现生产全流程透明化、可控化与智能化,是企业迈向“数字化智造”的核心引擎。面对众多国内厂商,如何选择最适合的MES系统?本文将为您揭晓综合实力领先的五大国内MES厂商,并提供实用的选型策略。 国内五大MES系统厂商综合实力排名 1.  盘古信息l 核心优势:盘古信息IMS智能制造系统,通过智能柔性计划排程系统,实时展
    盘古信息IMS 2025-06-24 16:47 133浏览
  • 摘要核工业安全监测对压力传感器的精度、稳定性及抗极端环境能力提出了严苛要求。石英谐振压力传感器凭借其基于石英晶体压电效应的独特工作原理,在高精度测量、抗辐照、宽温域适应性等方面展现出显著优势。本文系统解析石英谐振压力传感器在核工业中的核心应用场景,包括反应堆压力容器监测、管道泄漏检测及放射性物质运输监控,并结合晨穹石英谐振压力传感器的技术特性与实际案例,论证其在核安全领域的不可替代性。研究表明,晨穹 RPS01 系列石英绝压压力芯体通过全金属密封封装、双通道温度补偿及 AI 自校准算法
    传感器晨穹 2025-06-23 10:43 330浏览
  •  汽车轮胎质量,轮胎胎压,等等,关系到汽车行驶安全,做车人,开车人生命安全,汽车轮胎胎压关系到汽车能否正常行驶,所以时刻监测胎压各种参数非常重要,下面我们对一款胎压监测传感器产品进行拆解和分析:  胎压监测传感器产品技术数据和外观图片介绍如下:胎压监测传感器技术数据如下:电池寿命:≥6年;工作温度:-40℃--+105℃;储存温度:-40℃--+125℃;工作湿度:<90%;频率:314.95MHz&433.92MHz;压力监测范围:0-800kpa;
    开发工匠 2025-06-25 12:07 52浏览
  • 记得是1989年在中美合资企业工作时,质检部任职,一次清理寿命实验后不要了的产品时,看到即将扔掉的有好有坏的产品中一个自己经手过的还可以使用的万用表,就留了一个,拿回家使用,都正常,后来,用的少了,放在柜子里,没有拿出电池,时间长了,电池泄露,腐蚀的一塌糊涂!做了清除,这是2017年的事了。这是2017年当时拆开来的状况:用酒精做了仔细的清洗,接下来就想着到哪儿找到可以利用的电池极片呢?买也不容易,总想着废物利用,手头有其它废弃的产品上拆下了保留着的,都不适用,反正不急。正好家人我们要外出一段时
    自做自受 2025-06-24 22:57 226浏览
  • 一、引言自5G正式商用以来,全球通信产业经历了前所未有的变革。5G以其超高带宽、超低时延、海量连接的能力,使得智能制造、自动驾驶、AR/VR、物联网等新兴产业得以快速落地。但随着5G的广泛应用,其在实际部署过程中仍面临一系列挑战:网络覆盖有限、边缘性能不足、上行能力偏弱等问题日益凸显。为解决这些瓶颈并为6G的演进奠定基础,3GPP于Rel-18阶段提出了“5G Advanced(5G-A)”标准。5G-A不仅是5G的增强版本,更是迈向6G的关键过渡技术,其将深度融合通信、感知、智能、控制、安全等
    用户1750544933504 2025-06-22 21:15 8116浏览
  • 要有效预防电磁铁损坏,需要从电气防护、环境控制、操作规范和定期维护四个方面采取综合措施。在电气防护方面,要严格控制工作电压,确保其与额定值的偏差不超过±15%,对于高压电磁铁还需加装短路保护装置。同时要做好绝缘保护,shou次使用前必须测量绝缘电阻,在潮湿环境中要增加检测频率。环境控制同样重要,要根据工作环境的温湿度条件选择合适的电磁铁型号,ji端环境下要采取特殊防护措施。运输过程中要做好缓冲包装,避免机械损伤。操作时要注意控制通电时间,监测线圈温度,避免超负荷运行。多台电磁铁同时使用时,要保证
    锦正茂科技 2025-06-23 11:35 417浏览
  • 射频同轴连接器材料领域近年来取得显著突破,主要体现在导体、绝缘介质和结构件三个方面。在导体材料方面,高强度铜铍合金的应用大幅降低了信号失真,其热稳定性提升至175℃,特别适合毫米波连接器使用。纳米晶合金的引入使得外壳厚度缩减至0.35mm,同时保持you异的电磁屏蔽性能,为微型化设备提供了可能。绝缘材料方面,交联PEEK等高温聚合物可耐受300℃高温环境,PTFE微粉注塑技术则实现了超薄绝缘层的低损耗传输。复合绝缘结构的一体化成型设计不仅提升了性能,还显著缩短了生产周期。结构件创新包括轻量化航空
    锦正茂科技 2025-06-25 10:02 52浏览
  • 一、引言随着汽车新四化“电动化、网联化、智能化、共享化”全面推进,几乎每一项新技术的诞生都离不开汽车电子的身影。其中,电子控制单元(Electronic Control Unit,ECU)作为汽车电子控制系统的核心。与传统ECU相比,采用AUTOSAR(AUTomotive Open System ARchitecture,汽车开放系统架构)这种分层架构,极大降低了汽车嵌入式系统软、硬件耦合度。图1 传统软件架构与AUTOSAR架构对比此外,随着国内新能源汽车相关控制器正向开发需求的增长,AUT
    康谋 2025-06-25 10:10 71浏览
  • 电磁铁损坏通常由电气、机械、环境和操作等多方面因素共同导致。电气系统异常是zui常见的原因,包括电压超标和绝缘失效。电压偏离额定值15%以上容易造成线圈过热烧毁,而潮湿环境则会导致绝缘电阻骤降,引发击穿故障。机械结构问题也不容忽视,铁芯卡滞、异物堵塞以及超负荷运行都会加速部件磨损,影响电磁铁寿命。环境因素对电磁铁的影响主要体现在温湿度和散热条件上。高温环境会加速绝缘材料老化,潮湿则可能导致非防水型号的性能下降。此外,散热设计缺陷或连续通电时间过长都会使线圈温度异常升高。操作和维护不当同样会引发故
    锦正茂科技 2025-06-23 11:11 376浏览
  • 一、 平流层超压气球:极端环境下的监测挑战  平流层超压气球长期悬浮于18-40公里高空,持续承受-70℃至+85℃的剧烈温变、不足地面10%的低压环境(30km高度约10hPa)及强宇宙辐射。传统MEMS压阻传感器在此环境下易出现零点漂移、灵敏度衰减,导致高度控制失准或科学数据失真。  典型案例:2021年印尼弗洛雷斯海7.3级地震监测中,平流层气球需在3000公里外检测次声波引发的微帕级压力波动——相当于海平面气压的百万分之一。此场景对传感器的分辨率与抗干扰能力
    传感器晨穹 2025-06-23 13:58 484浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦