国产精品久久久久影院,成人午夜福利视频,国产精品久久久久高潮,国产精品 欧美 亚洲 制服,国产精品白浆无码流出

歷史上的今天

今天是:2025年07月17日(星期四)

2018年07月17日 | STM32 FLASH做EEPROM用

發(fā)布者:superstar10 來源: eefocus關鍵字:STM32  FLASH  EEPROM 手機看文章 掃描二維碼
隨時隨地手機看文章

STM32 本身沒有自帶 EEPROM,但是 STM32 具有 IAP(在應用編程)功能,所以我們可以把它的 FLASH 當成 EEPROM 來使用

STM32 FLASH 簡介

不同型號的 STM32,其 FLASH 容量也有所不同,最小的只有 16K 字節(jié),最大的則達到了1024K 字節(jié)。戰(zhàn)艦 STM32 開發(fā)板選擇的 STM32F103ZET6 的 FLASH 容量為 512K 字節(jié),屬于大容量產品(另外還有中容量和小容量產品),

STM32 的閃存模塊由:主存儲器、信息塊和閃存存儲器接口寄存器等 3 部分組成。

主存儲器,該部分用來存放代碼和數(shù)據(jù)常數(shù)(如 const 類型的數(shù)據(jù))。對于大容量產品,其被劃分為 256 頁,每頁 2K 字節(jié)。注意,小容量和中容量產品則每頁只有 1K 字節(jié)。從上圖可以看出主存儲器的起始地址就是 0X08000000,  B0、B1 都接 GND 的時候,就是從 0X08000000開始運行代碼的。

信息塊,該部分分為 2 個小部分,其中啟動程序代碼,是用來存儲 ST 自帶的啟動程序,用于串口下載代碼,當 B0 接 V3.3,B1 接 GND 的時候,運行的就是這部分代碼。用戶選擇字節(jié),則一般用于配置寫保護、讀保護等功能,

閃存存儲器接口寄存器,該部分用于控制閃存讀寫等,是整個閃存模塊的控制機構。

閃存的讀取

內置閃存模塊可以在通用地址空間直接尋址,任何 32 位數(shù)據(jù)的讀操作都能訪問閃存模塊的內容并得到相應的數(shù)據(jù)。讀接口在閃存端包含一個讀控制器,還包含一個 AHB 接口與 CPU 銜接。這個接口的主要工作是產生讀閃存的控制信號并預取 CPU 要求的指令塊,預取指令塊僅用于在 I-Code 總線上的取指操作,數(shù)據(jù)常量是通過 D-Code 總線訪問的。這兩條總線的訪問目標是相同的閃存模塊,訪問 D-Code 將比預取指令優(yōu)先級高

這里要特別留意一個閃存等待時間,因為 CPU 運行速度比 FLASH 快得多,STM32F103的 FLASH 最快訪問速度≤24Mhz,如果 CPU 頻率超過這個速度,那么必須加入等待時間,比如我們一般使用 72Mhz 的主頻,那么 FLASH 等待周期就必須設置為 2,該設置通過 FLASH_ACR寄存器設置。

使用 STM32 的官方固件庫操作 FLASH 的幾個常用函數(shù)。這些函數(shù)和定義分布在文件 stm32f10x_flash.c 以及 stm32f10x_flash.h 文件中。

1.  鎖定解鎖函數(shù)

在對 FLASH 進行寫操作前必須先解鎖,解鎖操作也就是必須在 FLASH_KEYR 寄存器寫入特定的序列(KEY1 和 KEY2),固件庫函數(shù)實現(xiàn)很簡單:

void FLASH_Unlock(void);

同樣的道理,在對 FLASH 寫操作完成之后,我們要鎖定 FLASH,使用的庫函數(shù)是:

void FLASH_Lock(void);

2.  寫操作函數(shù)

固件庫提供了三個 FLASH 寫函數(shù):

FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);

FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);

FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);

顧名思義分別為:FLASH_ProgramWord 為  32 位字寫入函數(shù),其他分別為 16 位半字寫入和用戶選擇字節(jié)寫入函數(shù)。這里需要說明,32 位字節(jié)寫入實際上是寫入的兩次 16 位數(shù)據(jù),寫完第一次后地址+2,這與我們前面講解的 STM32 閃存的編程每次必須寫入 16 位并不矛盾。寫入 8位實際也是占用的兩個地址了,跟寫入 16 位基本上沒啥區(qū)別。

3.  擦除函數(shù)

固件庫提供三個 FLASH 擦除函數(shù):

FLASH_Status FLASH_ErasePage(uint32_t Page_Address);

FLASH_Status FLASH_EraseAllPages(void);

FLASH_Status FLASH_EraseOptionBytes(void);

這三個函數(shù)可以顧名思義了,非常簡單。

4.  獲取 FLASH 狀態(tài)

主要是用的函數(shù)是:

FLASH_Status FLASH_GetStatus(void);

返回值是通過枚舉類型定義的:

typedef enum

  FLASH_BUSY = 1,//忙

  FLASH_ERROR_PG,//編程錯誤

  FLASH_ERROR_WRP,//寫保護錯誤

  FLASH_COMPLETE,//操作完成

  FLASH_TIMEOUT//操作超時

}FLASH_Status;

從這里面我們可以看到 FLASH 操作的 5 個狀態(tài),每個代表的意思我們在后面注釋了。

5.  等待操作完成函數(shù)

在執(zhí)行閃存寫操作時,任何對閃存的讀操作都會鎖住總線,在寫操作完成后讀操作才能正確地進行;既在進行寫或擦除操作時,不能進行代碼或數(shù)據(jù)的讀取操作。所以在每次操作之前,我們都要等待上一次操作完成這次操作才能開始。使用的函數(shù)是:

FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout)

入口參數(shù)為等待時間,返回值是 FLASH 的狀態(tài),這個很容易理解,這個函數(shù)本身我們在固件庫中使用得不多,但是在固件庫函數(shù)體中間可以多次看到。

6.  讀 FLASH 特定地址數(shù)據(jù)函數(shù)

有寫就必定有讀,而讀取 FLASH 指定地址的半字的函數(shù)固件庫并沒有給出來,這里我們自己寫的一個函數(shù):

u16 STMFLASH_ReadHalfWord(u32 faddr)

{

return *(vu16*)faddr; 

}

//讀取指定地址的半字(16位數(shù)據(jù))

//faddr:讀地址(此地址必須為2的倍數(shù)!!)

//返回值:對應數(shù)據(jù).

u16 STMFLASH_ReadHalfWord(u32 faddr)

{

    return *(vu16*)faddr; 

}



#if STM32_FLASH_WREN    //如果使能了寫 

//不檢查的寫入

//WriteAddr:起始地址

//pBuffer:數(shù)據(jù)指針

//NumToWrite:半字(16位)數(shù) 

void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite) 

{                       

    u16 i;

    for(i=0;i

    {

        FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);

     WriteAddr+=2;//地址增加2.

    } 

//從指定地址開始寫入指定長度的數(shù)據(jù)

//WriteAddr:起始地址(此地址必須為2的倍數(shù)!!)

//pBuffer:數(shù)據(jù)指針

//NumToWrite:半字(16位)數(shù)(就是要寫入的16位數(shù)據(jù)的個數(shù).)

#if STM32_FLASH_SIZE<256

#define STM_SECTOR_SIZE 1024 //字節(jié)

#else 

#define STM_SECTOR_SIZE    2048

#endif         

u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字節(jié)

void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)    

{

    u32 secpos;     //扇區(qū)地址

    u16 secoff;     //扇區(qū)內偏移地址(16位字計算)

    u16 secremain; //扇區(qū)內剩余地址(16位字計算)     

     u16 i; 

    u32 offaddr; //去掉0X08000000后的地址

    if(WriteAddr=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址

    FLASH_Unlock();                        //解鎖

    offaddr=WriteAddr-STM32_FLASH_BASE;        //實際偏移地址.

    secpos=offaddr/STM_SECTOR_SIZE;            //扇區(qū)地址 0~127 for STM32F103RBT6

    secoff=(offaddr%STM_SECTOR_SIZE)/2;        //在扇區(qū)內的偏移(2個字節(jié)為基本單位.)

    secremain=STM_SECTOR_SIZE/2-secoff;        //扇區(qū)剩余空間大小 

    if(NumToWrite<=secremain)secremain=NumToWrite;//不大于該扇區(qū)范圍

    while(1) 

    {    

        STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//讀出整個扇區(qū)的內容

        for(i=0;i

        {

            if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除      

        }

        if(i

        {

            FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除這個扇區(qū)

            for(i=0;i

            {

                STMFLASH_BUF[i+secoff]=pBuffer[i];     

            }

            STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//寫入整個扇區(qū) 

        }else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//寫已經擦除了的,直接寫入扇區(qū)剩余區(qū)間.                  

        if(NumToWrite==secremain)break;//寫入結束了

        else//寫入未結束

        {

            secpos++;                //扇區(qū)地址增1

            secoff=0;                //偏移位置為0      

             pBuffer+=secremain;     //指針偏移

            WriteAddr+=secremain;    //寫地址偏移     

             NumToWrite-=secremain;    //字節(jié)(16位)數(shù)遞減

            if(NumToWrite>(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//下一個扇區(qū)還是寫不完

            else secremain=NumToWrite;//下一個扇區(qū)可以寫完了

        }     

    };    

    FLASH_Lock();//上鎖

}

#endif



//從指定地址開始讀出指定長度的數(shù)據(jù)

//ReadAddr:起始地址

//pBuffer:數(shù)據(jù)指針

//NumToWrite:半字(16位)數(shù)

void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)     

{

    u16 i;

    for(i=0;i

    {

        pBuffer[i]=STMFLASH_ReadHalfWord(ReadAddr);//讀取2個字節(jié).

        ReadAddr+=2;//偏移2個字節(jié).    

    }

}


//////////////////////////////////////////////////////////////////////////////////////////////////////

//WriteAddr:起始地址

//WriteData:要寫入的數(shù)據(jù)

void Test_Write(u32 WriteAddr,u16 WriteData)     

{

    STMFLASH_Write(WriteAddr,&WriteData,1);//寫入一個字 

}


關鍵字:STM32  FLASH  EEPROM 引用地址:STM32 FLASH做EEPROM用

上一篇:STM32中斷設置相關寄存器的分析
下一篇:STM32系統(tǒng)學習——I2C (讀寫EEPROM)

推薦閱讀

就在特朗普政府宣布加征關稅的同一天,7月10日,美國汽車制造商特斯拉宣布,已與中國達成協(xié)議,將在上海建造一座電池和汽車工廠,特斯拉表示,其在上海的計劃將包括一個研發(fā)中心和一個銷售企業(yè)。CEO馬斯克宣告,上海將成為美國以外第一個超級工廠所在地。?兩周前,另一家美國虛擬機霸主VMware剛剛在西安開完其在中國的大中華區(qū)合作伙伴領導人峰會,這是這...
智能語音助手與四輪汽車大概是屬性最契合的CP,畢竟癱在家里動動嘴皮子去指使家電自己干活兒大多只是懶,而在駕駛途中,老司機們才是真的抽不出手去進行一些復雜的操作。去年奧迪在自家全新的e-tron電動車系列中搭載了亞馬遜Alexa,算是讓這個整日附身于智能音箱的語音助手正式“出圈”。不過最近亞馬遜表示這只是他們進入汽車領域的第一步,接下來他們要...
在STM32中,有五個時鐘源,為HSI、HSE、LSI、LSE、PLL。①HSI是高速內部時鐘,RC振蕩器,頻率為8MHz。②HSE是高速外部時鐘,可接石英/陶瓷諧振器,或者接外部時鐘源,頻率范圍為4MHz~16MHz。③LSI是低速內部時鐘,RC振蕩器,頻率為40kHz。④LSE是低速外部時鐘,接頻率為32.768kHz的石英晶體。⑤PLL為鎖相環(huán)倍頻輸出,其時鐘輸入源可選擇為HSI/2、HSE或者HS...
(文/程文智)7月15日,在第七屆中國機器人峰會暨智能經濟人才峰會上,中國工程院院士、國家農業(yè)信息化工程技術研究趙春江分享了《農業(yè)機器人展望》的報告。他在分享中提到,2020年農業(yè)機器人市場的規(guī)模大概為74億美元,預計2025年達到206億美元。他同時提到了目前農業(yè)機器人遇到的瓶頸問題,以及目前我國在農業(yè)機器人方面的一些實踐案例。圖:中國工程院...

史海拾趣

小廣播
設計資源 培訓 開發(fā)板 精華推薦

最新單片機文章

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發(fā)圈

 
機器人開發(fā)圈

電子工程世界版權所有 京ICP證060456號 京ICP備10001474號-1 電信業(yè)務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved