STM32CubeMX-Flash Hal库 内部Flash掉电存储

本文介绍了如何使用STM32F103ZET6的内部FLASH进行数据的读写操作,通过HAL库提供的函数,实现了数据的解锁、擦除、写入和锁定。文章强调了如何存储不同类型的數據,并提供了代码示例,包括`WriteFlash`、`Flash_Read`及自定义的读写函数,适用于不同场景下的数据持久化需求。
摘要由CSDN通过智能技术生成


前言

本文将介绍STM32F1的内部FLASH,通过内部FLASH实现数据读写操作。从而做到掉电存储。不同型号的STM32,其FLASH:容量也有所不同,最小的只有 16K字节,最大的则达到了1024K字节。此处我们使用的是 STM32F103ZET6,其FLASH容量为512K字节,属于大容量产品,大容量产品的闪存模块组织图如下图示
在这里插入图片描述

别的博主的文章大多都是用键盘来验证是否存储完成,但是我感觉我又不是每次都要用按键存储,且存储的东西都很单一,我这篇里面会提到如何存储各种数据。


一、HAL库提供的代码

//源文件: stm32f1xx_hal_flash.c和stm32f1xx_hal_flash_ex.c
HAL_FLASH_Unlock(void); //解锁函数
HAL_FLASH_Lock(void);   //锁定函数
HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data);   //写操作函数
HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError);   //擦除函数
HAL_FLASH_WaitForLastOperation(uint32_t Timeout);   //等待操作完成函数

这些都是本文要用到的。

cubemx不需要进行额外的配置。

二、代码编程

1.flash.c文件

首先给出整体代码随后会对每一部分进行一定的分析

#include "flash.h"
#include <stdio.h>
#include <string.h>
/*FLASH写入程序*/
void WriteFlash(uint32_t addr,uint32_t *Data,uint32_t L)
{
	uint32_t i=0;
	/* 1/4解锁FLASH*/
	HAL_FLASH_Unlock();
	/* 2/4擦除FLASH*/
	/*初始化FLASH_EraseInitTypeDef*/
	/*擦除方式页擦除FLASH_TYPEERASE_PAGES,块擦除FLASH_TYPEERASE_MASSERASE*/
	/*擦除页数*/
	/*擦除地址*/
	FLASH_EraseInitTypeDef FlashSet;
	FlashSet.TypeErase = FLASH_TYPEERASE_PAGES;
	FlashSet.PageAddress = addr;
	FlashSet.NbPages = 1;
	/*设置PageError,调用擦除函数*/
	uint32_t PageError = 0;
	HAL_FLASHEx_Erase(&FlashSet, &PageError);
	/* 3/4对FLASH烧写*/
	for(i=0;i<L;i++)
	{
		HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr+4*i, Data[i]);
	}
	/* 4/4锁住FLASH*/
	HAL_FLASH_Lock();
}

void Flash_Read(uint32_t address, uint32_t *data, uint16_t length)
{
    uint16_t i;
    for (i = 0; i < length; i++) {
        data[i] = *(__IO uint32_t *)(address + (i * 4)); // 以字为单位读取Flash
    }
}
//
DataToSave data_to_save ;//这个是要保存的数据
void my_flash_write(void)
{
	// 将数据转换为uint32_t数组以便写入Flash
	uint32_t flash_data[sizeof(DataToSave) / sizeof(uint32_t)];
	memcpy(flash_data, &data_to_save, sizeof(DataToSave));

	// 将数据写入Flash
	WriteFlash(FLASH_SAVE_ADDR, flash_data, sizeof(DataToSave) / sizeof(uint32_t));
}
int fff;//这是用来测试的
void my_flash_read(void)
{
	// 将读取到的数据转换回原始结构体
	DataToSave data_read;
	// 从Flash中读取数据
	uint32_t flash_data_read[sizeof(DataToSave) / sizeof(uint32_t)];
	Flash_Read(FLASH_SAVE_ADDR, flash_data_read, sizeof(DataToSave) / sizeof(uint32_t));
	memcpy(&data_read, flash_data_read, sizeof(DataToSave));
	// 现在,data_read.float_data 和 data_read.int_data 中分别包含从Flash中读取的float和int数据
	//读取完以后的数据可以从这里拿出!!!!
	fff=data_read.int_data[0];
}

WriteFlash函数

先解锁flash然后配置一下,再进行擦除(写入0即可),接着把需要数据写入,最后还需要上锁

Flash_Read函数

以字为单位读取Flash

my_flash_read函数

当你需要存储数据的时候直接调用这个函数就可以

my_flash_read函数

当你需要读取的时候直接调用就可以

2.flash.h文件

这里注意定义了一个结构体DataToSave,结构体里面就是你需要的存储的数据,你只需要定义好你需要存储的类型即可。

#ifndef __FLASH_H
#define __FLASH_H
#include "main.h"
void WriteFlash(uint32_t addr,uint32_t *Data,uint32_t L);
void Flash_Read(uint32_t address, uint32_t *data, uint16_t length);
#define FLASH_SAVE_ADDR  (0x08060000) // 这地方不用改直接用这个地址。
typedef struct {
    float float_data[4];
    int int_data[4];
} DataToSave;								//这个是要保存数据的结构体
extern DataToSave data_to_save ;//这个是要保存的数据
void my_flash_write(void);
void my_flash_read(void);
#endif

三、主函数编写

由于我们在.h文件中声明了外部变量extern DataToSave data_to_save ;所以当使用的时候只需要包含头文件就可以了,不用在main.c中进行变量的声明了。
由此在循环之前写这些。

	data_to_save.float_data[0] = float_variable1;
	data_to_save.float_data[1] = float_variable2;
	data_to_save.float_data[2] = float_variable3;
	data_to_save.float_data[3] = float_variable4;

	data_to_save.int_data[0] = int_variable1;
	data_to_save.int_data[1] = int_variable2;
	data_to_save.int_data[2] = int_variable3;
	data_to_save.int_data[3] = int_variable4;	

//	my_flash_write();//写入的时候就可以把这个注释取消。
	my_flash_read();//读取的时候就可以把这个注释取消。

由于在.h文件的函数my_flash_read()中有fff这个全局变量,所以当你写入以后,断电,再重新烧录读取的那个代码就可以在调试窗口中看到那个全局变量的值是你存进去的值!!!!!


总结

本文讲述了STM32CubeMX-ADC Hal库 内部Flash掉电存储
也说明了如何存储和读取不同类型数据,希望对你有所帮助。

  • 9
    点赞
  • 92
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是使用HAL库STM32L431微控制器上读写内部Flash的详细步骤和完整代码案例: 步骤1:打开STM32CubeMX并选择STM32L431微控制器。然后在“Pinout & Configuration”选项卡中配置Flash的引脚和时钟。 步骤2:在“Project Manager”选项卡中选择“Generate Code”按钮以生成代码。 步骤3:在生成的代码中打开“main.c”文件。 步骤4:在“main.c”文件中添加以下代码以初始化Flash: ```c HAL_FLASH_Unlock(); FLASH_Erase_Sector(FLASH_SECTOR_2, VOLTAGE_RANGE_3); HAL_FLASH_Lock(); ``` 这将解锁Flash并擦除扇区2。 步骤5:使用以下代码向Flash中写入数据: ```c uint32_t Address = 0x08008000; uint32_t Data = 0x12345678; HAL_FLASH_Unlock(); if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, Data) == HAL_OK) { // Data has been successfully written to Flash } HAL_FLASH_Lock(); ``` 这将在Flash的地址0x08008000处写入数据0x12345678。 步骤6:使用以下代码从Flash中读取数据: ```c uint32_t Address = 0x08008000; uint32_t Data; Data = *(uint32_t*)Address; ``` 这将从Flash的地址0x08008000处读取数据并将其存储在变量Data中。 完整代码示例: ```c #include "main.h" #include "stm32l4xx_hal.h" void SystemClock_Config(void); static void MX_GPIO_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); uint32_t Address = 0x08008000; uint32_t Data = 0x12345678; HAL_FLASH_Unlock(); if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, Data) == HAL_OK) { // Data has been successfully written to Flash } HAL_FLASH_Lock(); uint32_t ReadData = *(uint32_t*)Address; while (1) { } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.LSEState = RCC_LSE_ON; RCC_OscInitStruct.MSIState = RCC_MSI_ON; RCC_OscInitStruct.MSICalibrationValue = 0; RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { Error_Handler(); } } static void MX_GPIO_Init(void) { /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); } ``` 请注意,此示例代码仅写入和读取了一个32位数据。您可以根据自己的需求修改代码以读写更多数据。此外,还应该添加错误处理程序以在出现错误时通知用户。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值