STM32实现数据掉电存储

        在嵌入式系统中,实现数据的掉电存储通常是为了确保关键数据在系统断电或重启时不会丢失。

实现方式:数据量不大时将数据保存在片内flash中。(注意flash的读写寿命)

一、STM32内部flash简介

        STM32 芯片内部有一个 FLASH 存储器,它主要用于存储代码。
        除了使用外部的工具(如下载器)读写内部 FLASH 外, STM32 芯片在运行的时候,也能对自身 的内部 FLASH 进行读写,因此,若内部 FLASH 存储了应用程序后还有剩余的空间,我们可以把 它像外部 SPI-FLASH 那样利用起来,存储一些程序运行时产生的需要掉电保存的数据。
        由于访问内部 FLASH 的速度要比外部的 SPI-FLASH 快得多,所以在紧急状态下常常会使用内部 FLASH 存储关键记录;为了防止应用程序被抄袭,有的应用会禁止读写内部 FLASH 中的内容或者在第一次运行时计算加密信息并记录到某些区域,然后删除自身的部分加密代码,这些应用
都涉及到内部 FLASH 的操作。
内部flash的构成:
        STM32 的内部 FLASH 包含主存储器、系统存储器以及选项字节区域,它们的地址分布及大小见 表 STM32 大容量产品内部 FLASH 的构成 (在《 STM32 参考手册》中没有关于其内部 FLASH 的 说明,需要了解这些内容时,要查阅《STM32F10x 闪存编程参考手册》)。
二、STM32内部flash的读写过程
1 解锁
由于内部 FLASH 空间主要存储的是应用程序,是非常关键的数据,为了防止误操作修改了这些
内容,芯片复位后默认会给控制寄存器 FLASH_CR 上锁,这个时候不允许设置 FLASH 的控制寄
存器,从而不能修改 FLASH 中的内容。
所以对 FLASH 写入数据前,需要先给它解锁。解锁的操作步骤如下:
(1) FPEC 键寄存器 FLASH_KEYR 中写入 KEY1 = 0x45670123
(2) 再往 FPEC 键寄存器 FLASH_KEYR 中写入 KEY2 = 0xCDEF89AB
2 页擦除
在写入新的数据前,需要先擦除存储区域, STM32 提供了页(扇区)擦除指令和整个 FLASH
( 批量擦除 ) 的指令,批量擦除指令仅针对主存储区。
页擦除的过程如下:
(1) 检查 FLASH_SR 寄存器中的“忙碌寄存器位 BSY ”,以确认当前未执行任何 Flash 操作;
(2) FLASH_CR 寄存器中,将“激活页擦除寄存器位 PER ”置 1
(3) FLASH_AR 寄存器选择要擦除的页;
(4) FLASH_CR 寄存器中的“开始擦除寄存器位 STRT ”置 1 ,开始擦除;
(5) 等待 BSY 位被清零时,表示擦除完成。
3 写入数据
擦除完毕后即可写入数据,写入数据的过程并不是仅仅使用指针向地址赋值,赋值前还还需要配
置一系列的寄存器,步骤如下:
(1) 检查 FLASH_SR 中的 BSY 位,以确认当前未执行任何其它的内部 Flash 操作;
(2) FLASH_CR 寄存器中的“激活编程寄存器位 PG ”置 1
(3) 向指定的 FLASH 存储器地址执行数据写入操作,每次只能以 16 位的方式写入;
(4) 等待 BSY 位被清零时,表示写入完成。
三、STM32内部flash的验证
实现功能:创建1个变量,将变量的值写入flash中,两个按键分别控制变量的增加和减小,对百年变量的值进行修改,然后断电观察打印的变量的值是不是最后设定的值。
写入流程:检查状态–>解锁–>擦除–>写入–>上锁。
读出流程:解锁–>读取–>上锁
1. flash写入函数:
void flash_write(void)
{
		/* 解锁 */
  FLASH_Unlock();

  /* 清空所有标志位 */
  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);	

  /* 擦除 */ 
  FLASHStatus = FLASH_ErasePage(Address);
  
  /* 向内部FLASH写入数据 */
  while(FLASHStatus == FLASH_COMPLETE)   //判断是否擦除成功
  {
    FLASHStatus = FLASH_ProgramWord(Address, data);   //写入数据
  }

  /* 上锁 */	
  FLASH_Lock();	
}

2. flash读出函数:使用指针寻址读出地址的内容

//读取flash的值
FLASH_Unlock();
data = (*(__IO uint32_t*) Address); 
FLASH_Lock();

3. 整体显示代码:

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "key.h" 

uint32_t data = 1000; 	            //定义一个变量,4个字节
uint32_t Address = 0x08008000;			//记录写入的地址

typedef enum 
{
	FAILED = 0, 
  PASSED = !FAILED
} TestStatus;

FLASH_Status FLASHStatus = FLASH_COMPLETE;  //记录每次擦除的结果	
TestStatus MemoryProgramStatus = PASSED;    //记录整个测试结果

void flash_write(void)
{
		/* 解锁 */
  FLASH_Unlock();

  /* 清空所有标志位 */
  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);	

  /* 擦除 */ 
  FLASHStatus = FLASH_ErasePage(Address);
  
  /* 向内部FLASH写入数据 */
  while(FLASHStatus == FLASH_COMPLETE)   //判断是否擦除成功
  {
    FLASHStatus = FLASH_ProgramWord(Address, data);   //写入数据
  }

  /* 上锁 */	
  FLASH_Lock();	
}

//按下key1,data减小10
void key1_handler(void)
{
	data += 10;
	flash_write();

}

//按下key2,data增加10
void key2_handler(void)
{
	data -= 10;
	flash_write();

}


u16 count=0;

 int main(void)
 {	
 
	delay_init();	    	 //延时函数初始化	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	uart_init(115200);	 //串口初始化为115200
	LED_Init();		  	 //初始化与LED连接的硬件接口 
	KEY_Init();
 
	printf("\r\n STM32  flash 读写测试 \r\n");	
	
	//读取flash的值
  FLASH_Unlock();
	data = (*(__IO uint32_t*) Address); 
	FLASH_Lock();
	 	 
	while(1)
	{
		u8 t=0;	
		if(0==count%1)
		{
				t=KEY_Scan(0);		//得到键值
				switch(t)
				{
						case 1:
						{
							key1_handler();   
						}
						break;
						case 2:
						{
							key2_handler(); 
						}		
						break;			
					default:
					  break;
				}
		}
		
		if(0==count%1000)
		{
			printf("The duchu

4. 实现效果:

通过按键修改数值为:6160

重新断电重启,观察数值:

可以看到数值就是最后保存的数值。

完整代码:https://download.csdn.net/download/qq_39742246/88582982

  • 12
    点赞
  • 73
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值