STM32 Flash编程,利用内部FLASH,抛弃外挂芯片实现永久化存储

本文讲述了作者在物联网智能门禁项目中,如何将密码永久存储在STM32F407的Flash内存中,包括查找资料、选择存储区域、使用指针操作Flash外设寄存器以及处理擦除、编程和解锁操作的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近一个物联网智能门禁项目,其中开锁的密码需要永久化存储,原来的方案是外挂一个EEPROM类型芯片,觉得这样操作有些繁琐,于是想把数据存放在STM32内部,想法成立,实践开始!

第一步:查找资料

本次使用的是STM32F407,从ST官网找到了相应的数据手册,该芯片的Flash内存是这样分布的

Flash结构:

  • 主存储器块,共12个扇区,4个16KB,1个64KB,7个128KB的扇区,地址分布如下
    在这里插入图片描述
  • 系统存储器:
  • 512OPT存储器
  • 选项字节
    本次会把数据存储在主存储器中的最后一个扇区中,选择这块扇区的原因是F407的程序代码区域大小有1MB,一般来说,写的代码是不会到达最后一个扇区. 主要对该区域进行读写,通过闪存存储器接口(外设),对程序存储器和选项字节进行擦除和编程.

补充知识:使用指针访问存储器

//使用指针读指定地址下的存储器
//0x080e0000 是扇区11的起始地址
uint32_t Data = *((__IO uint32_t* )(0x080e0000));

//对指定地址的存储器进行赋值
*((__IO uint32_t* )(0x080e0000)) = 0x12345678;

//其中,__IO 读取flash中的变量,一般要加volatile修饰
// volatile 表示易变的,用该关键字修饰的变量,CPU每次读取该变量的值时,必须到该变量存储的地址处读值,不能进行假设
#define __IO  volatile 

第二步: 代码编写

  • 擦除指定存储器的内容
  • 写指定存储器的内容
  • 读指定存储器的内容
    在实现代码之前首先了解一些Flash外设寄存器
    stm32f407的flash共有6个寄存器,其中我们要了解的有2个
    CR(控制寄存器),SR(状态寄存器)
    在这里插入图片描述
    位0:PG,开始编程,当开始写数据时需要将该位置1
    位1:SER Sector Erase 扇区擦除,当要擦除扇区时,将该位置1,擦除结束后置0
    位2:MER Mass Erase 擦除所有的扇区,谨慎使用,因为主储存器存放代码
    位7:3 SNB sector number 扇区编号,可以指定要擦除的扇区号 0~11
    位9:8 PSIZE 编程宽度,表示写入flash中的字节数,根据电压的不同请选择对应的位,否者写数据时无法写入
    位16:STRT start 启动擦除操作,在BSY位置零后,自动置零,无需手动操作

    位31: LOCK 表示当前Flash的状态为1时,表示已锁定,必须用解锁序列才能够对Flash进行读写操作
//解锁Flash主存储器需要连续对KEYR寄存器连续写入该序列,两者不可拆分,不可颠倒
void mFlash_Unlock(void)
{
	FLASH->KEYR = 0x45670123;
	FLASH->KEYR = 0xCDEF89AB;
}
//上锁
void  mFlash_Lock(void)
{
	FLASH->CR = 0x01;
}

//擦除Flash的一个扇区
void mFlash_EraseSector(uint8_t sector)
{
	while((FLASH->SR & BIT(16)) == BIT(16)){};	//检测FLASH_SR 的BSY位
	mFlash_UnLock();
	FLASH->CR |= BIT(1);					//块擦除
	FLASH->CR |= (sector<<3);			//指定擦除的扇区
	FLASH->CR |= BIT(9);					//这个是x32,看手册根据电压的不同,并行位也会不同
	FLASH->CR |= (0x01 << 16); 				// STRT位置1
	while((FLASH->SR & BIT(16)) == BIT(16)){};	//检测FLASH_SR 的BSY位
	FLASH->CR &= (~BIT(1)); 					//对指定位进行擦除
	mFlash_Lock();
}

//其中BIT
#define BIT(x)		(0x01<<x)
//往Flash的指定扇区写数据	
void mFlash_WriteData(__IO uint32_t* address,uint32_t data)
{
	mFlash_UnLock();
	FLASH->CR |= BIT(0);	// FLASH_CR的第零位置1 PG = 1 
	*(address) = data;	//由此可见,写入失败,为什么呢???? FLASH->CR BIT(9) 原因在这里
	while((FLASH->SR & BIT(16)) == BIT(16)){};	//检测FLASH_SR 的BSY位
	FLASH->CR &= (~BIT(0));
	mFlash_Lock();
}

/*
 * sector: 哪个区,F407,共有12个区,要往扇区0写数据,那么填写0x00
* address 该扇区的起始地址
* data:   要写入数据的数组首地址
* size:   写入多少数据
* @note:  在写入扇区之前,会把该扇区的内容全部清空,因此,如果想单独写入几字节数据,请注意数据的备份
**/

void mFlash_Write(uint8_t sector, __IO uint32_t* address,uint32_t *data,uint8_t size)
{
	mFlash_Erase(sector);
	//首地址写入是否写过数据标志 0XA5A5, 如果读取到该数据,那么表示该扇区存储过数据
	
	address++;
	for(int i = 1; i < size+1; i++)
	{
		mFlash_WriteData(address++, data[i-1]);	
	}
}
//读flash指定地址的数据
uint32_t mFlash_ReadWord(__IO uint32_t* address)
{
	return *(address);
}

在编程中遇到的问题

  • 下载程序时会报错,提示cannot …,手按住复位键,点击下载,松开复位键即可下载
  • 程序写入失败,请检查自己的单片机电压,根据电压的不同,写入的位数也是不同的,一般3.3v电压,是要求写入32位数据
    在这里插入图片描述- 附上扇区首地址

#define Sector0		((__IO uint32_t *)0x08000000)
#define Sector1		((__IO uint32_t *)0x08004000)
#define Sector2		((__IO uint32_t *)0x08008000)
#define Sector3		((__IO uint32_t *)0x0800C000)
#define Sector4		((__IO uint32_t *)0x08010000)
#define Sector5		((__IO uint32_t *)0x08020000)
#define Sector6		((__IO uint32_t *)0x08040000)
#define Sector7		((__IO uint32_t *)0x08060000)
#define Sector8		((__IO uint32_t *)0x08080000)
#define Sector9		((__IO uint32_t *)0x080a0000)
#define Sector10	((__IO uint32_t *)0x080c0000)
#define Sector11	((__IO uint32_t *)0x080e0000)	//将数据都存放在这里
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值