在此篇文章前,写过另外一篇关于STM32内部FLash读写的文章——点击跳转。之前那篇文章的代码是移植于正点原子的,比较复杂,因为它考虑了写入字节大于1K或2K时需要换页写入的问题。但是在实际使用过程中,我们需要写入的数据常常远小于1K,因此本篇文章的代码适用于写入小量数据使用(即小于1K或2K——取决于单片机最小写入页)。
本次代码是借鉴了CubeMX固件库官方例程的代码,经过和上一篇代码结合整理,比较简约易懂。
1.关于CubeMX的配置
本次实验的选择的是STM32F103C8T6
CubeMX选择配置一下时钟树,开启串口1即可
2.具体代码如下
(1)Flash.h
本次例程选择写入的页是第62页到第64页,可自定义修改
#ifndef _FLASH_H_
#define _FLASH_H_
#include "main.h"
#include "stm32f1xx_hal_flash_ex.h"
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
#define STM32_FLASH_SIZE 64 //所选STM32的FLASH容量大小(单位为K)
#if STM32_FLASH_SIZE < 256 //设置扇区大小
#define STM_SECTOR_SIZE 1024 //1K字节
#else
#define STM_SECTOR_SIZE 2048 //2K字节
#endif
#define STM32_FLASH_BASE 0x08000000 //STM32 FLASH的起始地址
#define FLASH_USER_START_ADDR ( STM32_FLASH_BASE + STM_SECTOR_SIZE * 62 ) //写Flash的地址,这里从第62页开始
#define FLASH_USER_END_ADDR ( STM32_FLASH_BASE + STM_SECTOR_SIZE * 64 ) //写Flash的地址,这里以第64页结束
void Flash_Erase(void);
void Flash_Write(u32 *pBuffer,u32 NumToWrite);
void Flash_Read(u32 *pBuffer,u32 NumToRead);
#endif
(2)Flash.c
#include "Flash.h"
#include <stdio.h>
static FLASH_EraseInitTypeDef EraseInitStruct;
u32 PAGEError = 0;
/**********************************************************************************
* 函数功能: 页擦除
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
void Flash_Erase(void)
{
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.PageAddress = FLASH_USER_START_ADDR;
EraseInitStruct.NbPages = (FLASH_USER_END_ADDR - FLASH_USER_START_ADDR) / STM_SECTOR_SIZE;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
{
HAL_FLASH_Lock();
printf(" Error...1\r\n");
Error_Handler( );
}
}
/**********************************************************************************
* 函数功能: 数据写入
* 输入参数: 写入数据缓存数组指针、写入数据数
* 返 回 值: 无
* 说 明:无
*/
void Flash_Write(u32 *pBuffer,u32 NumToWrite)
{
u16 i=0;
u32 Address = FLASH_USER_START_ADDR;
HAL_FLASH_Unlock(); //解锁
Flash_Erase( ); //先擦除
//再写入
printf(" 擦除完成,准备写入......\r\n");
while ( (Address < FLASH_USER_END_ADDR) && (i<NumToWrite) )
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, pBuffer[i]) == HAL_OK)
{
Address = Address + 4; //地址后移4个字节
i++;
}
else
{
printf(" Error...2\r\n");
Error_Handler( );
}
}
HAL_FLASH_Lock(); //上锁
}
/**********************************************************************************
* 函数功能: 数据读取
* 输入参数: 读取数据缓存数组指针、读出数据数
* 返 回 值: 无
* 说 明:无
*/
void Flash_Read(u32 *pBuffer,u32 NumToRead)
{
u16 i=0;
u32 Address = FLASH_USER_START_ADDR;
while ( (Address < FLASH_USER_END_ADDR) && (i<NumToRead) )
{
pBuffer[i++]= *(__IO u32 *)Address;
Address = Address + 4; //地址后移4个字节
}
}
(3)main.c
①添加头文件、变量声明
#include "Flash.h"
#include <stdio.h>
u8 TEXT_Buffer[]={"STM32_HAL_FLASH_TEST_"};//要写入到STM32 FLASH的字符串数组
#define SIZE sizeof(TEXT_Buffer) //数组长度
u8 datatemp[SIZE]; //Flash读取缓存数组
u8 *p=datatemp; //数组指针
②main函数
测试时添加在while循环前即可,此段代码不需要重复运行。实现的操作为运行一次写入函数后,运行一次读取函数。
printf(" 串口OK!......\r\n");
HAL_Delay(2000);
Flash_Write((u32*)TEXT_Buffer,(SIZE+3)/4); //强制转换后写入数组长度向上取整(SIZE+3)/4
printf(" 写入成功,准备读取......\r\n");
Flash_Read((u32*)datatemp,(SIZE+3)/4);
printf(" 读取成功......写入内容为:\r\n");
printf(" %s\r\n",p);