STM32单片机-FLASH闪存

STM32单片机-FLASH闪存

  • 一、FLASH简介
  • 二、FLASH工作原理
  • 三、读写内部FLASH
  • 四、读取芯片ID

一、FLASH简介

  • STM32F1系列的FLASH包含程序存储器系统存储器选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程
  • 读写FLASH的用途:

  利用程序存储器的剩余空间来保存掉电不丢失的用户数据
  通过在程序中编程(IAP),实现程序的自我更新

  • 在线编程(ICP)用于更新存储器的全部内容,它通过JTAGSWD协议系统加载程序(Bootloader)下载程序
  • 程序中编程(IAP)可以使用微控制器支持的任一种通信接口下载程序

  下图为中容量闪存模块组织
  主存储器:用来存放程序代码,主要且容量最大的部分,基本单位是1K的页,C8T6只有64K
  信息块启动程序代码-系统存储器,存放原厂写入的Bootloader,用于串口下载。用户选择字节-存放独立的参数
  闪存存储器接口寄存器:普通外设,存储介质是SRAM,控制擦除和编程

在这里插入图片描述

二、FLASH工作原理

  下图为FLASH基本结构图
  整个闪存分为程序存储器、系统存储器和选项字节
  以C8T6为例,程序存储器为64K,最后一页地址是0x0800 FC00。左边控制器是闪存管理院,可以擦除和编程程序存储器和选项字节。选项字节配置程序存储器的读写保护

在这里插入图片描述

FPEC擦除和编程程序存储器和选项字节时需要前置操作

  • FLASH解锁:FLASH操作前需要解锁,在键寄存器写入指定的键值来实现

  FPEC有三个键值:RDPRT键 = 0x000000A5(解除读保护)、KEY1 = 0x45670123、KEY2 = 0xCDEF89AB
  复位后,FPEC被保护,不能写入FLASH_CR。在FLASH_KEYR先写入KEY1,再写入KEY2解锁。错误的操作序列会在下次复位前锁死FPEC和LASH_CR
  加锁:设置FLASH_CR中的LOCK位锁住FPEC和FLASH_CR

  下图为闪存页擦除过程
  判断LOCK锁没锁,需要解锁,随后置寄存器、判断页地址、等待状态寄存器标志位,擦除

在这里插入图片描述

  下图为闪存全擦除过程
  判断LOCK锁没锁,需要解锁,随后置寄存器、等待状态寄存器标志位,擦除

在这里插入图片描述

  下图为闪存写入过程
  判断LOCK锁没锁,需要解锁,随后置寄存器、在指定地址写入数据、等待状态寄存器标志位

在这里插入图片描述

三、读写内部FLASH

  读内部FLASH指定地址的数据,只需要调用读函数即可uint16_t Data = *((__IO uint16_t *)(0x8000000)),其中数据位数可以更改,地址可以更改
  指定地址写数据时,需要先擦除再写
  下面为MyFLASH.c,其中包括擦除写数据

#include "stm32f10x.h"                  // Device header

/*
@brief:读取指定地址FLASH里的地址-32、16和8位
*/
uint32_t MyFLASH_ReadWord(uint32_t Address)
{
	return *((__IO uint32_t *)(Address));//读取32位数据
}
uint16_t MyFLASH_ReadHalfWord(uint32_t Address)
{
	return *((__IO uint16_t *)(Address));//读取16位数据
}
uint8_t MyFLASH_ReadByte(uint32_t Address)
{
	return *((__IO uint8_t *)(Address));//读取8位数据
}

/*
@brief:全擦除
*/
void MyFLASH_EraseAllPages()
{
	FLASH_Unlock();//解锁
	FLASH_EraseAllPages();
	FLASH_Lock();//锁上
}
/*
@brief:指定页擦除
*/
void MyFLASH_ErasePage(uint32_t PageAddress)
{
	FLASH_Unlock();//解锁
	FLASH_ErasePage(PageAddress);
	FLASH_Lock();//锁上
}
/*
@brief:指定地址写32位数据
*/
void MyFLASH_ProgramWord(uint32_t Address,uint32_t Data)
{
	FLASH_Unlock();//解锁
	FLASH_ProgramWord(Address,Data);
	FLASH_Lock();//锁上
}
/*
@brief:指定地址写16位数据
*/
void MyFLASH_ProgramHalfWord(uint32_t Address,uint16_t Data)
{
	FLASH_Unlock();//解锁
	FLASH_ProgramHalfWord(Address,Data);
	FLASH_Lock();//锁上
}

  由于FLASH是擦除后再写入,擦除后还容易丢数据,可以在RSAM里新建一个数组,FLASH的数据复制到SRAM,实现掉电不丢失,往FLASH里写入SRAM里的数据,实现参数的任意读写和保存
  首次上电,FLASH数据复制给SRAM数组时,需要判断第一个数据-标志位(任意设置),之后断电上电或者复位时,存在FLASH的数据(不丢失)继续复制给SRAM
  下面为Store.c

uint16_t Store_Data[512];

void Store_Init()
{
	//第一次需要判断标志位
	if(MyFLASH_ReadHalfWord(0x0800FC00) != 0xA5A5)
	{
		MyFLASH_ErasePage(0x0800FC00);
		MyFLASH_ProgramHalfWord(0x0800FC00,0xA5A5);
		for(uint16_t i = 1;i<512;i++)
		{
			MyFLASH_ProgramHalfWord(0x0800FC00+i*2,0x0000);
		}
	}//设置闪存最后一页第一个半字为A5A5,剩下全部为0
	
	for(uint16_t i = 0;i<512;i++)
	{
		Store_Data[i] = MyFLASH_ReadHalfWord(0x0800FC00+i*2);
	}//上电时保证数据不丢失,将FLASH数据复制到SRAM数组中
}
/*
@brief:往闪存里面写数据(SRAM数组-FLASH)
*/
void Store_Save()
{
	MyFLASH_ErasePage(0x0800FC00);
	for(uint16_t i = 0;i<512;i++)
	{
		MyFLASH_ProgramHalfWord(0x0800FC00+i*2,Store_Data[i]);
	}
}
/*
@brief:清除FLASH
*/
void Store_Clear()
{
	for(uint16_t i = 1;i<512;i++)//标志位不擦除
	{
		Store_Data[i] = 0x0000;
	}
	Store_Save();
}

  下面为main.c,按键1-SRAM数组值加1,按键2-清零数组

uint8_t KeyNum;

int main(void)
{
	OLED_Init();
	Key_Init();
	Store_Init();
	
	OLED_ShowString(1,1,"FLAG:");
	OLED_ShowString(2,1,"Data:");
	while(1)
	{
		KeyNum = Key_GetNum();
		if(KeyNum == 1)
		{
			Store_Data[1] ++;
			Store_Data[2] += 2;
			Store_Data[3] += 3;
			Store_Data[4] += 4;
			Store_Save();//SRAM数组写入到FLASH
		}
		if(KeyNum == 2)
		{
			Store_Clear();
		}
		OLED_ShowHexNum(1,6,Store_Data[0],4);
		OLED_ShowHexNum(3,1,Store_Data[1],4);
		OLED_ShowHexNum(3,6,Store_Data[2],4);
		OLED_ShowHexNum(4,1,Store_Data[3],4);
		OLED_ShowHexNum(4,6,Store_Data[4],4);
	}
}

四、读取芯片ID

  读取ID只需要读取指定地址的数据即可

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,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)
	{
		
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/727272.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024年6月20日 (周四) 叶子游戏新闻

超市播音系统: 定时播放不同音乐 强制卸载软件: 一款强制卸载软件 免费多人沙盒游戏《宝藏世界》推出更新“潮起潮落”&#xff0c;带来全新克苏鲁风冒险准备好迎接一场超凡的冒险吧&#xff0c;MMORPG发行商gamigo宣布《宝藏世界》的最新更新&#xff1a;“潮起潮落”。这次更…

计算机编码以及URL转码

目录 一、计算机编码 1.ASCII编码 2. GB2312编码 3.GBK编码 4.UTF-8编码 二、URL转码 1.encodeURI和decodeURI 2.encodeURIComponent 和 decodeURIComponent 三、Base64 一、计算机编码 在计算机中&#xff0c;所有的数据在存储和运算时都要使用二进制数表示&#xf…

Redis 网络模型

一、用户空间和内核空间 1.1 linux 简介 服务器大多采用 Linux 系统&#xff0c;这里我们以 Linux 为例来讲解&#xff0c;下面有两个不同的 linux 发行版&#xff0c;分别位 ubuntu 和 centos&#xff0c;其实发行版就是在 Linux 系统上包了一层壳。 任何 Linux 发行版&#…

【ARM】PK51如何将BL51链接器切换成LX51链接器

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 解决客户在使用PK51进行项目研发的时候&#xff0c;想要使用LX51链接器进行使用。 2、 问题场景 客户在使用51芯片进行开发的时候&#xff0c;发现工程中使用的是BL51链接器&#xff0c;而不是LX51链接器&#xff…

多模块存储器

随着计算机技术的发展&#xff0c;处理的信息量越来越多&#xff0c;对存储器的速度和容量要求也越来越高&#xff1b;而且随着CPU性能的不断提高、IO设备数量不断增加&#xff0c;导致主存的存取速度已经称为了整个计算机系统的性能瓶颈。这就要求我们必须提高主存的访问速度。…

Hadoop3:MapReduce中实现自定义排序

一、场景描述 以统计号码的流量案例为基础&#xff0c;进行开发。 流量统计结果 我们现在要对这个数据的总流量进行自定义排序。 二、代码实现 我们要对总流量进行排序&#xff0c;就是对FlowBean中的sumFlow字段进行排序。 所以&#xff0c;我们需要让FlowBean实现Writab…

第二十五篇——信息加密:韦小宝说谎的秘诀

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 加密这件事&#xff0c;对于这个时代的我们来说非常重要&#xff0c;那么…

互联网应用主流框架整合之Spring Boot基本概念

Spring Boot是用来简化Spring应用程序的搭建、开发、测试和部署过程的&#xff0c;该框架使用了特定的方式进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置&#xff0c;SpringBoot致力于快速应用开发(Rapid Application Development)领域的发展&#xff0c;它通过…

这些帮助你成长的IOS应用,建议收藏

TrackIt TrackIt是一款功能丰富的任务清单、日程管理和习惯打卡应用&#xff0c;旨在帮助用户提高效率和专注力。通过这些功能&#xff0c;用户可以更好地规划时间和任务&#xff0c;从而实现个人目标和养成良好习惯。 在目标设定方面&#xff0c;SMART原则是一个常用的方法&a…

【CPP】选择排序:冒泡排序、快速排序

目录 1.冒泡排序简介代码分析 2.快速排序2.1霍尔版本简介代码分析 2.2挖坑版本2.3前后指针版本2.4非递归的快排思路代码 什么是交换排序&#xff1f; 基本思想&#xff1a;所谓 交换&#xff0c;就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置&#xff0…

Meta FAIR研究新成果:图像到文本、文本到音乐的生成模型,多标记预测模型以及AI生成语音检测技术

Meta AI研究实验室(FAIR)公开发布了多项新研究成果&#xff0c;包括图像到文本和文本到音乐的生成模型&#xff0c;多词预测模型&#xff0c;以及检测AI生成语音的技术。发布的成果体现了开放性、协作、卓越和规模化等核心原则。公开早期研究工作旨在激发迭代&#xff0c;推动A…

uniapp 实人认证

首先Dcloud创建云服务空间&#xff0c;开启一键登录并充值 下一步 1. 右键项目 》 创建uniCloud云开发环境 》右键uniCloud》关联云服务空间 2. cloudfunctions右键 新建云函数&#xff0c;任意命名&#xff08;例&#xff1a;veify&#xff09;&#xff0c;然后右键项目》管…

加密好的WPSword文档,忘记密码怎么办?

在日常办公和学习中&#xff0c;我们经常使用WPS Word等文档处理软件来创建和编辑重要文件。为了保护这些文件不被未经授权的人访问&#xff0c;我们通常会选择给文档设置密码。然而&#xff0c;有时我们可能会因为时间久远或其他原因而忘记自己设置的密码&#xff0c;这时该如…

IT运维全面数字化|芯片设计行业领跑打造运维流程闭环

在当今数字化转型的浪潮中&#xff0c;科技行业正经历着前所未有的变革。随着5G、人工智能、物联网等新兴技术的快速发展&#xff0c;企业对于高效、智能的运营模式的需求日益迫切。 芯片设计公司作为科技产业链中的关键一环&#xff0c;不仅要在技术创新上保持领先&#xff0…

javascript--类型检测 type of 和 instanceof

类型判断 1、typeof2、instanceof**instanceof 的原理** 3、constructor 1、typeof typeof在检测null、object、array、data的结果中都是object&#xff0c;所以无法用来区分这几个类型的区别。 <script>let a ["123",123,false,true,Symbol(1),new Date(),n…

双层循环和循环语句

echo 打印 echo -n 表示不换行输出 echo -e 表示输出转义字符 echo \b 相当于退格键&#xff08;backspace&#xff09; echo \n 换行&#xff0c;相当于回车 echo \f 换行&#xff0c;换行后的新行的开头连着上一行的行尾 echo \t 相当于tab健 &#xff08;…

Linux基础命令大全(详解版)

Linux基础命令&#xff08;详解版&#xff09; 文章目录 Linux基础命令&#xff08;详解版&#xff09;1.Linux的目录结构**2.Linux路径的描述方式**3.Linux命令基础格式4.ls命令 隐藏文件、文件夹5.pwd命令6.cd命令 特殊路径符7.mkdir命令 文件操作命令8.touch命令9.cat命令10…

DB9母头接口定义485

在通信技术中&#xff0c;DB9接口广泛应用于串行通信&#xff0c;尤其是在RS232和RS485标准中。虽然DB9接口最常见于RS232通信&#xff0c;但通过适当的引脚映射&#xff0c;它也可以用于RS485通信。本文将详细介绍如何定义和使用DB9母头接口进行RS485连接。 DB9母头接口简介 …

Ecahrts竖向柱状图实现自动滚动

效果如下&#xff1a; 1.首先声明一个timer定时器标识 let timer: NodeJS.Timer; // 定时器 2.再声明窗口展示的数量&#xff0c;yAxisIndex2用来记录当前index已经加了多少&#xff0c;方便再formatter中格式化标题的相关信息 const dataZoomEndValue 6; // 数据窗口范围的…

C语言程序设计-7 数组

在程序设计中&#xff0c;为了处理方便&#xff0c;把具有相同类型的若干变量按有序的形式组织起来。这些按序排列的同类数据元素的集合称为数组。在&#xff23;语言中&#xff0c;数组属于构造数据类型。一个数 组可以分解为多个数组元素&#xff0c;这些数组元素可以是基本数…