在我们应用开发时,经常会有一些程序运行参数需要保存,如一些修正系数。这些数据的特点是:数量少而且不需要经常修改,但又不能定义为常量,因为每台设备可能不一样而且在以后还有修改的可能。将这类数据存在指定的位置,需要修改时直接修改存储位置的数值,需要使用时则直接读取,会是一种方便的做法。考虑到这些数据量比较少,使用专门的存储单元既不经济,也没有必要,而STM32F103内部的Flash容量较大,而且ST的库函数中还提供了基本的Flash操作函数,实现起来也比较方便。
以大容量产品STM32F103VE为例,其Flash容量达到512K,可以将其中一部分用作数据存储。如下是大容量的Flash组织模式:
根据上面的Flash组织模式,我们可以根据自己的使用方便来作相应的定义。因为大容量每个扇区定义为2K,而小容量和中容量都定义为1K,所以我们做如下宏定义:
#define FLASH_SIZE 512 //所选MCU的FLASH容量大小(单位为K)
#if FLASH_SIZE<256
#define SECTOR_SIZE 1024 //字节
#else
#define SECTOR_SIZE 2048 //字节
#endif
虽然ST的库函数比较全面,但都是基本操作,为了使用方面,根据我们自己的需要对其进行再次封装。
对于读操作相对比较简单,内置闪存模块可以在通用地址空间直接寻址,就像读取变量一样。
//从指定地址开始读取多个数据
void FLASH_ReadMoreData(uint32_t startAddress,uint16_t *readData,uint16_t countToRead)
{
uint16_t dataIndex;
for(dataIndex=0;dataIndex {
readData[dataIndex]=FLASH_ReadHalfWord(startAddress+dataIndex*2);
}
}
//读取指定地址的半字(16位数据)
uint16_t FLASH_ReadHalfWord(uint32_t address)
{
return *(__IO uint16_t*)address;
}
//读取指定地址的全字(32位数据)
uint32_t FLASH_ReadWord(uint32_t address)
{
uint32_t temp1,temp2;
temp1=*(__IO uint16_t*)address;
temp2=*(__IO uint16_t*)(address+2);
return (temp2<<16)+temp1;
}
对于写操作相对来说要复杂得多,写操作包括对用户数据的写入和擦除。为了防止误操作还有写保护锁。但这些基本的操作ST的库函数已经为我们写好了,我们只需要调用即可。
STM32复位后,FPEC模块是被保护的,只有在写保护被解除后,我们才能操作相关寄存器。STM32闪存的编程每次必须写入16位,任何不是半字的操作都会造成错误。如下图是Flash写的过程:
STM32的FLASH在编程的时候,也必须要求其写入地址的FLASH 是被擦除了的(也就是其值必须是0XFFFF),否则无法写入。Flash的擦除要求必须整页擦除,所以也必须整页写入,否则可能会丢失数据。如下图是Flash页擦除过程:
如下为Flash全擦除过程
根据以上图示我们便写数据写入函数如下:
//从指定地址开始写入多个数据
void FLASH_WriteMoreData(uint32_t startAddress,uint16_t *writeData,uint16_t countToWrite)
{
if(startAddress=(FLASH_BASE+1024*FLASH_SIZE)))
{
return;//非法地址
}
FLASH_Unlock(); //解锁写保护
uint32_t offsetAddress=startAddress-FLASH_BASE; //计算去掉0X08000000后的实际偏移地址
uint32_t sectorPosition=offsetAddress/SECTOR_SIZE; //计算扇区地址,对于STM32F103VET6为0~255
uint32_t sectorStartAddress=sectorPosition*SECTOR_SIZE+FLASH_BASE; //对应扇区的首地址
FLASH_ErasePage(sectorStartAddress);//擦除这个扇区
uint16_t dataIndex;
for(dataIndex=0;dataIndex {
FLASH_ProgramHalfWord(startAddress+dataIndex*2,writeData[dataIndex]);
}
FLASH_Lock();//上锁写保护
}
在擦除之前应该将页面上的数据读取出来与要写入的数据合并,待擦除后再写入,但这样数据量很大(大容量是2K一个扇区),所以考虑到是少量数据存储,所以每次都将全部数据同时写入,简化操作,也减少数据处理量。经测试以上程序写入和读出数据均正确,可以实现内部Flash的读写操作。需要更深入了解可以参考《STM32F10xxx 闪存编程参考手册》。
关键字:STM32 内部Flash
引用地址:
STM32学习之:内部Flash
推荐阅读最新更新时间:2024-03-16 16:01
STM32开发笔记72: 使用命名空间解决类名冲突问题
单片机型号:STM32L053R8T6 在程序设计中,使用了两个类,这两个类都有引脚定义并同名,程序如下: #ifndef E32_400T20S_H_ #define E32_400T20S_H_ #include io.h #include mini_uart.h #ifdef __cplusplus extern C { class CM0:public CIO_Output { public: CM0(void); }; class CM1:public CIO_Output { public: CM1(void); }; class CE32_400t20s:public CMiniUA
[单片机]
STM32单片机的外部中断和中断控制器的特点解析
在外部中断和中断控制器中,我们首先阐述嵌套向量中断控制器(NVIC),他和处理器核的接口紧紧相连。可以实现低延时的中断处理和处理晚到的中断。主要具有以下几个特点: 1.60个可屏蔽中断通道; 2.16个可编程的优先等级; 3.低延时的异常和中断处理; 4.电源管理控制; 5.系统控制寄存器的实现。 其中每一个STM32系列芯片都会有一个产品向量表,博友们可以在相关 产品说明书中查看具体的中断问题。 接下来介绍中断优先级 在M3中有两个优先级的概念-抢占优先级和响应优先级。每一个中断源都必须指定这两种优先级。这里的中断抢占其实和89C51差不多,高中断优先级可以抢占正在进行中断处理的低中断优先级,也就是我们所说的中断嵌套。学习过
[单片机]
STM32-串口实验学习笔记
USART1_IRQHandler(void)函数: 当串口1发生了相应的中断,就会跳到改函数执行。这里设计了一个小小的接收协议(系统并未定义):通过这个函数,配合一个数组USART_RX_BUF ,一个接收状态寄存器USART_RX_STA实现对串口的数据的接收管理。USART_RX_BUF 最大值为64,也就是一次接收的数据最大不能超过64字节。USART_RX_STA是一个接收状态寄存器,其各位的定义如表所示: (注意:这个是作者设计的协议,怎样判断串口接收一组数据完毕?由于每次接收的数据长度不一样,少的就3个8位数据,多的时候有十多个,这个数据个数是不定的,且没规律的数据,有什么好的方法让它接收完整? 协议的设
[单片机]
STM32学习笔记— SPI通信异常分析
SPI,全称为 Serial Peripheral Interface(串行外设接口),是一种用于短距离通信的同步串行通信接口,主要应用在嵌入式系统。 SPI的应用场合很广,显示模组、时钟芯片、存储芯片、温度传感器等众多器件都有使用SPI接口通信。这些器件通常作为从设备,STM32作为主设备来控制它们。 STM32 SPI基础内容 绝大部分STM32芯片都有多个SPI外设,它可与外部SPI器件进行半双工/全双工同步串行通信。 1. SPI特性 三条线全双工、双线单工同步传输 支持 8 位或 16 位传输帧格式选择 支持主模式或从模式操作 可编程的时钟极性和相位 支持 MSB 或 LSB 数据顺序 支持DMA
[单片机]
STM32PWM配置详解笔记
关于STM32的PWM模式配置 ,核心代码如下,以原子的mini板STM32F103RCT6为例子 void TIM1_PWM_Init(u16 arr,u16 psc)//定时器1的PWM初始化 { /*结构体变量定义*/ GPIO_InitTypeDef GPIO_Initstrue; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitstrue; TIM_OCInitTypeDef TIM_OCInitstrue; /*-------------*/ /*开启TIM1时钟,配置对应管脚(PA8)为复用输出*/ RCC_APB2PeriphClockCmd(RCC_APB2Per
[单片机]
基于STM32的四种波形发生器设计
(1) 可以实现四种波形:正弦波、方波、三角波、锯齿波; (2) 通过按键进行选择,频率可以调整; (3) LCD液晶显示; (4)设计出来之后用Proteus软件仿真出效果; 主要硬件设备:STM32F103单片机、DAC0832数模转换芯片、矩阵键盘、LCD12864液晶屏幕。 效果图 正弦波 方波 三角波 锯齿波 单片机源程序如下: #include stm32f10x.h #include sys.h #include delay.h #include 12864.h #include key4_4.h #include timer.h //LYF #define KE
[单片机]
应用笔记 | MPU 子区话题
1. 问题起因 有人询问STM32F7 和STM32H7 系列库例程中有关MPU 配置中的下面这句加绿色下划线的代码的意思是什么?有何用? 图1、芯片存储空间MPU 背景配置 从上面截图中的红色框内代码我们不难看出,这里进行MPU 设置就是将从0 开始的4G 空间,即整个STM32 可寻址空间定义为Strongly Ordered 存储属性。且此时MPU Region 编号为0。可代码注释上又说只是将未定义的区域配置为Strongly Ordered,这未定义区域到底啥意思,该如何理解?难道跟绿色下划线标示的那行代码有关系。 那么,这句代码MPU_InitStruct.SubRegionDisable = 0x87;
[单片机]
STM32中断入口地址与中断服务函数的关系
在stm32单片机的编程时,中断函数的名称都是“xxx_Handler()”格式。这是固定的格式吗?编译的时候是怎么知道这是一个中断函数?哪里有注明? 我们知道,每个中断都是有入口地址的。程序在执行过程中遇到中断的时候,会先判断这个中断的类型,根据类型再到中断向量表中查找,找到之后,根据表中指明的地址,程序就跳到该地址开始执行代码。 ST提供的旧版本固件库(V3.0.0及以前),有提供一个stm32f10x_it.c文件,打开之后会发现里面放的都是些空函数,但是名字都是“xxx_Handler()”格式,需要使用某个中断的时候,在代码中使能该中断,并到这个文件中将中断服务函数添加上,就OK了。但是较新版本的库里没有了这个文件,用户
[单片机]