文章目录
FLASH
FLASH简介
STM32 Flash 基础概念
1. Flash 存储结构
- 组成部分
- 程序存储器(主存储器):存储程序代码,起始地址
0x08000000
,容量根据芯片型号不同(如 C8T6 为 64KB)。 - 系统存储器:存储原厂 Bootloader,用于串口下载程序,起始地址
0x1FFFF000
,容量 2KB。 - 选项字节(Option Bytes):存储配置参数(如读写保护、看门狗设置),起始地址
0x1FFFF800
,容量 16 字节。
- 程序存储器(主存储器):存储程序代码,起始地址
- 特点:非易失性存储器(掉电不丢失),写入前需擦除,擦除最小单位为页(Page)。
2. 核心术语
页(Page)
- 小容量产品(≤32KB):32 页,每页 1KB。
- 中容量产品(64-128KB):128 页,每页 1KB(如 C8T6 为 64 页)。
- 大容量产品(≥256KB):256 页,每页 2KB。
字(Word):32 位数据;半字(Halfword):16 位数据;字节(Byte):8 位数据。
ICP(在线编程):通过外部工具直接对嵌入式系统设备进行存储器进行编程,无需拆除芯片,程序内容直接全部更新。
- 硬件接口
- ST-Link/J-Link:通过 SWD/JTAG 协议连接芯片,适用于调试和批量下载。
- 串口(USART):通过芯片内置的 Bootloader(系统存储器)接收数据,需配置启动引脚(如 BOOT0=1)触发串口下载模式。
- 硬件接口
IAP(在应用编程):IAP 指程序在运行过程中自行更新存储器内容,允许设备在不依赖外部工具的情况下实现 “自我升级”,是实现 OTA(空中下载技术) 的基础。
核心组件:Bootloader
- 作用
- 作为独立于主程序的 “引导程序”,负责接收新程序数据并写入 Flash。
- 主程序(App)运行时,Bootloader 处于静默状态;需要升级时,主程序跳转至 Bootloader 执行更新逻辑。
- 存储位置
- 通常存放在 Flash 非易失性区域(如主存储区的起始段或独立分区),确保更新过程中不被覆盖。
- 作用
工作流程
- 烧录 Bootloader
- 通过 ICP 提前烧录 Bootloader 到芯片(如地址
0x08000000
)。
- 通过 ICP 提前烧录 Bootloader 到芯片(如地址
- 主程序运行
- 主程序存放在 Bootloader 之后的地址(如
0x08005000
),正常运行时通过函数跳转执行。
- 主程序存放在 Bootloader 之后的地址(如
- 触发升级
- 主程序检测到升级指令(如串口接收到特定命令、蓝牙信号),跳转至 Bootloader。
- 接收新程序
- Bootloader 通过任意通信接口(串口、USB、蓝牙、Wi-Fi 等)接收升级包数据。
- 擦写 Flash
- 擦除主程序存储区,将新程序写入指定地址。
- 重启运行新程序
- 更新完成后,跳转至新程序起始地址,或复位芯片加载新程序。
- 烧录 Bootloader
-
类型 起始地址 存储器 用途 ROM 0x0800 0000 程序存储器Flash 存储C语言编译后的程序代码 系统存储器 0x1FFF F000 存储BootLoader,用于串口下载 存储BootLoader,用于串口下载 0x1FFF F800 0x1FFF F800 存储一些独立于程序代码的配置参数 存储一些独立于程序代码的配置参数 RAM 0x2000 0000 运行内存SRAM 存储运行过程中的临时变量 外设寄存器 0x4000 0000 存储各个外设的配置参数 存储各个外设的配置参数 内核外设寄存器 0xE000 0000 存储内核各个外设的配置参数 存储内核各个外设的配置参数
闪存模块组织
1. 主存储器(程序存储器)
- 结构
- 共 128 页,每页 1K 字节(地址范围
0x08000000
至0x0801FFFF
,每页间隔0x400
字节,如表格所示)。 - 用途:存储程序代码,剩余空间可用于 用户数据存储(掉电不丢失)或 IAP 程序更新(动态升级)。
- 当代码比较少时,空余部分较多,可以节省空间的利用等。
- 共 128 页,每页 1K 字节(地址范围
2. 信息块
- 系统存储器(启动程序代码)
- 地址:
0x1FFF F000 - 0x1FFF F7FF
,长度 2K 字节,存储原厂 Bootloader(支持 ICP 下载,如串口更新程序)。
- 地址:
- 选项字节(用户选择字节)
- 地址:
0x1FFF F800 - 0x1FFF F80F
,长度 16 字节,存储 配置参数(读写保护、看门狗设置等)。 - 操作:需解锁
OPT KR
寄存器(写入反码验证),支持擦除(OPTER
位)和编程(OPT PG
位),对应会议中 “选项字节擦除与编程” 流程。
- 地址:
3. 闪存存储器接口寄存器
- 起始地址0x40022000,每个寄存器4 字节,核心功能:
- KR(密钥寄存器,FLASH_KEYR):解锁 / 加锁 Flash(写入
K1/K2
密钥)。 - SR(状态寄存器,FLASH_SR):监控
BUSY位
(擦写进度)、EOP位
(操作完成)。 - CR(控制寄存器,FLASH_CR):控制擦除(
PER
页擦除、MER
全擦除)、写入(PG
半字写入)及加锁(LOCK位
)。 - AR(地址寄存器,FLASH_AR):指定擦除页地址(页擦除时使用)。
- OBR(选项字节寄存器,FLASH_OBR):存储选项字节配置(如
RDP
读保护、WRP
写保护)。 - WRPR(写保护寄存器,FLASH_WRPR):配置写保护页(反逻辑,
0
表示保护生效)。
- KR(密钥寄存器,FLASH_KEYR):解锁 / 加锁 Flash(写入

FLASH基本结构
FLASH解锁
1. FPEC 密钥与安全机制
- 密钥体系
- 主存储区解锁密钥:
KEY1=0x45670123
、KEY2=0xCDF89AB
,用于解锁FLASH_CR
寄存器,允许擦除 / 写入操作。 - 选项字节读保护密钥:
RDPRT键=0x000000A5
,用于配置RDP
位(解除读保护时使用,反逻辑验证)。
- 主存储区解锁密钥:
- 复位保护:复位后 FPEC 默认锁定,禁止操作
FLASH_CR
,需通过合法密钥序列解锁,防止误操作。
2. 解锁流程(主存储区操作)
- 步骤
- 写入 KEY1:向
FLASH_KEYR
寄存器写入0x45670123
。 - 写入 KEY2:接着写入
0xCDF89AB
,完成解锁(顺序严格,硬件验证)。 - 操作权限:解锁后可设置
FLASH_CR
的PER
(页擦除)、MER
(全擦除)、PG
(写入)等位,执行 Flash 操作。
- 写入 KEY1:向
- 错误处理:若密钥顺序错误或非法值,FPEC 和
FLASH_CR
锁死,需复位芯片重新解锁,确保操作合法性。
3. 加锁流程
- 操作:设置
FLASH_CR
的LOCK位
(1
表示加锁),禁止后续对FLASH_CR
的写入,保护 FPEC。 - 场景:擦除 / 写入完成后立即加锁,防止程序异常(如中断、跑飞)导致的 Flash 误操作,提升系统稳定性。
使用指针访问存储器
直接操作指针来对存储器进行访问,为了防止编译器的优化,使用volatile 关键字 ,来防止编译器的优化作用。
volatile 关键字详解
一、基本概念与作用
volatile
是 C/C++ 等语言的类型修饰符,核心功能是禁止编译器对变量的优化,确保每次读写都直接操作内存(而非寄存器缓存)。其作用包括:
- 防止编译器优化:避免变量被缓存到寄存器,确保每次从内存读取最新值(如硬件寄存器、多线程共享变量)。
- 保证内存可见性:多线程或硬件场景下,变量修改后其他线程 / 硬件操作能立即感知(如 STM32 Flash 指针操作中
__IO
宏定义为volatile
,保证实时读写)。 - 禁止指令重排序:通过内存屏障确保代码执行顺序与预期一致(如多线程同步逻辑)。
二、工作原理
- 编译器行为:对
volatile
变量,编译器生成代码时不缓存其值,每次访问都显式读写内存。 - 硬件交互:在嵌入式开发中(如 STM32),直接映射的硬件地址(如 Flash、寄存器)需用
volatile
确保操作真实作用于硬件(如会议中*(__IO uint16_t*)addr
的__IO
即volatile
,保证 Flash 读写的实时性)。
三、典型使用场景
硬件寄存器访问(嵌入式开发):
读写 STM32 的 Flash、GPIO、UART 等寄存器时,
volatile
确保每次操作直接访问硬件,避免编译器优化(如会议中 Flash 指针操作的代码示例)。示例:
#define GPIOA_ODR (*(volatile uint32_t*)0x4001080C) // 直接访问GPIO输出寄存器 GPIOA_ODR = 0x00000001; // 写操作,编译器不优化,确保硬件输出
多线程共享变量(并发编程):
- 线程间的标志位(如停止标志
stopFlag
),volatile
保证修改后其他线程立即读取最新值(避免线程缓存不一致)。 - 注意:
volatile
不保证原子性(如cnt++
需结合锁或原子类,但嵌入式场景需注意硬件中断与主程序的变量交互)。
- 线程间的标志位(如停止标志
中断 / 异步事件处理:
- 中断服务程序(ISR)中修改的变量(如
interruptFlag
),主程序用volatile
读取,确保不会因编译器优化而 “忽略” 中断(如 STM32 的 EXTI 中断标志处理)。
- 中断服务程序(ISR)中修改的变量(如
防止空循环优化:
- 空循环(如延迟函数)添加
volatile
后,编译器不会优化掉循环(如for (volatile int i=0; i<1e6; i++);
用于简单延迟)。
- 空循环(如延迟函数)添加
四、与会议内容的关联(STM32 Flash 操作)
- Flash 指针操作:会议中代码使用
__IO
(即volatile
)修饰指针,确保读写 Flash 时直接操作内存,避免编译器缓存优化(如*(__IO uint16_t*)addr
,保证每次读写 Flash 硬件,而非寄存器缓存,这是实现掉电数据存储和 IAP 升级的基础)。 - 硬件寄存器访问:
volatile
保证对FLASH_KEYR
、FLASH_CR
等寄存器的操作实时生效(解锁 / 加锁、擦除 / 写入流程中的寄存器读写,必须通过volatile
确保硬件级响应,避免编译器优化导致的操作失效)。
五、代码示例解析(对应会议代码)
// 读取Flash数据(volatile确保从内存读取,无缓存)
uint16_t data = *(__IO uint16_t*)(0x08000000); // __IO是volatile宏,直接访问Flash地址
// 写入Flash(需先解锁,此处省略解锁代码,volatile保证写操作实时)
*(__IO uint16_t*)(0x08000000) = 0x1234; // 直接写Flash内存,编译器不优化,确保硬件写入
__IO
宏:定义为volatile
,确保指针访问的内存操作不被优化,与 STM32 硬件手册中的寄存器访问要求一致(会议中 “加 volatile 防止编译器优化” 的具体实现)。
六、总结
volatile
是嵌入式开发(如 STM32)中处理硬件交互和内存可见性的关键关键字。在会议涉及的 Flash 操作中,它确保了指针读写的实时性(无编译器优化),是实现掉电数据存储、程序升级(IAP/ICP)的基础。其核心价值在于强制内存访问,避免编译器对硬件相关代码的优化,确保系统与硬件行为一致。合理使用volatile
可提升嵌入式系统的稳定性,尤其在直接内存映射(如 Flash、寄存器)场景中不可或缺。
关键要点速记
- 作用:禁止编译器优化,保证内存可见性,适用于硬件交互、多线程标志。
- STM32 场景:Flash 指针操作(
__IO
宏)、寄存器访问(如FLASH_CR
)均依赖volatile
确保实时性。 - 局限:不保证原子性,多线程复杂操作需结合锁 / 原子类,嵌入式中主要用于硬件相关代码。
程序存储器编程
流程解析
- 解锁检查:
- 读取
FLASH_CR
的LOCK位
,若为1
(加锁状态),执行解锁序列(写入KEY1
和KEY2
到FLASH_KEYR
),解除 FPEC 保护( “解锁与加锁” 机制的具体实现)。 - 若
LOCK位
为0
(已解锁),直接进入写入步骤,确保操作合法性。
- 读取
- 写入配置:
- 置
FLASH_CR
的PG位
为1
,使能半字(16 位)写入模式( “写入操作需设置 PG 位” 的硬件要求)。
- 置
- 数据写入:
- 通过指针(如
*(__IO uint16_t*)addr
)向指定地址写入数据,利用volatile
(__IO
宏)确保实时访问硬件(指针操作的volatile
应用,防止编译器优化)。
- 通过指针(如
- 忙等待:
- 轮询
FLASH_SR
的BSY位
,直至0
(操作完成),保证 CPU 在擦写期间不执行其他任务( “等待 busy 位清零” 的同步机制,确保操作原子性)。
- 轮询
- 数据校验:
- 写入后读取地址数据,验证正确性,防止硬件故障或地址错误( 嵌入式开发的常规数据可靠性检查)。
程序存储器页擦除
流程解析
- 解锁检查:
- 读取
FLASH_CR
的LOCK位
,若为1
(加锁),执行解锁序列(写入KEY1
和KEY2
到FLASH_KEYR
),解除 FPEC 保护(会议中 “解锁与加锁” 机制的硬件实现,确保操作合法性)。 - 若
LOCK位
为0
(已解锁),直接进入擦除步骤。
- 读取
- 擦除配置:
- 置
FLASH_CR
的PER位
为1
(选择页擦除模式,区别于全擦除MER位
, “页擦除” 与 “全擦除” 的硬件配置差异)。 - 在
FLASH_AR
中指定擦除页地址(如中容量产品每页 1K,地址间隔0x400
, “内存模块组织” 的页地址规划)。 - 置
FLASH_CR
的STRT位
为1
,触发擦除(硬件级启动擦除流程)。
- 置
- 忙等待:
- 轮询
FLASH_SR
的BSY位
,直至0
(擦除完成),确保 CPU 同步( “等待 busy 位清零” 的同步机制,避免硬件冲突,保证操作原子性)。
- 轮询
- 数据验证:
- 擦除后读取页数据,验证是否为全
0xFFFF
(Flash 擦除后默认值),确保擦除成功(嵌入式开发常规可靠性检查,防止硬件故障)。
- 擦除后读取页数据,验证是否为全
程序存储器全擦除
流程解析
- 解锁检查:
- 读取
FLASH_CR
的LOCK位
,若为1
(加锁),执行解锁序列(写入KEY1
和KEY2
到FLASH_KEYR
),解除 FPEC 保护(与会议中 “解锁与加锁” 机制一致,确保操作合法性)。 - 若
LOCK位
为0
(已解锁),直接进入全擦除步骤。
- 读取
- 擦除配置:
- 置
FLASH_CR
的MER位
为1
(选择全擦除模式,区别于页擦除PER位
,会议中 “全擦除” 与 “页擦除” 的硬件配置差异)。 - 置
FLASH_CR
的STRT位
为1
,触发全擦除(擦除主存储区所有页,信息块和选项字节保留,符合会议 “内存模块组织” 的存储区划分)。
- 置
- 忙等待:
- 轮询
FLASH_SR
的BSY位
,直至0
(擦除完成),确保 CPU 同步(会议中 “等待 busy 位清零” 的同步机制,保证操作原子性)。
- 轮询
- 数据验证:
- 擦除后读取所有页数据,验证是否为全
0xFFFF
(Flash 擦除后默认值),确保全擦除成功(常规可靠性检查,防止硬件故障)。
- 擦除后读取所有页数据,验证是否为全
选项字节
地址与反码设计:
选项字节位于0x1FFF F800
起,共 16 字节,含RDP
(读保护)、USER
(硬件配置)、Data0/1
(用户自定义)、WRP0-3
(写保护)及其反码(n
前缀字段),硬件验证写入合法性(反逻辑确保安全)。核心字段
RDP
:写入RDPRT键(0x000000A5)
解除读保护(开发时),默认值开启保护(量产防盗)。USER
:配置看门狗、低功耗模式复位,影响系统启动与运行(硬件级功能定制)。Data0/1
:用户自定义存储(如设备参数、序列号),替代外挂存储,掉电不丢失。WRP0-3
:每 1 位保护 4 页(中容量),0
生效(反逻辑),防止指定页擦写(数据安全防护)。
选项字节编程
流程解析
- 忙等待检查(BSY 位):读取
FLASH_SR
的BSY位
,确保无正在进行的擦写操作,避免硬件冲突,保证操作原子性(对应会议中 “操作前同步检查” 的安全机制)。 - 解锁选项字节写保护(
OPTWARE位
):写入RDPRT键(0x000000A5)
解锁FLASH_CR
的OPTWARE位
,允许选项字节编程(会议中 “选项字节小锁解锁” 的硬件步骤,独立于主存储区解锁,实现分层安全)。 - 配置编程模式(
OPTPG位
):置FLASH_CR
的OPTPG位
为1
,使能选项字节半字写入(与主存储区PG位
类似,确保数据格式正确,会议 “半字写入” 的硬件配置)。 - 数据写入:通过指针向选项字节地址(如
0x1FFF F800
)写入半字数据(如RDP
、WRP
等配置,依赖volatile
确保实时访问,会议中指针操作的__IO
宏应用)。 - 忙等待与校验:等待
BSY位
清零,读取地址验证数据,确保写入正确(会议 “数据可靠性检查”,防止硬件故障)。
读取Flash数据有关代码
//MyFLASH.c
#include "stm32f10x.h" // Device header
//读取数据不用开启读保护,读保护是应用于外部的设备对flash地址内容的读取
//读取指定地址的字
uint32_t MyFLASH_ReadWord(uint32_t Address)
{
return *((__IO uint32_t*) Address);
}
//FLASH读取半字
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_EraseAllPage(void)
{
//先开锁
FLASH_Unlock();
FLASH_EraseAllPages();
//上锁
FLASH_Lock();
}
void MyFlash_ErasePage(uint32_t PageAddress)
{
//先开锁
FLASH_Unlock();
FLASH_ErasePage(PageAddress);
//上锁
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();
}
//Store.c
//存储数据的逻辑
#include "stm32f10x.h" // Device header
#include "MyFlash.h"
#define STORE_START_ADDRESS 0x0800FC00 //存储的起始地址
#define STORE_COUNT 512 //存储数据的个数
uint16_t Store_Data[STORE_COUNT]; //定义SRAM数组
//模块实现的功能 就是使用一个数组来存储 最后一页的 flash 数据,因为 进行对flash数据进行操作是不方便的,
//使用一个数组来作为flash模块的分身,想要对flash中数据进行变化时,直接对数组中数据进行变化,然后再同步到flash
//这样数据也就有了数据掉电不丢失的性质,上电之后再将存储到flash中的数据读到数组中。
//初始化 判断如果flash中已经存储了数据,将数据读出,否则将数据都初始化为0
void Store_Init(void)
{
//判断标志位 将要存储的第一个半字 作为标志位,也就是用来判断是否 flash中已经存储过数据
if(MyFLASH_ReadHalfWord(STORE_START_ADDRESS) != 0xA5A5)
{
//擦除页
MyFlash_ErasePage(STORE_START_ADDRESS);
//第一个半字写入 0xA5A5 也就是置标志位
MyFlash_ProgramHalfWord(STORE_START_ADDRESS, 0xA5A5);
//将整页的数据初始化为0, 不包括第一个半字
for(uint16_t i = 1; i < STORE_COUNT; i++)
{
MyFlash_ProgramHalfWord(STORE_START_ADDRESS + i* 2, 0x0000);
}
}
//上电之后将flash中存储的数据同步到数组中
for(uint16_t i = 0; i < STORE_COUNT; i++)
{
//标志位也存到数组中
Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS + i*2);
}
}
//每次数组中数据变化一次 就将数组中数据存储一次
void Store_Save(void)
{
//将数据写入到flash中时,要先进行页擦除
MyFlash_ErasePage(STORE_START_ADDRESS);
for(uint16_t i = 0; i < STORE_COUNT; i++)
{
MyFlash_ProgramHalfWord(STORE_START_ADDRESS + i*2, Store_Data[i]);
}
}
void Store_Clear(void)
{
for(uint16_t i = 1; i < STORE_COUNT; i++)
{
Store_Data[i] = 0x0000;
}
//将数据同步到flash中
Store_Save();
}
//main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "key.h"
#include "Store.h"
uint8_t keynum;
int main(void)
{
OLED_Init();
Key_Init();
Store_Init();
/*显示静态字符串*/
OLED_ShowString(1, 1, "Flag:");
OLED_ShowString(2, 1, "Data:");
while(1)
{
keynum = Key_GetNum();
if(keynum == 1)
{
Store_Data[1] ++;
Store_Data[2] +=2;
Store_Data[3] += 3;
Store_Data[4] += 4;
//写完数据要同步数据
Store_Save();
}
if(keynum == 2)
{
Store_Clear();
}
OLED_ShowHexNum(1, 6, Store_Data[0], 4);
OLED_ShowHexNum(3, 1, Store_Data[1], 4);
OLED_ShowHexNum(3, 6, Store_Data[2], 4);
OLED_ShowHexNum(4, 1, Store_Data[3], 4);
OLED_ShowHexNum(4, 6, Store_Data[4], 4);
}
}
选项字节擦除
流程解析
忙等待检查(BSY 位):读取FLASH_SR
的BSY位
,确保无正在进行的闪存操作(擦除 / 写入),避免硬件冲突,保证操作原子性(与会议中 “操作前同步检查” 的安全机制一致,如全擦除、页擦除前的 BSY 检查)。
解锁选项字节写保护(OPTWARE位
):写入RDPRT键(0x000000A5)
解锁FLASH_CR
的OPTWARE位
,允许选项字节擦除(会议中 “选项字节小锁解锁” 的硬件步骤,独立于主存储区解锁,实现分层安全防护)。
配置擦除模式(OPTER位
):置FLASH_CR
的OPTER位
为1
,选择选项字节擦除模式(区别于主存储区擦除的PER
/MER位
,会议中 “选项字节擦除的硬件配置”)。
触发擦除(STRT位
):置FLASH_CR
的STRT位
为1
,启动选项字节擦除(硬件级操作,确保擦除指令生效)。
忙等待与校验:等待BSY位
清零,读取选项字节地址验证是否为全0xFFFF
(擦除后默认值),确保擦除成功(会议 “数据可靠性检查”,防止硬件故障)。
器件电子签名
1. 存储与特性
系统存储区:电子签名位于闪存系统存储区(出厂写入,不可更改),通过指针(volatile
修饰,确保实时读取)访问,如*(__IO uint32_t*)0x1FFF F7E8
获取 96 位唯一 ID(UID),0x1FFF F7E0
获取 16 位 Flash 容量(FSize)。
2. 核心寄存器
闪存容量(FSize):地址0x1FFF F7E0
,16 位,标识芯片 Flash 大小(如 64KB 对应0x0040
),用于硬件适配(如动态内存分配)。
唯一身份标识(UID):地址0x1FFF F7E8
,96 位,芯片唯一 ID,支撑设备认证、软件授权(如物联网设备 ID、加密序列号)。
3. 应用场景
安全认证:UID 作为设备唯一标识,实现物联网设备身份验证(如 MQTT 协议中的设备 ID),防止盗版(结合加密算法生成授权码)。
硬件识别:读取 FSize 自动适配程序(如代码中根据容量调整存储策略),提升兼容性。
4. 与会议关联
代码实现:会议中 “读取芯片 ID” 的代码示例(指针操作)直接访问上述寄存器,体现内存映射的硬件级读取(简洁高效,无需外设)。
安全机制:UID 的唯一性增强系统安全(如 IAP 升级时的身份校验,防止恶意代码注入)。
5. 总结
器件电子签名通过只读寄存器提供硬件级唯一标识(UID)和容量信息(FSize),支持设备认证、安全授权等功能。结合会议中的指针操作(volatile
确保实时性),实现高效、安全的硬件识别,为嵌入式系统的智能化(物联网、安全防护)奠定基础,提升系统安全性与可维护性。
查看芯片id有关代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "key.h"
#include "Store.h"
//想要读取芯片的id直接在指定地址读就可以了
int main(void)
{
OLED_Init();
Key_Init();
Store_Init();
/*显示静态字符串*/
OLED_ShowString(1, 1, "F-SIZE:");
OLED_ShowHexNum(1, 8, *((__IO uint16_t*) 0x1FFFF7E0), 4);
OLED_ShowString(2, 1, "UID:");
//读参考手册查看id有关信息所在地址
OLED_ShowHexNum(2, 5, *((__IO uint16_t*) 0x1FFFF7E8), 4);
OLED_ShowHexNum(2, 10, *((__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)
{
}
}