STM32:内部 Flash 写读和唯一 ID 获取
这篇技术文章介绍了STM32嵌入式开发中利用内部Flash实现数据持久存储和读取芯片唯一ID的方法。文章详细讲解了Flash存储原理,包括擦除页面(1KB)需全变为1、写入次数限制等特性。提供了完整的代码实现,包含Flash工具函数封装(MyFLASH.c)、数据存储模块(Store.c)和主程序交互逻辑(main.c),支持初始化判断、数据保存/清除和OLED显示功能。同时演示了如何读取STM3
演示视频:https://www.bilibili.com/video/BV11YdbYuEJb/?share_source=copy_web&vd_source=0e4269581b0bc60d57a80c9a27c98905
一、前言
在 STM32 的嵌入式开发中,经常会遇到掉电数据保存、设备身份识别的需求。比如:
-
保存用户配置参数,即使断电也能保留
-
为每台设备分配唯一编号,方便售后追踪
-
记录运行日志或状态,便于调试和维护
STM32 内部自带 Flash 存储区,不仅能存储程序,还能被当作数据存储区使用(类似 EEPROM)。
同时,芯片还内置了一个 96 位的 唯一 ID,这为设备身份管理提供了天然的硬件保障。
本文结合我在项目中的实测,演示如何:
-
使用内部 Flash 写入、读取、初始化数据
-
掉电后保持数据不丢失
-
读取并显示芯片唯一 ID 以及 Flash 大小
全文包含原理分析 + 完整源码
二、演示目标
-
使用最后一页 Flash 存储 16 位数据,程序掉电后仍可恢复。
-
存储区首位置放标志(
0xA5A5),判断是否已初始化。 -
支持用户按键触发数据写入或清空。
-
上电自动读取 Flash 存储区数据显示在 OLED。
-
读取 STM32 内部 Flash 容量、唯一 ID并在 OLED 上显示。
三、原理分析
1. STM32 Flash 写读基本原理(以 STM32F1 为例)
-
擦除页面(1 KB)时,所有位变为
1(即0xFF或半字0xFFFF) -
编程只能将
1写为0,不能反向 -
写入之前必须先擦除整个页,否则可能写入失败
-
Flash 擦写次数有限(一般在万次级别)
2. 唯一 ID 与 Flash 大小地址
-
Flash 容量存在地址
0x1FFFF7E0(16 位数值:闪存大小,单位 KB) -
唯一 ID 位于
0x1FFFF7E8起的 96 位区域,可读作三个段分别显示
四、源码
(1) MyFLASH.c:Flash 工具函数封装
#include "stm32f10x.h" // Device header
uint32_t MyFLASH_ReadWord(uint32_t Address)
{
return *((__IO uint32_t *)(Address));
}
uint16_t MyFLASH_ReadHalfWord(uint32_t Address)
{
return *((__IO uint16_t *)(Address));
}
uint8_t MyFLASH_ReadByte(uint32_t Address)
{
return *((__IO uint8_t *)(Address));
}
void MyFlASH_EraseAllPages(void)
{
FLASH_Unlock();
FLASH_EraseAllPages();
FLASH_Lock();
}
void MyFlASH_ErasePage(uint32_t PageAddress)
{
FLASH_Unlock();
FLASH_ErasePage(PageAddress);
FLASH_Lock();
}
void MyFLASH_ProgramWord(uint32_t Address,uint32_t Data)
{
FLASH_Unlock();
FLASH_ProgramWord(Address,Data);
FLASH_Lock();
}
void MyFLASH_ProgramHalfWord(uint32_t Address,uint16_t Data)
{
FLASH_Unlock();
FLASH_ProgramHalfWord(Address,Data);
FLASH_Lock();
}
-
使用易变存取方式读取 Flash 内容
-
写操作中使用解锁/写入/锁定流程
-
可扩展写入字(ProgramWord)函数
(2) Store.c:Flash 数据存储模块
#include "stm32f10x.h" // Device header
#include "MyFLASH.h"
#define STORE_START_ADDRESS 0x0800FC00
#define STORE_COUNT 512
uint16_t Store_Data[STORE_COUNT];
void Store_Init(void)
{
if(MyFLASH_ReadHalfWord(STORE_START_ADDRESS)!=0xA5A5)
{
MyFlASH_ErasePage(STORE_START_ADDRESS);
MyFLASH_ProgramHalfWord(STORE_START_ADDRESS,0xA5A5);
for(uint16_t i=1;i<STORE_COUNT;i++)
{
MyFLASH_ProgramHalfWord(STORE_START_ADDRESS+i*2,0x0000);
}
}
for(uint16_t i=0;i<STORE_COUNT;i++)
{
Store_Data[i]=MyFLASH_ReadHalfWord(STORE_START_ADDRESS+i*2);
}
}
void Store_Save(void)
{
MyFlASH_ErasePage(STORE_START_ADDRESS);
for(uint16_t i=0;i<STORE_COUNT;i++)
{
MyFLASH_ProgramHalfWord(STORE_START_ADDRESS+i*2,Store_Data[i]);
}
}
void Store_Clear(void)
{
for(uint16_t i=1;i<STORE_COUNT;i++)
{
Store_Data[i]=0x0000;
}
Store_Save();
}
-
使用
0xA5A5判断是否初始化,避免重复擦写 -
后续数据用
0x0000表示空值 -
可通过
Store_Save()和Store_Clear()更新 Flash 数据
(3) main.c:OLED 显示与存储交互
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Store.h"
#include "Key.h"
uint8_t KeyNum;
int main(){
OLED_Init();
Key_Init();
Store_Init();
OLED_ShowString(1,1,"Flag:");
OLED_ShowString(2,1,"Data:");
while(1){
KeyNum=Key_GetNum();
if(KeyNum==1)
{
Store_Data[1]++;
Store_Data[2]+=2;
Store_Data[3]+=3;
Store_Data[4]+=4;
Store_Save();
}
if(KeyNum==2)
{
Store_Clear();
}
OLED_ShowHexNum(1,6,Store_Data[0],4);
OLED_ShowHexNum(3,1,Store_Data[1],4);
OLED_ShowHexNum(3,6,Store_Data[2],4);
OLED_ShowHexNum(4,1,Store_Data[3],4);
OLED_ShowHexNum(4,6,Store_Data[4],4);
}
}
-
按键 1:修改数据(自增、加值等)并保存
-
按键 2:清空数据区
-
OLED 显示当前标志位与部分数据项
(4) Flash 大小与芯片唯一 ID 的读取示例
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
int main(){
OLED_Init();
OLED_ShowString(1,1,"F_SIZE:");
OLED_ShowHexNum(1,8,*((__IO uint16_t *)(0x1FFFF7E0)),4);
OLED_ShowString(2,1,"U_ID:");
OLED_ShowHexNum(2,6,*((__IO uint16_t *)(0x1FFFF7E8)),4);
OLED_ShowHexNum(2,11,*((__IO uint16_t *)(0x1FFFF7E8+0x02)),4);
OLED_ShowHexNum(3,1,*((__IO uint32_t *)(0x1FFFF7E8+0x04)),8);
OLED_ShowHexNum(4,1,*((__IO uint32_t *)(0x1FFFF7E8+0x08)),8);
while(1){
}
}
-
显示 Flash 容量(单位 KB,如 1024 或 2048 等)
-
显示芯片唯一 ID 的完整 96 位(分段 16 位 + 16 位 + 32 位 + 32 位格式)
五、实测说明
-
上电后,如果首次运行,标志位为 0xFFFF → 写入标志与清空 → OLED 显示
0xA5A5 -
按键 1 操作数据修改并保存,掉电重启依旧保持
-
按键 2 清空,OLED 显示后数据区变为 0
-
同时显示 Flash 容量和唯一 ID,方便硬件追踪与序列号显示
六、总结
本文通过示例代码讲解了STM32内部Flash的读写操作及芯片唯一ID的读取方法,帮助开发者实现数据持久存储和硬件识别,为嵌入式项目的稳定性和功能扩展提供了实用参考。
更多推荐



所有评论(0)