模拟EEPROM功能
EEPROM(带电可擦写可编程读写存储器)是用户可更改的只读存储器(ROM),其可通过高于普通电压的作用来擦除和重编程(重写)。
模拟原理
本系统基于Linux,自带文件系统,带均衡擦写算法。将保存的数据写入到 NorFlash(不低于10万次擦写次数,注意不是Nandfalsh,NandFlash 出现坏块后就是各种风险了)。
FlyThings OS内部预留了 /data 分区,用于用户数据,为了方便熟悉单片机操作的用户使用,我们在/data分区下创建一个文件来模拟一个EEPROM空间。 (/data分区的大小为1M或几百KB不等,依具体系统版本而定)
是不是感觉特别像国内炼丹炉里面出来的STC大法的单片机。
使用场景
掉电保存数据。
实现步骤
首先在项目的 src 目录下创建一个头文件。
选中项目下的 src ,点击鼠标右键,在弹出的上下文菜单中选择 头文件 选项, 然后命名为 vireeprom.h, 点击完成。
将以下代码完整拷贝到刚才添加的头文件中. (刚才创建头文件时,可能会自动添加一些内容,将这些内容删除)
这些代码实现了EEPROM的模拟功能。#ifndef JNI_VIREEPROM_H_ #define JNI_VIREEPROM_H_ #include <stdio.h> #include <string.h> #include <unistd.h> /** * 模拟EEPROM的存储大小,字节为单位,建议不宜过大 */ #define EEPROM_SIZE 1024 /** * 实际保存为文件 /data/eeprom.eep */ #define EEPROM_FILE "/data/eeprom.eep" class VirEEPROM { public: VirEEPROM() { memset(buff_, 0, sizeof(buff_)); file_ = fopen(EEPROM_FILE, "rb+"); if (file_) { fread(buff_, 1, EEPROM_SIZE, file_); fseek(file_, 0, SEEK_END); int f_size = ftell(file_); //调整文件到合适大小 if (f_size != sizeof(buff_)) { ftruncate(fileno(file_), sizeof(buff_)); fseek(file_, 0, SEEK_SET); fwrite(buff_, 1, sizeof(buff_), file_); fflush(file_); sync(); } } else { file_ = fopen(EEPROM_FILE, "wb+"); //调整文件到合适大小 ftruncate(fileno(file_), sizeof(buff_)); } } virtual ~VirEEPROM() { if (file_) { fflush(file_); fclose(file_); sync(); } } /** * 返回值:小于0 是失败的,大于0是实际写入的字节数 * 参数:value需要保存的数据指针,可以是结构体指针,char*,int*……,size是要保存的数据大小 * 使用举例: * const char buff[]="12345678"; * VIREEPROM->WriteEEPROM(0,buff,sizeof(buff); */ int Write(int addr, const void* value, int size) { if (file_ == NULL) { return -1; } if ((addr >= EEPROM_SIZE) || ((addr + size) > EEPROM_SIZE)) { //超出大小 return -2; } memcpy(buff_ + addr, value, size); if (0 != fseek(file_, addr, SEEK_SET)) { return -3; } int n = fwrite((char*)value, 1, size, file_); fflush(file_); sync(); return n; } /** * 返回值:小于0 是失败的,大于0是实际读取到的字节数 * 参数:value需要读取的数据指针,可以是结构体指针,char*,int*……,size是要读取的数据大小 * 应用举例: * char buff[9]; * VIREEPROM->ReadEEPROM(0,buff,sizeof(buff); */ int Read(int addr,void* value,int size) { if (file_ == NULL) { return -1; } if ((addr >= EEPROM_SIZE) || ((addr + size) > EEPROM_SIZE)) { //超出大小 return -2; } memcpy(value, buff_ + addr, size); return size; } /** * 返回值: * 0 成功 * 小于0 失败 */ int Erase() { if (file_ == NULL) { return -1; } if (0 != fseek(file_, 0, SEEK_SET)) { return -2; } memset(buff_, 0, sizeof(buff_)); if (sizeof(buff_) != fwrite(buff_, 1, sizeof(buff_), file_)) { return -3; } fflush(file_); sync(); return 0; } static VirEEPROM* getInstance() { static VirEEPROM singleton; return &singleton; } private: unsigned char buff_[EEPROM_SIZE]; FILE* file_; }; #define VIREEPROM VirEEPROM::getInstance() #endif /* JNI_VIREEPROM_H_ */
至此准备工作已经完成,我们再写一些例子测试是否正常。
打开mainLogic.cc
源文件,先在文件顶部引用刚才的头文件。#include "vireeprom.h"
测试代码
static void onUI_init(){ //把value数组,从地址0开始,依次写入 char value[4] = {1, 2, 3, 4}; VIREEPROM->Write(0, value, sizeof(value)); //从0地址开始读,依次读取4个字节 ,读取的内容保存到buf中 char buf[4] = {0}; VIREEPROM->Read(0, buf, sizeof(buf)); //输出日志 LOGD("读出的数据: %02x, %02x, %02x, %02x", buf[0], buf[1], buf[2], buf[3]); //将eeprom全部清空为0 VIREEPROM->Erase(); }