主存储器是以页为单位划分的。stm32根据FLASH主存储块容量、页面的不同,系统存储器的不同,分为小容量、中容量、大容量、互联型,共四类产品。
要想选定安全的Flash地址进行读写,可以根据自己的STM32 MCU型号,查找数据手册,确定FLASH的地址区段,因为起始段会存储代码,所以一定要避开起始段,以避免数据错误。(我一般是根据Flash大小计算Flash的最末尾地址,往前推一段地址空间,在这里一般不会对代码中的数据产生覆盖等影响)这里采用的是STM32F103(大容量产品)写入的首地址为0x0807F800;
添加STM32 flash底层固件库文件stm32f10x_flash.c编写自己的Flash驱动库文件,如下
Flash.h #ifndef __FLASH_H#define __FLASH_H #include "sys.h" void FLASH_W(u32 add,u16 dat);u16 FLASH_R(u32 add);#endif Flash.c #include "flash.h"//FLASH写入数据void FLASH_W(u32 add,u16 dat){ //参数1:32位FLASH地址。参数2:16位数据// RCC_HSICmd(ENABLE); //打开HSI时钟 FLASH_Unlock();//解锁FLASH编程擦除控制器 FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);//清除标志位 FLASH_ErasePage(add); //擦除指定地址页 FLASH_ProgramHalfWord(add,dat); //从指定页的addr地址开始写 FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);//清除标志位 FLASH_Lock();//锁定FLASH编程擦除控制器}//FLASH读出数据u16 FLASH_R(u32 add){ //参数1:32位读出FLASH地址。返回值:16位数据u16 a;a = *(u16*)(add);//从指定页的addr地址开始读return a;} main.c #include "stm32f10x.h" //STM32头文件#include "sys.h"#include "delay.h"#include "led.h"#include "key.h" #include "flash.h" #define FLASH_START_ADDR0x0807F800//写入的起始地址int main (void){//主程序u8 key;u16 a; //定义变量//初始化程序RCC_Configuration(); //时钟设置LED_Init();//LED初始化KEY_Init();//按键初始化a = FLASH_R(FLASH_START_ADDR);//从指定页的地址读FLASH//GPIO_Write(LEDPORT,a); //直接数值操作将变量值写入LED(LED在GPIOB组的PB0和PB1上)//主循环while(1){key = KEY_Scan(0);if(key == WK_UP_PRES){a++;if(a>1)a=0;FLASH_W(FLASH_START_ADDR,a);}else{delay_ms(10);}LED0=a;}} Flash操作注意事项: 操作一定要先擦后写每页是1024个地址,起始地址0x08000000擦除操作以页为单位,写操作必须以16位宽度为单位,允许跨页写入。STM32内置Flash擦或写时,必须打开外部/内部高速振荡器。Flash可最多擦写10万次,不可死循环擦写。擦写时要避开用户程序存储的区域,否则会擦掉用户程序导致错误。擦除一页要10ms(对于1k大小的一页),比较慢,而且不能单个字节的擦写。