STM32 没有自带 EEPROM,但是 STM32 具有 IAP(在应用编程)功能,所以我们可以把它的 FLASH 当成 EEPROM 来使用。内部FLASH可以省存储芯片和IO引脚,但是需要有额外的FLASH资源。

数据保存,简单来说就是在特定的内存地址上插入一段想保存的数据, 先保存扇区(1~2K)的数据,然后擦除该片区,然后拼接插入改扇区,再把最终数据写入到扇区,因为写操作费时间也易出错,可以再写入前后分别进行和校验

● 写数据

/******************************************************************** @brief   写数据到flash中,在STM32F302中,一页为1k(2K)* @param   [buf] 写入的数据[flash_addr] 写入的数据的地址[len] 写入的数据的长度* @retval  None* @note    暂不支持跨扇区写数据, 充分验证通过,所以写入的地址需要严格控制* @runtime 78.86ms 其中主要是写数据的时间,0.86ms为两次和校验的计算2048byte~78ms、1024byte~50ms、2byte~22ms
********************************************************************/
u8 WriteDataToFlash(void *buf, u32 flash_addr, u16 len)
{/*0.关闭所有串口中断,因为串口中断没有关闭,而执行写flash操作时候,会优先执行flash操作,串口接收中断不被执行,会卡死整个系统*/DisableUsartInterrupt();
//1.校验地址和合理性                              if(flash_addr<STM32_FLASH_BASE_ADDR || (flash_addr>=STM32_FLASH_END_ADDR)) {return 1; } flashstm.addr    =  flash_addr - STM32_FLASH_BASE_ADDR ;flashstm.secPos  =  flashstm.addr / FLASH_PAGE_SIZE;                             //第几个扇区flashstm.secAddr = flashstm.secPos * FLASH_PAGE_SIZE + STM32_FLASH_BASE_ADDR;    //扇区的地址flashstm.secOff  = flash_addr - flashstm.secAddr;                                //相对于N号扇区首地址的偏移值
//2.读出扇区的数据    ReadDataFromFlash(&flashstm.buf[0], flashstm.secAddr, FLASH_PAGE_SIZE);
//3.擦除扇区的数据HAL_FLASH_Unlock();
//  printf("addr is: %X\r\nsecPos is %d\r\nsecAddr is %X\r\nflashstm.secOff is %X\r\n\r\n", flashstm.addr,flashstm.secPos,flashstm.secAddr,flashstm.secOff);FlashErase(flashstm.secAddr, 1);       //一擦就是1页  1页为1024bytes
//4.插入数据到1K的buf中for(u8 i=0; i<len; i++) {flashstm.buf[flashstm.secOff+i] = ((u8 *)buf)[i];}
//5.计算写入前的校验和for(u16 j=0; j<FLASH_PAGE_SIZE; j++) {flashstm.chucksumold += flashstm.buf[j];}
//6.写入数据到扇区 ,利用了HAL库写的,函数里,需要解锁写数据再上锁的。FlashWrite(flashstm.secAddr, (void *)flashstm.buf, FLASH_PAGE_SIZE); //48byteSHAL_FLASH_Lock();
//7.读出写入的数据到buf中ReadDataFromFlash(&flashstm.buf[0], flashstm.secAddr, FLASH_PAGE_SIZE);
//8.计算读出的数据for(u16 j=0; j<FLASH_PAGE_SIZE; j++) {flashstm.chucksumnew += flashstm.buf[j];}
//9.校验if(flashstm.chucksumold != flashstm.chucksumnew) {while (1) {/* Make LED2 blink (100ms on, 2s off) to indicate error in Erase operation */LED_ON();  HAL_Delay(100);LED_OFF();  HAL_Delay(2000);}return 2;}
//  printf("flashstm.chucksumold is: %d\r\nflashstm.chucksumnew is %d\r\n\r\n",flashstm.chucksumold,flashstm.chucksumnew);
/*10.打开所有串口中断*/EnableUsartInterrupt();return 0;
}

● 读数据:

/******************************************************************** @brief  必须为4的倍数,这bug,后续再改进* @param  PRO_INFOm: 校准参数结构体* @retval None
********************************************************************/
void ReadDataFromFlash(void *buf, u32 flash_addr, u16 len)
{u8  val = 0;u32 tmp = 0;for(int i = 0; i < len; i += 4) //48  --49{val = len-i;switch(val){//            case 1:
//                *((char *)buf + i) = *((unsigned int *)(flash_addr + i)) & 0xff;
//                break;
//            case 2:
//                *((u16 *)(char *)buf + i) = (*((unsigned int *)(flash_addr + i)) & 0xffff);
//                break;
//            case 3:
//                tmp = (*((unsigned int *)(flash_addr + i)) & 0xffffff);
//                break;default :*((unsigned int *)((char *)buf + i)) = *((unsigned int *)(flash_addr + i));break;            } }
}

● 测试代码

//test.h:
//**FLASH, 注意内存大小为4的倍数
typedef struct _stUserSave_t_
{u32            irPowerCode;u32            irFuncCode;u8             isPowerOpen;  //1:开机 0:关机
} stUserSave_t;#define STM32_FLASH_SIZE             32                  //FLASH 容量为32K
#define STM32_FLASH_BASE_ADDR        0x08000000             //STM32 FLASH起始地址
#define STM32_FLASH_END_ADDR         (STM32_FLASH_BASE_ADDR + 1024*STM32_FLASH_SIZE)
#define  LAST_SEC_FLASH_ADDR          STM32_FLASH_BASE_ADDR + 31*1024//test.c:
stUserSave_t userSave;void testWrite(void) {WriteDataToFlash(&userSave, LAST_SEC_FLASH_ADDR, sizeof(stUserSave_t));
}void testRead(void) {ReadDataFromFlash(&userSave, LAST_SEC_FLASH_ADDR, sizeof(userSave));
}

经验证,重启单片机,数据和写入的一致,并且掉电不丢失:


完整的代码如下:

● flash.c


#include "flash.h"
#include "led.h"       FLASH_T flashstm;
/******************************************************************** @brief   关闭所有串口中断* @param   None* @retval  None
********************************************************************/
static void DisableUsartInterrupt(void)
{//  USART_Cmd(USART1, DISABLE);//失能串口1
//  USART_Cmd(USART2, DISABLE);//失能串口2
    __set_PRIMASK(1);
}/******************************************************************** @brief   打开所有串口中断* @param   None* @retval  None
********************************************************************/
static void EnableUsartInterrupt(void)
{//  USART_Cmd(USART1, ENABLE);//使能串口1
//  USART_Cmd(USART2, ENABLE);//使能串口2
    __set_PRIMASK(0);
}/******************************************************************** @brief   写数据到flash中,在STM32F302中,一页为2K,本芯片K8U6共64K有32页,擦除以页为单位* @param   [buf] 写入的数据[flash_addr] 写入的数据的地址[len] 写入的数据的长度* @retval  None* @note    暂不支持跨扇区写数据,充分验证通过* @runtime 78.86ms 其中主要是写数据的时间,0.86ms为两次和校验的计算2048byte~78ms、1024byte~50ms、2byte~22ms
********************************************************************/
u8 WriteDataToFlash(void *buf, u32 flash_addr, u16 len)
{/*0.关闭所有串口中断,因为串口中断没有关闭,而执行写flash操作时候,会优先执行flash操作,串口接收中断不被执行,会卡死整个系统*/DisableUsartInterrupt();
//1.校验地址和合理性                              if(flash_addr<STM32_FLASH_BASE_ADDR || (flash_addr>=STM32_FLASH_END_ADDR)) {return 1; } flashstm.addr    =  flash_addr - STM32_FLASH_BASE_ADDR ;flashstm.secPos  =  flashstm.addr / FLASH_PAGE_SIZE; //第几个扇区flashstm.secAddr = flashstm.secPos * FLASH_PAGE_SIZE + STM32_FLASH_BASE_ADDR;    //扇区的地址flashstm.secOff  = flash_addr - flashstm.secAddr;   //相对于N号扇区首地址的偏移值
//2.读出扇区的数据    ReadDataFromFlash(&flashstm.buf[0], flashstm.secAddr, FLASH_PAGE_SIZE);
//3.擦除扇区的数据HAL_FLASH_Unlock();
//  printf("addr is: %X\r\nsecPos is %d\r\nsecAddr is %X\r\nflashstm.secOff is %X\r\n\r\n", flashstm.addr,flashstm.secPos,flashstm.secAddr,flashstm.secOff);FlashErase(flashstm.secAddr, 1);       //一擦就是1页  1页为1024bytes
//4.插入数据到1K的buf中for(u8 i=0; i<len; i++) {flashstm.buf[flashstm.secOff+i] = ((u8 *)buf)[i];}
//5.计算写入前的for(u16 j=0; j<FLASH_PAGE_SIZE; j++) {flashstm.chucksumold += flashstm.buf[j];}
//6.写入数据到扇区   FlashWrite(flashstm.secAddr, (void *)flashstm.buf, FLASH_PAGE_SIZE); //48byteSHAL_FLASH_Lock();//7.读出写入的数据到buf中ReadDataFromFlash(&flashstm.buf[0], flashstm.secAddr, FLASH_PAGE_SIZE);
//8.计算读出的数据for(u16 j=0; j<FLASH_PAGE_SIZE; j++) {flashstm.chucksumnew += flashstm.buf[j];}
//9.校验if(flashstm.chucksumold != flashstm.chucksumnew) {while (1) {/* Make LED2 blink (100ms on, 2s off) to indicate error in Erase operation */LED_ON();HAL_Delay(100);LED_OFF();HAL_Delay(2000);}return 2;}
//  printf("flashstm.chucksumold is: %d\r\nflashstm.chucksumnew is %d\r\n\r\n",flashstm.chucksumold,flashstm.chucksumnew);
/*10.打开所有串口中断*/EnableUsartInterrupt();return 0;
}/******************************************************************** @brief  必须为4的倍数* @param  PRO_INFOm: 校准参数结构体* @retval None
********************************************************************/
void ReadDataFromFlash(void *buf, u32 flash_addr, u16 len)
{u8  val = 0;u32 tmp = 0;for(int i = 0; i < len; i += 4) {        val = len-i;switch(val) {//            case 1:
//                *((char *)buf + i) = *((unsigned int *)(flash_addr + i)) & 0xff;
//                break;
//            case 2:
//                *((u16 *)(char *)buf + i) = (*((unsigned int *)(flash_addr + i)) & 0xffff);
//                break;
//            case 3:
//                tmp = (*((unsigned int *)(flash_addr + i)) & 0xffffff);
//                break;default :*((unsigned int *)((char *)buf + i)) = *((unsigned int *)(flash_addr + i));break;            } }
}/******************************************************************** @brief  从addr地址开始,连续擦除page_num页* @param  addr:要擦除页的首地址@param  page_num:页数 * @retval 1
********************************************************************/
int FlashErase(unsigned int addr, unsigned int page_num)
{int i;uint32_t PAGEError = 0;FLASH_EraseInitTypeDef EraseInitStruct;EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;  //页擦除EraseInitStruct.PageAddress = addr;EraseInitStruct.NbPages     = page_num;   //默认就是1页if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK) {while (1) {/* Make LED2 blink (100ms on, 2s off) to indicate error in Erase operation */LED_ON();HAL_Delay(100);LED_OFF();HAL_Delay(2000);}}return 1;
}/******************************************************************** @brief  从addr地址开始,连续写入len个字节,len应当是4的倍数,利用HAL库* @param  addr:要写入的首地址@param  buf: 数据源的首地址@param  len: 写入的长度* @retval 1
********************************************************************/
//flashstm.secAddr,     (void *)flashstm.buf, FLASH_PAGE_SIZE
int FlashWrite(unsigned int addr, void *buf, unsigned int len)
{for(int i = 0; i < len; i+=4) {if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr + i, *((unsigned int *)((char *)buf + i))) != HAL_OK) {while (1) {/* Make LED2 blink (100ms on, 2s off) to indicate error in Write operation */LED_ON();HAL_Delay(100);LED_OFF();HAL_Delay(2000);}}}return 1;
}

● flash.h

#ifndef __FLASH_H
#define __FLASH_H#include "system.h"#define STM32_FLASH_SIZE             32                   //FLASH 容量为32K
#define STM32_FLASH_BASE_ADDR        0x08000000     //STM32 FLASH起始地址
#define STM32_FLASH_END_ADDR         (STM32_FLASH_BASE_ADDR + 1024*STM32_FLASH_SIZE)#define    LAST_SEC_FLASH_ADDR                  STM32_FLASH_BASE_ADDR + 31*1024
#define    USRE_FLASH_ADDR                       LAST_SEC_FLASH_ADDRtypedef struct
{u8   buf[1024]; //1024 2048 因SRAM不够只用512Ku32  addr; //实际的偏移地址u8   secPos; //第几个扇区u32  secAddr; //扇区起始地址u32  secOff; //偏移值u8  chucksumold;u8  chucksumnew;
}FLASH_T;u8 WriteDataToFlash(void *buf, u32 flash_addr, u16 len);
void ReadDataFromFlash(void *buf, u32 flash_addr, u16 len);
int FlashErase(unsigned int addr, unsigned int page_num);
int FlashWrite(unsigned int addr, void *buf, unsigned int len);#endif //_FLASH_H_

需要复杂点的可以直接移植正点原子的,它考虑了各种跨扇区的操作,但是阅读性没那么舒服~

STM32内部FLASH使用简易流程相关推荐

  1. STM32内部flash详解(1)

    STM32 内部FLAsh概述 今天说一下STM32中的内部flash. 当我们把写好的代码下载MCU中,这个代码时存放在flash中的.当芯片重启复位上电后,会通过内核对flash进行代码的加载运行 ...

  2. map文件分析 stm32_使用STM32内部Flash额外的空间来存储数据

    本次分享关于STM32内部FLASH的笔记. STM32 芯片内部的 FLASH 存储器,主要用于存储我们代码.如果内部FLASH存储完我们的代码还有剩余的空间,那么这些剩余的空间我们就可以利用起来, ...

  3. STM32 内部Flash读写 程序源码 [已验证]

    目录 STM32 内部Flash带缓存读写 程序源码 0 Macro 1.Flash_Erase 2. Flash_Read_Byte 3.Flash_Write_NoBuffer 4.Flash_W ...

  4. stm32内部Flash读写

    文章目录 1.stm32内部flash介绍 2.读写驱动编写 3.源码 上篇文章讲到了STM32来驱动外部flah的操作,flash真是好东西啊,内存大,能存的东西多,这样我们就可以用它来做一些大点的 ...

  5. 读写STM32内部flash读写代码

    读写STM32内部flash读写代码 由于老师的要求,所以写了一份读写STM32内部FLASH的代码,这样的话就可以把STM32里面没有用来保存代码段的部分用来存储数据了. 由于<stm32fl ...

  6. STM32CubeMX系列|STM32内部FLASH

    STM32内部FLASH 1. 内部FLASH简介 之前的文章中介绍过STM32F1利用SPI与外部FLASH(W25QXX芯片)通讯的例程,本例程将介绍STM32F1的内部FLASH,通过内部FLA ...

  7. 【STM32】STM32内部flash编程和擦除

    一直在想设计OTA方案,使用开源的软件工具实现OTA,因为涉及较多,暂未完成... 关于OTA设计,可以先参考IAP:[IAP]IAP在线升级流程,涉及对芯片BootLoader和flash操作:升级 ...

  8. STM32内部Flash的使用

    简介 STM32内部自带不同大小的Flash,其主要功能是保存已经编译完成的代码.在实际的产品中为了节约成本如果有需要存储少量的数据会选择存放在内部Flash中. 注:STM32对于Flash 大小的 ...

  9. c语言flash里能存文件吗,STM32内部FLASH打包读写

    最近做到的项目在运行需要把一组uint8_t(unsigned char)的数据进行掉电储存,想到单片机STM32f030f4p6内部flash可以直接由程序操作,写了以下代码用于uint8_t数据打 ...

  10. STM32内部Flash读写问题

    STM32Flash读写之Flash调试技巧 文章目录 1.先熟悉所用MCU的Flash存储大小以及扇区地址 2.Flsah写之前为什么要先擦除 3.Flash擦除长时间占用CPU 4.实测Flash ...

最新文章

  1. [UWP]了解模板化控件(5):VisualState
  2. ASP.NET Core开发之HttpContext
  3. 通宵加班、猝死频发,但仍建议你不要轻易买保险
  4. Python基础第27天
  5. fedora7 常用软件安装
  6. scala rest_使用路标的Scala和Java的Twitter REST API
  7. LeetCode:二进制手表【401】
  8. python全栈开发网络_Python 全栈开发:网络编程
  9. CentOS禁用root用户远程登录
  10. 一年突破3亿游戏安装量 小米游戏双发行模式助力游戏开发者
  11. centos,apache运维经验
  12. AI智能写作指导:Wordhero AI写作英语长文流程
  13. linux 之 查看文件夹大小(du),Linux查看文件或文件夹大小du命令
  14. findfont: Font family ['DejaVu Sans'] not found. Falling back to DejaVu Sans.
  15. 【Java】学习日记 Day20
  16. 穿越火线老是卡在正在连接服务器,修复cf经常提示网络出现异常与服务器断开连接的方法...
  17. OCJP(1Z0-851) 模拟题分析(四)
  18. 实验室信息化管理系统创新管理模式
  19. windows无法打开添加打印机_如何删除打印机
  20. 高德地图坐标转换为具体地址

热门文章

  1. 读后感系列2:《看见》柴静(一)
  2. word之无法插入公式,公式图标灰色
  3. 两个分数化简比怎么化_分数化简比的方法什么,六年级上求比值与化简比的对比...
  4. C语言社区水电费管理系统,C语言水电费管理系统.doc
  5. 面试计算机有什么优势和不足,面试时如何介绍自己的优缺点
  6. 电脑自动跳转加QQ好友html,自动添加QQ好友.html
  7. 复旦退休教授直播间吸烟被举报:此前因违规吸烟被学校要求做检讨
  8. ps计算机设置,ps标尺怎么调出来
  9. 【板栗糖GIS】如何给文件夹批量重命名
  10. 深度学习 —— 偏差与方差