文章目錄
- 讀寫內部Flash
- 接線
- 程序編寫
- 測試效果
- 補充
- 讀取芯片id
- 代碼編寫
讀寫內部Flash
接線
程序編寫
首先使用ThisFlash.c來寫入flash的基本操作,寫入、讀取、擦除,然后使用Store.c配合數組來進行主存與flash的交互
ThisFlash.c
#include "stm32f10x.h" // Device header
/*** @brief 讀取此地址一個字的數據* @param Address,頁地址* @retval 此地址的一個字的數據*/
uint32_t ThisFlash_ReadWord(uint32_t Address){return *((__IO uint32_t *)(Address));
}
/*** @brief 讀取此地址的半字數據* @param Address,頁地址* @retval 此地址的半字數據*/
uint16_t ThisFlash_ReadHalfWord(uint32_t Address){return *((__IO uint16_t *)(Address));
}
/*** @brief 讀取此地址一個字節的數據* @param Address,頁地址* @retval 此地址的一個字節的數據*/
uint8_t ThisFlash_ReadByte(uint32_t Address){return *((__IO uint8_t *)(Address));
}
/*** @brief 擦除整頁數據* @param 無* @retval 無*/
void ThisFlash_EraseAllPages(void){FLASH_Unlock(); // 解鎖FLASH_EraseAllPages(); // 擦除所有頁FLASH_Lock(); // 重新上鎖
}
/*** @brief 擦除指定頁數據* @param 無* @retval 無*/
void ThisFlash_ErasePage(uint32_t PageAddress){FLASH_Unlock(); // 解鎖FLASH_ErasePage(PageAddress); // 擦除指定頁FLASH_Lock(); // 重新上鎖
}
/*** @brief 指定地址寫入一個字的數據* @param Address,頁地址 Data,數據* @retval 無*/
void ThisFlash_PragramWord(uint32_t Address,uint32_t Data){FLASH_Unlock(); // 解鎖FLASH_ProgramWord(Address,Data); // 指定地址寫入一個字的數據FLASH_Lock(); // 重新上鎖
}
/*** @brief 指定地址寫入半字數據* @param Address,頁地址 Data,數據* @retval 無*/
void ThisFlash_PragramHalfWord(uint32_t Address,uint16_t Data){FLASH_Unlock(); // 解鎖FLASH_ProgramHalfWord(Address,Data); // 指定地址寫入一個字的數據FLASH_Lock(); // 重新上鎖
}
ThisFlash.h
#ifndef __THISFLASH_H
#define __THISFLASH_H
uint32_t ThisFlash_ReadWord(uint32_t Address);
uint16_t ThisFlash_ReadHalfWord(uint32_t Address);
uint8_t ThisFlash_ReadByte(uint32_t Address);
void ThisFlash_EraseAllPages(void);
void ThisFlash_ErasePage(uint32_t PageAddress);
void ThisFlash_PragramWord(uint32_t Address,uint32_t Data);
void ThisFlash_PragramHalfWord(uint32_t Address,uint16_t Data);#endif
store.c
#include "stm32f10x.h" // Device header
#include "ThisFlash.h"// 用于與flash交互的數組,存儲與ram中
uint16_t Store_Data[512];/*** @brief 初始化最后一頁* @param 無* @retval 無*/
void Store_Init(void){// 使用最后一頁第一個半字作為是否為第一次寫入的標志位if(ThisFlash_ReadHalfWord(0x0800fc00) != 0xa5a5){ThisFlash_ErasePage(0x0800fc00); // 第一次寫入,擦掉此頁數據ThisFlash_PragramHalfWord(0x0800fc00,0xa5a5); // 寫入標志位for(uint16_t i=1;i<512;i++){ThisFlash_PragramHalfWord(0x0800fc00+i*2,0x0000); }}for(uint16_t i=0;i<512;i++){Store_Data[i] = ThisFlash_ReadHalfWord(0x0800fc00+i*2); // 寫入標志位}
}
/*** @brief 備份Store_Data到flash* @param 無* @retval 無*/
void Store_Backup(void){ThisFlash_ErasePage(0x0800fc00);for(uint16_t i=0;i<512;i++){ThisFlash_PragramHalfWord(0x0800fc00+i*2,Store_Data[i]); // 寫入標志位}
}
/*** @brief 擦除Store_Data并備份到flash* @param 無* @retval 無*/
void Store_Clear(void){for(uint16_t i=0;i<512;i++){Store_Data[i] = 0x0000; // 寫入標志位}Store_Backup(); // flash同步清空
}
store.h
#ifndef __STORE_H
#define __STORE_H
extern uint16_t Store_Data[512];
void Store_Init(void);
void Store_Backup(void);
void Store_Clear(void);#endif
button.c
#include "stm32f10x.h" // Device header
#include "Delay.h"/*** @brief 初始化Button相關端口* @param 無* @retval 無*/
void Button_Init(void){// 初始化時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/*** @brief 返回所按按鍵值* @param 無* @retval KeyNum 按鍵值*/
uint8_t Key_Num(void){uint8_t KeyNum = 0;if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)==0);Delay_ms(20);KeyNum = 1;}if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)==0);Delay_ms(20);KeyNum = 11;}return KeyNum;
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Store.h"
#include "button.h"uint8_t KeyNum;int main(void)
{OLED_Init();Button_Init();Store_Init();// 為了不影響芯片的其他功能,在flash最后一頁寫入數據來測試while (1){KeyNum = Key_Num();if(KeyNum == 1){Store_Data[1] = 0x1314;Store_Data[3] = 0X3344;Store_Backup();}if(KeyNum == 11){Store_Clear();}OLED_ShowHexNum(1,1,Store_Data[1],4);OLED_ShowHexNum(2,1,Store_Data[3],4); OLED_ShowString(3,1,"Flag:");OLED_ShowHexNum(3,7,Store_Data[0],4);}
}
測試效果
下載程序后按下b11的按鍵最后一頁數據清零,使用ST-LINK Utility查看
然后按下復位鍵,初始化函數執行,標志位置a5a5(為小端對齊反式)
然后按下b1按鍵,寫入數據到數組并備份到flash,并且掉電不丟失
補充
還可以根據所需要的閃存空間來設置留給程序的閃存大小
讀取芯片id
代碼編寫
根據手冊給出的器件id地址一一使用指針讀取
- 顯示閃存大小
顯示uid
main.c內容如下:
#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,8,*((__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(3,1,*((__IO uint32_t *)(0x1FFFF7E8+0x08)),8);while (1){}
}