Flash閃存

15.Flash

FLASH簡(jiǎn)介:

  1. STM32F1系列的FLASH包含程序存儲(chǔ)器、系統(tǒng)存儲(chǔ)器和選項(xiàng)字節(jié)三個(gè)部分,
    通過(guò)閃存存儲(chǔ)器接口(外設(shè))可以對(duì)程序存儲(chǔ)器和選項(xiàng)字節(jié)進(jìn)行擦除和編程
  1. 讀寫FLASH的用途:
    利用程序存儲(chǔ)器的剩余空間來(lái)保存掉電不丟失的用戶數(shù)據(jù)
    通過(guò)在程序中編程(IAP),實(shí)現(xiàn)程序的自我更新
  2. 在線編程(In-Circuit Programming-ICP)用于更新程序存儲(chǔ)器的全部?jī)?nèi)容,它通過(guò)JTAG、SWD協(xié)議或系統(tǒng)加載程序(Bootloader)下載程序
  3. 在程序中編程(In-Application Programming-IAP)可以使用微控制器支持的任一種通信接口下載程序

15.1 讀寫內(nèi)部Flash

MyFlash--> Store--> main

#ifndef __MYFLASH_H
#define __MYFLASH_H
uint32_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_ErasePage(uint32_t PageAddress);
void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data);
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);
#endif


#include "stm32f10x.h"                  // Device header

/**
  * 函    數(shù):FLASH讀取一個(gè)32位的字
  * 參    數(shù):Address 要讀取數(shù)據(jù)的字地址
  * 返 回 值:指定地址下的數(shù)據(jù)
  */
uint32_t MyFLASH_ReadWord(uint32_t Address)
{
    return *((__IO uint32_t *)(Address));   //使用指針訪問(wèn)指定地址下的數(shù)據(jù)并返回
}

/**
  * 函    數(shù):FLASH讀取一個(gè)16位的半字
  * 參    數(shù):Address 要讀取數(shù)據(jù)的半字地址
  * 返 回 值:指定地址下的數(shù)據(jù)
  */
uint16_t MyFLASH_ReadHalfWord(uint32_t Address)
{
    return *((__IO uint16_t *)(Address));   //使用指針訪問(wèn)指定地址下的數(shù)據(jù)并返回
}

/**
  * 函    數(shù):FLASH讀取一個(gè)8位的字節(jié)
  * 參    數(shù):Address 要讀取數(shù)據(jù)的字節(jié)地址
  * 返 回 值:指定地址下的數(shù)據(jù)
  */
uint8_t MyFLASH_ReadByte(uint32_t Address)
{
    return *((__IO uint8_t *)(Address));    //使用指針訪問(wèn)指定地址下的數(shù)據(jù)并返回
}

/**
  * 函    數(shù):FLASH全擦除
  * 參    數(shù):無(wú)
  * 返 回 值:無(wú)
  * 說(shuō)    明:調(diào)用此函數(shù)后,F(xiàn)LASH的所有頁(yè)都會(huì)被擦除,包括程序文件本身,擦除后,程序?qū)⒉粡?fù)存在
  */
void MyFLASH_EraseAllPages(void)
{
    FLASH_Unlock();                 //解鎖
    FLASH_EraseAllPages();          //全擦除
    FLASH_Lock();                   //加鎖
}
/**
  * 函    數(shù):FLASH頁(yè)擦除
  * 參    數(shù):PageAddress 要擦除頁(yè)的頁(yè)地址
  * 返 回 值:無(wú)
  */
void MyFLASH_ErasePage(uint32_t PageAddress)
{
    FLASH_Unlock();                 //解鎖
    FLASH_ErasePage(PageAddress);   //頁(yè)擦除
    FLASH_Lock();                   //加鎖
}

/**
  * 函    數(shù):FLASH編程字
  * 參    數(shù):Address 要寫入數(shù)據(jù)的字地址
  * 參    數(shù):Data 要寫入的32位數(shù)據(jù)
  * 返 回 值:無(wú)
  */
void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data)
{
    FLASH_Unlock();                         //解鎖
    FLASH_ProgramWord(Address, Data);       //編程字
    FLASH_Lock();                           //加鎖
}

/**
  * 函    數(shù):FLASH編程半字
  * 參    數(shù):Address 要寫入數(shù)據(jù)的半字地址
  * 參    數(shù):Data 要寫入的16位數(shù)據(jù)
  * 返 回 值:無(wú)
  */
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{
    FLASH_Unlock();                         //解鎖
    FLASH_ProgramHalfWord(Address, Data);   //編程半字
    FLASH_Lock();                           //加鎖
}

//Store.h Store.c

#ifndef __STORE_H
#define __STORE_H
extern uint16_t Store_Data[];
void Store_Init(void);
void Store_Save(void);
void Store_Clear(void);
#endif


#include "stm32f10x.h"                  // Device header
#include "MyFLASH.h"   //繼承于MyFlash
#define STORE_START_ADDRESS     0x0800FC00      //存儲(chǔ)的起始地址,存儲(chǔ)到最后一頁(yè).
#define STORE_COUNT             512             //存儲(chǔ)數(shù)據(jù)的個(gè)數(shù)

uint16_t Store_Data[STORE_COUNT];               //定義SRAM數(shù)組
/**
  * 函    數(shù):參數(shù)存儲(chǔ)模塊初始化
  * 參    數(shù):無(wú)
  * 返 回 值:無(wú)
  */
void Store_Init(void)
{
    /*判斷是不是第一次使用*/
    if (MyFLASH_ReadHalfWord(STORE_START_ADDRESS) != 0xA5A5)    //讀取第一個(gè)半字的標(biāo)志位,if成立,則執(zhí)行第一次使用的初始化
    {
        MyFLASH_ErasePage(STORE_START_ADDRESS);                 //擦除指定頁(yè)
        MyFLASH_ProgramHalfWord(STORE_START_ADDRESS, 0xA5A5);   //在第一個(gè)半字寫入自己規(guī)定的標(biāo)志位,用于判斷是不是第一次使用
        for (uint16_t i = 1; i < STORE_COUNT; i ++)             //循環(huán)STORE_COUNT次,除了第一個(gè)標(biāo)志位
        {
            MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, 0x0000);       //除了標(biāo)志位的有效數(shù)據(jù)全部清0
        }
    }
    
    /*上電時(shí),將閃存數(shù)據(jù)加載回SRAM數(shù)組,實(shí)現(xiàn)SRAM數(shù)組的掉電不丟失*/
    for (uint16_t i = 0; i < STORE_COUNT; i ++)                 //循環(huán)STORE_COUNT次,包括第一個(gè)標(biāo)志位
    {
        Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS + i * 2);      //將閃存的數(shù)據(jù)加載回SRAM數(shù)組
    }
}

/**
  * 函    數(shù):參數(shù)存儲(chǔ)模塊保存數(shù)據(jù)到閃存
  * 參    數(shù):無(wú)
  * 返 回 值:無(wú)
  */
void Store_Save(void)
{
    MyFLASH_ErasePage(STORE_START_ADDRESS);             //擦除指定頁(yè)
    for (uint16_t i = 0; i < STORE_COUNT; i ++)         //循環(huán)STORE_COUNT次,包括第一個(gè)標(biāo)志位
    {
        MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, Store_Data[i]);    //將SRAM數(shù)組的數(shù)據(jù)備份保存到閃存
    }
}

/**
  * 函    數(shù):參數(shù)存儲(chǔ)模塊將所有有效數(shù)據(jù)清0
  * 參    數(shù):無(wú)
  * 返 回 值:無(wú)
  */
void Store_Clear(void)
{
    for (uint16_t i = 1; i < STORE_COUNT; i ++)         //循環(huán)STORE_COUNT次,除了第一個(gè)標(biāo)志位
    {
        Store_Data[i] = 0x0000;                         //SRAM數(shù)組有效數(shù)據(jù)清0
    }
    Store_Save();                                       //保存數(shù)據(jù)到閃存
}
#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();                //OLED初始化
    Key_Init();                 //按鍵初始化
    Store_Init();               //參數(shù)存儲(chǔ)模塊初始化,在上電的時(shí)候?qū)㈤W存的數(shù)據(jù)加載回Store_Data,實(shí)現(xiàn)掉電不丟失
    
    /*顯示靜態(tài)字符串*/
    OLED_ShowString(1, 1, "Flag:");
    OLED_ShowString(2, 1, "Data:");
    
    while (1)
    {
        KeyNum = Key_GetNum();      //獲取按鍵鍵碼    
        if (KeyNum == 1)            //按鍵1按下
        {
            Store_Data[1] ++;       //變換測(cè)試數(shù)據(jù)
            Store_Data[2] += 2;
            Store_Data[3] += 3;
            Store_Data[4] += 4;
            Store_Save();           //將Store_Data的數(shù)據(jù)備份保存到閃存,實(shí)現(xiàn)掉電不丟失
        }
        if (KeyNum == 2)            //按鍵2按下
        {
            Store_Clear();          //將Store_Data的數(shù)據(jù)全部清0
        }
        
        OLED_ShowHexNum(1, 6, Store_Data[0], 4);    //顯示Store_Data的第一位標(biāo)志位
        OLED_ShowHexNum(3, 1, Store_Data[1], 4);    //顯示Store_Data的有效存儲(chǔ)數(shù)據(jù)
        OLED_ShowHexNum(3, 6, Store_Data[2], 4);
        OLED_ShowHexNum(4, 1, Store_Data[3], 4);
        OLED_ShowHexNum(4, 6, Store_Data[4], 4);
    }
}

2. 讀取芯片ID

int main(void)
{
    OLED_Init();                        //OLED初始化
    
    OLED_ShowString(1, 1, "F_SIZE:");   //顯示靜態(tài)字符串
    OLED_ShowHexNum(1, 8, *((__IO uint16_t *)(0x1FFFF7E0)), 4);     //使用指針讀取指定地址下的閃存容量寄存器
    
    OLED_ShowString(2, 1, "U_ID:");     //顯示靜態(tài)字符串
    OLED_ShowHexNum(2, 6, *((__IO uint16_t *)(0x1FFFF7E8)), 4);     //使用指針讀取指定地址下的產(chǎn)品唯一身份標(biāo)識(shí)寄存器
    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)
    {
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容