STM32之FLASH闪存实现数据掉电不丢失
利用程序存储器的剩余空间来保存掉电不丢失的用户数据,通过在程序中编程(IAP),实现程序的自我更新(串口发出指令,要更新的数据存储在flash,接受指令,将flash存储的数据发送到入口地址),后面的0x是地址,uint16_t *是指针类型,16代表以读取字符,最前面的*经转化为指针指向的内容,_IO是防止编译器优化,优化是指编译器删除无用代码,比如延迟函数的延迟就是通过空循环消耗时间,_IO会
1.什么是FLASH闪存
flash闪存是一种断电不丢失数据的存储方式。STM32F1系列的FLASH包含程序存储器(主存储器)、系统存储器和选项字节(信息块)三个部分,通过闪存存储器接口可以对程序存储器和选项字节进行擦除和编程,以下是闪存模块的分配构成,

2.有什么功能作用
在之前提到的W25Q系列的数据存储是一种常见的外挂式存储模块,在STM32单片机之flash闪存可以减少外挂存储模块。利用程序存储器的剩余空间来保存掉电不丢失的用户数据,通过在程序中编程(IAP),实现程序的自我更新(串口发出指令,要更新的数据存储在flash,接受指令,将flash存储的数据发送到入口地址)
3.工作原理及其代码模块
这是一个用flash闪存读取保存数据实验以便同学掌握


以下是一个大体框架

先介绍一下如何使用指针访问存储器,后面的0x是地址,uint16_t *是指针类型,16代表以读取字符,最前面的*经转化为指针指向的内容,_IO是防止编译器优化,优化是指编译器删除无用代码,比如延迟函数的延迟就是通过空循环消耗时间,_IO会删除空函数,就会弄巧成拙
uint16_t Data = *((__IO uint16_t *)(0x08000000));
//_IO要进行宏定义
*((__IO uint16_t *)(0x08000000)) = 0x1234;
使用指针写指定地址下的存储器:
*((__IO uint16_t *)(0x08000000)) = 0x1234;
flash基本结构

首先介绍一下闪存控制器的三个键位FPEC共有三个键值: RDPRT键 = 0x000000A5 KEY1 = 0x45670123 KEY2 = 0xCDEF89AB。在写入数据流程是,调用key1>数据读写>保存>key2>清零
这是主函数(因为STM有很多现成的库函数所以可以直接调用)
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Store.h"
#include "Key.h"
uint8_t KeyNum; //定义用于接收按键键码的变量
int main(void)
{
/*模块初始化*/
OLED_Init(); //OLED初始化
Key_Init(); //按键初始化
Store_Init(); //参数存储模块初始化,在上电的时候将闪存的数据加载回Store_Data,实现掉电不丢失
/*显示静态字符串*/
OLED_ShowString(1, 1, "Flag:");
OLED_ShowString(2, 1, "Data:");
while (1)
{
KeyNum = Key_GetNum(); //获取按键键码
if (KeyNum == 1) //按键1按下
{
Store_Data[1] ++; //变换测试数据
Store_Data[2] += 2;
Store_Data[3] += 3;
Store_Data[4] += 4;
Store_Save(); //将Store_Data的数据备份保存到闪存,实现掉电不丢失
}
if (KeyNum == 2) //按键2按下
{
Store_Clear(); //将Store_Data的数据全部清0
}
OLED_ShowHexNum(1, 6, Store_Data[0], 4); //显示Store_Data的第一位标志位
OLED_ShowHexNum(3, 1, Store_Data[1], 4); //显示Store_Data的有效存储数据
OLED_ShowHexNum(3, 6, Store_Data[2], 4);
OLED_ShowHexNum(4, 1, Store_Data[3], 4);
OLED_ShowHexNum(4, 6, Store_Data[4], 4);
}
}
介绍一下flash模块
#include "stm32f10x.h" // Device header
/**
* 函 数:FLASH读取一个32位的字
* 参 数:Address 要读取数据的字地址
* 返 回 值:指定地址下的数据
*/
uint32_t MyFLASH_ReadWord(uint32_t Address)
{
return *((__IO uint32_t *)(Address)); //使用指针访问指定地址下的数据并返回
}
/**
* 函 数:FLASH读取一个16位的半字
* 参 数:Address 要读取数据的半字地址
* 返 回 值:指定地址下的数据
*/
uint16_t MyFLASH_ReadHalfWord(uint32_t Address)
{
return *((__IO uint16_t *)(Address)); //使用指针访问指定地址下的数据并返回
}
/**
* 函 数:FLASH读取一个8位的字节
* 参 数:Address 要读取数据的字节地址
* 返 回 值:指定地址下的数据
*/
uint8_t MyFLASH_ReadByte(uint32_t Address)
{
return *((__IO uint8_t *)(Address)); //使用指针访问指定地址下的数据并返回
}
/**
* 函 数:FLASH全擦除
* 参 数:无
* 返 回 值:无
* 说 明:调用此函数后,FLASH的所有页都会被擦除,包括程序文件本身,擦除后,程序将不复存在
*/
void MyFLASH_EraseAllPages(void)
{
FLASH_Unlock(); //解锁
FLASH_EraseAllPages(); //全擦除
FLASH_Lock(); //加锁
}
/**
* 函 数:FLASH页擦除
* 参 数:PageAddress 要擦除页的页地址
* 返 回 值:无
*/
void MyFLASH_ErasePage(uint32_t PageAddress)
{
FLASH_Unlock(); //解锁
FLASH_ErasePage(PageAddress); //页擦除
FLASH_Lock(); //加锁
}
/**
* 函 数:FLASH编程字
* 参 数:Address 要写入数据的字地址
* 参 数:Data 要写入的32位数据
* 返 回 值:无
*/
void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data)
{
FLASH_Unlock(); //解锁
FLASH_ProgramWord(Address, Data); //编程字
FLASH_Lock(); //加锁
}
/**
* 函 数:FLASH编程半字
* 参 数:Address 要写入数据的半字地址
* 参 数:Data 要写入的16位数据
* 返 回 值:无
*/
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{
FLASH_Unlock(); //解锁
FLASH_ProgramHalfWord(Address, Data); //编程半字
FLASH_Lock(); //加锁
}
FLASH解锁
解锁: 复位后,FPEC被保护,不能写入FLASH_CR 在FLASH_KEYR先写入KEY1,再写入KEY2,解锁 错误的操作序列会在下次复位前锁死FPEC和FLASH_CR
加锁: 设置FLASH_CR中的LOCK位锁住FPEC和FLASH_CR
程序存储器编程


介绍一下store模块
#include "stm32f10x.h" // Device header
#include "MyFLASH.h"
#define STORE_START_ADDRESS 0x0800FC00 //存储的起始地址
#define STORE_COUNT 512 //存储数据的个数
uint16_t Store_Data[STORE_COUNT]; //定义SRAM数组
/**
* 函 数:参数存储模块初始化
* 参 数:无
* 返 回 值:无
*/
void Store_Init(void)
{
/*判断是不是第一次使用*/
if (MyFLASH_ReadHalfWord(STORE_START_ADDRESS) != 0xA5A5) //读取第一个半字的标志位,if成立,则执行第一次使用的初始化
{
MyFLASH_ErasePage(STORE_START_ADDRESS); //擦除指定页
MyFLASH_ProgramHalfWord(STORE_START_ADDRESS, 0xA5A5); //在第一个半字写入自己规定的标志位,用于判断是不是第一次使用
for (uint16_t i = 1; i < STORE_COUNT; i ++) //循环STORE_COUNT次,除了第一个标志位
{
MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, 0x0000); //除了标志位的有效数据全部清0
}
}
/*上电时,将闪存数据加载回SRAM数组,实现SRAM数组的掉电不丢失*/
for (uint16_t i = 0; i < STORE_COUNT; i ++) //循环STORE_COUNT次,包括第一个标志位
{
Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS + i * 2); //将闪存的数据加载回SRAM数组
}
}
/**
* 函 数:参数存储模块保存数据到闪存
* 参 数:无
* 返 回 值:无
*/
void Store_Save(void)
{
MyFLASH_ErasePage(STORE_START_ADDRESS); //擦除指定页
for (uint16_t i = 0; i < STORE_COUNT; i ++) //循环STORE_COUNT次,包括第一个标志位
{
MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, Store_Data[i]); //将SRAM数组的数据备份保存到闪存
}
}
/**
* 函 数:参数存储模块将所有有效数据清0
* 参 数:无
* 返 回 值:无
*/
void Store_Clear(void)
{
for (uint16_t i = 1; i < STORE_COUNT; i ++) //循环STORE_COUNT次,除了第一个标志位
{
Store_Data[i] = 0x0000; //SRAM数组有效数据清0
}
Store_Save(); //保存数据到闪存
}
更多推荐



所有评论(0)