文章目录

  • 序言:flash相关知识背景
  • 一、FLASH操作流程与操作选址
    • 1.1 FLASH操作流程
    • 1.2 如何查找并选定要写入Flash十六进制地址
  • 二、Flash基本知识点
    • 2.1 Flash容量
    • 2.2 ST库对Flash操作的支持
  • 三、OK,上干货,上代码
    • 3.1 先定义一个Flash操作的**起始地址宏定义**和**Flash状态指示标志位**
    • 3.2 编写各个读写函数

序言:flash相关知识背景

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

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

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

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

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

一、FLASH操作流程与操作选址

1.1 FLASH操作流程

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

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

1.2 如何查找并选定要写入Flash十六进制地址

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

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

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

二、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);

注:在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。所以在每次操作之前,我们都要等待上一次操作完成这次操作才能开始。

三、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();    //解锁flashFLASH_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++;}
}

STM32操作访问flash,包括写入数据到flash和从flash读取数据相关推荐

  1. MATLAB笔记:打开数据文件的三种方法+读取数据文件的两种方法+保存数据文件的两种方法

    1.打开数据文件 1.1 直接打开文件 PATHNAME = 'C:\Users\s55\Desktop\dat'; FILENAME = '\data_1.dat'; str0=strcat(PAT ...

  2. 文件操作ofstream,open,close,ifstream,fin,按照行来读取数据, fstream,iosin iosout,fio.seekg(),文件写入和文件读写,文件拷贝和文件

     1.ofstream,open,close 写入文件 #include<iostream> #include<fstream> using namespace std; ...

  3. java acr122 读取数据_使用ACR122U 从NTAG203Chip 读取数据

    1.使用NFC Pro(Android APK)读取的TAG信息: 2.连接ACR 122U之后,从设备管理处可以看出ACR122U采用标准的微软CCID和PC/SC驱动(USB CCID): 3.P ...

  4. Hibernate上传数据到数据库,从数据库读取数据到本地模板代码

    1.Hibernate上传数据到数据库: 1 //创建一个session对象 2 Session session1=HibernateTools.getSession(); 3 //Fenciresu ...

  5. python怎么从excel获取数据_python怎么从excel中读取数据?/python 读取 excle

    如何通过python快速输出数据库数据到excel 扩展库 xlrd 读excle xlwt 写excle 直接度就能下载 下载后使用 import xlrd 就可excle文件了 打开文件: xls ...

  6. java从控制台读取数据_Java不同版本从控制台读取数据方法及优缺点分析

    从JDK 5.0版本开始,能从控制台中输入数据的方法每增加一个版本号,就有一种新增的方法,这也增加了选择的种类,可以依据不同的要求来进行选择. 下面和绿茶小编一起来了解一下各个版本从控制台中读取数据的 ...

  7. 使用Matlab对PIV数据中的dat文件进行读取数据并求平均值

    该方法是借鉴 争渡.争渡博主的文章,在他的文章上略微改动,进行求解. Matlab新手对PIV数据的大量dat文件中的某一列进行平均值计算,该方法可以对整个文件夹内的dat文件进行求平均值,对于文件名 ...

  8. java读取hadoop数据_从Hadoop URL中读取数据_hadoop 数据读取_hadoop读取文件

    3.5  Java接口 在本小节,我们要深入探索Hadoop的Filesystem类:与Hadoop的文件系统交互的API. 虽然我们主要关注的是HDFS的实现DistributedFileSyste ...

  9. python读excel成数组_python读取excel数据 python怎么从excel中读取数据?

    python怎么从excel中读取数据?分母那么浩瀚,分子那么微弱.唯一就等于没有. #导入包 import xlrd #设置路径 path='C:\\Users\\jyjh\\Desktop\\da ...

最新文章

  1. mysql replace语句
  2. source insight 添加行号
  3. Kendo UI Validator 概述
  4. iOS 网络输入流提供请求体(适用于大容量内容)
  5. 【腾讯Bugly干货分享】那些年,我们一起写过的“单例模式”
  6. JavaScript实现简单计算器
  7. ylbtech-dbs:ylbtech-4,PurpleHouse(房地产楼盘销售系统)
  8. 今日恐慌与贪婪指数为25 等级转为极度恐慌
  9. think在PHP中什么意思,thinkphp框架是什么意思
  10. Linux 加密与解密应用
  11. pytorch系统学习
  12. 【BZOJ 2243】染色
  13. Android clippling使用
  14. 基于JSP的煤炭销售系统,源码下载
  15. 瑞泰设立西南医科大学口腔医学院•瑞泰口腔奖学金
  16. Single SPI、Dual SPI、Qaud SPI
  17. [市场产品部]MP部副部长(陈晓慧):餐饮公司LOGO设计与制作
  18. 电梯屏只有新潮的一半了!阿里的150亿,能否让分众扛住挑战?
  19. codeblocks:: frotran 调用dll(详细)
  20. 解决 https 无法访问

热门文章

  1. 向你汇报三件事,有意义的事儿
  2. 出行平台为了规范司机驾驶行为:按键精灵 PHP抓取司机监控摄像头视频数据并按帧截图保存,AI识别玩手机,抽烟等违规行为
  3. 漂亮国因一颗气球而疯狂给质量团队带来的启示
  4. 为什么要使用ngnix
  5. 细数流落民间的10大贵族CN域名
  6. HTML提供了许多标记,HTML提供了许多标记,下列选项中,属于HTML标记的是
  7. 怎么批量删除qq空间说说
  8. 数据结构--串、数组、广义表
  9. 计算机网络安全外文文献,计算机网络安全与防范外文翻译文献(18页)-原创力文档...
  10. Projected gradient methods for NMF