当前位置: 首页 > news >正文

STM32单片机入门学习——第49节: [15-2] 读写内部FLASH读取芯片ID

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做!

本文写于:2025.04.29

STM32开发板学习——第49节: [15-2] 读写内部FLASH&读取芯片ID

  • 前言
  • 开发板说明
  • 引用
  • 解答和科普
  • 一、FLASH 硬件
  • 问题
  • 总结

前言

   本次笔记是用来记录我的学习过程,同时把我需要的困难和思考记下来,有助于我的学习,同时也作为一种习惯,可以督促我学习,是一个激励自己的过程,让我们开始32单片机的学习之路。
   欢迎大家给我提意见,能给我的嵌入式之旅提供方向和路线,现在作为小白,我就先学习32单片机了,就跟着B站上的江协科技开始学习了.
   在这里会记录下江协科技32单片机开发板的配套视频教程所作的实验和学习笔记内容,因为我之前有一个开发板,我大概率会用我的板子模仿着来做.让我们一起加油!
   另外为了增强我的学习效果:每次笔记把我不知道或者问题在后面提出来,再下一篇开头作为解答!

开发板说明

   本人采用的是慧净的开发板,因为这个板子是我N年前就买的板子,索性就拿来用了。另外我也购买了江科大的学习套间。
   原理图如下
1、开发板原理图
在这里插入图片描述
2、STM32F103C6和51对比
在这里插入图片描述
3、STM32F103C6核心板
在这里插入图片描述

视频中的都用这个开发板来实现,如果有资源就利用起来。另外也计划实现江协科技的套件。

下图是实物图
在这里插入图片描述

引用

【STM32入门教程-2023版 细致讲解 中文字幕】
还参考了下图中的书籍:
STM32库开发实战指南:基于STM32F103(第2版)
在这里插入图片描述
数据手册
在这里插入图片描述

解答和科普

一、FLASH 硬件

在这里插入图片描述
工程结构:建立两个底层模块,最底层计划叫MyFLASH,在这里实现闪存最基本的3个功能,也就是读取、擦除和编程,之后,在此模块之上,在建一个模块,叫Store,主要实现参数数据的读写和存储管理,因为最终应用层想要实现的功能是,任意读写参数,并且这些参数是掉电不丢失的,至于你存在什么地方,怎么擦除,采用什么读写策略,这些不是应用层所关心的,所以Store会定义一个SRAM数组,需要掉电不丢失的参数,就写到SRAM数组里,之后调用保持的函数,这个SRAM数组就自动备份到闪存里,上电后,Store初始化, 会自动再把闪存里的数据读回SRAM数组里,这时闪存管理策略。
最后是main.c里面的应用层了,想要保持参数,就写到Store层的数组,再调用保持函数,备份到闪存,这样就能实现最终功能了。
辅助软件:stlink ultility,可以该数据,底层也是有擦除和写
选项字节,
在这里插入图片描述
Bank是加大容量

void FLASH_Unlock(void);
void FLASH_Unlock(void)
{/* Authorize the FPEC of Bank1 Access */FLASH->KEYR = FLASH_KEY1;FLASH->KEYR = FLASH_KEY2;#ifdef STM32F10X_XL/* Authorize the FPEC of Bank2 Access */FLASH->KEYR2 = FLASH_KEY1;FLASH->KEYR2 = FLASH_KEY2;
#endif /* STM32F10X_XL */
}
先写入Key1,再写入Key2.
void FLASH_Lock(void);
void FLASH_Lock(void)
{/* Set the Lock Bit to lock the FPEC and the CR of  Bank1 */FLASH->CR |= CR_LOCK_Set;#ifdef STM32F10X_XL/* Set the Lock Bit to lock the FPEC and the CR of  Bank2 */FLASH->CR2 |= CR_LOCK_Set;
#endif /* STM32F10X_XL */
}
加锁对应设置FLASH_CR的LOCK位锁住FPEC和FLASH_CR;非常的直观。对主闪存和选项字节进行擦除和编程的函数了。
FLASH_Status FLASH_ErasePage(uint32_t Page_Address);
闪存擦除某一页;返回值高速状态;
FLASH_Status FLASH_EraseAllPages(void); 
全擦除
FLASH_Status FLASH_EraseOptionBytes(void);
擦除选项字节
status = FLASH_WaitForLastOperation(EraseTimeout);if(status == FLASH_COMPLETE){/* Authorize the small information block programming */FLASH->OPTKEYR = FLASH_KEY1;FLASH->OPTKEYR = FLASH_KEY2;/* if the previous operation is completed, proceed to erase the option bytes */FLASH->CR |= CR_OPTER_Set;FLASH->CR |= CR_STRT_Set;/* Wait for last operation to be completed */status = FLASH_WaitForLastOperation(EraseTimeout);
FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);
写入字
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);
写入半字
/* Wait for last operation to be completed */status = FLASH_WaitForLastOperation(ProgramTimeout);if(status == FLASH_COMPLETE){/* if the previous operation is completed, proceed to program the new data */FLASH->CR |= CR_PG_Set;*(__IO uint16_t*)Address = Data;/* Wait for last operation to be completed */status = FLASH_WaitForLastOperation(ProgramTimeout);/* Disable the PG Bit */FLASH->CR &= CR_PG_Reset;} 
#endif  /* STM32F10X_XL */

第一步,事前等待,第二步,PG位置1,第三步,Address强转为指针,再指针取内容,赋值Data,也就是在指定地址Address下,写入指定数据Data;第四步,事后等待,最后PG位恢复为0;
FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);
FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages);
FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState);
FLASH_Status FLASH_UserOptionByteConfig(uint16_t OB_IWDG, uint16_t OB_STOP, uint16_t OB_STDBY);

FlagStatus FLASH_GetPrefetchBufferStatus(void);
获取预取缓存期状态
FLASH_Status FLASH_GetStatus(void);
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);
1、MyFLSAH

#include "stm32f10x.h"                  // Device headeruint32_t  MyFLASH_ReadWord(uint32_t Address)
{return  *((__IO uint32_t *)(Address)) ;}uint16_t  MyFLASH_ReadHalfWord(uint32_t Address)
{return  *((__IO uint16_t *)(Address)) ;}uint8_t  MyFLASH_ReadByte(uint32_t Address)
{return  *((__IO uint8_t *)(Address)) ;}void MyFLASH_EraseAllPages(void)
{FLASH_Unlock();FLASH_EraseAllPages();FLASH_Lock();
}void MyFLASH_ErasePages(uint32_t Address)
{FLASH_Unlock();FLASH_ErasePage(Address);FLASH_Lock();
}void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data)
{FLASH_Unlock();FLASH_ProgramWord(Address,Data);FLASH_Lock();
}void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{FLASH_Unlock();FLASH_ProgramHalfWord(Address,Data);FLASH_Lock();
}
#ifndef   __MyFLASH_H
#define   __MyFLASH_Huint32_t  MyFLASH_ReadWord(uint32_t Address);
uint16_t  MyFLASH_ReadHalfWord(uint32_t Address);
uint8_t  MyFLASH_ReadByte(uint32_t Address);void MyFLASH_EraseAllPages(void);
void MyFLASH_ErasePages(uint32_t Address);void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data);
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);
#endif

2、Store

#include "stm32f10x.h"                  // Device header
#include "MyFLASH.h"#define STORE_START_ADDRESS   0x0800FC00
#define STORE_COUNT				512uint16_t  Store_Data[512];void Store_Init(void)
{if ( MyFLASH_ReadHalfWord(0x0800FC00)!= 0xA5A5 ){MyFLASH_ErasePages(0x0800FC00);MyFLASH_ProgramHalfWord(0x0800FC00,0xA5A5);for(uint16_t i=1;i<512;i++ ){MyFLASH_ProgramHalfWord(0x0800FC00+ i*2 ,0x0000);}}for(uint16_t i=0;i<512;i++ ){Store_Data[i]=MyFLASH_ReadHalfWord(0x0800FC00+ i*2 );}
}void Store_Save(void)
{MyFLASH_ErasePages(0x0800FC00);for(uint16_t i=0;i<512;i++ ){MyFLASH_ProgramHalfWord(0x0800FC00+ i*2 ,Store_Data[i]);}}void Store_Clear(void)
{for(uint16_t i=1;i<512;i++ ){Store_Data[i]=0x0000;}Store_Save();}
#ifndef    __STORE_H
#define    __STORR_Hextern uint16_t  Store_Data[];void Store_Init(void);
void Store_Save(void);
void Store_Clear(void);#endif

在这里插入图片描述在这里插入图片描述
所以这个是以小端模式读取的
在这里插入图片描述

void MyFLASH_EraseAllPages(void)
{FLASH_Unlock();FLASH_EraseAllPages();FLASH_Lock();
} 

页擦除
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
首先,把闪存初始化一下,比如你第一次使用这个代码,那闪存默认全是FF,而参数和SRAM,一般都默认0,所以对于第一次使用,我们要给闪存的各个参数都置0,怎么判断是不是第一次使用,定义一个标志位,把闪存最后一页的第一个半字,当作标志位,判断。

if ( MyFLASH_ReadHalfWord(0x0800FC00)!= 0xA5A5 ){MyFLASH_ErasePages(0x0800FC00);MyFLASH_ProgramHalfWord(0x0800FC00,0xA5A5);for(uint16_t i=1;i<512;i++ ){MyFLASH_ProgramHalfWord(0x0800FC00+ i*2 ,0x0000);}}

第二大步,上电的时候,把闪存的数据全都转存到SRAM数组里,转存到这个数组里的过程,就是上电的时候恢复数据,实现数据掉电不丢失。
上电的时候,把闪存备份的数据,恢复到SRAM数组里,之后,我们响存储掉电不丢失的参数的时候,就先任意更改这个数组,除了标志位的其他数据,更改后之后,把这个数组,整体备份到闪存的最后一页。

梳理:
这时闪存的最后一页,直接对它读写的话,那肯定不方便,效率低,还容易丢失数据,所以在SRAM中,定义一个数组,它就是闪存的“分身”,我们再读写任何数据,就直接对SRAM操作,这样就非常方便了,但是SRAM掉电丢失,所以我们需要闪存来配合,SRAM每次更改的时候,都把数组整体备份到闪存里,而在上电的时候,再把闪存里的数据,初始化加载,回到SRAM里,这样SRAM数组,是不是就相当于掉电不丢失了。如果标志位是A5A5,就说明已经保持过了,如果不是A5A5,说明闪存是第一次使用,我们就先初始化一下,再加载数据。

在这里插入图片描述
对于出现很多次又可以修改的数据,最好使用宏定义替换一下,

程序过大影响最后一页了,可以设置不然程序影响用户存储
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2、读取ID号
在这里插入图片描述
在这里插入图片描述

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"
#include "OLED.h"int main(void)
{OLED_Init();OLED_ShowString(1,1,"F_SIZE:");OLED_ShowHexNum(1,8,*((__IO uint16_t *)(0x1FFFF7E0)),4 );OLED_ShowString(2,1,"U_ID:");OLED_ShowHexNum(2,6,*((__IO uint16_t *)(0x1FFFF7E8)),4 );OLED_ShowHexNum(2,11,*((__IO uint16_t *)(0x1FFFF7E8+0x02)),4 );OLED_ShowHexNum(3,1,*((__IO uint32_t *)(0x1FFFF7E8+0x04)),8 );OLED_ShowHexNum(4,1,*((__IO uint32_t *)(0x1FFFF7E8+0x08)),8);while(1){}
}

问题

总结

读写内部FLASH&读取芯片ID

相关文章:

  • 本地大模型编程实战(29)查询图数据库NEO4J(2)
  • Mysql中索引的知识
  • 洛谷P12238 [蓝桥杯 2023 国 Java A] 单词分类
  • 基于LVS+Keepalived+NFS的高可用负载均衡集群部署
  • 基于大模型的大肠息肉全程管理研究报告
  • 破茧成蝶:一家传统制造企业的年轻化转型之路
  • 总结小程序的坑
  • ​钓鱼网页散播银狐木马,远控后门威胁终端安全
  • 数字中国浪潮下:Coremail AI赋能邮件办公,筑牢安全防线引领转型
  • VSCode突然连接不上服务器(已解决)
  • “情况说明“以后,Unity XR 开发者如何选择?
  • JavaWeb:后端web基础(TomcatServletHTTP)
  • Linux《进程概念(中)》
  • SSM书籍管理(业务编写)
  • c#WebsocketSever
  • 【3D基础】顶点法线与平面法线在光照与PBR中的区别与影响
  • 第13讲:图形尺寸与分辨率设置——适配论文版面,打造专业图稿!
  • upload-labs PASS 1-5通关
  • 【无报错,亲测有效】如何在Windows和Linux系统中查看MySQL版本
  • 第一章 应急响应- Linux入侵排查
  • 游客曝九寨沟打网约车被出租车围堵,官方:前者违规,后者做法不对
  • 人社部:一季度全国城镇新增就业308万人,同比增加5万人
  • 体坛联播|安切洛蒂预计执教巴西国家队,利拉德确诊跟腱撕裂
  • 物业也能成为居家养老“服务员”,上海多区将开展“物业+养老”试点
  • 【社论】优化限购限行,激发汽车消费潜能
  • 外交部:对伊朗拉贾伊港口爆炸事件遇难者表示深切哀悼