向FLASH中写入数据函数
/*
函数说明:向FLASH中写数据
形参:addr-要写入数据的起始地址 data-准备写入数据 len-数据大小
返回值:1-成功,0-失败
*/
uint8_t FlashWriteData(uint64_t addr,uint8_t data[],size_t len)
{
uint32_t FirstPage = 0, NbOfPages = 0; //FirstPage:第一页,NbOfPages:Number of pages to be erased,需要被擦除的页数
uint32_t Address = 0, PageError = 0; //Address:要写入FLASH的地址
//FLASH解锁
HAL_FLASH_Unlock(); //FLASH解锁
//获取要擦除的第一页
FirstPage = GetPage(FLASH_USER_START_ADDR); //获取要擦除的第一页
//设置要擦除多少页
NbOfPages = 1; //1页,擦除一页
//对要擦除结构体中的内容赋值
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; //仅擦除页面
EraseInitStruct.Page = FirstPage; //要擦除的起始页面
EraseInitStruct.NbPages = NbOfPages; //需要擦除的页数
//擦除FLASH
if(HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)//擦除FLASH
{
while (1)
{
}
}
if(PageError != 0xFFFFFFFF)
{
return FLASH_WRITE_FAIL;
}
//对要写入FLASH的初始地址赋值
Address = addr; //初始地址赋值
//写入数据到FLASH中
for(int i = 0 ; i < len;i ++ ,Address+=8)
{
//写入数据,写入位置Address+=8,每次+8是因为存储的类型是uint64_t,占用64bit,8字节
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, data[i]);
}
HAL_FLASH_Lock(); //FLASH上锁
return FLASH_READ_SUCCESS;
}
/**
* @brief Gets the page of a given address 获取给定地址的页面
* @param Addr: Address of the FLASH Memory FLASH中的地址
* @retval The page of a given address
*/
static uint32_t GetPage(uint32_t Addr)
{
return (Addr - FLASH_BASE) / FLASH_PAGE_SIZE;
}
读取FLASH中数据函数
/*
函数说明:读取FLASH中的数据
形参:addr-要读取数据的起始地址 data-读出数据存放的地址 len-数据大小
*/
void FalshReadData(uint64_t addr,uint8_t *data,size_t len)
{
uint32_t Address = 0; //要读取数据的地址
Address = addr; //起始地址
for(int i = 0; i < len; i++, Address+=8)
{
data[i] = *(__IO uint32_t*)(Address);
}
}
程序汇总在一起,.c和.h文件如下:
hal_falsh.c文件
#include "hal_flash.h"
static uint32_t GetPage(uint32_t Address);
static FLASH_EraseInitTypeDef EraseInitStruct; //FLASH擦除结构体
/*
函数说明:向FLASH中写数据
形参:addr-要读取数据的起始地址 data-准备写入数据 len-数据大小
返回值:1-成功,0-失败
*/
uint8_t FlashWriteData(uint64_t addr,uint8_t data[],size_t len)
{
uint32_t FirstPage = 0, NbOfPages = 0; //FirstPage:第一页,NbOfPages:Number of pages to be erased,需要被擦除的页数
uint32_t Address = 0, PageError = 0; //Address:要写入FLASH的地址
//FLASH解锁
HAL_FLASH_Unlock(); //FLASH解锁
//获取要擦除的第一页
FirstPage = GetPage(FLASH_USER_START_ADDR); //获取要擦除的第一页
//设置要擦除多少页
NbOfPages = 1; //1页,擦除一页
//对要擦除结构体中的内容赋值
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; //仅擦除页面
EraseInitStruct.Page = FirstPage; //要擦除的起始页面
EraseInitStruct.NbPages = NbOfPages; //需要擦除的页数
//擦除FLASH
if(HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)//擦除FLASH
{
while (1)
{
}
}
if(PageError != 0xFFFFFFFF)
{
return FLASH_WRITE_FAIL;
}
//对要写入FLASH的初始地址赋值
Address = addr; //初始地址赋值
//写入数据到FLASH中
for(int i = 0 ; i < len;i ++ ,Address+=8)
{
//写入数据,写入位置Address+=8,每次+8是因为存储的类型是uint64_t,占用64bit,8字节
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, data[i]);
}
HAL_FLASH_Lock(); //FLASH上锁
return FLASH_READ_SUCCESS;
}
/*
函数说明:读取FLASH中的数据
形参:addr-要读取数据的起始地址 data-读出数据存放的地址 len-数据大小
*/
void FalshReadData(uint64_t addr,uint8_t *data,size_t len)
{
uint32_t Address = 0; //要读取数据的地址
Address = addr; //起始地址
for(int i = 0; i < len; i++, Address+=8)
{
data[i] = *(__IO uint32_t*)(Address);
}
}
/**
* @brief Gets the page of a given address 获取给定地址的页面
* @param Addr: Address of the FLASH Memory FLASH中的地址
* @retval The page of a given address
*/
static uint32_t GetPage(uint32_t Addr)
{
return (Addr - FLASH_BASE) / FLASH_PAGE_SIZE;
}
hal_falsh.h文件
#ifndef _HAL_FLASH_H_
#define _HAL_FLASH_H_
#include "stm32g0xx_hal.h"
//FLASH写入状态
typedef enum
{
FLASH_WRITE_FAIL, //0,失败
FLASH_READ_SUCCESS, //1,成功
}FLASH_WRITE_STATE;
uint8_t FlashWriteData(uint64_t addr,uint8_t data[],size_t len);
void FalshReadData(uint64_t addr,uint8_t *data,size_t len);
#endif
在主函数中,需要对FLASH写入或读取数据,直接调用这两个函数即可。
注意:
如果将串口接收到的数据直接通过这个FLASH写函数写入FALSH中的话,会出现每个数据之间间隔8个字节,如下图所示,因为串口是8位数据(1字节),而这个FLASH写函数一次性写入时64位(8字节)。
在读FLASH函数中,也是一次性读取64位(8字节)数据,所以如果串口接收数据不是特别多,间隔八个字节存储在FLASH中可以存储下,那么就可以直接调用上面的写函数和读函数进行数据的读写,最终可以得到正确的结果。
参考文章: