STM32中存储区分为:随机存取存储器RAM只读存储器ROM。 
其中:

  • RAM为常说的内存,比如手机的2G内存4G内存等,就是程序跑起来的时候所占用的存储空间,特点是掉电数据丢失
  • ROM为常说的硬盘,比如手机的64G和128G等,可以简单的理解为硬盘的存储空间,特点是掉电数据不丢失,所以又叫“非易失性存储器件”。 
    • ROM又包含:EEPROM和flash。

画个嵌入式产品存储器件的思维导图如下(如有什么地方不对,恳请大神们进行指正): 

作为ROM的一份子,flash的特点自然是掉电数据不丢失。但是,flash在STM32中比较重要,程序也是保存在这个地方,所以轻易不让用户进行随意的读写,以避免不必要的问题。

而这篇博客就先简单记录一下flash的访问流程和方法(读和写),具体原理以后理解深刻了再做补充。

1、STM32 FLASH操作流程

Flash操作已经属于嵌入式设备中很底层的操作了,直接对地址进行存取,简单描述,Flash操作大致需要以下流程:

  • 1、确定要写入Flash的首地址(稍后介绍确定地址的方法)
  • 2、解锁Flash
  • 3、对Flash进行操作(写入数据)
  • 4、对Flash重新上锁

1.1 如何查找并选定要写入Flash十六进制地址值的方法

要想选定安全的Flash地址进行读写,可以根据自己的STM32 MCU型号,查找数据手册,确定FLASH的地址区段,因为起始段会存储代码,所以一定要避开起始段,以避免数据错误。(我一般是根据Flash大小计算Flash的最末尾地址,往前推一段地址空间,在这里一般不会对代码中的数据产生覆盖等影响)

我此次操作Flash使用的MCU是STM32103C8T6,所以以该型号MCU为例进行描述:

  • 在数据手册中,可以看到STM32103C8T6的flash起始地址是0x0800 0000(如下图所示),而STM32103C8T6的Flash大小为64K,可以计算出STM32103C8T6的Flash地址范围是:0x0800 0000——0x0800 FFFF(计算方法参考另一篇博客:STM32内存大小与地址的对应关系以及计算方法)。这里选取0x0800 F000作为读写操作的起始地址,对于C8T6这款MCU,操作这个起始地址应该算是很安全的范围了。 

2、Flash基本知识点

2.1 Flash容量

Flash根据容量大小可以分为以下三种:

  • 1、小容量产品:Flash大小为1-32KB(STM32F10X_LD)
  • 2、中容量产品:Flash大小为64-128KB(STM32F10X_MD)
  • 3、大容量产品:Flash大小为256KB以上(STM32F10X_HD)

2.2 ST库对Flash操作的支持

ST库中对Flash操作主要提供了以下几类操作API函数:

  • 1、Flash解锁、锁定函数

    • void FLASH_Unlock(void);//解锁函数:在对Flash操作之前必须解锁
    • void FLASH_Lock(void);//锁定函数:同理,操作完Flash之后必须重新上锁
  • 2、Flash写操作函数 
    • FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);//32位字写入函数
    • FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);//16位半字写入函数
    • FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);//用户选择字节写入函数 
      注:这里需要说明,32 位字节写入实际上是写入的两次 16 位数据,写完第一次后地址+2,这与我们前面讲解的 STM32 闪存的编程每次必须写入 16 位并不矛盾。写入 8位实际也是占用的两个地址了,跟写入 16 位基本上没啥区别。
  • 3、Flash擦除函数 
    • FLASH_Status FLASH_ErasePage(uint32_t Page_Address);
    • FLASH_Status FLASH_EraseAllPages(void);
    • FLASH_Status FLASH_EraseOptionBytes(void);
  • 4、获取Flash状态 
    • FLASH_Status FLASH_GetStatus(void); 
      获取Flash状态函数,主要是为了获取Flash的状态,以便于根据状态对Flash进行操作。该函数返回值是通过枚举类型定义的,在代码中可以看到FLASH_Status类型定义如下(具体含义看注释即可):
    • typedef enum 
                                                       { 
                                                          FLASH_BUSY = 1,        //忙 
                                                          FLASH_ERROR_PG,      //编程错误 
                                                          FLASH_ERROR_WRP,   //写保护错误 
                                                          FLASH_COMPLETE,      //操作完成 
                                                          FLASH_TIMEOUT         //操作超时 
                                                        }FLASH_Status;
  • 5、等待操作完成函数 
    • FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout); 
      注:在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。所以在每次操作之前,我们都要等待上一次操作完成这次操作才能开始。

3、OK,上干货,上代码

根据ST库提供的上述函数,我们可以自己编写Flash的读写操作代码如下:

3.1 先定义一个Flash操作的起始地址宏定义Flash状态指示标志位

#define STARTADDR 0x0800F000 //STM32F103C8T6适用

volatile FLASH_Status FLASHStatus = FLASH_BUSY; //Flash操作状态变量

3.2 编写各个读写函数

//////////////////////////////////////////////////////////////////////////////////
// Name: WriteFlashOneWord
//
// Function: 向内部Flash写入32位数据
//
// Input: WriteAddress:数据要写入的目标地址(偏移地址)
// WriteData: 写入的数据
//////////////////////////////////////////////////////////////////////////////////
void WriteFlashOneWord(uint32_t WriteAddress, uint32_t WriteData)
{
FLASH_UnlockBank1();
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); FLASHStatus = 1; //清空状态指示标志位
FLASHStatus = FLASH_ErasePage(STARTADDR);
if(FLASHStatus == FLASH_COMPLETE)
{
FLASHStatus = 1; //清空状态指示标志位
FLASHStatus = FLASH_ProgramWord(STARTADDR+WriteAddress, WriteData); //flash.c 中API函数
} FLASHStatus = 1; //清空状态指示标志位
FLASH_LockBank1();
} //////////////////////////////////////////////////////////////////////////////////
// Name: WriteFlashData
//
// Function: 向内部Flash写入数据
//
// Input: WriteAddress:数据要写入的目标地址(偏移地址)
// data[]: 写入的数据首地址
// num: 写入数据的个数
//////////////////////////////////////////////////////////////////////////////////
void WriteFlashData(uint32_t WriteAddress, uint8_t data[], uint32_t num)
{
uint32_t i = 0;
uint16_t temp = 0; FLASH_UnlockBank1(); //解锁flash
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); FLASHStatus = 1; //清空状态指示标志位
FLASHStatus = FLASH_ErasePage(STARTADDR);//擦除整页
if(FLASHStatus == FLASH_COMPLETE)//flash操作完成
{
FLASHStatus = 1; //清空状态指示标志位
for(i=0; i<num; i++)
{
temp = (uint16_t)data[i];
FLASHStatus = FLASH_ProgramHalfWord(STARTADDR+WriteAddress+i*2, temp);//写入数据
}
} FLASHStatus = 1; //清空状态指示标志位 FLASH_LockBank1(); //锁定flash
}

//////////////////////////////////////////////////////////////////////////////////
// Name: ReadFlashNBtye
//
// Function: 从内部Flash读取N字节数据
//
// Input: ReadAddress:数据地址(偏移地址)
// ReadBuf:读取到的数据存放位置指针
// ReadNum:读取字节个数
//
// Output: 读取的字节数
//////////////////////////////////////////////////////////////////////////////////
int ReadFlashNBtye(uint32_t ReadAddress, uint8_t *ReadBuf, int32_t ReadNum)
{
int DataNum = 0; ReadAddress = (uint32_t)STARTADDR + ReadAddress;
while(DataNum < ReadNum)
{
*(ReadBuf + DataNum) = *(__IO uint8_t*) ReadAddress++;
DataNum++;
} return DataNum;
} //////////////////////////////////////////////////////////////////////////////////
// Name: ReadFlashData
//
// Function: 从内部Flash读取num字节数据
//
// Input: ReadAddress:数据地址(偏移地址)
// dest_Data: 读取到的数据存放位置指针
// num: 读取字节个数
//////////////////////////////////////////////////////////////////////////////////
void ReadFlashData(uint32_t ReadAddress, uint8_t *dest_Data, uint32_t num)
{
int i = 0;
ReadAddress = (uint32_t)STARTADDR + ReadAddress;
while(i < num)
{
*(dest_Data+i) = *(__IO uint16_t*) ReadAddress;
ReadAddress += 2; i++;
}
} 来源:https://blog.csdn.net/Ace_Shiyuan/article/details/78196648

STM32的Flash的更多相关文章

  1. 关于STM32的FLASH操作【转载】

    说到STM32的FLSAH,我们的第一反应是用来装程序的,实际上,STM32的片内FLASH不仅用来装程序,还用来装芯片配置.芯片ID.自举程序等等.当然, FLASH还可以用来装数据. FLASH分 ...

  2. flash stm32的flash编写

    定义一个全局变量数组:const u8 TEXT_Buffer[]={"STM32F103 FLASH TEST"};    //u8和char* 写入到内存里会有什么区别???? ...

  3. USB Mass Storage学习笔记-STM32+FLASH实现U盘

    一.内容概述  采用STM32内部自带USB控制器外加大页NAND FLASH K9F1G08U0A实现一个128M的U盘. 1.STM32的USB控制器 STM32F103的MCU自带USB从控制器 ...

  4. STM32的FLASH ID加密

    #define FLASH_ID_OFFSET 30000    //任意定义一个数 //把地址直接减去或者加上一个数是不要程序中直接出现这个地址 volatile u32 Flash_ID_addr ...

  5. STM32内部flash存储小数——别样的C语言技巧

    今天在进行STM32内部falsh存储的时候,发现固件库历程的函数原型是这样的: 第一个是地址,在我的STM32中是2K一页的,第二个是要写入的数据. 问题就来了,存储一个小数该怎么办呢?固件库给的是 ...

  6. stm32的flash操作注意事项

    从STM32编程手册中,可以知道:在进行写或擦除操作时,不能进行代码或数据的读取操作. 比如:你在写Flash期间有接收串口数据,很有可能会丢串口数据. 因为比较耗时,所以,在写数据时,CPU不会执行 ...

  7. STM32 内部flash的读写程序

    ​ /* Base address of the Flash sectors */ #define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base ...

  8. stm32 内部flash

    嵌入式闪存 闪存存储器有主存储块和信息块组成 大容量产品主存储块最大为64K×64位,每个存储块划分为256个2K字节的页 编程和擦除闪存 闪存编程一次可以写入16位(半字) 闪存擦除操作可以按页面擦 ...

  9. 利用ST-LINK配合ST-LINK Utility 将bin文件下载到STM32的FLASH中

    文章目录 背景 1.连接ST-LINK V2与单片机 2.配置工程 3.配置ST-LINK Utility 4.烧录bin文件 背景 项目需求,要把字模文件导入到32中FLASH的指定地址,使用了ST ...

随机推荐

  1. 引用axiv文献的问题

    首先找了一下对8种常见引用格式进行说明的文章 https://blog.csdn.net/wkd22775/article/details/51798927 然后就是水木社区大神们的记录http:// ...

  2. 【转载】犀利的 oracle 注入技术

    介绍一个在web上通过oracle注入直接取得主机cmdshell的方法. 以下的演示都是在web上的sql plus执行的,在web注入时 把select SYS.DBMS_EXPORT_EXTEN ...

  3. mybatis批量插入、批量更新和批量删除

    转载 https://www.jianshu.com/p/041bec8ae6d3

  4. n阶方阵,数字从1~n^2,顺时针增大

    运行结果如下图: 解题思路:可以将这个问题分解成x个外围正方形所围成的图形,外围的正方形又可以分为4个步骤,向右依次增大.向下依次增大.向左依次增大.向上依次增大.基本思路就是如此,最关键的就是什么时 ...

  5. [HNOI2008]越狱 快速幂 逆推

    考虑越狱的情况有些复杂,不如考虑总情况减去不越狱的情况. 显然,总情况为 $m^n$ 种,不越狱的情况为 $m*(m-1)*(m-1)*(m-1)....$ 即为 $m*(m-1)^(n-1)$. 做 ...

  6. 【转载】如何学习C++

    原文地址: http://www.hankcs.com/program/cpp/how_to_learn_c__.html 1.把C++当成一门新的语言学习(和C没啥关系!真的.): 2.看<T ...

  7. C语言变量名转字符串的方法

    C语言中将变量名转换成字符串使用的是#符号,来看下边两个宏定义: #define name2str(name) (#name) #define print_val(x) printf(#x" ...

  8. 什么是面向对象以及其意义,prototpye原型

    什么是面向对象: 使用对象时,只关注对象提供的功能,不关注其内部的细节 例如:jquery 什么是对象: 对象是一个整体对外提供一些操作,比如 收音机 面向对象编程OOP的特点: 1.抽象:把主要的特 ...

  9. Qt之自定义布局管理器(QFlowLayout)

    简述 QFlowLayout,顾名思义-流布局,实现了处理不同窗口大小的布局.根据应用窗口的宽度来进行控件放置的变化. 具体实现要求不再赘述,请参考前两节内容. 简述 实现 效果 源码 实现 QFlo ...

  10. Swift,Objective-C语言性能对照測试

    原文发表于踏得网 Swift包括了非常多现代语言特性尤其是从一些脚本语言如Javascript/Ruby中汲取了营养. 此外苹果公布Swift时,使用特别选用的一些样例来宣称Swift性能对于Ojbe ...