基于STM32F103RCT6的内部FLASH模拟为EEPROM的读写使用

基于STM32F103RCT6的内部FLASH模拟为EEPROM的读写使用

前言

STM32单片机都带有ROM和RAM,其中STM32根据自身的ROM(Flash)可以分为小容量产品、中容量产品、大容量产品。
根据FLASH容量可以分为:
1.小容量:0-32K
2.中容量:64-128K
3.大容量:256K以上(包含256K)
在这里插入图片描述

代码

/**
  * 函数功能: 读取指定地址的半字(16位数据)
  * 输入参数: faddr:读地址(此地址必须为2的倍数!!)
  * 返 回 值: 返回值:对应数据.
  * 说    明:无
  */
uint16_t STMFLASH_ReadHalfWord (uint32_t faddr)
{
    return *(__IO uint16_t*)faddr;
}

/**
  * 函数功能: 从指定地址开始读出指定长度的数据
  * 输入参数: ReadAddr:起始地址
  * 				pBuffer:数据指针
  * 				NumToRead:半字(16位)数
  * 返 回 值: 无
  * 说    明:无
  */
void STMFLASH_Read ( uint32_t ReadAddr, uint16_t *pBuffer, uint16_t NumToRead )
{
    uint16_t i;
    
    for(i = 0; i < NumToRead; i++)
    {
        pBuffer[i] = STMFLASH_ReadHalfWord(ReadAddr); //读取2个字节.
        ReadAddr += 2; //偏移2个字节.
    }
}

#if STM32_FLASH_WREN	//如果使能了写   
/**
  * 函数功能: 不检查的写入
  * 输入参数: WriteAddr:起始地址
  *                 pBuffer:数据指针
  *                 NumToWrite:半字(16位)数
  * 返 回 值: 无
  * 说    明:无
  */
void STMFLASH_Write_NoCheck( uint32_t WriteAddr, uint16_t * pBuffer, uint16_t NumToWrite)
{
    uint16_t i;

    for(i = 0; i < NumToWrite; i++)
    {
        FLASH_ProgramHalfWord(WriteAddr, pBuffer[i]);
        WriteAddr += 2;                                  //地址增加2.
    }
}

/**
  * 函数功能: 从指定地址开始写入指定长度的数据
  * 输入参数: WriteAddr:起始地址(此地址必须为2的倍数!!)
  *           pBuffer:数据指针
  *           NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
  * 返 回 值:  
			-1;越界
			-2:地址错误
  * 说    明:指定长度的多页可写
  */
unsigned char StmFlash_WriteS( uint32_t WriteAddr, uint16_t * pBuffer, uint16_t NumToWrite)
{
    uint32_t SECTORError = 0;
	uint16_t i;
    
	uint16_t secoff;	   	//扇区内偏移地址(16位字计算)
    uint16_t secremain;  	//扇区内剩余地址(16位字计算)
    uint32_t secpos;	   	//扇区地址
    uint32_t offaddr;    	//去掉0X08000000后的地址
    uint32_t PageAddress;
	
	uint16_t length_sy=0;
	uint16_t length_page_sy=0;
	uint16_t length_secremain_sy=0;
	/*非法地址,越界:不在该款芯片的限定的可写flash区域*/
    if((WriteAddr < STM32_FLASH_START) || ((WriteAddr+NumToWrite) >STM32_FLASH_END))
		return -1; 
	/*地址不是一个半字节的整数*/
	if(1 == (WriteAddr%2))
		return -2;

	DIS_INT
    FLASH_Unlock();							//解锁

    offaddr = WriteAddr - FLASH_BASE;			//实际偏移地址(基于起始地址如:0x0807 0000的偏移地址).
    secpos = offaddr/FLASH_PAGE_SIZE;			//扇区地址  0~256 for STM32F103RCT6,实际起始地址的页数
    secoff = (offaddr%FLASH_PAGE_SIZE)/2;		//起始地址在扇区内的偏移(2个字节为基本单位)
    secremain = FLASH_PAGE_SIZE/2 - secoff;		//当前起始地址所在扇区剩余空间大小
    
	if(NumToWrite <= secremain)//不大于该扇区范围
	{
		STMFLASH_Read(secpos*FLASH_PAGE_SIZE +FLASH_BASE, STMFLASH_BUF, FLASH_PAGE_SIZE/2); //读出整个扇区的内容
		
		/* 擦除这个扇区 Fill EraseInit structure*/
		PageAddress = secpos * FLASH_PAGE_SIZE + FLASH_BASE;//PageAddress:写起始地址的当前页数(扇区)
		FLASH_ErasePage(PageAddress);
		
		for(i = 0; i < secremain; i++)//复制实际写入数据插入中间段
		{
			STMFLASH_BUF[i + secoff] = pBuffer[i];
		}
		STMFLASH_Write_NoCheck( secpos*FLASH_PAGE_SIZE +FLASH_BASE, STMFLASH_BUF, FLASH_PAGE_SIZE/2); //写入整个扇区,注:将之前为了擦除的页原有的数据(前+后 两段多余空间数据)+需要写入的数据整合后,重新写入原地址。但不会影响到后面的数据	
	}
	
	if(NumToWrite > secremain)//大于该扇区范围
	{
		/*前段*/		 
		STMFLASH_Read( secpos*FLASH_PAGE_SIZE +FLASH_BASE, STMFLASH_BUF, FLASH_PAGE_SIZE/2); //读出整个扇区的内容
		/* Fill EraseInit structure*/
		PageAddress = secpos * FLASH_PAGE_SIZE + FLASH_BASE;//PageAddress:写起始地址的当前页数(扇区)
		FLASH_ErasePage(PageAddress);
		
		for(i = 0; i < secremain; i++) //复制
		{
			STMFLASH_BUF[i + secoff] = pBuffer[i];
		}	
		STMFLASH_Write_NoCheck( secpos*FLASH_PAGE_SIZE +FLASH_BASE, STMFLASH_BUF,FLASH_PAGE_SIZE/2);  //写入整个扇区,注:将之前为了擦除的页原有的数据(前+后 两段多余空间数据)+需要写入的数据整合后,重新写入原地址。但不会影响到后面的数据
		
		length_sy = NumToWrite-secremain;
		length_page_sy = length_sy/(FLASH_PAGE_SIZE/2);
		length_secremain_sy = length_sy%(FLASH_PAGE_SIZE/2);//最后一页多出的字节
		/*中段*/	
		pBuffer+=secremain;
		for(i=0;i<length_page_sy;i++)/* Fill EraseInit structure*/
		{
			PageAddress += FLASH_PAGE_SIZE;
			/* Fill EraseInit structure*/
			FLASH_ErasePage(PageAddress);
			STMFLASH_Write_NoCheck( PageAddress, pBuffer+(i*(FLASH_PAGE_SIZE/2)), FLASH_PAGE_SIZE/2); //写入整个扇区,注:将之前为了擦除的页原有的数据
		}
		/*后段*/
		/* Fill EraseInit structure*/
		pBuffer =pBuffer+(length_page_sy*(FLASH_PAGE_SIZE/2));
		PageAddress += FLASH_PAGE_SIZE;
		STMFLASH_Read(PageAddress, STMFLASH_BUF, FLASH_PAGE_SIZE/2); //读出整个扇区的内容
		FLASH_ErasePage(PageAddress);
		
		for(i = 0; i < length_secremain_sy; i++) //复制
		{
			STMFLASH_BUF[i] = *(pBuffer)++;
		}
		
		STMFLASH_Write_NoCheck(PageAddress, STMFLASH_BUF,FLASH_PAGE_SIZE/2);  //写入整个扇区,注:将之前为了擦除的页原有的数据(前+后 两段多余空间数据)+需要写入的数据整合后,重新写入原地址。但不会影响到后面的数据
	}

    FLASH_Lock();//上锁
	EN_INT
}
#endif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值