STM32读写内部FLASH

文章目录

[1. FLASH](#1. FLASH)

[2. 读写内部FLASH](#2. 读写内部FLASH)

[2.1 软件调试](#2.1 软件调试)

[2.2 MyFLASH.c](#2.2 MyFLASH.c)

[2.3 MyFLASH.h](#2.3 MyFLASH.h)

[2.4 Store.c](#2.4 Store.c)

[2.5 Store.h](#2.5 Store.h)

[2.6 main.c](#2.6 main.c)

[3. 读取芯片ID](#3. 读取芯片ID)

[3.1 main.c](#3.1 main.c)


1. FLASH

对于FLASH闪存的详细解析可以看下面这篇文章:

STM32单片机FLASH闪存详解-CSDN博客

2. 读写内部FLASH

代码中My实现闪存的读取,擦除和编程功能,store实现参数数据的读写和储存管理。最终实现任意读写参数,参数掉电不丢失。

2.1 软件调试

使用STM32 ST-LINK Utility软件可以实时查看闪存中保存的参数。

打开软件后,使用ST-link将stm32连接到电脑,点击第三个按钮(Connect to the target),就可以看到闪存中保存的参数。

Address: 0x08000000 代表闪存地址的起始位。下面数据就是程序代码

size:0x1000 代表从起始地址开始,一共查看多少个字节。这里是查看64kb的字节数,计算方法为:先转为十进制:65536,然后除以1024,得到64.

Data Width:数据宽度,这里是32bits

并且点击任意一个数据,可以直接修改stm32中的数据。

选项字节配置

点击Target - Option Core,打开选项字节配置页面,包括读保护,用户配置,自定义两个字节和写保护。

需要使用的相关函数在文件stm32f10x_flash.c 和 stm32f10x_flash.h中

2.2 MyFLASH.c

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:FLASH读取一个32位的字
  * 参    数:Address 要读取数据的字地址
  * 返 回 值:指定地址下的数据
  */
uint32_t MyFLASH_ReadWord(uint32_t Address)
{
	return *((__IO uint32_t *)(Address));	//使用指针访问指定地址下的数据并返回
}

/**
  * 函    数:FLASH读取一个16位的半字
  * 参    数:Address 要读取数据的半字地址
  * 返 回 值:指定地址下的数据
  */
uint16_t MyFLASH_ReadHalfWord(uint32_t Address)
{
	return *((__IO uint16_t *)(Address));	//使用指针访问指定地址下的数据并返回
}

/**
  * 函    数:FLASH读取一个8位的字节
  * 参    数:Address 要读取数据的字节地址
  * 返 回 值:指定地址下的数据
  */
uint8_t MyFLASH_ReadByte(uint32_t Address)
{
	return *((__IO uint8_t *)(Address));	//使用指针访问指定地址下的数据并返回
}

/**
  * 函    数:FLASH全擦除
  * 说    明:调用此函数后,FLASH的所有页都会被擦除,包括程序文件本身,擦除后,程序将不复存在
  */
void MyFLASH_EraseAllPages(void)
{
	FLASH_Unlock();					//解锁
	FLASH_EraseAllPages();			//全擦除
	FLASH_Lock();					//加锁
}

/**
  * 函    数:FLASH页擦除
  * 参    数:PageAddress 要擦除页的页地址
  */
void MyFLASH_ErasePage(uint32_t PageAddress)
{
	FLASH_Unlock();					//解锁
	FLASH_ErasePage(PageAddress);	//页擦除
	FLASH_Lock();					//加锁
}

/**
  * 函    数:FLASH编程字
  * 参    数:Address 要写入数据的字地址
  * 参    数:Data 要写入的32位数据
  */
void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data)
{
	FLASH_Unlock();							//解锁
	FLASH_ProgramWord(Address, Data);		//编程字
	FLASH_Lock();							//加锁
}

/**
  * 函    数:FLASH编程半字
  * 参    数:Address 要写入数据的半字地址
  * 参    数:Data 要写入的16位数据
  */
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{
	FLASH_Unlock();							//解锁
	FLASH_ProgramHalfWord(Address, Data);	//编程半字
	FLASH_Lock();							//加锁
}

2.3 MyFLASH.h

#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

2.4 Store.c

#include "stm32f10x.h"                  // Device header
#include "MyFLASH.h"

#define STORE_START_ADDRESS		0x0800FC00		//存储的起始地址
#define STORE_COUNT				512				//存储数据的个数

uint16_t Store_Data[STORE_COUNT];				//定义SRAM数组

//参数存储模块初始化
void Store_Init(void)
{
	/*判断是不是第一次使用*/
	if (MyFLASH_ReadHalfWord(STORE_START_ADDRESS) != 0xA5A5)	//读取第一个半字的标志位,if成立,则执行第一次使用的初始化
	{
		MyFLASH_ErasePage(STORE_START_ADDRESS);					//擦除指定页
		MyFLASH_ProgramHalfWord(STORE_START_ADDRESS, 0xA5A5);	//在第一个半字写入自己规定的标志位,用于判断是不是第一次使用
		for (uint16_t i = 1; i < STORE_COUNT; i ++)				//循环STORE_COUNT次,除了第一个标志位
		{
			MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, 0x0000);		//除了标志位的有效数据全部清0
		}
	}
	
	/*上电时,将闪存数据加载回SRAM数组,实现SRAM数组的掉电不丢失*/
	for (uint16_t i = 0; i < STORE_COUNT; i ++)					//循环STORE_COUNT次,包括第一个标志位
	{
		Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS + i * 2);		//将闪存的数据加载回SRAM数组
	}
}

//参数存储模块保存数据到闪存
void Store_Save(void)
{
	MyFLASH_ErasePage(STORE_START_ADDRESS);				//擦除指定页
	for (uint16_t i = 0; i < STORE_COUNT; i ++)			//循环STORE_COUNT次,包括第一个标志位
	{
		MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, Store_Data[i]);	//将SRAM数组的数据备份保存到闪存
	}
}

//参数存储模块将所有有效数据清0
void Store_Clear(void)
{
	for (uint16_t i = 1; i < STORE_COUNT; i ++)			//循环STORE_COUNT次,除了第一个标志位
	{
		Store_Data[i] = 0x0000;							//SRAM数组有效数据清0
	}
	Store_Save();										//保存数据到闪存
}

2.5 Store.h

#ifndef __STORE_H
#define __STORE_H

extern uint16_t Store_Data[];

void Store_Init(void);
void Store_Save(void);
void Store_Clear(void);

#endif

2.6 main.c

  • 模块初始化

    • 初始化OLED显示屏。
    • 初始化按键模块。
    • 初始化参数存储模块,并在上电时将闪存中的数据加载回 Store_Data
  • 显示静态字符串

    • 在OLED显示屏上显示静态字符串"Flag:"和"Data:"。
  • 主循环

    • 获取按键键码。

    • 根据按键键码执行不同操作:

      • 如果按键1按下,更新 Store_Data 中的数据,并将数据备份保存到闪存中。
      • 如果按键2按下,清除 Store_Data 中的所有数据。
    • 显示 Store_Data 中的数据。

      #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(); //参数存储模块初始化,在上电的时候将闪存的数据加载回Store_Data,实现掉电不丢失

      /*显示静态字符串*/
      OLED_ShowString(1, 1, "Flag:");
      OLED_ShowString(2, 1, "Data:");
      
      while (1)
      {
      	KeyNum = Key_GetNum();		//获取按键键码
      	
      	if (KeyNum == 1)			//按键1按下
      	{
      		Store_Data[1] ++;		//变换测试数据
      		Store_Data[2] += 2;
      		Store_Data[3] += 3;
      		Store_Data[4] += 4;
      		Store_Save();			//将Store_Data的数据备份保存到闪存,实现掉电不丢失
      	}
      	
      	if (KeyNum == 2)			//按键2按下
      	{
      		Store_Clear();			//将Store_Data的数据全部清0
      	}
      	
      	OLED_ShowHexNum(1, 6, Store_Data[0], 4);	//显示Store_Data的第一位标志位
      	OLED_ShowHexNum(3, 1, Store_Data[1], 4);	//显示Store_Data的有效存储数据
      	OLED_ShowHexNum(3, 6, Store_Data[2], 4);
      	OLED_ShowHexNum(4, 1, Store_Data[3], 4);
      	OLED_ShowHexNum(4, 6, Store_Data[4], 4);
      }
      

      }

3. 读取芯片ID

这个代码可以实现读取闪存容量和身份标识。

3.1 main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"

int main(void)
{
	OLED_Init();						//OLED初始化
	
	OLED_ShowString(1, 1, "F_SIZE:");	//显示静态字符串
	OLED_ShowHexNum(1, 8, *((__IO uint16_t *)(0x1FFFF7E0)), 4);		//使用指针读取指定地址下的闪存容量寄存器
	
	OLED_ShowString(2, 1, "U_ID:");		//显示静态字符串
	OLED_ShowHexNum(2, 6, *((__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(4, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x08)), 8);
	
	while (1)
	{
		
	}
}
相关推荐
BT-BOX几秒前
STM32仿真proteus位带操作和keil增加头文件C文件
c语言·stm32·proteus
7yewh1 小时前
嵌入式硬件实战提升篇(一)-泰山派RK3566制作多功能小手机
linux·arm开发·驱动开发·嵌入式硬件·物联网·智能手机·硬件架构
@晓凡3 小时前
STM32编程遇到的问题随笔【一】
stm32·单片机·嵌入式硬件
虾球xz3 小时前
游戏引擎学习第11天
stm32·学习·游戏引擎
DevinLGT4 小时前
6Pin Type-C Pin脚定义:【图文讲解】
人工智能·单片机·嵌入式硬件
小A1595 小时前
STM32完全学习——系统时钟设置
stm32·嵌入式硬件·学习
CoderBob5 小时前
【EmbeddedGUI】脏矩阵设计说明
c语言·单片机
陌夏微秋6 小时前
51单片机基础02 动态数码管显示-并串转换
arm开发·单片机·嵌入式硬件·51单片机·硬件工程·信息与通信·信号处理
面包板扎6 小时前
51单片机应用开发---LCD1602显示应用
单片机·嵌入式硬件·51单片机
面包板扎7 小时前
51单片机应用开发(进阶)---定时器应用(电子时钟)
单片机