文章目录
- 读写内部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)
{
}
}