STM32开发项目:STM32F103与F407的EEPROM仿真及其应用层扩展

本文详细介绍了如何在STM32F103和STM32F407单片机上实现基于Flash的EEPROM仿真,包括库的原理、源码分析和应用层扩展。仿真库通过耗损均衡算法增加Flash的可擦写次数,应用层扩展提供了一种方便的方式来声明和管理可存储数据的变量,支持浮点数的存储和读取。
摘要由CSDN通过智能技术生成
日期作者版本说明
2020.10.24TaoV0.0完成主体内容的撰写
2020.10.26TaoV0.1在EEPROM仿真章节的使用指南部分增加了关于Flash扇区分配的注意事项
2020.11.03TaoV0.2在EEPROM仿真章节的使用指南部分增加了容量设置小节,提供了128与256个变量存储的源码模板

说明

在工业应用中经常使用 EEPROM(电可擦除可编程只读存储器)来存储可更新的数据。EEPROM 是用在复杂系统(例如计算机)和其它电子器件中的一种永久(非易失)存储器存储系统,它可以在电源故障时存储和保留少量数据。

由于STM32的单片机支持IAP功能,因此可以通过读写Flash的某个特定区域来实现对EEPROM的模拟。STM32F103与F407的EEPROM仿真主要参考了意法半导体公司官方应用笔记

笔者在EEPROM仿真库的基础上,进一步封装了应用层的扩展库。利用此扩展库,可以直接声明和定义一个StorableData类型的变量。该变量可以利用扩展库提供的接口方便的实现掉电存储、上电加载、重置默认等功能。

需要特别说明的是:

  • 笔者提供的EEPROM仿真库源码与官方提供的源码相比,稍作了修改以使其能更好的配合应用层扩展库使用。
  • 由于STM32F103与STM32F407的标准外设库函数中对flash的操作API不同,因此EEPROM仿真库针对不同单片机平台的函数实现(源文件)是有所不同的
  • 应用层扩展是基于EEPROM仿真库实现的,利用了EEPROM仿真库统一的接口,因此可以兼容不同的单片机平台。

EEPROM仿真

框架介绍

EEPROM 是许多需要非易失性数据存储的嵌入式应用的关键组件,它在运行期间以字节或字为粒度。这些系统中使用的微控制器通常是基于嵌入式 Flash 存储器的。为了避免使用这些组件、节约 PCB 空间并降低系统成本,可使用 STM32的Flash代替外部 EEPOM,模拟代码和数据的存储。但是与 Flash 不同的是,外部 EEPROM 在重写数据之前并不需要执行擦除操作来释放空间。要将数据存储到嵌入式 Flash 中,需要执行特殊的软件管理。

官方提供的应用笔记介绍了使用 STM32F103/STM32F407 器件的片上 Flash 通过仿真 EEPROM 机制来取代独立 EEPROM 的软件解决方案。由于Flash的可采写次数较少(1万次),因此EEPROM仿真库采用了耗损均衡算法以增加Flash可擦写次数。

源码

容量设置

根据项目需要可以修改头文件与源文件中的相关内容,设置一个合适的16位数据可存储的数量

在头文件中指定了16位数据可存储的数量为128个,如果都以32位的浮点数类型来保存数据的话,保存的浮点数数量为64个。
头文件中相关内容:

/* Variables' number */
#define EEPROM_NumbOfVar		128
extern uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar];

源文件中相关内容:

/* Virtual address defined by the user: 0xFFFF value is prohibited */
uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar] =
{
	0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
	0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010,
	0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
	0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020,
	0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
	0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030,
	0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
	0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040,
	0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
	0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
	0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
	0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060,
	0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068,
	0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
	0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
	0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x0080,
};

在头文件中指定了16位数据可存储的数量为256个,如果都以32位的浮点数类型来保存数据的话,保存的浮点数数量为128个
头文件中相关内容:

/* Variables' number */
#define EEPROM_NumbOfVar		256
extern uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar];

源文件中相关内容:

/* Virtual address defined by the user: 0xFFFF value is prohibited */
uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar] =
{
	0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
	0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010,
	0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
	0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020,
	0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
	0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030,
	0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
	0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040,
	0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
	0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
	0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
	0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060,
	0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068,
	0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
	0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
	0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x0080,

	0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088,
	0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, 0x0090,
	0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098,
	0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, 0x00A0,
	0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8,
	0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0,
	0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8,
	0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0,
	0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8,
	0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0,
	0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8,
	0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0,
	0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8,
	0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0,
	0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8,
	0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, 0x0100,
};

STM32F103

头文件
/**
  ******************************************************************************
  * @file    EEPROM_Emulation/inc/eeprom.h 
  * @author  MCD Application Team
  * @version V3.1.0
  * @date    07/27/2009
  * @brief   This file contains all the functions prototypes for the EEPROM 
  *          emulation firmware library.
  ******************************************************************************
  * @copy
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2009 STMicroelectronics</center></h2>
  */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __EEPROM_H
#define __EEPROM_H

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "stm32f10x_conf.h"

/* Exported constants --------------------------------------------------------*/
/* Define the STM32F10Xxx Flash page size depending on the used STM32 device */
#if defined (STM32F10X_LD) || defined (STM32F10X_MD)
  #define PAGE_SIZE  (uint16_t)0x400  /* Page size = 1KByte */
  #define FLASH_END_ADDRESS 0x08010000

#elif defined (STM32F10X_HD) || defined (STM32F10X_CL)
  #define PAGE_SIZE  (uint16_t)0x800  /* Page size = 2KByte */
  #define FLASH_END_ADDRESS 0x08040000

#endif

/* EEPROM start address in Flash */
#define EEPROM_START_ADDRESS    ((uint32_t)(FLASH_END_ADDRESS - 2 * PAGE_SIZE))


/* Pages 0 and 1 base and end addresses */
#define PAGE0_BASE_ADDRESS      ((uint32_t)(EEPROM_START_ADDRESS + 0x000))
#define PAGE0_END_ADDRESS       ((uint32_t)(EEPROM_START_ADDRESS + (PAGE_SIZE - 1)))

#define PAGE1_BASE_ADDRESS      ((uint32_t)(EEPROM_START_ADDRESS + PAGE_SIZE))
#define PAGE1_END_ADDRESS       ((uint32_t)(EEPROM_START_ADDRESS + (2 * PAGE_SIZE - 1)))

/* Used Flash pages for EEPROM emulation */
#define PAGE0                   ((uint16_t)0x0000)
#define PAGE1                   ((uint16_t)0x0001)

/* No valid page define */
#define NO_VALID_PAGE           ((uint16_t)0x00AB)

/* Page status definitions */
#define ERASED                  ((uint16_t)0xFFFF)     /* PAGE is empty */
#define RECEIVE_DATA            ((uint16_t)0xEEEE)     /* PAGE is marked to receive data */
#define VALID_PAGE              ((uint16_t)0x0000)     /* PAGE containing valid data */

/* Valid pages in read and write defines */
#define READ_FROM_VALID_PAGE    ((uint8_t)0x00)
#define WRITE_IN_VALID_PAGE     ((uint8_t)0x01)

/* Page full define */
#define PAGE_FULL               ((uint8_t)0x80)

/* Variables' number */
//#define EEPROM_NumbOfVar               ((uint8_t)STORABLE_DATA_COUNT * 2)
#define EEPROM_NumbOfVar		128

extern uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar];

/* Exported types ------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
uint16_t EE_Init(void);
uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data);
uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data);

#endif /* __EEPROM_H */

/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/

源文件
/**
 ******************************************************************************
 * @file    EEPROM_Emulation/src/eeprom.c
 * @author  MCD Application Team
 * @version V3.1.0
 * @date    07/27/2009
 * @brief   This file provides all the EEPROM emulation firmware functions.
 ******************************************************************************
 * @copy
 *
 * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
 * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
 * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
 * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
 * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
 * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
 *
 * <h2><center>&copy; COPYRIGHT 2009 STMicroelectronics</center></h2>
 */
/** @addtogroup EEPROM_Emulation
 * @{
 */

/* Includes ------------------------------------------------------------------*/
#include "eeprom.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/

/* Global variable used to store variable value in read sequence */
static uint16_t DataVar = 0;

/* Virtual address defined by the user: 0xFFFF value is prohibited */
uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar] =
{
	0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
	0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010,
	0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
	0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020,
	0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
	0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030,
	0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
	0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040,
	0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
	0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
	0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
	0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060,
	0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068,
	0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
	0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
	0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x0080,
};

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
static FLASH_Status EE_Format(void);
static uint16_t EE_FindValidPage(uint8_t Operation);
static uint16_t EE_VerifyPageFullWriteVariable(uint16_t VirtAddress, uint16_t Data);
static uint16_t EE_PageTransfer(uint16_t VirtAddress, uint16_t Data);

/**
 * @brief  Restore the pages to a known good state in case of page's status
 *   corruption after a power loss.
 * @param  None.
 * @retval - Flash error code: on write Flash error
 *         - FLASH_COMPLETE: on success
 */
uint16_t EE_Init(void)
{
	uint16_t PageStatus0 = 6, PageStatus1 = 6;
	uint16_t VarIdx = 0;
	uint16_t EepromStatus = 0, ReadStatus = 0;
	int16_t x = -1;
	uint16_t FlashStatus;

	/* Get Page0 status */
	PageStatus0 = (*(__IO uint16_t*) PAGE0_BASE_ADDRESS);
	/* Get Page1 status */
	PageStatus1 = (*(__IO uint16_t*) PAGE1_BASE_ADDRESS);

	/* Check for invalid header states and repair if necessary */
	switch (PageStatus0)
	{
	case ERASED:
		if (PageStatus1 == VALID_PAGE) /* Page0 erased, Page1 valid */
		{
			/* Erase Page0 */
			FlashStatus = FLASH_ErasePage(PAGE0_BASE_ADDRESS);
			/* If erase operation was failed, a Flash error code is returned */
			if (FlashStatus != FLASH_COMPLETE)
			{
				return FlashStatus;
			}
		}
		else if (PageStatus1 == RECEIVE_DATA) /* Page0 erased, Page1 receive */
		{
			/* Erase Page0 */
			FlashStatus = FLASH_ErasePage(PAGE0_BASE_ADDRESS);
			/* If erase operation was failed, a Flash error code is returned */
			if (FlashStatus != FLASH_COMPLETE)
			{
				return FlashStatus;
			}
			/* Mark Page1 as valid */
			FlashStatus = FLASH_ProgramHalfWord(PAGE1_BASE_ADDRESS, VALID_PAGE);
			/* If program operation was failed, a Flash error code is returned */
			if (FlashStatus != FLASH_COMPLETE)
			{
				return FlashStatus;
			}
		}
		else /* First EEPROM access (Page0&1 are erased) or invalid state -> format EEPROM */
		{
			/* Erase both Page0 and Page1 and set Page0 as valid page */
			FlashStatus = EE_Format();
			/* If erase/program operation was failed, a Flash error code is returned */
			if (FlashStatus != FLASH_COMPLETE)
			{
				return FlashStatus;
			}
		}
		break;

	case RECEIVE_DATA:
		if (PageStatus1 == VALID_PAGE) /* Page0 receive, Page1 valid */
		{
			/* Transfer data from Page1 to Page0 */
			for (VarIdx = 0; VarIdx < EEPROM_NumbOfVar; VarIdx++)
			{
				if ((*(__IO uint16_t*) (PAGE0_BASE_ADDRESS + 6))
						== EEPROM_VirtAddVarTab[VarIdx])
				{
					x = VarIdx;
				}
				if (VarIdx != x)
				{
					/* Read the last variables' updates */
					ReadStatus = EE_ReadVariable(EEPROM_VirtAddVarTab[VarIdx],
							&DataVar);
					/* In case variable corresponding to the virtual address was found */
					if (ReadStatus != 0x1)
					{
						/* Transfer the variable to the Page0 */
						EepromStatus = EE_VerifyPageFullWriteVariable(
								EEPROM_VirtAddVarTab[VarIdx], DataVar);
						/* If program operation was failed, a Flash error code is returned */
						if (EepromStatus != FLASH_COMPLETE)
						{
							return EepromStatus;
						}
					}
				}
			}
			/* Mark Page0 as valid */
			FlashStatus = FLASH_ProgramHalfWord(PAGE0_BASE_ADDRESS, VALID_PAGE);
			/* If program operation was failed, a Flash error code is returned */
			if (FlashStatus != FLASH_COMPLETE)
			{
				return FlashStatus;
			}
			/* Erase Page1 */
			FlashStatus = FLASH_ErasePage(PAGE1_BASE_ADDRESS);
			/* If erase operation was failed, a Flash error code is returned */
			if (FlashStatus != FLASH_COMPLETE)
			{
				return FlashStatus;
			}
		}
		else if (PageStatus1 == ERASED) /* Page0 receive, Page1 erased */
		{
			/* Erase Page1 */
			FlashStatus = FLASH_ErasePage(PAGE1_BASE_ADDRESS);
			/* If erase operation was failed, a Flash error code is returned */
			if (FlashStatus != FLASH_COMPLETE)
			{
				return FlashStatus;
			}
			/* Mark Page0 as valid */
			FlashStatus = FLASH_ProgramHalfWord(PAGE0_BASE_ADDRESS, VALID_PAGE);
			/* If program operation was failed, a Flash error code is returned */
			if (FlashStatus != FLASH_COMPLETE)
			{
				return FlashStatus;
			}
		}
		else /* Invalid state -> format eeprom */
		{
			/* Erase both Page0 and Page1 and set Page0 as valid page */
			FlashStatus = EE_Format();
			/* If erase/program operation was failed, a Flash error code is returned */
			if (FlashStatus != FLASH_COMPLETE)
			{
				return FlashStatus;
			}
		}
		break;

	case VALID_PAGE:
		if (PageStatus1 == VALID_PAGE) /* Invalid state -> format eeprom */
		{
			/* Erase both Page0 and Page1 and set Page0 as valid page */
			FlashStatus = EE_Format();
			/* If erase/program operation was failed, a Flash error code is returned */
			if (FlashStatus != FLASH_COMPLETE)
			{
				return FlashStatus;
			}
		}
		else if (PageStatus1 == ERASED) /* Page0 valid, Page1 erased */
		{
			/* Erase Page1 */
			FlashStatus = FLASH_ErasePage(PAGE1_BASE_ADDRESS);
			/* If erase operation was failed, a Flash error code is returned */
			if (FlashStatus != FLASH_COMPLETE)
			{
				return FlashStatus;
			}
		}
		else /* Page0 valid, Page1 receive */
		{
			/* Transfer data from Page0 to Page1 */
			for (VarIdx = 0; VarIdx < EEPROM_NumbOfVar; VarIdx++)
			{
				if ((*(__IO uint16_t*) (PAGE1_BASE_ADDRESS + 6))
						== EEPROM_VirtAddVarTab[VarIdx])
				{
					x = VarIdx;
				}
				if (VarIdx != x)
				{
					/* Read the last variables' updates */
					ReadStatus = EE_ReadVariable(EEPROM_VirtAddVarTab[VarIdx],
							&DataVar);
					/* In case variable corresponding to the virtual address was found */
					if (ReadStatus != 0x1)
					{
						/* Transfer the variable to the Page1 */
						EepromStatus = EE_VerifyPageFullWriteVariable(
								EEPROM_VirtAddVarTab[VarIdx], DataVar);
						/* If program operation was failed, a Flash error code is returned */
						if (EepromStatus != FLASH_COMPLETE)
						{
							return EepromStatus;
						}
					}
				}
			}
			/* Mark Page1 as valid */
			FlashStatus = FLASH_ProgramHalfWord(PAGE1_BASE_ADDRESS, VALID_PAGE);
			/* If program operation was failed, a Flash error code is returned */
			if (FlashStatus != FLASH_COMPLETE)
			{
				return FlashStatus;
			}
			/* Erase Page0 */
			FlashStatus = FLASH_ErasePage(PAGE0_BASE_ADDRESS);
			/* If erase operation was failed, a Flash error code is returned */
			if (FlashStatus != FLASH_COMPLETE)
			{
				return FlashStatus;
			}
		}
		break;

	default: /* Any other state -> format eeprom */
		/* Erase both Page0 and Page1 and set Page0 as valid page */
		FlashStatus = EE_Format();
		/* If erase/program operation was failed, a Flash error code is returned */
		if (FlashStatus != FLASH_COMPLETE)
		{
			return FlashStatus;
		}
		break;
	}

	return FLASH_COMPLETE;
}

/**
 * @brief  Returns the last stored variable data, if found, which correspond to
 *   the passed virtual address
 * @param  VirtAddress: Variable virtual address
 * @param  Data: Global variable contains the read variable value
 * @retval Success or error status:
 *           - 0: if variable was found
 *           - 1: if the variable was not found
 *           - NO_VALID_PAGE: if no valid page was found.
 */
uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data)
{
	uint16_t ValidPage = PAGE0;
	uint16_t AddressValue = 0x5555, ReadStatus = 1;
	uint32_t Address = 0x08010000, PageStartAddress = 0x08010000;

	/* Get active Page for read operation */
	ValidPage = EE_FindValidPage(READ_FROM_VALID_PAGE);

	/* Check if there is no valid page */
	if (ValidPage == NO_VALID_PAGE)
	{
		return NO_VALID_PAGE;
	}

	/* Get the valid Page start Address */
	PageStartAddress = (uint32_t) (EEPROM_START_ADDRESS
			+ (uint32_t) (ValidPage * PAGE_SIZE ));

	/* Get the valid Page end Address */
	Address = (uint32_t) ((EEPROM_START_ADDRESS - 2)
			+ (uint32_t) ((1 + ValidPage) * PAGE_SIZE ));

	/* Check each active page address starting from end */
	while (Address > (PageStartAddress + 2))
	{
		/* Get the current location content to be compared with virtual address */
		AddressValue = (*(__IO uint16_t*) Address);

		/* Compare the read address with the virtual address */
		if (AddressValue == VirtAddress)
		{
			/* Get content of Address-2 which is variable value */
			*Data = (*(__IO uint16_t*) (Address - 2));

			/* In case variable value is read, reset ReadStatus flag */
			ReadStatus = 0;

			break;
		}
		else
		{
			/* Next address location */
			Address = Address - 4;
		}
	}

	/* Return ReadStatus value: (0: variable exist, 1: variable doesn't exist) */
	return ReadStatus;
}

/**
 * @brief  Writes/upadtes variable data in EEPROM.
 * @param  VirtAddress: Variable virtual address
 * @param  Data: 16 bit data to be written
 * @retval Success or error status:
 *           - FLASH_COMPLETE: on success
 *           - PAGE_FULL: if valid page is full
 *           - NO_VALID_PAGE: if no valid page was found
 *           - Flash error code: on write Flash error
 */
uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data)
{
	uint16_t Status = 0;

	/* Write the variable virtual address and value in the EEPROM */
	Status = EE_VerifyPageFullWriteVariable(VirtAddress, Data);

	/* In case the EEPROM active page is full */
	if (Status == PAGE_FULL)
	{
		/* Perform Page transfer */
		Status = EE_PageTransfer(VirtAddress, Data);
	}

	/* Return last operation status */
	return Status;
}

/**
 * @brief  Erases PAGE0 and PAGE1 and writes VALID_PAGE header to PAGE0
 * @param  None
 * @retval Status of the last operation (Flash write or erase) done during
 *         EEPROM formating
 */
static FLASH_Status EE_Format(void)
{
	FLASH_Status FlashStatus = FLASH_COMPLETE;

	/* Erase Page0 */
	FlashStatus = FLASH_ErasePage(PAGE0_BASE_ADDRESS);

	/* If erase operation was failed, a Flash error code is returned */
	if (FlashStatus != FLASH_COMPLETE)
	{
		return FlashStatus;
	}

	/* Set Page0 as valid page: Write VALID_PAGE at Page0 base address */
	FlashStatus = FLASH_ProgramHalfWord(PAGE0_BASE_ADDRESS, VALID_PAGE);

	/* If program operation was failed, a Flash error code is returned */
	if (FlashStatus != FLASH_COMPLETE)
	{
		return FlashStatus;
	}

	/* Erase Page1 */
	FlashStatus = FLASH_ErasePage(PAGE1_BASE_ADDRESS);

	/* Return Page1 erase operation status */
	return FlashStatus;
}

/**
 * @brief  Find valid Page for write or read operation
 * @param  Operation: operation to achieve on the valid page.
 *   This parameter can be one of the following values:
 *     @arg READ_FROM_VALID_PAGE: read operation from valid page
 *     @arg WRITE_IN_VALID_PAGE: write operation from valid page
 * @retval Valid page number (PAGE0 or PAGE1) or NO_VALID_PAGE in case
 *   of no valid page was found
 */
static uint16_t EE_FindValidPage(uint8_t Operation)
{
	uint16_t PageStatus0 = 6, PageStatus1 = 6;

	/* Get Page0 actual status */
	PageStatus0 = (*(__IO uint16_t*) PAGE0_BASE_ADDRESS);

	/* Get Page1 actual status */
	PageStatus1 = (*(__IO uint16_t*) PAGE1_BASE_ADDRESS);

	/* Write or read operation */
	switch (Operation)
	{
	case WRITE_IN_VALID_PAGE: /* ---- Write operation ---- */
		if (PageStatus1 == VALID_PAGE)
		{
			/* Page0 receiving data */
			if (PageStatus0 == RECEIVE_DATA)
			{
				return PAGE0; /* Page0 valid */
			}
			else
			{
				return PAGE1; /* Page1 valid */
			}
		}
		else if (PageStatus0 == VALID_PAGE)
		{
			/* Page1 receiving data */
			if (PageStatus1 == RECEIVE_DATA)
			{
				return PAGE1; /* Page1 valid */
			}
			else
			{
				return PAGE0; /* Page0 valid */
			}
		}
		else
		{
			return NO_VALID_PAGE; /* No valid Page */
		}

	case READ_FROM_VALID_PAGE: /* ---- Read operation ---- */
		if (PageStatus0 == VALID_PAGE)
		{
			return PAGE0; /* Page0 valid */
		}
		else if (PageStatus1 == VALID_PAGE)
		{
			return PAGE1; /* Page1 valid */
		}
		else
		{
			return NO_VALID_PAGE; /* No valid Page */
		}

	default:
		return PAGE0; /* Page0 valid */
	}
}

/**
 * @brief  Verify if active page is full and Writes variable in EEPROM.
 * @param  VirtAddress: 16 bit virtual address of the variable
 * @param  Data: 16 bit data to be written as variable value
 * @retval Success or error status:
 *           - FLASH_COMPLETE: on success
 *           - PAGE_FULL: if valid page is full
 *           - NO_VALID_PAGE: if no valid page was found
 *           - Flash error code: on write Flash error
 */
static uint16_t EE_VerifyPageFullWriteVariable(uint16_t VirtAddress,
		uint16_t Data)
{
	FLASH_Status FlashStatus = FLASH_COMPLETE;
	uint16_t ValidPage = PAGE0;
	uint32_t Address = 0x08010000, PageEndAddress = 0x080107FF;

	/* Get valid Page for write operation */
	ValidPage = EE_FindValidPage(WRITE_IN_VALID_PAGE);

	/* Check if there is no valid page */
	if (ValidPage == NO_VALID_PAGE)
	{
		return NO_VALID_PAGE;
	}

	/* Get the valid Page start Address */
	Address = (uint32_t) (EEPROM_START_ADDRESS
			+ (uint32_t) (ValidPage * PAGE_SIZE ));

	/* Get the valid Page end Address */
	PageEndAddress = (uint32_t) ((EEPROM_START_ADDRESS - 2)
			+ (uint32_t) ((1 + ValidPage) * PAGE_SIZE ));

	/* Check each active page address starting from begining */
	while (Address < PageEndAddress)
	{
		/* Verify if Address and Address+2 contents are 0xFFFFFFFF */
		if ((*(__IO uint32_t*) Address) == 0xFFFFFFFF)
		{
			/* Set variable data */
			FlashStatus = FLASH_ProgramHalfWord(Address, Data);
			/* If program operation was failed, a Flash error code is returned */
			if (FlashStatus != FLASH_COMPLETE)
			{
				return FlashStatus;
			}
			/* Set variable virtual address */
			FlashStatus = FLASH_ProgramHalfWord(Address + 2, VirtAddress);
			/* Return program operation status */
			return FlashStatus;
		}
		else
		{
			/* Next address location */
			Address = Address + 4;
		}
	}

	/* Return PAGE_FULL in case the valid page is full */
	return PAGE_FULL;
}

/**
 * @brief  Transfers last updated variables data from the full Page to
 *   an empty one.
 * @param  VirtAddress: 16 bit virtual address of the variable
 * @param  Data: 16 bit data to be written as variable value
 * @retval Success or error status:
 *           - FLASH_COMPLETE: on success
 *           - PAGE_FULL: if valid page is full
 *           - NO_VALID_PAGE: if no valid page was found
 *           - Flash error code: on write Flash error
 */
static uint16_t EE_PageTransfer(uint16_t VirtAddress, uint16_t Data)
{
	FLASH_Status FlashStatus = FLASH_COMPLETE;
	uint32_t NewPageAddress = 0x080103FF, OldPageAddress = 0x08010000;
	uint16_t ValidPage = PAGE0, VarIdx = 0;
	uint16_t EepromStatus = 0, ReadStatus = 0;

	/* Get active Page for read operation */
	ValidPage = EE_FindValidPage(READ_FROM_VALID_PAGE);

	if (ValidPage == PAGE1) /* Page1 valid */
	{
		/* New page address where variable will be moved to */
		NewPageAddress = PAGE0_BASE_ADDRESS;

		/* Old page address where variable will be taken from */
		OldPageAddress = PAGE1_BASE_ADDRESS;
	}
	else if (ValidPage == PAGE0) /* Page0 valid */
	{
		/* New page address where variable will be moved to */
		NewPageAddress = PAGE1_BASE_ADDRESS;

		/* Old page address where variable will be taken from */
		OldPageAddress = PAGE0_BASE_ADDRESS;
	}
	else
	{
		return NO_VALID_PAGE; /* No valid Page */
	}

	/* Set the new Page status to RECEIVE_DATA status */
	FlashStatus = FLASH_ProgramHalfWord(NewPageAddress, RECEIVE_DATA);
	/* If program operation was failed, a Flash error code is returned */
	if (FlashStatus != FLASH_COMPLETE)
	{
		return FlashStatus;
	}

	/* Write the variable passed as parameter in the new active page */
	EepromStatus = EE_VerifyPageFullWriteVariable(VirtAddress, Data);
	/* If program operation was failed, a Flash error code is returned */
	if (EepromStatus != FLASH_COMPLETE)
	{
		return EepromStatus;
	}

	/* Transfer process: transfer variables from old to the new active page */
	for (VarIdx = 0; VarIdx < EEPROM_NumbOfVar; VarIdx++)
	{
		if (EEPROM_VirtAddVarTab[VarIdx] != VirtAddress) /* Check each variable except the one passed as parameter */
		{
			/* Read the other last variable updates */
			ReadStatus = EE_ReadVariable(EEPROM_VirtAddVarTab[VarIdx], &DataVar);
			/* In case variable corresponding to the virtual address was found */
			if (ReadStatus != 0x1)
			{
				/* Transfer the variable to the new active page */
				EepromStatus = EE_VerifyPageFullWriteVariable(
						EEPROM_VirtAddVarTab[VarIdx], DataVar);
				/* If program operation was failed, a Flash error code is returned */
				if (EepromStatus != FLASH_COMPLETE)
				{
					return EepromStatus;
				}
			}
		}
	}

	/* Erase the old Page: Set old Page status to ERASED status */
	FlashStatus = FLASH_ErasePage(OldPageAddress);
	/* If erase operation was failed, a Flash error code is returned */
	if (FlashStatus != FLASH_COMPLETE)
	{
		return FlashStatus;
	}

	/* Set new Page status to VALID_PAGE status */
	FlashStatus = FLASH_ProgramHalfWord(NewPageAddress, VALID_PAGE);
	/* If program operation was failed, a Flash error code is returned */
	if (FlashStatus != FLASH_COMPLETE)
	{
		return FlashStatus;
	}

	/* Return last operation flash status */
	return FlashStatus;
}

/**
 * @}
 */

/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/

STM32F407

头文件
/**
  ******************************************************************************
  * @file    EEPROM_Emulation/inc/eeprom.h
  * @author  MCD Application Team
   * @version V1.0.0
  * @date    10-October-2011
  * @brief   This file contains all the functions prototypes for the EEPROM
  *          emulation firmware library.
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
  ******************************************************************************
  */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __EEPROM_H
#define __EEPROM_H

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"

/* Exported constants --------------------------------------------------------*/

#define ADDR_FLASH_SECTOR_0			((uint32_t) 0x08000000)
#define ADDR_FLASH_SECTOR_1			((uint32_t) 0x08004000)
#define ADDR_FLASH_SECTOR_2			((uint32_t) 0x08008000)
#define ADDR_FLASH_SECTOR_3			((uint32_t) 0x0800C000)
#define ADDR_FLASH_SECTOR_4			((uint32_t) 0x08010000)
#define ADDR_FLASH_SECTOR_5			((uint32_t) 0x08020000)
#define ADDR_FLASH_SECTOR_6			((uint32_t) 0x08040000)
#define ADDR_FLASH_SECTOR_7			((uint32_t) 0x08060000)
#define ADDR_FLASH_SECTOR_8			((uint32_t) 0x08080000)
#define ADDR_FLASH_SECTOR_9			((uint32_t) 0x080A0000)
#define ADDR_FLASH_SECTOR_10			((uint32_t) 0x080C0000)
#define ADDR_FLASH_SECTOR_11			((uint32_t) 0x080E0000)

#define ADDR_FLASH_SECTOR_12			((uint32_t) 0x08100000)
#define ADDR_FLASH_SECTOR_13			((uint32_t) 0x08104000)
#define ADDR_FLASH_SECTOR_14			((uint32_t) 0x08108000)
#define ADDR_FLASH_SECTOR_15			((uint32_t) 0x0810C000)
#define ADDR_FLASH_SECTOR_16			((uint32_t) 0x08110000)
#define ADDR_FLASH_SECTOR_17			((uint32_t) 0x08120000)
#define ADDR_FLASH_SECTOR_18			((uint32_t) 0x08140000)
#define ADDR_FLASH_SECTOR_19			((uint32_t) 0x08160000)
#define ADDR_FLASH_SECTOR_20		((uint32_t) 0x08180000)
#define ADDR_FLASH_SECTOR_21			((uint32_t) 0x081A0000)
#define ADDR_FLASH_SECTOR_22		((uint32_t) 0x081C0000)
#define ADDR_FLASH_SECTOR_23		((uint32_t) 0x081E0000)

/*Bootload占用了Flash的0~1扇区,模拟EEPROM占用2~3扇区,用户APP从4扇区开始启动*/

/* Define the size of the sectors to be used */
#define PAGE_SIZE               (uint32_t)0x4000  /* Page size = 16KByte */

/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
   be done by word  */
#define VOLTAGE_RANGE           (uint8_t)VoltageRange_3

/* EEPROM start address in Flash */
/* EEPROM emulation start address: from sector2 : after 16KByte of usedFlash memory */
#define EEPROM_START_ADDRESS  ADDR_FLASH_SECTOR_2

/* Pages 0 and 1 base and end addresses */
#define PAGE0_BASE_ADDRESS    ((uint32_t)(EEPROM_START_ADDRESS + 0x0000))
#define PAGE0_END_ADDRESS     ((uint32_t)(EEPROM_START_ADDRESS + (PAGE_SIZE - 1)))
#define PAGE0_ID               FLASH_Sector_2

#define PAGE1_BASE_ADDRESS    ((uint32_t)(EEPROM_START_ADDRESS + 0x4000))
#define PAGE1_END_ADDRESS     ((uint32_t)(EEPROM_START_ADDRESS + (2 * PAGE_SIZE - 1)))
#define PAGE1_ID               FLASH_Sector_3

/* Used Flash pages for EEPROM emulation */
#define PAGE0                 ((uint16_t)0x0000)
#define PAGE1                 ((uint16_t)0x0001)

/* No valid page define */
#define NO_VALID_PAGE         ((uint16_t)0x00AB)

/* Page status definitions */
#define ERASED                ((uint16_t)0xFFFF)     /* Page is empty */
#define RECEIVE_DATA          ((uint16_t)0xEEEE)     /* Page is marked to receive data */
#define VALID_PAGE            ((uint16_t)0x0000)     /* Page containing valid data */

/* Valid pages in read and write defines */
#define READ_FROM_VALID_PAGE  ((uint8_t)0x00)
#define WRITE_IN_VALID_PAGE   ((uint8_t)0x01)

/* Page full define */
#define PAGE_FULL             ((uint8_t)0x80)

/* Variables' number */
#define EEPROM_NumbOfVar		128
extern uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar];

/* Exported types ------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
uint16_t EE_Init(void);
uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data);
uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data);

#endif /* __EEPROM_H */

/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

源文件
/**
  ******************************************************************************
  * @file    EEPROM_Emulation/src/eeprom.c
  * @author  MCD Application Team
  * @version V1.0.0
  * @date    10-October-2011
  * @brief   This file provides all the EEPROM emulation firmware functions.
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
  ******************************************************************************
  */

/** @addtogroup EEPROM_Emulation
  * @{
  */

/* Includes ------------------------------------------------------------------*/
#include "eeprom.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/

/* Global variable used to store variable value in read sequence */
uint16_t DataVar = 0;

/* Virtual address defined by the user: 0xFFFF value is prohibited */
uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar] =
{
	0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
	0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010,
	0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
	0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020,
	0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
	0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030,
	0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
	0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040,
	0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
	0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
	0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
	0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060,
	0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068,
	0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
	0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
	0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x0080,
};

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
static FLASH_Status EE_Format(void);
static uint16_t EE_FindValidPage(uint8_t Operation);
static uint16_t EE_VerifyPageFullWriteVariable(uint16_t VirtAddress, uint16_t Data);
static uint16_t EE_PageTransfer(uint16_t VirtAddress, uint16_t Data);

/**
  * @brief  Restore the pages to a known good state in case of page's status
  *   corruption after a power loss.
  * @param  None.
  * @retval - Flash error code: on write Flash error
  *         - FLASH_COMPLETE: on success
  */
uint16_t EE_Init(void)
{
  uint16_t PageStatus0 = 6, PageStatus1 = 6;
  uint16_t VarIdx = 0;
  uint16_t EepromStatus = 0, ReadStatus = 0;
  int16_t x = -1;
  uint16_t  FlashStatus;

  /* Get Page0 status */
  PageStatus0 = (*(__IO uint16_t*)PAGE0_BASE_ADDRESS);
  /* Get Page1 status */
  PageStatus1 = (*(__IO uint16_t*)PAGE1_BASE_ADDRESS);

  /* Check for invalid header states and repair if necessary */
  switch (PageStatus0)
  {
    case ERASED:
      if (PageStatus1 == VALID_PAGE) /* Page0 erased, Page1 valid */
      {
        /* Erase Page0 */
        FlashStatus = FLASH_EraseSector(PAGE0_ID,VOLTAGE_RANGE);
        /* If erase operation was failed, a Flash error code is returned */
        if (FlashStatus != FLASH_COMPLETE)
        {
          return FlashStatus;
        }
      }
      else if (PageStatus1 == RECEIVE_DATA) /* Page0 erased, Page1 receive */
      {
        /* Erase Page0 */
        FlashStatus = FLASH_EraseSector(PAGE0_ID, VOLTAGE_RANGE);
        /* If erase operation was failed, a Flash error code is returned */
        if (FlashStatus != FLASH_COMPLETE)
        {
          return FlashStatus;
        }
        /* Mark Page1 as valid */
        FlashStatus = FLASH_ProgramHalfWord(PAGE1_BASE_ADDRESS, VALID_PAGE);
        /* If program operation was failed, a Flash error code is returned */
        if (FlashStatus != FLASH_COMPLETE)
        {
          return FlashStatus;
        }
      }
      else /* First EEPROM access (Page0&1 are erased) or invalid state -> format EEPROM */
      {
        /* Erase both Page0 and Page1 and set Page0 as valid page */
        FlashStatus = EE_Format();
        /* If erase/program operation was failed, a Flash error code is returned */
        if (FlashStatus != FLASH_COMPLETE)
        {
          return FlashStatus;
        }
      }
      break;

    case RECEIVE_DATA:
      if (PageStatus1 == VALID_PAGE) /* Page0 receive, Page1 valid */
      {
        /* Transfer data from Page1 to Page0 */
        for (VarIdx = 0; VarIdx < EEPROM_NumbOfVar; VarIdx++)
        {
          if (( *(__IO uint16_t*)(PAGE0_BASE_ADDRESS + 6)) == EEPROM_VirtAddVarTab[VarIdx])
          {
            x = VarIdx;
          }
          if (VarIdx != x)
          {
            /* Read the last variables' updates */
            ReadStatus = EE_ReadVariable(EEPROM_VirtAddVarTab[VarIdx], &DataVar);
            /* In case variable corresponding to the virtual address was found */
            if (ReadStatus != 0x1)
            {
              /* Transfer the variable to the Page0 */
              EepromStatus = EE_VerifyPageFullWriteVariable(EEPROM_VirtAddVarTab[VarIdx], DataVar);
              /* If program operation was failed, a Flash error code is returned */
              if (EepromStatus != FLASH_COMPLETE)
              {
                return EepromStatus;
              }
            }
          }
        }
        /* Mark Page0 as valid */
        FlashStatus = FLASH_ProgramHalfWord(PAGE0_BASE_ADDRESS, VALID_PAGE);
        /* If program operation was failed, a Flash error code is returned */
        if (FlashStatus != FLASH_COMPLETE)
        {
          return FlashStatus;
        }
        /* Erase Page1 */
        FlashStatus = FLASH_EraseSector(PAGE1_ID, VOLTAGE_RANGE);
        /* If erase operation was failed, a Flash error code is returned */
        if (FlashStatus != FLASH_COMPLETE)
        {
          return FlashStatus;
        }
      }
      else if (PageStatus1 == ERASED) /* Page0 receive, Page1 erased */
      {
        /* Erase Page1 */
        FlashStatus = FLASH_EraseSector(PAGE1_ID, VOLTAGE_RANGE);
        /* If erase operation was failed, a Flash error code is returned */
        if (FlashStatus != FLASH_COMPLETE)
        {
          return FlashStatus;
        }
        /* Mark Page0 as valid */
        FlashStatus = FLASH_ProgramHalfWord(PAGE0_BASE_ADDRESS, VALID_PAGE);
        /* If program operation was failed, a Flash error code is returned */
        if (FlashStatus != FLASH_COMPLETE)
        {
          return FlashStatus;
        }
      }
      else /* Invalid state -> format eeprom */
      {
        /* Erase both Page0 and Page1 and set Page0 as valid page */
        FlashStatus = EE_Format();
        /* If erase/program operation was failed, a Flash error code is returned */
        if (FlashStatus != FLASH_COMPLETE)
        {
          return FlashStatus;
        }
      }
      break;

    case VALID_PAGE:
      if (PageStatus1 == VALID_PAGE) /* Invalid state -> format eeprom */
      {
        /* Erase both Page0 and Page1 and set Page0 as valid page */
        FlashStatus = EE_Format();
        /* If erase/program operation was failed, a Flash error code is returned */
        if (FlashStatus != FLASH_COMPLETE)
        {
          return FlashStatus;
        }
      }
      else if (PageStatus1 == ERASED) /* Page0 valid, Page1 erased */
      {
        /* Erase Page1 */
        FlashStatus = FLASH_EraseSector(PAGE1_ID, VOLTAGE_RANGE);
        /* If erase operation was failed, a Flash error code is returned */
        if (FlashStatus != FLASH_COMPLETE)
        {
          return FlashStatus;
        }
      }
      else /* Page0 valid, Page1 receive */
      {
        /* Transfer data from Page0 to Page1 */
        for (VarIdx = 0; VarIdx < EEPROM_NumbOfVar; VarIdx++)
        {
          if ((*(__IO uint16_t*)(PAGE1_BASE_ADDRESS + 6)) == EEPROM_VirtAddVarTab[VarIdx])
          {
            x = VarIdx;
          }
          if (VarIdx != x)
          {
            /* Read the last variables' updates */
            ReadStatus = EE_ReadVariable(EEPROM_VirtAddVarTab[VarIdx], &DataVar);
            /* In case variable corresponding to the virtual address was found */
            if (ReadStatus != 0x1)
            {
              /* Transfer the variable to the Page1 */
              EepromStatus = EE_VerifyPageFullWriteVariable(EEPROM_VirtAddVarTab[VarIdx], DataVar);
              /* If program operation was failed, a Flash error code is returned */
              if (EepromStatus != FLASH_COMPLETE)
              {
                return EepromStatus;
              }
            }
          }
        }
        /* Mark Page1 as valid */
        FlashStatus = FLASH_ProgramHalfWord(PAGE1_BASE_ADDRESS, VALID_PAGE);
        /* If program operation was failed, a Flash error code is returned */
        if (FlashStatus != FLASH_COMPLETE)
        {
          return FlashStatus;
        }
        /* Erase Page0 */
        FlashStatus = FLASH_EraseSector(PAGE0_ID, VOLTAGE_RANGE);
        /* If erase operation was failed, a Flash error code is returned */
        if (FlashStatus != FLASH_COMPLETE)
        {
          return FlashStatus;
        }
      }
      break;

    default:  /* Any other state -> format eeprom */
      /* Erase both Page0 and Page1 and set Page0 as valid page */
      FlashStatus = EE_Format();
      /* If erase/program operation was failed, a Flash error code is returned */
      if (FlashStatus != FLASH_COMPLETE)
      {
        return FlashStatus;
      }
      break;
  }

  return FLASH_COMPLETE;
}

/**
  * @brief  Returns the last stored variable data, if found, which correspond to
  *   the passed virtual address
  * @param  VirtAddress: Variable virtual address
  * @param  Data: Global variable contains the read variable value
  * @retval Success or error status:
  *           - 0: if variable was found
  *           - 1: if the variable was not found
  *           - NO_VALID_PAGE: if no valid page was found.
  */
uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data)
{
  uint16_t ValidPage = PAGE0;
  uint16_t AddressValue = 0x5555, ReadStatus = 1;
  uint32_t Address = EEPROM_START_ADDRESS, PageStartAddress = EEPROM_START_ADDRESS;

  /* Get active Page for read operation */
  ValidPage = EE_FindValidPage(READ_FROM_VALID_PAGE);

  /* Check if there is no valid page */
  if (ValidPage == NO_VALID_PAGE)
  {
    return  NO_VALID_PAGE;
  }

  /* Get the valid Page start Address */
  PageStartAddress = (uint32_t)(EEPROM_START_ADDRESS + (uint32_t)(ValidPage * PAGE_SIZE));

  /* Get the valid Page end Address */
  Address = (uint32_t)((EEPROM_START_ADDRESS - 2) + (uint32_t)((1 + ValidPage) * PAGE_SIZE));

  /* Check each active page address starting from end */
  while (Address > (PageStartAddress + 2))
  {
    /* Get the current location content to be compared with virtual address */
    AddressValue = (*(__IO uint16_t*)Address);

    /* Compare the read address with the virtual address */
    if (AddressValue == VirtAddress)
    {
      /* Get content of Address-2 which is variable value */
      *Data = (*(__IO uint16_t*)(Address - 2));

      /* In case variable value is read, reset ReadStatus flag */
      ReadStatus = 0;

      break;
    }
    else
    {
      /* Next address location */
      Address = Address - 4;
    }
  }

  /* Return ReadStatus value: (0: variable exist, 1: variable doesn't exist) */
  return ReadStatus;
}

/**
  * @brief  Writes/upadtes variable data in EEPROM.
  * @param  VirtAddress: Variable virtual address
  * @param  Data: 16 bit data to be written
  * @retval Success or error status:
  *           - FLASH_COMPLETE: on success
  *           - PAGE_FULL: if valid page is full
  *           - NO_VALID_PAGE: if no valid page was found
  *           - Flash error code: on write Flash error
  */
uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data)
{
  uint16_t Status = 0;

  /* Write the variable virtual address and value in the EEPROM */
  Status = EE_VerifyPageFullWriteVariable(VirtAddress, Data);

  /* In case the EEPROM active page is full */
  if (Status == PAGE_FULL)
  {
    /* Perform Page transfer */
    Status = EE_PageTransfer(VirtAddress, Data);
  }

  /* Return last operation status */
  return Status;
}

/**
  * @brief  Erases PAGE and PAGE1 and writes VALID_PAGE header to PAGE
  * @param  None
  * @retval Status of the last operation (Flash write or erase) done during
  *         EEPROM formating
  */
static FLASH_Status EE_Format(void)
{
  FLASH_Status FlashStatus = FLASH_COMPLETE;

  /* Erase Page0 */
  FlashStatus = FLASH_EraseSector(PAGE0_ID, VOLTAGE_RANGE);

  /* If erase operation was failed, a Flash error code is returned */
  if (FlashStatus != FLASH_COMPLETE)
  {
    return FlashStatus;
  }

  /* Set Page0 as valid page: Write VALID_PAGE at Page0 base address */
  FlashStatus = FLASH_ProgramHalfWord(PAGE0_BASE_ADDRESS, VALID_PAGE);

  /* If program operation was failed, a Flash error code is returned */
  if (FlashStatus != FLASH_COMPLETE)
  {
    return FlashStatus;
  }

  /* Erase Page1 */
  FlashStatus = FLASH_EraseSector(PAGE1_ID, VOLTAGE_RANGE);

  /* Return Page1 erase operation status */
  return FlashStatus;
}

/**
  * @brief  Find valid Page for write or read operation
  * @param  Operation: operation to achieve on the valid page.
  *   This parameter can be one of the following values:
  *     @arg READ_FROM_VALID_PAGE: read operation from valid page
  *     @arg WRITE_IN_VALID_PAGE: write operation from valid page
  * @retval Valid page number (PAGE or PAGE1) or NO_VALID_PAGE in case
  *   of no valid page was found
  */
static uint16_t EE_FindValidPage(uint8_t Operation)
{
  uint16_t PageStatus0 = 6, PageStatus1 = 6;

  /* Get Page0 actual status */
  PageStatus0 = (*(__IO uint16_t*)PAGE0_BASE_ADDRESS);

  /* Get Page1 actual status */
  PageStatus1 = (*(__IO uint16_t*)PAGE1_BASE_ADDRESS);

  /* Write or read operation */
  switch (Operation)
  {
    case WRITE_IN_VALID_PAGE:   /* ---- Write operation ---- */
      if (PageStatus1 == VALID_PAGE)
      {
        /* Page0 receiving data */
        if (PageStatus0 == RECEIVE_DATA)
        {
          return PAGE0;         /* Page0 valid */
        }
        else
        {
          return PAGE1;         /* Page1 valid */
        }
      }
      else if (PageStatus0 == VALID_PAGE)
      {
        /* Page1 receiving data */
        if (PageStatus1 == RECEIVE_DATA)
        {
          return PAGE1;         /* Page1 valid */
        }
        else
        {
          return PAGE0;         /* Page0 valid */
        }
      }
      else
      {
        return NO_VALID_PAGE;   /* No valid Page */
      }

    case READ_FROM_VALID_PAGE:  /* ---- Read operation ---- */
      if (PageStatus0 == VALID_PAGE)
      {
        return PAGE0;           /* Page0 valid */
      }
      else if (PageStatus1 == VALID_PAGE)
      {
        return PAGE1;           /* Page1 valid */
      }
      else
      {
        return NO_VALID_PAGE ;  /* No valid Page */
      }

    default:
      return PAGE0;             /* Page0 valid */
  }
}

/**
  * @brief  Verify if active page is full and Writes variable in EEPROM.
  * @param  VirtAddress: 16 bit virtual address of the variable
  * @param  Data: 16 bit data to be written as variable value
  * @retval Success or error status:
  *           - FLASH_COMPLETE: on success
  *           - PAGE_FULL: if valid page is full
  *           - NO_VALID_PAGE: if no valid page was found
  *           - Flash error code: on write Flash error
  */
static uint16_t EE_VerifyPageFullWriteVariable(uint16_t VirtAddress, uint16_t Data)
{
  FLASH_Status FlashStatus = FLASH_COMPLETE;
  uint16_t ValidPage = PAGE0;
  uint32_t Address = EEPROM_START_ADDRESS, PageEndAddress = EEPROM_START_ADDRESS+PAGE_SIZE;

  /* Get valid Page for write operation */
  ValidPage = EE_FindValidPage(WRITE_IN_VALID_PAGE);

  /* Check if there is no valid page */
  if (ValidPage == NO_VALID_PAGE)
  {
    return  NO_VALID_PAGE;
  }

  /* Get the valid Page start Address */
  Address = (uint32_t)(EEPROM_START_ADDRESS + (uint32_t)(ValidPage * PAGE_SIZE));

  /* Get the valid Page end Address */
  PageEndAddress = (uint32_t)((EEPROM_START_ADDRESS - 2) + (uint32_t)((1 + ValidPage) * PAGE_SIZE));

  /* Check each active page address starting from begining */
  while (Address < PageEndAddress)
  {
    /* Verify if Address and Address+2 contents are 0xFFFFFFFF */
    if ((*(__IO uint32_t*)Address) == 0xFFFFFFFF)
    {
      /* Set variable data */
      FlashStatus = FLASH_ProgramHalfWord(Address, Data);
      /* If program operation was failed, a Flash error code is returned */
      if (FlashStatus != FLASH_COMPLETE)
      {
        return FlashStatus;
      }
      /* Set variable virtual address */
      FlashStatus = FLASH_ProgramHalfWord(Address + 2, VirtAddress);
      /* Return program operation status */
      return FlashStatus;
    }
    else
    {
      /* Next address location */
      Address = Address + 4;
    }
  }

  /* Return PAGE_FULL in case the valid page is full */
  return PAGE_FULL;
}

/**
  * @brief  Transfers last updated variables data from the full Page to
  *   an empty one.
  * @param  VirtAddress: 16 bit virtual address of the variable
  * @param  Data: 16 bit data to be written as variable value
  * @retval Success or error status:
  *           - FLASH_COMPLETE: on success
  *           - PAGE_FULL: if valid page is full
  *           - NO_VALID_PAGE: if no valid page was found
  *           - Flash error code: on write Flash error
  */
static uint16_t EE_PageTransfer(uint16_t VirtAddress, uint16_t Data)
{
  FLASH_Status FlashStatus = FLASH_COMPLETE;
  uint32_t NewPageAddress = EEPROM_START_ADDRESS;
  uint16_t OldPageId=0;
  uint16_t ValidPage = PAGE0, VarIdx = 0;
  uint16_t EepromStatus = 0, ReadStatus = 0;

  /* Get active Page for read operation */
  ValidPage = EE_FindValidPage(READ_FROM_VALID_PAGE);

  if (ValidPage == PAGE1)       /* Page1 valid */
  {
    /* New page address where variable will be moved to */
    NewPageAddress = PAGE0_BASE_ADDRESS;

    /* Old page ID where variable will be taken from */
    OldPageId = PAGE1_ID;
  }
  else if (ValidPage == PAGE0)  /* Page0 valid */
  {
    /* New page address  where variable will be moved to */
    NewPageAddress = PAGE1_BASE_ADDRESS;

    /* Old page ID where variable will be taken from */
    OldPageId = PAGE0_ID;
  }
  else
  {
    return NO_VALID_PAGE;       /* No valid Page */
  }

  /* Set the new Page status to RECEIVE_DATA status */
  FlashStatus = FLASH_ProgramHalfWord(NewPageAddress, RECEIVE_DATA);
  /* If program operation was failed, a Flash error code is returned */
  if (FlashStatus != FLASH_COMPLETE)
  {
    return FlashStatus;
  }

  /* Write the variable passed as parameter in the new active page */
  EepromStatus = EE_VerifyPageFullWriteVariable(VirtAddress, Data);
  /* If program operation was failed, a Flash error code is returned */
  if (EepromStatus != FLASH_COMPLETE)
  {
    return EepromStatus;
  }

  /* Transfer process: transfer variables from old to the new active page */
  for (VarIdx = 0; VarIdx < EEPROM_NumbOfVar; VarIdx++)
  {
    if (EEPROM_VirtAddVarTab[VarIdx] != VirtAddress)  /* Check each variable except the one passed as parameter */
    {
      /* Read the other last variable updates */
      ReadStatus = EE_ReadVariable(EEPROM_VirtAddVarTab[VarIdx], &DataVar);
      /* In case variable corresponding to the virtual address was found */
      if (ReadStatus != 0x1)
      {
        /* Transfer the variable to the new active page */
        EepromStatus = EE_VerifyPageFullWriteVariable(EEPROM_VirtAddVarTab[VarIdx], DataVar);
        /* If program operation was failed, a Flash error code is returned */
        if (EepromStatus != FLASH_COMPLETE)
        {
          return EepromStatus;
        }
      }
    }
  }

  /* Erase the old Page: Set old Page status to ERASED status */
  FlashStatus = FLASH_EraseSector(OldPageId, VOLTAGE_RANGE);
  /* If erase operation was failed, a Flash error code is returned */
  if (FlashStatus != FLASH_COMPLETE)
  {
    return FlashStatus;
  }

  /* Set new Page status to VALID_PAGE status */
  FlashStatus = FLASH_ProgramHalfWord(NewPageAddress, VALID_PAGE);
  /* If program operation was failed, a Flash error code is returned */
  if (FlashStatus != FLASH_COMPLETE)
  {
    return FlashStatus;
  }

  /* Return last operation flash status */
  return FlashStatus;
}

/**
  * @}
  */

/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

使用指南

EEPROM 仿真应用所需的扇区大小和扇区数量可根据系统使用寿命内写入的数据量进行选择。需要特别注意的是STM32F103与STM32F407的Flash扇区大小、扇区数量、扇区地址是不一样的,因此为仿真EEPROM分配扇区时,针对不同的单片机应当有不同的分配扇区策略

以STM32F103VE为例,它的主存储器分为256页,每页大小为2KB,共512KB。由于每页的大小相同的,因此可以直接选取最后两个扇区作为EEPROM仿真应用的扇区

以STM32F407ZG为例,它的主存储器分为12个扇区,其中包含4个16KB扇区、1个64KB扇区和7个128KB 的扇区,共1MB。由于最后的7个扇区容量过大,因此直接选取最后两个扇区是不合适的。如果选取两个16KB扇区作为EEPROM仿真应用的扇区,将破坏正常程序烧录在Flash中的结构(从第一个扇区的首地址开始烧写)。因此最好设置一个BootLoader程序(占用前两个扇区,共32K空间),然后通过此程序跳转到用户程序。用户程序从第五个扇区开始烧录。这样可以将第三与第四扇区作为EEPROM仿真应用的扇区

应用层扩展

源码

应用层的StorableData数组以float类型的数据保存变量的值,因此需要两个16位的空间在仿真EEPROM中储存。通过定义一个联合体类型,可以方便的实现float类型的数据与16位字节数组的相互转换。

typedef union
{
	float toFloat;
	uint16_t toUint16Array[2];
} EepDataUnion;

要使用一个完善的“可存储类型”的变量,还需要指定在EEPROM中的存储位置默认值索引值等其他信息。通过定义一个结构体类型来封装可存储类型的变量:

typedef struct
{
	char name[6];
	EepDataUnion value;
	const EepDataUnion defaultValue;
	const uint16_t EEP_Index;
	const uint16_t GLO_Index;
} EepromData_typedef;

EepromData_typedef结构体类型的各成员简介如下:

  • name为变量的名称,不影响存储与读写的功能,可以根据需要调整字符串存储空间大小
  • value为变量的值,这是一个联合体变量,可以通过.toFloat获取浮点数表示的值,通过.toUint16Array获取16位数组表示的值
  • defaultValue为变量的默认值,数据类型与value相同,它记录了这个变量的默认值。
  • EEP_Index为此变量在EEPROM中存储的位置,在连续存储的情况下,它一般设置为GLO_Index的两倍
  • GLO_Index为此变量的全局序列号,如果是在一个数组中,它应当设置为在数组中的索引号

为了增加数据存储安全性能,将全局数组变量StorableData[]的第一个成员设置为校验数据,它主要有以下几个作用:

  • 检测是否首次烧录(启用仿真EEPROM)程序,如果是首次烧录程序(EEPROM中没有保存StorableData成员的值)则执行初始化,将StorableData成员的默认值保存在EEPROM中的对应位置。
  • 记录MCU的启动次数。完成StorableData成员在EEPROM中的初始化之后,每次启动MCU都会将此值加1。因此通过读取此值可以判断MCU的开机次数,进而推断电路板的工作时长、使用寿命等信息。

头文件

#ifndef __GLOBALVARIATE_H__
#define __GLOBALVARIATE_H__

#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"

typedef union
{
	float toFloat;
	uint16_t toUint16Array[2];
} EepDataUnion;

typedef struct
{
	char name[6];
	EepDataUnion value;
	EepDataUnion defaultValue;
	uint16_t EEP_Index;
	uint16_t GLO_Index;
} EepromData_typedef;

#define EEPROM_CKECKCODE_COUNT 		100000.0f

extern uint16_t STORABLE_DATA_COUNT;

extern volatile EepromData_typedef StorableData[];

void StorableData_InitAll();

void StorableData_SaveDefaultValue(const EepromData_typedef *EEPROM_Data_Struct);
void StorableData_SaveAllDefaultValue();

void StorableData_SaveValue(const EepromData_typedef *EEPROM_Data_Struct);
void StorableData_SaveAllValue();

void StorableData_LoadValueFromEEPROM(EepromData_typedef *EEPROM_Data_Struct);
void StorableData_LoadAllValueFromEEPROM();

void StorableData_ResetValue(EepromData_typedef *EEPROM_Data_Struct);
void StorableData_ResetAllValue();

void StorableData_SetValue_Float(uint16_t index, float value);
void StorableData_SetValue_16BitArray(uint16_t index, uint16_t *array);

float StorableData_GetValue(uint16_t index);

#endif

源文件

#include "globalVariate.h"
#include "eeprom.h"

/**
 * STORABLE_DATA_COUNT的值必须等于EepromData_typedef数组数量,
 * 因此它将在void StorableData_InitAll()中被计算出来,以确保数值准确
 */

uint16_t STORABLE_DATA_COUNT = 0;

volatile EepromData_typedef StorableData[] =
{
	{ {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = EEPROM_CKECKCODE_COUNT }, 0, 0 },

	{ {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 2, 1 },		//通道1:Iout1-4mA 电压
	{ {""}, .value = { .toFloat = 500 }, .defaultValue = { .toFloat = 0 }, 4, 2 },		//通道1:Iout1-20mA对应电压
	{ {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 6, 3 },		//通道1:传感器类型
	{ {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 8, 4 },		//通道1:输出信号类型

	{ {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 10, 5 },		//通道2:Iout2-4mA对应电压
	{ {""}, .value = { .toFloat = 500 }, .defaultValue = { .toFloat = 0 }, 12, 6 },		//通道2:Iout2-20mA对应电压
	{ {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 14, 7 },		//通道2:传感器类型
	{ {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 16, 8 },		//通道2:输出信号类型
};


/**
 * @brief 初始化StorableData_Struct数组(应当在程序运行进入主循环之前调用)
 * 	主要通过第一个StorableData_Struct[0]是否等于默认值(100,000)来判断当前MCU是否为首次烧录。
 * 	如果当前MCU为首次烧录,则将默认值先保存进EEPROM,再加载到StorableData_Struct数组。
 * 	每次开机运行调用本函数时,都会将StorableData_Struct[0].value.toFloat的值加一。
 * 	通过读取StorableData_Struct[0].value.toFloat的值(减去100,000),亦可以判断MCU的累计开机次数。
 */
void StorableData_InitAll()
{

	STORABLE_DATA_COUNT = sizeof(StorableData) / sizeof(*StorableData);

	StorableData_LoadAllValueFromEEPROM();

	///首次烧录
	if(StorableData[0].value.toFloat < EEPROM_CKECKCODE_COUNT)
	{
		StorableData_SaveAllDefaultValue();
		StorableData_LoadAllValueFromEEPROM();
	}
	else
	{
		StorableData[0].value.toFloat += 1.0;
		StorableData_SaveValue((const EepromData_typedef*) &StorableData[0]);
	}
}


/**
 * @brief 将指定的StorableData默认值存储在EEPROM中
 */
void StorableData_SaveDefaultValue(const EepromData_typedef *EEPROM_Data_Struct) {
	FLASH_Unlock();
	EE_Init();

	EE_WriteVariable(EEPROM_VirtAddVarTab[EEPROM_Data_Struct->EEP_Index],EEPROM_Data_Struct->defaultValue.toUint16Array[0]);
	EE_WriteVariable(EEPROM_VirtAddVarTab[EEPROM_Data_Struct->EEP_Index+1],EEPROM_Data_Struct->defaultValue.toUint16Array[1]);

	FLASH_Lock();
}

/**
 * @brief 将全部的StorableData默认值存储在EEPROM中
 */
void StorableData_SaveAllDefaultValue() 
{
	FLASH_Unlock();
	EE_Init();

	for (uint16_t i = 0; i < STORABLE_DATA_COUNT; i++)
	{
		EE_WriteVariable(EEPROM_VirtAddVarTab[StorableData[i].EEP_Index],StorableData[i].defaultValue.toUint16Array[0]);
		EE_WriteVariable(EEPROM_VirtAddVarTab[StorableData[i].EEP_Index+1],StorableData[i].defaultValue.toUint16Array[1]);
	}

	FLASH_Lock();
}


/**
 * @brief 将指定的StorableData实时值存储在EEPROM中
 */
void StorableData_SaveValue(const EepromData_typedef *EEPROM_Data_Struct)
{
	FLASH_Unlock();
	EE_Init();

	EE_WriteVariable(EEPROM_VirtAddVarTab[EEPROM_Data_Struct->EEP_Index],EEPROM_Data_Struct->value.toUint16Array[0]);
	EE_WriteVariable(EEPROM_VirtAddVarTab[EEPROM_Data_Struct->EEP_Index+1],EEPROM_Data_Struct->value.toUint16Array[1]);

	FLASH_Lock();
}

/**
 * @brief 将全部的StorableData实时值存储在EEPROM中
 */
void StorableData_SaveAllValue()
{
	FLASH_Unlock();
	EE_Init();
	uint16_t count = sizeof(StorableData) / sizeof(*StorableData);
	for (uint16_t i = 0; i < count; i++)
	{
		EE_WriteVariable(EEPROM_VirtAddVarTab[StorableData[i].EEP_Index],StorableData[i].value.toUint16Array[0]);
		EE_WriteVariable(EEPROM_VirtAddVarTab[StorableData[i].EEP_Index+1],StorableData[i].value.toUint16Array[1]);
	}
	FLASH_Lock();
}

/**
 * @brief 将EEPROM中对应的值赋予指定的StorableData实时值
 */
void StorableData_LoadValueFromEEPROM(EepromData_typedef *EEPROM_Data_Struct)
{
	FLASH_Unlock();
	EE_Init();
	EE_ReadVariable(EEPROM_VirtAddVarTab[EEPROM_Data_Struct->EEP_Index],&EEPROM_Data_Struct->value.toUint16Array[0]);
	EE_ReadVariable(EEPROM_VirtAddVarTab[EEPROM_Data_Struct->EEP_Index+1],&EEPROM_Data_Struct->value.toUint16Array[1]);
	FLASH_Lock();
}

/**
 * @brief 将EEPROM中全部的值赋予全部的StorableData实时值
 */
void StorableData_LoadAllValueFromEEPROM()
{
	FLASH_Unlock();
	EE_Init();

	uint16_t count = sizeof(StorableData) / sizeof(*StorableData);
	for (uint16_t i = 0; i < count; i++)
	{
		EE_ReadVariable(EEPROM_VirtAddVarTab[StorableData[i].EEP_Index],(uint16_t *) &StorableData[i].value.toUint16Array[0]);
		EE_ReadVariable(EEPROM_VirtAddVarTab[StorableData[i].EEP_Index+1],(uint16_t *) &StorableData[i].value.toUint16Array[1]);
	}

	FLASH_Lock();
}

/**
 * @brief 将指定的StorableData实时值重置为默认值
 */
void StorableData_ResetValue(EepromData_typedef *EEPROM_Data_Struct)
{
	EEPROM_Data_Struct->value.toUint16Array[0] = EEPROM_Data_Struct->defaultValue.toUint16Array[0];
	EEPROM_Data_Struct->value.toUint16Array[1] = EEPROM_Data_Struct->defaultValue.toUint16Array[1];
}

/**
 * @brief 将全部的StorableData实时值重置为默认值
 */
void StorableData_ResetAllValue()
{
	uint16_t count = sizeof(StorableData) / sizeof(*StorableData);
	for (uint16_t i = 0; i < count; i++) {
		StorableData[i].value.toUint16Array[0] = StorableData[i].defaultValue.toUint16Array[0];
		StorableData[i].value.toUint16Array[1] = StorableData[i].defaultValue.toUint16Array[1];
	}
}


void StorableData_SetValue_Float(uint16_t index, float value)
{
	StorableData[index].value.toFloat = value;
}


void StorableData_SetValue_16BitArray(uint16_t index, uint16_t *array)
{
	StorableData[index].value.toUint16Array[0] = array[0];
	StorableData[index].value.toUint16Array[1] = array[1];
}


float StorableData_GetValue(uint16_t index)
{
	return StorableData[index].value.toFloat;
}

使用指南

  • 定义StorableData[]数组,正确设置数组成员的值(注意最大数组成员数量不能超过64,否则需要修改EEPROM库中的虚拟地址分配表)。示例如下:
volatile EepromData_typedef StorableData[] =
{
	{ {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = EEPROM_CKECKCODE_COUNT }, 0, 0 },

	{ {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 2, 1 },		//通道1:Iout1-4mA 电压
	{ {""}, .value = { .toFloat = 500 }, .defaultValue = { .toFloat = 0 }, 4, 2 },		//通道1:Iout1-20mA对应电压
	{ {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 6, 3 },		//通道1:传感器类型
	{ {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 8, 4 },		//通道1:输出信号类型

	{ {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 10, 5 },		//通道2:Iout2-4mA对应电压
	{ {""}, .value = { .toFloat = 500 }, .defaultValue = { .toFloat = 0 }, 12, 6 },		//通道2:Iout2-20mA对应电压
	{ {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 14, 7 },		//通道2:传感器类型
	{ {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 16, 8 },		//通道2:输出信号类型
};
  • 在程序启动的时候(一般在外设配置完成后)初始化应用层扩展库。应用层扩展库初始化的时候会自动先初始化EEPROM仿真库,并判断是否需要重置StorableData成员为默认值(一般在首次烧录程序的时候需要重置数据)。同时,用以表示数组长度的变量STORABLE_DATA_COUNT将被自动计算与更新。
	StorableData_InitAll();
  • 根据项目的需要对StorableData成员进行读取、写入、保存、重置等操作。
    • 读取:StorableData_GetValue(1)
    • 写入:StorableData_SetValue_Float(1, 919.0)
    • 保存:StorableData_SaveValue((const EepromData_typedef *)&StorableData[1])
    • 重置:StorableData_ResetValue(&StorableData[1])
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全能骑士涛锅锅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值