STM32 使用 Flash 存储数据时的一种管理办法

发布者:数据之翼最新更新时间:2016-08-26 来源: eefocus关键字:STM32  Flash  存储数据  管理办法 手机看文章 扫描二维码
随时随地手机看文章
使用 stm32f3xx,需要存储一些掉电不丢失的校准信息,查阅手册得知:1、stm32 写 flash 的长度是固定的 16bit;2、擦除时必须整块(2Kbytes)擦除,给出某 flash 块内的地址,执行擦除命令就可以了;3、参考手册给出了最小擦写次数为 10K。
以上三点对于实际使用时的影响,首先,写数据必须以 16bit 为单位,很多 32bit 长度的值就不能直接使用类似 A = B 的赋值语句的方法去操作了,可以统一转化为指向 16bit 无符号整形值的指针来处理。举例,有一个 32bit 长度的 float 变量 v_float,要存入地址为 (FLASH_ADDRESS)的 flash中:
 
#define FLASH_ADDRESS (0x0803F800)
 
 if(FLASH->CR &= FLASH_CR_LOCK) //解锁flash
 { 
FLASH->KEYR = (FLASH_KEYR_FKEYR & FLASH_KEY1);
FLASH->KEYR = (FLASH_KEYR_FKEYR & FLASH_KEY2); 
while(FLASH->CR & FLASH_CR_LOCK); 
 }
while(FLASH->SR &= FLASH_SR_BSY);
FLASH->CR |= FLASH_CR_PG; //功能选择,写flash
{
*( (unsigned short *)(FLASH_ADDRESS) + 0 ) = *( (unsigned short *)(& v_float) + 0 );
*( (unsigned short *)(FLASH_ADDRESS) + 1 ) = *( (unsigned short *)(& v_float) + 1 );
}
FLASH->CR &= ~FLASH_CR_PG;
FLASH->CR |= FLASH_CR_LOCK; //锁flash
 
如果需要读取写入到 flash 中的浮点数到 ram 中的变量 a_float,使用如下语句:
 
a_float = *((float *) FLASH_ADDRESS);
 
这样,写入和读取就完成了,下面是擦除,按照参考手册的流程来就可以了:
 
if(FLASH->CR &= FLASH_CR_LOCK) //解锁flash
{
FLASH->KEYR = (FLASH_KEYR_FKEYR & FLASH_KEY1);
FLASH->KEYR = (FLASH_KEYR_FKEYR & FLASH_KEY2);
while(FLASH->CR & FLASH_CR_LOCK);
}
while(FLASH->SR &= FLASH_SR_BSY); //Wait until flash not busy
FLASH->CR |= FLASH_CR_PER; //功能选择,擦除页
 
FLASH->AR = FLASH_ADDRESS; //写入flash地址
 
FLASH->CR |= FLASH_CR_STRT; //开始擦除
while(FLASH->SR &= FLASH_SR_BSY); //等待
 
if(FLASH->SR &= FLASH_SR_EOP)
{
FLASH->SR |= FLASH_SR_EOP; //重置EOP
}
FLASH->CR &= ~FLASH_CR_PER;
FLASH->CR |= FLASH_CR_LOCK; //锁flash
 
以上代码会擦除 FLASH_ADDRESS 所在的整个 flash 页。
 
实现少量数据的读写和擦除操作以后,下一步要开始组织 flash 中存储的数据,这样以后阅读和修改都更为方便,我使用类似 stm32 官方寄存器配置文件的方式,用结构体来组织。假设我要将某个人的个人信息储存在 flash 中地址为(FLASH_ADDRESS)的位置,包括:姓名、性别、身高、体重,代码如下:
 
typedef struct //构造结构体
{
unsigned char name[16];
unsigned char male;
float height;
float weight;
}Personal_Information_TypeDef;
 
#define FLASH_ADDRESS (0x0803F800) //flash地址
#define Personal_Data ( (Personal_Information_TypeDef *) FLASH_ADDRESS )
 
以上代码在起始地址为(FLASH_ADDRESS)的 flash 中,定义了用于储存个人信息的结构体指针 Personal_Data,也就是说 Personal_Data 这个指针的值就是 FLASH_ADDRESS,只不过除了这个指针的值以外,我们还定义了这个指针所指向的数据的结构。要读出这些储存于 flash 中的值,使用读取结构体指针的方式:
 
Temp_variable = Personal_Data -> male;
 
写 flash 的时候,因为每次只能写 16bit,所以除了 short 类型以外,类似 int 和 float 这种 32bit 的数据,都要取地址强制转化为 16bit 类型后再取值最后写入,方法类似一开始的 float 类型数据写入 flash 的操作。我为了操作方便,在 ram 中建立了一个和 flash 内结构相同的结构体,每次需要写入 flash 的时候,就将 ram 中结构体的所有值全部写入 flash:
 
typedef struct //构造结构体
{
unsigned char name[16];
unsigned char male;
float height;
float weight;
}Personal_Information_TypeDef;
 
#define Length (5) //结构体总长(16bit单位)
#define FLASH_ADDRESS  (0x0803F800) //flash地址
#define Personal_Data ( (Personal_Information_TypeDef *) FLASH_ADDRESS )
Personal_Information_TypeDef  Personal_Data_Mirror; //ram中的结构体
 
/* 写入过程 */
(unsigned short *)WriteAddress = (unsigned short *)Personal_Data;
(unsigned short *)ReadAddress = (unsigned short *)(&Personal_Data_Mirror);
 
if(FLASH->CR &= FLASH_CR_LOCK) //解锁flash
{
FLASH->KEYR = (FLASH_KEYR_FKEYR & FLASH_KEY1);
FLASH->KEYR = (FLASH_KEYR_FKEYR & FLASH_KEY2);
while(FLASH->CR & FLASH_CR_LOCK);
}
FLASH->CR |= FLASH_CR_PG; //功能选择,写入
while(Length > 0)
{
*WriteAddress = *ReadAddress; //Ram to Flash program, 16bit each
while(FLASH->SR &= FLASH_SR_BSY);
WriteAddress += 1;
ReadAddress += 1;
Length -= 1;
}
FLASH->CR &= ~FLASH_CR_PG; //Clear PG bit
FLASH->CR |= FLASH_CR_LOCK; //Lock flash
 
以上的写入过程之前,必须确保要写入的 flash 位置首先擦除过,或者说要保证要写入数据的地方的值为0xFFFFFFFF,否则无法写入,硬件会有标志位来报错。
这样以结构体为单位擦写 flash 的好处是,如果需要修改要储存的数据数量或类型的话,只需要修改结构体定义就可以了,而且用结构体来管理变量,程序的可读性较好。
 
最后就是 flash 的擦写次数问题了,最少10k次的擦写寿命,对于某些需要频繁更新的内容还是太少了,比EEPROM 通常的 100k 少了一个数量级,而且即使是改动一个变量,也必须首先擦除整个 flash 块,更加速了 flash 的消耗。但是 stm32 的 flash 容量还是不错的,动辄 256Kbytes,所以我们可以用容量换寿命,
具体思路就是不要在同一个地址重复擦写,写的时候不停的变换地址,写满以后再擦除。比如,需要储存的结构体长度为 20x16bit,那么一个 2Kbytes 的 flash 页就可以储存 50 个相同的结构体,那么执行完 50 次写操作以后才需要执行一次擦除操作,flash 的使用寿命随之大为延长。
还是以储存一个结构体为例说明如何实现这种储存方式,首先定义结构体,除了你需要储存的数据以外,还要额外增加一个变量,用于识别你当前读写的 flash 地址:
 
typedef struct //构造结构体
{
unsigned char flag; //用于识别当前地址的标记
unsigned char name[16];
unsigned char male;
float height;
float weight;
}Personal_Information_TypeDef;
 
#define Length (6) //结构体总长(16bit单位)
#define FLASH_ADDRESS  (0x0803F800) //flash地址
#define Personal_Data ( (Personal_Information_TypeDef *) FLASH_ADDRESS )
Personal_Information_TypeDef  Personal_Data_Mirror; //ram中的结构体
 
这部分除了结构体中增加了一个标记(flag)变量以外,其它部分相同,但是思想上,我们其实是在 flash 中定义了一个结构体数组,只不过没有使用通常的[]来遍历数组变量,取而代之的是直接使用指针来操作。每次写入时,将 flag 变量固定写为 0x00。需要读取 flash 数据时,就可以根据标记变量 flag 的值找到最新的 flash 数据地址:
 
#define FLASH_ADDRESS_MAX; //最大偏移量,防止跨区块操作
unsigned short FlashAddress_Offset = 0; //用于储存flash地址偏移量的临时变量
while( (Personal_Data + FlashAddress_Offset) -> flag == 0x00)
{
FlashAddress_Offset += 1;
if( (FlashAddress_Offset + FlashAddress_Offset) > MAX_OFFSET)
{
break;
}
}
 
找到写有数据的 flash 地址以后,后继的写操作和读操作和单个结构体的操作相似,写的地址变为:(Personal_Data + FlashAddress_Offset)
读的地址是:
(Personal_Data + FlashAddress_Offset - 1)
具体实现时要注意,结构体的长度要算好,不能出现两个结构体交叉写入;擦除 flash 需要时间,此间最好不进行需要读取 flash 的操作。

关键字:STM32  Flash  存储数据  管理办法 引用地址:STM32 使用 Flash 存储数据时的一种管理办法

上一篇:用STM32对编码开关实现精确计数
下一篇:S3C2410中断寄存器

推荐阅读最新更新时间:2024-03-16 15:07

STM32F103RCT6之FLASH读写操作
一、STM32F103的FLASH简介 1、如图所示,STM32F103内部FLASH存储区分为三个区域:主存储区、信信息块和闪存存储器接口寄存器。 储存储区是我们读写FLASH的主要的存储区,MCU程序以及一些需要掉电保存的数据都是存储在这个区域的。 信息快:程序启动代码被存储在这部分。 最后的寄存器则是FLASH读写需要配置的一些寄存器位置。 主存储器的起始位置0x08000000,除去程序占用的空间,剩余部分就可以作为数据保存的区域了,所以在利用内部FLASH存储数据的时候,一定不要占用程序本身所占用的空间,否则会导致死机。 主存储器一共256页,每页2K字节长度。 二、FLASH存储寄存器的配置 1、FPEC键寄存器
[单片机]
STM32F103RCT6之<font color='red'>FLASH</font>读写操作
STM32单片机内存管理器代码
本代码适用于无操作系统的STM32单片机开发,功能强大。 可申请到地址空间连续的不同大小的内存空间,且用户接口简单,使用方便。 memory.h: memory.c:
[单片机]
STM32仿真按键控制led灯源程序
刚学习 课上做的一个小实验 保存一下 在GPIOC口,分别接有一个开关K1和两个指示灯LED1和LED2。两个灯一亮一灭,每按一下开关,两个灯的亮灭状态翻。 单片机源程序如下: #include stm32f10x.h #include led.h #include key.h int main(void) { u8 key; LED_Init(); KEY_Init(); while(1){ key = KEY_Scan(); switch(key){ case WK_UP: LED1=!LED1, LED0=!LED0; break; }
[单片机]
<font color='red'>STM32</font>仿真按键控制led灯源程序
大容量NAND Flash TC58DVG02A1FT00在嵌入式系统中的应用
1 NAND和NOR flash 目前市场上的flash从结构上大体可以分为AND、NAND、NOR和DiNOR等几种。其中NOR和DiNOR的特点为相对电压低、随机读取快、功耗低、稳定性高,而NAND和AND的特点为容量大、回写速度快、芯片面积小。现在,NOR和NAND FLASH的应用最为广泛,在CompactFlash、Secure Digital、PC Cards、MMC存储卡以及USB闪盘存储器市场都占用较大的份额。 NOR的特点是可在芯片内执行(XIP,eXecute In Place),这样应该程序可以直接在flash内存内运行,不必再把代码读到系统RAM中。NOR的传输效率很高,但写入和探险速度较低。而NAND结
[单片机]
大容量NAND <font color='red'>Flash</font> TC58DVG02A1FT00在嵌入式系统中的应用
stm32的VCC/VDD/VSS/VEE/VBAT的区别
先看一下stm32vet6的引脚图吧 电路设计以及PCB制作中,经常碰见电源符号:VCC、 VDD、VEE、VSS,他们具有什么样的关系那? 一、解释   VCC:C=circuit 表示电路的意思, 即接入电路的电压   VDD:D=device 表示器件的意思, 即器件内部的工作电压;   VSS:S=series 表示公共连接的意思,通常指电路公共接地端电压 VEE:负电压供电;场效应管的源极(S) 二、说明 1、对于数字电路来说,VCC是电路的供电电压,VDD是芯片的工作电压(通常Vcc Vdd),VSS是接地点。 例如,对于ARM单片机来说,其供电电压VCC一般为5V,一般经过稳压模块将其转换为单片机
[单片机]
<font color='red'>stm32</font>的VCC/VDD/VSS/VEE/VBAT的区别
STM32 外部中断 易出错总结
一:触发方式 STM32的外部中断是通过边沿来触发的,不支持电平触发; 二:外部中断分组 STM32的每一个GPIO都能配置成一个外部中断触发源,STM32通过根据引脚的序号不同将众多中断触发源分成不同的组,比如:PA0,PB0,PC0,PD0,PE0,PF0,PG0为第一组,那么依此类推,我们能得出一共有16组,STM32规定,每一组中同时只能有一个中断触发源工作,那么,最多工作的也就是16个外部中断。 STM32分组和对应中断处理函数分配: 三:外部中断的配置过程 l配置触发源-GPIO 触发源为通过GPIO端口输入,所以,要配置GPIO的模式,输入方式,输入方式有以下几种: 1.GPIO_Mo
[单片机]
如何在STM32串口通信程序中使用printf发送数据
在STM32串口通信程序中使用printf发送数据,非常的方便。可在刚开始使用的时候总是遇到问题,常见的是硬件访真时无法进入main主函数,其实只要简单的配置一下就可以了。 下面就说一下使用printf需要做哪些配置。 有两种配置方法: 一、对工程属性进行配置,详细步骤如下 1、首先要在你的main 文件中 包含“stdio.h” (标准输入输出头文件)。 2、在main文件中重定义函数 如下: // 发送数据 int fputc(int ch, FILE *f) { USART_SendData(USART1, (unsigned char) ch);// USART1 可以换成 USART2 等 while (!(US
[单片机]
如何在<font color='red'>STM32</font>串口通信程序中使用printf发送<font color='red'>数据</font>
TMS320C6713的FLASH引导装载系统设计
前言 DSP系统的引导装载是指在系统加电时,由DSP将一段存储在外部非易失性存储器中的代码移植到内部高速存储器单元并执行的过程。这种方式即可利用外部存储单元扩展DSP本身有限的ROM资源,又能充分发挥DSP内部资源的高速效能。因此,引导装载系统的性能直接关系到整个DSP系统的可靠性和处理速度,是DSP系统设计中必不可少的重要环节。在装载系统中,外部非易失性存储器和DSP的性能尤为重要。FLASH是一种高密度、非易失性的电可擦写存储器,而且单位存储比特的价格比传统EPROM要低。为此,本文介绍了TMS320C6713浮点DSP芯片和SST公司提供的SST39VF400A FIASH存储器的基本特点,给出了使用该FLASH存储器设计
[应用]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved