其他分享
首页 > 其他分享> > STM32实现将简单的参数保存至flash,掉电不重置

STM32实现将简单的参数保存至flash,掉电不重置

作者:互联网

STM32实现存储简单的参数进flash
工程中加入flash.cflash.h
我使用是keil5,需要添加头文件路径,将flash.h包括在内,路径中不应该有中文,同时FWlib中需要引入stm32f10x_flash.c
直接复制可能会有中文符号,比如中文空格等等,从而报错,请注意。
使用原子战舰开发板可运行。

//flash.c

#include "stm32f10x.h"
#include "sys.h"
#include "delay.h"
#include "flash.h"

/***flash解锁*****/
void STMFLASH_Unlock(void)
{
    FLASH->KEYR=FLASH_KEY1;						//写入解锁序列
    FLASH->KEYR=FLASH_KEY2;
}


//flash上锁
void STMFLASH_Lock(void)
{
    FLASH->CR|=1<<7;									//上锁
}


//得到FLASH状态
u8 STMFLASH_GetStatus(void)
{
    u32 res;

    res=FLASH->SR;
    if(res&(1<<0))return 1;							//忙
    else if(res&(1<<2))return 2;				//编程错误
    else if(res&(1<<4))return 3;				//写保护错误
    return 0;														 //操作完成
}


//等待操作完成
//time:延时长短
//返回值:状态.
u8 STMFLASH_WaitDone(u16 time)
{
    u8 res;

    do
    {
        res=STMFLASH_GetStatus();
        if(res!=1)break;								//非忙,无需等待,直接退出.
        delay_us(1);
        time--;
    } while(time);
    if(time==0)res=0xff;								//TIMEOUT
    return res;
}


//擦除页
//paddr:页地址
//返回值:执行情况
u8 STMFLASH_ErasePage(u32 paddr)

{
    u8 res=0;

    res=STMFLASH_WaitDone(0X5FFF);		//等待上次操作结束,>20ms
    if(res==0)
    {
        FLASH->CR|=1<<1;							//页擦除
        FLASH->AR=paddr;							//设置页地址
        FLASH->CR|=1<<6;							//开始擦除
        res=STMFLASH_WaitDone(0X5FFF);//等待操作结束,>20ms
        if(res!=1)										 //非忙
        {
            FLASH->CR&=~(1<<1);				//清除页擦除标志.
        }
    }
    return res;
}


//读出指定地址的半字(16位数据)
//faddr:读地址(此地址必须为2的倍数!!)
//返回值:对应数据.
u16 STMFLASH_ReadHalfWord(u32 faddr)
{
    return *(vu16*)faddr;
}


//如果使能了写   STM32_FLASH_WREN==1
#if STM32_FLASH_WREN
//不检查的写入
//WriteAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
    u16 i;
    for(i=0; i<NumToWrite; i++)
    {
        FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);
        WriteAddr+=2;//地址增加2.
			}
}
//从指定地址开始写入指定长度的数据
//WriteAddr:起始地址(此地址必须为2的倍数!!)
//pBuffer:数据指针
//NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
#if STM32_FLASH_SIZE<256
#define STM_SECTOR_SIZE 1024                                       //字节
#else
#define STM_SECTOR_SIZE    2048
#endif
u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节

void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
    u32 secpos;                                                     //扇区地址
    u16 secoff;                                                     //扇区内偏移地址(16位字计算)
    u16 secremain;                                                  //扇区内剩余地址(16位字计算)
    u16 i;
    u32 offaddr;                                                    //去掉0X08000000后的地址

    if((WriteAddr<STM32_FLASH_BASE)||(WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))
			return;//非法地址
    FLASH_Unlock();																									//解锁
    offaddr=WriteAddr-STM32_FLASH_BASE;															//实际偏移地址.
    secpos=offaddr/STM_SECTOR_SIZE;                                 //扇区地址  0~127 for STM32F103RBT6
    secoff=(offaddr%STM_SECTOR_SIZE)/2;                             //在扇区内的偏移(2个字节为基本单位.)
    secremain=STM_SECTOR_SIZE/2-secoff;                             //扇区剩余空间大小
    if(NumToWrite<=secremain)secremain=NumToWrite;									//不大于该扇区范围
    while(1)
    {
        STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容
      //校验数据  
			for(i=0; i<secremain; i++)
        {
            if(STMFLASH_BUF[secoff+i]!=0XFFFF)
							break;//需要擦除
        }
        if(i<secremain)                                            //需要擦除
        {
            FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区
            for(i=0; i<secremain; i++)															 //复制
            {
                STMFLASH_BUF[i+secoff]=pBuffer[i];
            }
            STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区
        } else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain); //写已经擦除了的,直接写入扇区剩余区间.
        if(NumToWrite==secremain)break;                            //写入结束了
        else                                                       //写入未结束
        {
            secpos++;                                              //扇区地址增1
            secoff=0;                                              //偏移位置为0
            pBuffer+=secremain;                                 //指针偏移
            WriteAddr+=secremain;                                  //写地址偏移
            NumToWrite-=secremain;                              //字节(16位)数递减
            if(NumToWrite>(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完
            else secremain=NumToWrite;                             //下一个扇区可以写完了
        }
    };
    FLASH_Lock();                                                  //上锁
}
#endif

//从指定地址开始读取指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)
{
    u16 i;
    for(i=0; i<NumToRead; i++)
    {
        pBuffer[i]=STMFLASH_ReadHalfWord(ReadAddr);               //读取2个字节.
        ReadAddr+=2;                                              //偏移2个字节
    }
}

//
//WriteAddr:起始地址
//WriteData:要写入的数据
void Test_Write(u32 WriteAddr,u16 WriteData)
{
    STMFLASH_Write(WriteAddr,&WriteData,1);                       //写入一个字
}
//flash.h

#ifndef __FLASH_H__
#define __FLASH_H__
#include "sys.h"


#define FLASH_KEY1               0X45670123
#define FLASH_KEY2               0XCDEF89AB

#define STM32_FLASH_SIZE 512	//所选STM32的FLASH容量大小(单位为K)
#define STM32_FLASH_WREN 1  	//使能FLASH写入(0,不使能;1,使能)
//

//FLASH起始地址
#define STM32_FLASH_BASE 0x08000000 	//STM32 FLASH的起始地址


void STMFLASH_Unlock(void);						//解锁
void STMFLASH_Lock(void);							//上锁
u8 STMFLASH_GetStatus(void);					//获得状态
u8 STMFLASH_WaitDone(u16 time);       //等待操作结束
u8 STMFLASH_ErasePage(u32 paddr);     //擦除页
u16 STMFLASH_ReadHalfWord(u32 faddr);	//读出半字
void STMFLASH_WriteLenByte(u32 WriteAddr,u32 DataToWrite,u16 Len);	//指定地址开始写入指定长度的数据
u32 STMFLASH_ReadLenByte(u32 ReadAddr,u16 Len);	//指定地址开始读取指定长度的数据
void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite);	//从指定地址开始写入指定长度的数据
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead);	//从指定地址开始读取指定长度的数据

//测试写入
void Test_Write(u32 WriteAddr,u16 WriteData);
#endif

在主函数中,使用

STMFLASH_Write(FLASH_SAVE_ADDR,(u16*)TEXT_Buffer,SIZE)

将 SIZE 大小的 TEXT_Buffer 保存进 flash 中地址为 FLASH_SAVE_ADDR的位置
可通过

STMFLASH_Read(FLASH_SAVE_ADDR,(u16*)datatemp,SIZE)

读取相应地址位的数据,保存至 datatemp 中。
注意:要提前查询芯片参考手册了解flash大小,STM32F103ZET6为大容量芯片,其主存储块组织如下:
STM32F103ZET6主存储块
设置FLASH 保存地址,必须为偶数,且其值要大于程序本身所占用FLASH的大小+0X08000000,保存的数据量比较少的时候,如果为了省事,可以尽量往后靠。

参考引用:https://www.cnblogs.com/lucky-3/p/11269510.html

标签:flash,void,FLASH,掉电,STM32,地址,u32,STMFLASH,u16
来源: https://blog.csdn.net/qq_37135535/article/details/121581028