flash_emulateEEprom
1.0.0
使用flash模擬eeprom的使用體驗
void ee_flashInit() :格式化flash,只有格式化後的flash才能使用後面兩個api函數。ee_uint8 ee_readDataFromFlash() :讀數據ee_uint8 ee_writeDataToFlash(); :寫數據variableLists ,通過此表讀寫flash中的數據首先進入頭文件,根據註釋將四個宏填寫完整
SECTOR_SIZE : 當前flash一個扇區(flash的最小存儲單元)容量大小ee_flashWrite : flash寫操作驅動函數名ee_flashRead : flash讀操作驅動函數名ee_flashEraseASector : flash擦除一個扇區(flash的最小存儲單元)驅動函數名可填寫的宏(不填不影響函數運行)
BLOCk_SECTOR_NUM :當前flash一個塊有多少個扇區兩個特殊的宏:
SECTORS(x) :返回x扇區的總大小BLOCKS(x) :返回x塊的總大小,要使用此宏,你需要事先填寫宏BLOCk_SECTOR_NUM上面兩個宏,主要用於ee_flashInit()函數傳參方便定位flash地址使用。
實例:
// 首先在flash_MemMang.h枚举类型中添加数据名,用于管理数据
typedef enum
{
// 用户将变量名添加到下面
G_MYSENSORDATA ,
G_FLOAT ,
// DATA_NUM用于标识flash中一共存了多少个数据(不允许删改)
DATA_NUM ,
} variableLists ;
//------------------主函数-------------
/* 创建flash管理句柄 */
ee_flash_t g_fm ;
/* 想要存入flash中的变量 */
int g_mySensorData = 16 ;
float g_float = 3.14 ;
char g_txt [ 20 ] = "change data test" ;
int main ( void )
{
int dataTmp = 0 ;
float ftmp = 0 ;
char tt [ 20 ];
/* 格式化传入地址的格式 */
ee_flashInit ( & g_fm , /* 管理句柄 */
SECTORS ( 0 ), /* 索引区起始地址 */
SECTORS ( 2 ), /* 交换索引区起始地址 */
2 , /* 总索引区大小(单位:扇区) */
1 , /* 索引区大小(详见README图例,indexRegionSize) */
SECTORS ( 4 ), /* 数据区起始地址 */
SECTORS ( 5 ), /* 交换数据区起始地址 */
1 ); /* 数据区大小(单位:扇区) */
/* 数据写入顺序错误,写入失败 */
ee_writeDataToFlash ( & g_fm , & g_float , sizeof ( g_float ), G_FLOAT );
ee_writeDataToFlash ( & g_fm , & g_mySensorData , sizeof ( g_mySensorData ), G_MYSENSORDATA );
/* 正确将数据写入flash */
ee_writeDataToFlash ( & g_fm , & g_mySensorData , sizeof ( g_mySensorData ), G_MYSENSORDATA );
ee_writeDataToFlash ( & g_fm , & g_float , sizeof ( g_float ), G_FLOAT );
/* 将数据读出 */
ee_readDataFromFlash ( & g_fm , & dataTmp , G_MYSENSORDATA );
ee_readDataFromFlash ( & g_fm , & ftmp , G_FLOAT );
/* 将G_FLOAT管理的数据改成g_txt */
ee_writeDataToFlash ( & g_fm , g_txt , strlen ( g_txt ) + 1 , G_FLOAT );
/* 再读取一次数据 */
dataTmp = 0 ;
ee_readDataFromFlash ( & g_fm , & dataTmp , G_MYSENSORDATA );
ee_readDataFromFlash ( & g_fm , & tt , G_FLOAT );
}flash只能將1變成0,只能通過擦除一整個扇區(flash的最小存儲結構)才能將0變成1,因此對於一個被寫過的地址,如果再次對其進行寫入,必定會導致已經變成0的位無法變成1,從而導致數據無效。
本程序的思路就是將想要改寫的數據寫入後面沒被寫過的區域,之前寫入的數據就被作廢,將最新寫入的數據當作有效的。等到整個區域被寫滿,將有效數據搬移另外一個區域,再將當前區域一塊全部擦除。
程序實現的flash的內部結構圖:

當執行void ee_flashInit()格式化flash後,格式化後的flash佈局如上圖所示。
總索引區:包含兩個區域,索引區和重寫區
索引區:用於保存每個數據的索引結構,每個索引結構的地址位置是固定的,如1號數據的地址在0x00,那麼2號數據索引的地址就在0x08,用戶可指定索引區的大小,大小指定可以參考後面公式:索引區可存儲數據的個數= 索引區總字節數/ 8
/* 数据索引结构 */
typedef struct
{
/* 当前数据状态 */
ee_uint16 dataStatus ;
/* 当前数据大小 */
ee_uint16 dataSize ;
/* 当前数据在数据区的地址(相对于dataStartAddr的偏移地址) */
ee_uint16 dataAddr ;
/* 当前数据被重写的地址(相对于overwriteAddr的偏移地址),默认为0xFFFF */
ee_uint16 dataOverwriteAddr ;
} ee_dataIndex ;重寫區:當數據索引區的數據被重寫後,重寫後的索引結構保存在當前區域
重寫計數區:由程序自動分配,用戶不需要在意,此區域記錄當前重寫區一共寫入了多少次,用於定位重寫區的空閒位置。
數據區:保存我們存入flash中實際的值,每個值的大小、讀寫偏移地址由索引區的索引結構管理。
交換區:當活動區滿了之後,將活動區的所有有效數據效索引搬運到此區域,當做活動區域,同時清空之前的活動區,當作下一次活動區域使用
狀態管理:
狀態管理用於處理單片機出現各種的異常現象,如單片機在操作flash時發生了斷電情況。