STM32F103和STM32F407的Flash读写基于 页和扇区

STM32F1x和STM32F4x的Flash读写

1.理论:STM32f103的flash读写是基于 “页” STM32f407的flash读写是基于 “扇区”
flash读写原理转自:https://blog.csdn.net/lushoumin/article/details/87694389?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162297841016780261913587%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=162297841016780261913587&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-2-87694389.first_rank_v2_pc_rank_v29&utm_term=STM32+flahs&spm=1018.2226.3001.4187
2代码:
##stm32f103flash 基于页
在这里插入图片描述

/*---------------------------------------flash.h---------------------------------------------*/
#ifndef __FLASH_H__
#define __FLASH_H__

#define STM32_FLASH_SIZE 512 	 		//根据MCU所选FLASH容量大小(单位为K)
#define STM32_FLASH_BASE 0x08000000 	//FLASH的起始地址
#define FLASH_SAVE_ADDR  0X0800C004    //存放起始地址,可自己改
#endif


/*---------------------------------------flash.c---------------------------------------------*/
#if     STM32_FLASH_SIZE < 256
#define STM_SECTOR_SIZE 1024 //根据flash容量小于256K的每页大小是1k  1k = 1024B
#else 
#define STM_SECTOR_SIZE	2048 //根据flash容量大于256K的每页大小是2k  2k = 2048B
#endif	

u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节

//读取指定地址的半字(16位数据)
//faddr:读地址(此地址必须为2的倍数!!)
//返回值:对应数据.
u16 STMFLASH_ReadHalfWord(u32 faddr)
{
	return *(vu16*)faddr; 
}


//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)   	
{
	u16 i;
	for(i=0;i<NumToRead;i++)
	{
		pBuffer[i]=STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节.
		ReadAddr+=2;//偏移2个字节.	
	}
}




//WriteAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数   
void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)   
{ 			 		 
	u16 i;
	for(i=0;i<NumToWrite;i++)
	{
		FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);
	    WriteAddr+=2;//地址增加2.
	}  
}

//从指定地址开始写入指定长度的数据
//WriteAddr:起始地址(此地址必须为2的倍数!!)
//pBuffer:数据指针
//NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)	
{
	u32 secpos;	   //第几页
	u16 secoff;	   //页内偏移地址(16位字计算)
	u16 secremain; //页内剩余地址(16位字计算)	   
 	u16 i;    
	u32 offaddr;   //相对flash基地址0X08000000偏移了地址量
	
	if( WriteAddr<STM32_FLASH_BASE || (WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)) )return;//非法地址
	
	FLASH_Unlock();						    //解锁
	
	offaddr=WriteAddr-STM32_FLASH_BASE;		//相对于flash基地址偏移了多少地址
	
	secpos=offaddr / STM_SECTOR_SIZE;		//求出所在的页如0,1,2,3..页
	
	secoff=(offaddr % STM_SECTOR_SIZE)/2;	//在该页内偏移地址 即是在第几个u16 数据上(2 是读取和写入的字节是u16)
	
	secremain=STM_SECTOR_SIZE/2-secoff;		//在该页内剩余的空间大小   
	
	if(NumToWrite<=secremain)secremain=NumToWrite;//写入的数据没超过当前页内剩余的空间
	
	while(1) 
	{	
			STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整页
			
			for(i=0;i<secremain;i++)//判断是否需要擦除
			{
				if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;	  
			}
			if(i<secremain)//需要擦除
			{
				FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个页
				for(i=0;i<secremain;i++)//赋值
				{
					STMFLASH_BUF[i+secoff]=pBuffer[i];	  
				}
				STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整页
			}
			else//不需要擦除
			{
				STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//直接写入页剩余区间. 
			}			
			
			if(NumToWrite==secremain)//没有跨页存入
			{
				break;//写入结束了,跳出循环
			}
			else//有跨页写入,增加新页
			{
				secpos++;				//页地址增1
				secoff=0;				//页内偏移地址为0 	 
				pBuffer+=secremain;  	//指针偏移
				WriteAddr+=secremain;	//写地址偏移	   
				NumToWrite-=secremain;	//剩余要写入的字节(16位)数递减
				if(NumToWrite>(STM_SECTOR_SIZE/2))
					secremain=STM_SECTOR_SIZE/2;//新页还是写不完
				else 
					secremain=NumToWrite;//新页可以写完了
			}	 
	}	
	
	FLASH_Lock();//上锁
}

/*---------------------------------------main.c---------------------------------------------*/
u16  flash1_rx_buff[100];//读取flash内容存放到该数组
u16  flash1_rx_len=10;
u16  flash1_tx_buff[100];//将该数组写入flash
u16  flash1_tx_len=10;

u8  flash2_rx_buff[100];//读取flash内容存放到该数组
u8  flash2_rx_len=10;
u8  flash2_tx_buff[100];//将该数组写入flash
u8  flash2_tx_len=10;
int main()
{

STMFLASH_Write(FLASH_SAVE_ADDR,flash1_tx_buff,flash1_tx_len);
STMFLASH_Read(FLASH_SAVE_ADDR, flash1_rx_buff,flash1_rx_len);

//如若要定义u8数组可
//STMFLASH_Write(FLASH_SAVE_ADDR,(u16*)flash2_tx_buff,len);//len= flash2_tx_len/2 + (flash2_tx_len%2)? 1 : 0
//STMFLASH_Read(FLASH_SAVE_ADDR, (u16*)flash2_rx_buff,len);//len= flash2_rx_len/2 + (flash2_rx_len%2)? 1 : 0
}



##stm32f407flash 基于扇区
在这里插入图片描述

/*---------------------------------------flash.h---------------------------------------------*/
#define STM32_FLASH_BASE 0x08000000 	//FLASH的起始地址
#define FLASH_SAVE_ADDR  0X0800C004     //存放起始地址,可自己改
 
//FLASH 扇区的起始地址
#define ADDR_FLASH_SECTOR_0     ((u32)0x08000000) 	//扇区0起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_1     ((u32)0x08004000) 	//扇区1起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_2     ((u32)0x08008000) 	//扇区2起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_3     ((u32)0x0800C000) 	//扇区3起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_4     ((u32)0x08010000) 	//扇区4起始地址, 64 Kbytes  
#define ADDR_FLASH_SECTOR_5     ((u32)0x08020000) 	//扇区5起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_6     ((u32)0x08040000) 	//扇区6起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_7     ((u32)0x08060000) 	//扇区7起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_8     ((u32)0x08080000) 	//扇区8起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_9     ((u32)0x080A0000) 	//扇区9起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_10    ((u32)0x080C0000) 	//扇区10起始地址,128 Kbytes  
#define ADDR_FLASH_SECTOR_11    ((u32)0x080E0000) 	//扇区11起始地址,128 Kbytes  

/*---------------------------------------flash.c---------------------------------------------*/

//读取指定地址的半字(16位数据) 
//faddr:读地址 
//返回值:对应数据.
u32 STMFLASH_ReadWord(u32 faddr)
{
	return *(vu32*)faddr; 
}  


//获取某个地址所在的flash扇区
//addr:flash地址
//返回值:0~11,即addr所在的扇区
uint16_t STMFLASH_GetFlashSector(u32 addr)
{
	if(addr<ADDR_FLASH_SECTOR_1)return FLASH_Sector_0;
	else if(addr<ADDR_FLASH_SECTOR_2)return FLASH_Sector_1;
	else if(addr<ADDR_FLASH_SECTOR_3)return FLASH_Sector_2;
	else if(addr<ADDR_FLASH_SECTOR_4)return FLASH_Sector_3;
	else if(addr<ADDR_FLASH_SECTOR_5)return FLASH_Sector_4;
	else if(addr<ADDR_FLASH_SECTOR_6)return FLASH_Sector_5;
	else if(addr<ADDR_FLASH_SECTOR_7)return FLASH_Sector_6;
	else if(addr<ADDR_FLASH_SECTOR_8)return FLASH_Sector_7;
	else if(addr<ADDR_FLASH_SECTOR_9)return FLASH_Sector_8;
	else if(addr<ADDR_FLASH_SECTOR_10)return FLASH_Sector_9;
	else if(addr<ADDR_FLASH_SECTOR_11)return FLASH_Sector_10; 
	return FLASH_Sector_11;	
}

//从指定地址开始写入指定长度的数据
//WriteAddr:起始地址(此地址必须为4的倍数!!)
//pBuffer:数据指针
//NumToWrite:字(32位)数(就是要写入的32位数据的个数.) 
void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)	
{ 
  FLASH_Status status = FLASH_COMPLETE;
	u32 addrx=0;
	u32 endaddr=0;	
  if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return;	//非法地址
	FLASH_Unlock();									//解锁 
  FLASH_DataCacheCmd(DISABLE);//FLASH擦除期间,必须禁止数据缓存
 		
	addrx=WriteAddr;				//写入的起始地址
	endaddr=WriteAddr+NumToWrite*4;	//写入的结束地址
	if(addrx<0X1FFF0000)			//只有主存储区,才需要执行擦除操作!!
	{
		while(addrx<endaddr)		//扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
		{
			if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区
			{   
				status=FLASH_EraseSector(STMFLASH_GetFlashSector(addrx),VoltageRange_3);//VCC=2.7~3.6V之间!!
				if(status!=FLASH_COMPLETE)break;	//发生错误了
			}else addrx+=4;
		} 
	}
	if(status==FLASH_COMPLETE)
	{
		while(WriteAddr<endaddr)//写数据
		{
			if(FLASH_ProgramWord(WriteAddr,*pBuffer)!=FLASH_COMPLETE)//写入数据
			{ 
				break;	//写入异常
			}
			WriteAddr+=4;
			pBuffer++;
		} 
	}
  FLASH_DataCacheCmd(ENABLE);	//FLASH擦除结束,开启数据缓存
	FLASH_Lock();//上锁
} 

//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToRead:字(4位)数
void STMFLASH_Read(u32 ReadAddr,u32 *pBuffer,u32 NumToRead)   	
{
	u32 i;
	for(i=0;i<NumToRead;i++)
	{
		pBuffer[i]=STMFLASH_ReadWord(ReadAddr);//读取4个字节.
		ReadAddr+=4;//偏移4个字节.	
	}
}

/*---------------------------------------main.c---------------------------------------------*/
u32  flash1_rx_buff[100];//读取flash内容存放到该数组
u32  flash1_rx_len=10;
u32  flash1_tx_buff[100];//将该数组写入flash
u32  flash1_tx_len=10;

u8  flash2_rx_buff[100];//读取flash内容存放到该数组
u8  flash2_rx_len=10;
u8  flash2_tx_buff[100];//将该数组写入flash
u8  flash2_tx_len=10;
int main()
{

STMFLASH_Write(FLASH_SAVE_ADDR,flash1_tx_buff,flash1_tx_len);
STMFLASH_Read(FLASH_SAVE_ADDR, flash1_rx_buff,flash1_rx_len);

//如若要定义u8数组可
//STMFLASH_Write(FLASH_SAVE_ADDR,(u32*)flash2_tx_buff,len);//len= flash2_tx_len/4 + (flash2_tx_len%4)? 1 : 0
//STMFLASH_Read(FLASH_SAVE_ADDR, (u32*)flash2_rx_buff,len);//len= flash2_rx_len/4 + (flash2_rx_len%4)? 1 : 0
}
  • 25
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: STM32F103是意法半导体推出的一款32位单片机,内置了一块FLASH存储器,用于程序和数据的读写。下面将详细介绍STM32F103内部FLASH读写操作。 首先,内部FLASH是非易失性存储器,可以长时间保存数据,即使在断电后也不会丢失。该存储器分为多个扇区,每个扇区大小为2KB或16KB,总的容量取决于具体型号。 对于写操作,首先需要擦除要写入的扇区。擦除是一个扇区级别的操作,即需要擦除整个扇区,每个扇区都有一个固定的扇区号。在擦除之前,必须保证该扇区的所有数据已经备份,因为擦除操作会将该扇区的数据全部清除。 擦除完成后,可以对扇区进行编程操作。编程是以字为单位进行的,每个单元的大小是2个字节。对于编程操作,可以选择使用不同的编程函数,例如“HAL_FLASH_Program”函数。编程时需要注意,每个单元只能由0xFF写入0x00,即从1到0的写入是不被允许的。而且,编程操作之前需要先校验该单元是否已经被编程过。 读取操作则比较简单,可以使用“HAL_FLASH_Read”函数读取指定地址的数据。为了确保读取的数据的正确性,通常会在读取之前对要读取的地址进行校验。 需要注意的是,对于内部FLASH读写操作,必须先进行相应的初始化,例如,配置FLASH读写许可、时钟使能等。 综上所述,STM32F103内部FLASH读写操作主要包括擦除、编程和读取。通过合理地使用这些操作,可以对内部FLASH进行有效的数据存储和读取。 ### 回答2: STM32F103是一种基于ARM Cortex-M3内核的32位微控制器,它具有内部的Flash存储器,可以用于程序的存储和执行。下面我们将讨论STM32F103内部Flash读写操作。 STM32F103的内部Flash分为多个扇区,每个扇区的大小为2KB或16KB,具体取决于芯片的型号。在进行Flash读写之前,我们需要注意以下几点: 1. Flash编程需要先解锁,然后进行擦除和编程操作。解锁可以通过设置特定的Flash解锁和编程保护位来实现。 2. 在进行Flash编程之前,应该关闭中断,以防止程序干扰Flash访问过程。 3. 写入Flash之前,必须先进行擦除操作。擦除是以扇区为单位进行的,可以选择擦除单个扇区或多个相邻扇区。 4. 写入Flash时,需要将数据按字大小写入,特别是在写入半字(16位)或字(32位)数据时,需要确保数据对齐。 5. 每次写入Flash之后,应该进行校验,以确保数据写入正确。校验可以通过读取Flash中的数据并与原始数据进行比较来实现。 总结起来,STM32F103内部Flash读写操作需要解锁、擦除、编程和校验等步骤。在进行这些操作时,应该注意保护位设置、中断关闭、数据对齐和校验等问题。这样才能确保程序正确地读取和写入内部Flash,并且保证数据的完整性和一致性。 ### 回答3: STM32F103是STMicroelectronics(意法半导体)推出的一款基于ARM Cortex-M3内核的微控制器芯片。它内置了Flash存储器,可以用于程序代码和数据的存储。 首先,STM32F103系列芯片的内部Flash存储器容量可以根据不同型号而不同,通常为64KB、128KB、256KB或512KB。通过编程将代码和数据存储在Flash中,可以实现可靠的程序执行,而且Flash可以被擦除和编程多次,使得开发者能够灵活地进行程序的更新和修改。 对于STM32F103内部Flash的读取,开发者可以通过读取指定地址的方式来访问存储在Flash中的数据。可以使用如`*(uint32_t*)address`的语法,将Flash的指定地址强制类型转换为指向32位无符号整数的指针,并通过解引用指针访问Flash中的数据。需要注意的是,Flash存储器的读取速度相对较慢,因此在程序执行过程中可能会遇到一定的延迟。 至于内部Flash的写入,由于Flash存储器具有较高的可靠性要求,所以写入操作需要特定的处理来确保数据的完整性。开发者需要在编写程序时使用特定的编程算法和接口,例如ST提供的Flash等库函数,来进行数据的写入。此外,为了避免写入操作对Flash的擦除,开发者还需要提前进行相关的Flash扇区擦除操作。 总的来说,STM32F103的内部Flash存储器提供了方便可靠的程序代码和数据存储方式。通过正确的读取和写入操作,可以实现对Flash存储器的数据访问和更新。但需要开发者额外注意Flash的读取速度和写入算法的正确性,以确保程序的稳定性和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值