STM32內部讀寫FLASH

很多情況下,在STM32中寫入一些數據,在某些不可控因素下其數據無法保存。因此,解決此問題就要用到FLASH.

什么是內部 Flash??

Flash 是一種非易失性存儲器,STM32 的程序和常量數據就存在 Flash 中。它的關鍵特點是:

特性說明
地址映射Flash 地址從 0x08000000 開始
掉電不丟電源斷了之后數據還在
讀操作和 RAM 一樣,可以直接讀
寫操作必須擦除后寫入(寫之前必須全是 1)
寫入單位至少為半字(16位)
擦除單位以頁為單位(STM32F103 是 1KB)

Flash 是如何讀數據的??

STM32 的 Flash 是memory-mapped(內存映射)的,即:

Flash 被掛在總線上,和 SRAM 一樣的訪問方式,讀取數據只需要訪問地址。

底層硬件會自動完成數據譯碼、電荷檢測、字線控制等,所以我們可以像訪問 RAM 一樣訪問 Flash。

STM32 讀取和寫入內部 Flash 的本質區

操作是否需要解鎖是否需要擦除最小單位是否會改變 Flash 數據
讀取否?否?1字節/2字節/4字節否 (只讀)
寫入是?是(必須)半字(16位)是 (只能1→0)

?為什么不需要解鎖就能讀取?

因為 讀取 Flash 是只讀操作,不會修改 Flash 結構,不存在寫保護一說,也不需要擦除。Flash 讀取只需要:

uint16_t data = *(volatile uint16_t *)0x0800FC00;

STM32 會自動從 Flash 控制器中讀取該地址的數據。

讀取代碼詳解

uint32_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));
}
通用結構分析

*((__IO 類型 *)(Address)) 是什么意思?

組成部分含義
(類型 *)把地址強制轉換成指針類型
__IOvolatile,防止編譯器優化(告訴編譯器:值可能隨時變化)
*(指針)取出地址中的值(解引用)

舉個例子:?

*((__IO uint16_t *)0x0800FC00) → 讀取地址0x0800FC00的2字節數據

注意事項
不要讀取未對齊地址(比如讀取 uint16_t 不能從奇數地址讀取)

不要在 Flash 正在寫入時讀取 Flash

寫入 Flash 的完整流程?

寫入 Flash 是一個有順序、受保護的敏感操作,必須嚴格遵守 STM32 的流程!

要求原因
寫入前必須解鎖防止誤寫程序或數據
寫入前必須擦除因為 Flash 只能從 1 → 0,不能反向
寫入地址必須對齊每次只能寫一個 “半字”
寫入時 Flash 忙,不能再操作 Flash必須等待寫完成(BSY = 0)

?

  ┌────────────┐│ Flash_Unlock│ ← 解鎖 Flash 寫保護└─────┬──────┘↓┌──────────────┐│Flash_ErasePage│ ← 擦除所在頁(將所有位置1)└─────┬────────┘↓┌──────────────────────┐│Flash_ProgramHalfWord │ ← 寫入一個16位值(地址必須對齊)└────────────┬─────────┘↓┌────────────┐│ Flash_Lock │ ← 鎖回 Flash,防止誤寫└────────────┘
void MyFLASH_EraseAllPages(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();MyFLASH_ErasePage(Address);  FLASH_ProgramWord(Address, Data);FLASH_Lock();
}void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{FLASH_Unlock();MyFLASH_ErasePage(Address);  FLASH_ProgramHalfWord(Address, Data);FLASH_Lock();
}

把 STM32 的內部 Flash 最后一頁 0x0800FC00 用作數據存儲區

函數名功能說明
Store_Init()開機時檢查是否初始化過,若無則初始化數據,再加載到 RAM 數組
Store_Save()把當前 RAM 中的數據整體寫入 Flash(覆蓋)
Store_Clear()清除 RAM 中的數據,再寫入 Flash(相當于清空)

Store_Init() 函數解釋?

?

#define STORE_START_ADDRESS		0x0800FC00
#define STORE_COUNT				512uint16_t Store_Data[STORE_COUNT];void Store_Init(void)
{if (MyFLASH_ReadHalfWord(STORE_START_ADDRESS) != 0xA5A5){MyFLASH_ErasePage(STORE_START_ADDRESS);MyFLASH_ProgramHalfWord(STORE_START_ADDRESS, 0xA5A5);for (uint16_t i = 1; i < STORE_COUNT; i ++){MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, 0x0000);}}for (uint16_t i = 0; i < STORE_COUNT; i ++){Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS + i * 2);}
}

?

空間計算(為什么是 512?)
每個 uint16_t 是 2 字節(16 位),所以:

512 × 2 字節 = 1024 字節 = 1KB

正好使用 Flash 的最后一頁(1KB 大小)來存儲 512 個 uint16_t。

這是一種 對齊頁大小的設計,防止寫入跨頁、浪費空間或出錯。

步驟說明
讀取魔數檢查 Flash 中是否已經初始化過(首地址是否為 0xA5A5)
若未初始化則擦除該頁,寫入魔數 + 寫入 511 個 0x0000
讀取數據把 Flash 中的所有數據讀入 RAM 數組 Store_Data[]

為什么用魔數 0xA5A5?

Flash 出廠是全 0xFFFF,你寫入 0xA5A5 后,可以作為初始化標志,下次重啟時避免重復擦除。

Store_Save() 函數解釋(將 RAM 數據寫回 Flash)?

void Store_Save(void)
{MyFLASH_ErasePage(STORE_START_ADDRESS);for (uint16_t i = 0; i < STORE_COUNT; i ++){MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, Store_Data[i]);}
}
步驟說明
先擦除頁Flash 寫之前必須擦除
順序寫入Store_Data[] 數組中 512 個半字寫入 Flash

為什么每個數據偏移 i * 2?
因為你每個數據是 uint16_t,占用 2 字節,要避免覆蓋前一個數據。?

Store_Clear() 函數解釋(清除并保存)?

void Store_Clear(void)
{for (uint16_t i = 1; i < STORE_COUNT; i ++){Store_Data[i] = 0x0000;}Store_Save();
}

功能分析:
從第 1 個數據開始清 0(保留 Store_Data[0] 為魔數)

調用 Store_Save() 整頁重寫

main函數

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Store.h"
#include "Key.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);}
}

?FLASH讀取芯片ID

#include "stm32f10x.h"                  // Device header
#include "Delay.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 大小0x1FFFF7E0單位:KB(例如 64 → 64KB Flash)
UID[0]0x1FFFF7E8UID 第 0~15 位(低 16 位)
UID[1]0x1FFFF7EAUID 第 16~31 位(高 16 位)
UID[2]0x1FFFF7ECUID 第 32~63 位(32 位)
UID[3]0x1FFFF7F0UID 第 64~95 位(32 位)

應用場景
防偽 / 唯一性綁定:

使用 UID 作為設備編號上傳服務器或產品注冊

Flash 容量檢測:

某些型號可能 Flash 容量不一致,可動態檢測

License 系統:

生成授權碼綁定到 UID,防止盜版

設備信息顯示:

工程生產中可直接通過 OLED 顯示設備 ID 進行追溯

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/918135.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/918135.shtml
英文地址,請注明出處:http://en.pswp.cn/news/918135.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Oracle 12c + Pl/Sql windows系統下表空間創建、遷移,dmp備份導入,數據庫字符集更改

一、開發環境 操作系統&#xff1a;win11 Oracle版本&#xff1a;12c Oracle 數據庫字符集&#xff1a;AL32UTF8 Pl/Sql版本&#xff1a;14 二、表空間創建 表空間是 Oracle 數據庫中一種重要的邏輯結構&#xff0c;它是數據庫中數據文件的邏輯集合&#xff0c;用于存儲數據庫對…

GUI:QT簡介

一、什么是QT&#xff1f;Qt是一套跨平臺的 C 圖形用戶界面&#xff08;GUI&#xff09;應用程序開發框架&#xff0c;由挪威 Trolltech&#xff08;奇趣科技&#xff09;于 1991 年創建&#xff0c;2008 年被諾基亞收購&#xff0c;2012 年后由 Qt Company 負責維護。它廣泛應…

oceanbase執行execute immediate create table提示無權限

問題&#xff1a;OB庫4.2.5.4版本&#xff0c;執行到這一句的時候&#xff0c;報沒有權限&#xff1a;[rootlnob ~]# obclient -h192.168.207.28 -P2881 -ugistarlnzyob -pxxxxxx -A Welcome to the OceanBase. Commands end with ; or \g. Your OceanBase connection id is 3…

滴滴招java開發

滴滴集團 北京&#xff08;崗位信息已經過jobleap.cn授權&#xff0c;可在csdn發布&#xff09;收錄時間&#xff1a; 2025年08月01日職位描述 負責滴滴海外業務準入審核及反作弊相關系統的后端開發及系統維護&#xff1b; 職位要求 1、統招本科及以上學歷&#xff0c;計算機科…

深入解析基于Zookeeper分布式鎖在高并發場景下的性能優化實踐指南

深入解析基于Zookeeper分布式鎖在高并發場景下的性能優化實踐指南 在大規模分布式系統中&#xff0c;如何保證多個節點對同一資源的有序訪問&#xff0c;是提高系統穩定性與一致性的核心需求之一。Zookeeper 提供的分布式鎖機制&#xff0c;以其簡潔的原理和高可靠性&#xff0…

騰訊云CodeBuddy AI IDE+CloudBase AI ToolKit打造理財小助手網頁

CodeBuddy 騰訊云CodeBuddy AI IDECloudBase AI ToolKit打造理財小助手網頁 在線體驗地址&#xff1a;理財小助手 在線倉庫&#xff1a;https://cnb.cool/pickstars-2025/ai-financial-assistant &#x1f31f; Hello&#xff0c;我是摘星&#xff01; &#x1f308; 在彩虹般…

2025-08-08 李沐深度學習11——深度學習計算

文章目錄1 模型構造1.1 自定義 MLP&#xff08;多層感知機&#xff09;1.1.1 __init__ (構造函數)1.1.2 forward (前向傳播)1.2 使用自定義 MLP1.3 自定義 Sequential 類1.4 前向傳播1.5 模塊的嵌套使用2 參數管理2.1 參數訪問2.2 嵌套模型2.3 參數初始化2.4 參數共享3 自定義層…

匯編語言和高級語言的差異

匯編語言與高級語言在以下幾個方面存在重要的區別&#xff1a;缺少結構化流程控制。匯編語言不提供if/else、switch/case、for、while等高級控制結構&#xff0c;依賴于底層的無條件跳轉和條件跳轉指令來實現流程控制。這種基于標簽和跳轉的方式雖然極其靈活&#xff0c;但缺乏…

文件管理從基礎到高級:文件描述符、超大文件切片重組與快速刪除實戰

文件管理從基礎到高級&#xff1a;文件描述符、超大文件切片重組與快速刪除實戰目標讀者&#xff1a;Linux/macOS 用戶、后端/運維/數據工程師 環境默認&#xff1a;Linux&#xff08;GNU 工具鏈&#xff09;&#xff0c;macOS 類似&#xff1b;Windows 可使用 WSL1&#xff09…

RPC 解析

RPC&#xff08;Remote Procedure Call&#xff0c;遠程過程調用&#xff09;是一種讓分布式系統中的服務能夠像調用本地函數一樣調用遠程服務的通信機制。以下是其核心原理、技術實現及組件的詳細解析&#xff1a;&#x1f527; 一、RPC 核心工作原理&#xff08;10 步全流程&…

wstool的一個完整的工作流解析

moveit的倉庫源碼編譯的時候使用的是wstool來拉取倉庫的所有內容文件&#xff0c;其命令流程如下: wstool init src wstool merge -t src https://raw.githubusercontent.com/moveit/moveit/master/moveit.rosinstall wstool update -t src rosdep install -y --from-paths src…

對數函數分段定點實現

目錄 一、原理介紹 二、代碼實現 三、結果顯示 四、移植到C語言中的應用 4.1. 定義定點數配置和參數 4.2. 實現分段查找函數 4.3. 實現 log10 近似計算函數 4.4. &#xff08;可選&#xff09;定點數轉浮點數 一、原理介紹 之前的博文對數函數分段線性實…

qt系統--事件

文章目錄qt系統事件處理鼠標事件鼠標移動事件處理鍵盤事件定時器事件窗口移動和大小改變事件結語很高興和大家見面&#xff0c;給生活加點impetus&#xff01;&#xff01;開啟今天的編程之路&#xff01;&#xff01; 作者&#xff1a;?( ‘ω’ )?260 我的專欄&#xff1a…

Linux機器可直接使用的自動化編譯文件

還在為了Linux機器上一遍遍輸入編譯指令苦惱嗎&#xff1f;你需要make指令以及自己的makefile文件&#xff01;在makefile中寫入自己的個性化指令&#xff0c;讓編譯速度飛起&#xff0c;支持多文件編譯一下文件為個人應用&#xff0c;可以直接cp到相應項目的目錄&#xff0c;每…

Linux學習-數據結構(哈希表)

1.哈希表1.哈希算法將數據通過哈希算法映射成一個關鍵值&#xff0c;存放都在同一位置實現數據的高效存儲和查找&#xff0c;將時間復雜度盡可能降低至O&#xff08;1&#xff09;2.哈希碰撞多個數據通過哈希算法得到的鍵值相同&#xff0c;稱為產生哈希碰撞3.哈希表構建哈希表…

Google Chrome <139.0.7236.0 UAF漏洞

【高危】Google Chrome <139.0.7236.0 UAF漏洞 漏洞描述 Google Chrome 是美國谷歌&#xff08;Google&#xff09;公司的一款Web瀏覽器。 受影響版本中&#xff0c;OpenscreenSessionHost::ReportAndLogError 方法的參數使用了 std::string_view 類型來接收錯誤消息。當一…

CentOS8 Stream 網卡配置及重啟

在 CentOS 8 Stream 中&#xff0c;網卡配置已由 NetworkManager 管理&#xff0c;傳統的 ifcfg-eth0 文件仍然支持&#xff0c;但推薦使用 nmcli 或 nmtui 工具進行網絡配置和管理。以下是網卡配置及重啟的詳細步驟&#xff1a;1. 查看當前網卡狀態列出所有網卡bash復制nmcli …

SpringMvc的原理深度剖析及源碼解讀

一、springmvc啟動加載流程1、引入spring-web.jar包時&#xff0c;在這個包的META-INF/services/javax.servlet.ServletContainerInitializer文件中定義的加載類SpringServletContainerInitializer,提供給springmvc實現初始化的操作。2、在SpringServletContainerInitializer類…

【ESP32-menuconfig(1) -- Build Type及Bootloader config】

Build Type Bootloader configmenuconfig介紹Build typeCONFIG_APP_BUILD_TYPECONFIG_APP_BUILD_TYPE_PURE_RAM_APPCONFIG_APP_REPRODUCIBLE_BUILDCONFIG_APP_NO_BLOBSCONFIG_APP_COMPATIBLE_PRE_V2_1_BOOTLOADERSCONFIG_APP_COMPATIBLE_PRE_V3_1_BOOTLOADERSBootloader config…

C++信息學奧賽一本通-第一部分-基礎一-第3章-第1節

C信息學奧賽一本通-第一部分-基礎一-第3章-第1節 2051 偶數 #include <iostream>using namespace std;int main() {int number; cin >> number;if (number % 2 0) {cout << "yes";} }2052 范圍判斷 #include <iostream>using namespace std…