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