STM32Flash的读写处理

采用STM32库中的擦写库函数进行基本的擦除操作,读写通过指针实现。

芯片为STM32051,因此一个字为4个字节,每个字节占一个地址,芯片Flash大小64K。

执行读写逻辑为若Flash中读取为空,则写入我们需要的初值,否则读出数据赋给我们的变量。因为写入时需要擦除才可以写入,而单片机有擦写寿命,因此我们采用擦写一定次数(几万次一般都可以接受,ST手册上应该是10万次),然后用记忆页的后一页进行读写以保证长期频繁的擦写使用,这里让单片机的最后3K供记忆功能使用。

工程中遵循在主循环运行之前先读数据的方式来获取记忆值,然后需要记忆时调用写函数即可。

具体实现过程如下:

#define MCUFlashCapacity        64   		//MCUFlash大小
#define StartPage 			 62           		//记忆Flash所在的起始页
#define MaxAddrCnt 		2						//最大变更页次数(MCUFlashCapacity-StartPage)
#define FlashEraseCnt    15000				//每页擦写次数
#define NumberOfData    16					//16个数据
u32 *WriteStart_Addr;							//写操作起始地址
u16 *ReadStart_Addr;								//读起始地址
u8 G_AddrCnt_8u;                          		//换页次数
u16 CntValue_u16 = 0;							//擦写次数
u16 Peremeter1 = 0;								//实验参数
u16 ReadWriteDate[NumberOfData];	//读写数据传递数组

void FlashRead(void)
{
	u32 *TempAddr;								
	static u16 L_AddrCnt_8u = 0;
	u16 num;
	u16 *data;
	u16 *ReadAddrTemp;
	static u32 temp_addr;
	
	for(L_AddrCnt_8u = 0;L_AddrCnt_8u < 3;L_AddrCnt_8u++)	//检查已经写至第几预留记忆页
	{	
		TempAddr = (u32 *)((0x08000000 + (StartPage-1) * 1024) + L_AddrCnt_8u * 1024);

		if((*TempAddr) == 0xFFFFFFFF)//若为空,说明正在使用的页为前一页或还未进行过写操作为第一次操作,当第一次操作时,直接跳出无自增L_AddrCnt_8u为0
		{
			break;
		}	
	}
	num=NumberOfData;
	if(L_AddrCnt_8u == 0)		//第一个为空:还没写,写入初值
	{
		data=ReadWriteDate;
		WriteStart_Addr = TempAddr;
		temp_addr = (u32)WriteStart_Addr;
		G_AddrCnt_8u = 0;
		
		/*需要记忆的参数初值设定*/
		CntValue_u16=0;
		Peremeter1=1;
		ReadWriteDate[0] = CntValue_u16;
		ReadWriteDate[1] = Peremeter1; 
		ReadWriteDate[2] = 0x0000;
		ReadWriteDate[3] = 0x0000;
		ReadWriteDate[4] = 0x0000;
		ReadWriteDate[5] = 0x0000;
		ReadWriteDate[6] = 0x0000;
		ReadWriteDate[7] = 0x0000;
		ReadWriteDate[8] = 0x0000;
		ReadWriteDate[9] = 0x0000;
		ReadWriteDate[10] = 0x0000;
		ReadWriteDate[11] = 0x0000;
		ReadWriteDate[12] = 0x0000;
		ReadWriteDate[13] = 0x0000;
		ReadWriteDate[14] = 0x0000;
		ReadWriteDate[15] = 0x0000;
		/*需要记忆的参数初值设定*/
		FLASH_Unlock();
		while(num --)
		{
			FLASH_ProgramHalfWord(temp_addr,*data);//写半字,一次写两个字节
			temp_addr += 2;//每8位占一个地址,因此需要自增2个地址
			data++;//数据地址执政自增
		}
		FLASH_Lock();
	}
	else if(L_AddrCnt_8u < 3)						//在前两个记忆页
	{
		WriteStart_Addr =(u32 *)((u32)TempAddr - 1024);				//取前一页的地址为读起始地址
		ReadStart_Addr=(u16 *)((u32)TempAddr - 1024);					//取前一页的地址为写起始地址
		CntValue_u16 = (u16)(*WriteStart_Addr);								//由于WriteStart_Addr为u32的指针,指向的数据为u32的数据,而我们保存的数据都是两个字节的,所以需要转化一下
		G_AddrCnt_8u = L_AddrCnt_8u - 1;
	}
	else													//L_AddrCnt_8u=3时说明已经在最后一个记忆页
	{
		WriteStart_Addr = (u32 *)(TempAddr);
		ReadStart_Addr=(u16 *)(TempAddr);
		CntValue_u16 = (u16)(*WriteStart_Addr);								
		G_AddrCnt_8u = MaxAddrCnt;
	}
	
	/*v读存储的数据v*/
	if(CntValue_u16 < (3*FlashEraseCnt)&&L_AddrCnt_8u!=0)		//写满3页后不再读取Flash存储值,直接使用初始化值
	{
		ReadAddrTemp = ReadStart_Addr;
		data=ReadWriteDate;
		while(num --)
		{
			*data = *ReadAddrTemp;
			ReadAddrTemp++;
			data++;
		}
		CntValue_u16 = ReadWriteDate[0];
		Peremeter1 = ReadWriteDate[1];
//		 = ReadWriteDate[2];
//		 = ReadWriteDate[3];
//		 = ReadWriteDate[4];
//		 = ReadWriteDate[5];
//		 = ReadWriteDate[6];
//		 = ReadWriteDate[7];
//		 = ReadWriteDate[8];
//		 = ReadWriteDate[9];
//		 = ReadWriteDate[10];
//		 = ReadWriteDate[11];
//		 = ReadWriteDate[12];
//		 = ReadWriteDate[13];
//		 = ReadWriteDate[14];
//		 = ReadWriteDate[15];
	}
	/*^读存储的数据^*/
}

void FlashWrite(void)
{
	u16 num;
	u16 *data;
	static u32 temp_addr;
	
		data=ReadWriteDate;
		CntValue_u16 = (u16)(*WriteStart_Addr);//使用时每次会先读,在读取处已经知晓写的起始地址
		num=NumberOfData;
		/*需要记忆的参数*/
		ReadWriteDate[0] = CntValue_u16+1;
		ReadWriteDate[1] = G_MotorGear_16u; 
		ReadWriteDate[2] = 0x0000;
		ReadWriteDate[3] = 0x0000;
		ReadWriteDate[4] = 0x0000;
		ReadWriteDate[5] = 0x0000;
		ReadWriteDate[6] = 0x0000;
		ReadWriteDate[7] = 0x0000;
		ReadWriteDate[8] = 0x0000;
		ReadWriteDate[9] = 0x0000;
		ReadWriteDate[10] = 0x0000;
		ReadWriteDate[11] = 0x0000;
		ReadWriteDate[12] = 0x0000;
		ReadWriteDate[13] = 0x0000;
		ReadWriteDate[14] = 0x0000;
		ReadWriteDate[15] = 0x0000;
		/*需要记忆的参数*/
		if(CntValue_u16 < ((G_AddrCnt_8u+1)*FlashEraseCnt)) //判断换页
		{
			temp_addr = (u32)WriteStart_Addr;
			FLASH_Unlock();
			FLASH_ErasePage((u32)WriteStart_Addr);				// 擦除指定的页
			while(num --)
			{
				FLASH_ProgramHalfWord(temp_addr,*data);
				temp_addr += 2;//每8位占一个地址
				data++;
			}
			FLASH_Lock();
		}
		else
		{
			if((u32)WriteStart_Addr < 0x0800FC00)				//在有效范围内,正常切换地址,最后地址写满数据则不在记录
			{
				WriteStart_Addr = (u32 *)((u32)WriteStart_Addr+1024);
				temp_addr = (u32)WriteStart_Addr;
				FLASH_Unlock();
				FLASH_ErasePage((u32)WriteStart_Addr);				// 擦除指定的页
				while(num --)
				{
					FLASH_ProgramHalfWord(temp_addr,*data);
					temp_addr += 2;//每8位占一个地址
					data++;
				}
				FLASH_Lock();
			}
		}	
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值