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)
	{
		
	}
}
相关推荐
HQB20269 小时前
EG1198|屹晶微电子 120V 内置 MOS 异步降压 DC‑DC(高性价比)
嵌入式硬件·硬件工程
果壳science10 小时前
张祥前实验如何获取正电荷
笔记·科技·嵌入式硬件·硬件工程·制造
南山电子nscn10 小时前
中科芯CETC汽车电池管理系统BMS进口芯片国产型号替代指南
单片机·汽车·bms
沉淀的.晴天11 小时前
can总线
stm32
桀人11 小时前
认识AT24C02
stm32·单片机·嵌入式硬件
国科安芯12 小时前
星间激光通信终端CANFD控制网络的时延确定性与辐射可靠性
网络·嵌入式硬件·信息与通信·canfd·低轨卫星·商业航天·抗辐射
一直C13 小时前
嵌入式 Linux 驱动开发学习笔记:内核定时器、platform 总线与 I²C 驱动
linux·驱动开发·嵌入式硬件·学习·imx6ull
传感器与混合集成电路13 小时前
150MHz主频、8路DAC与6路PWM:JLH221360伺服控制SIP解析
嵌入式硬件
comyccccc13 小时前
STM32PID控制板设计全解析学习笔记
单片机·嵌入式硬件
碧海银沙音频科技研究院14 小时前
实现炬芯ATS308X的usb cdc 串口IAP 固件升级功能实现
人工智能·嵌入式硬件·深度学习·算法