织梦搭建商城网站,高端网站建设深圳,百度网站提交收录,如何在自己网站开发互动视频目录 1. FLASH和EEPROM读写数据的对比 2. FLASH模拟EEPROM的原理 3. FLASH模拟EEPROM的优点 4. 实战项目工程代码
1. FLASH和EEPROM读写数据的对比
1.1 擦除操作
EEPROM通常支持按单字节擦除和写入#xff0c;这一特性使其非常适合需要频繁更新小量数据的应…目录 1. FLASH和EEPROM读写数据的对比 2. FLASH模拟EEPROM的原理 3. FLASH模拟EEPROM的优点 4. 实战项目工程代码
1. FLASH和EEPROM读写数据的对比
1.1 擦除操作
EEPROM通常支持按单字节擦除和写入这一特性使其非常适合需要频繁更新小量数据的应用场景。Flash存储器通常是按块、扇区、页擦除的这意味着即使只更改一个字节的数据也需要擦除整个扇区或页。
1.2 写入速度
EEPROM的写入速度通常比Flash快尤其是在擦除和重新编程单个字节时。Flash的写入速度较慢特别是在擦除操作期间因为它涉及到更大的存储区域。
1.3 写入次数限制
EEPROM和Flash都有写入次数限制但EEPROM通常设计为能够承受更多的擦写循环通常达到百万次级别。Flash存储器的擦写次数限制较低通常在10,000到100,000次之间;对于频繁擦写数据的操作易造成flash损坏。
1.4 数据保持能力
EEPROM 的数据保持时间通常较长一般可达到 20 年以上这使得它非常适合长期保存关键数据的应用场景。FLASH 的数据保持时间通常在 10 年左右虽然也能满足大多数应用的需求但相较于 EEPROM 仍略逊一筹。 基本特性对比
特性FLASHEEPROM存储单元结构NAND共享位线高密度/ NOR独立位线高速双晶体管结构控制栅 存储栅支持字节操作擦除单位Block块擦除Byte字节级擦除写入速度0.2-10ms/page1-10ms/byte擦除时间1-300ms/block (NOR Flash)字节擦除与写入同时完成无需单独擦除步骤擦写次数10K-100K次100K-1M次存储密度高适合大容量存储低适合小数据存储功耗较高需要高压擦除较低典型应用场景操作系统存储、文件系统、代码 / 数据批量存储配置参数存储、少量数据频繁读写 2. FLASH模拟EEPROM的原理
2.1 划分区域
单片机的 FLASH 通常由多个页或扇区组成在写入数据前必须按页或扇区进行擦除操作可将 FLASH 按页或扇区划分为多个区域其中一个区域用于存储程序代码其他区域则可用于数据存储从而实现模拟 EEPROM 的功能;
2.2 擦除和写数据
在首次使用或存储空间不足时对模拟 EEPROM 的 FLASH 区域进行整体擦除并记录 FLASH 剩余空间大小其初始值等于分配给模拟 EEPROM 的总空间大小通过偏移写地址写入新的数据每次写入后FLASH 剩余空间大小相应减去写入数据的长度当 FLASH 空间即将写满或剩余空间不足时重复执行步骤 1 和步骤 2即先擦除整个区域再重新写入数据
2.3 磨损均衡技术
为了延长 FLASH 的使用寿命通常会采用磨损均衡技术将擦写操作均匀分布到各个块或扇区避免某些区域过早损坏。常见的磨损均衡算法有简单的顺序循环、基于计数的动态分配以及更复杂的基于使用频率的智能分配等。
2.4 数据结构设计
为了实现高效的数据管理通常会设计特定的数据结构如使用索引表记录每个数据项的存储位置和状态。在写入新数据时可以采用追加写入的方式而不是直接覆盖原有数据从而提高写入效率并减少擦除次数。 2.5 FLASH读写操作示意图 3. FLASH模拟EEPROM的优点
降低设计成本EEPROM通常提供较小的存储容量但单位容量的成本可能较高。Flash存储器通常提供更大的存储容量且单位容量的成本较低;提升写数据速度:FLASH模拟EEPROM写数据前是先整体擦除区域再对同一个扇区或页分段写入数据写入过程中不再涉及擦除FLASH操作提升了写数据的速度提高写数据次数:FLASH擦写数据是有次数限制的单个扇区或页通过偏移地址可多次写数据后再擦除 FLASH极大减少了FLASH擦除次数提高了可写数据的次数提高集成度使用单片机的内置Flash减少了外部组件的数量简化了电路设计和布局
核心优势对比
优势维度传统EEPROMFLASH模拟方案硬件成本需要独立芯片复用现有FLASH存储容量通常512KB可扩展至MB级别系统集成度需要额外接口电路片上集成可移植性依赖特定硬件纯软件实现功耗表现静态功耗较高静态功耗趋近于零 4. 实战项目工程代码
可使用的flash 软件模拟EEPROM lib功能库 https://download.csdn.net/download/weixin_43176196/90797265
flash 软件模拟EEPROM 项目工程程序 https://download.csdn.net/download/weixin_43176196/90789413 需将功能模块 eepromSoft 添加到工程下并实现 flash读写操作.具体应用如下
4.1 通用接口定义 eepromSoft.h
// eeprom 可分配使用的个数, 最大不超过 5
#define EPROM_SOFT_NUM (5 )// 分配页缓冲区大小, 该数值必须为使用 pageSize 最大的一个 EEPROM_SOFT_INDEX 的 pageSize
#define EPROM_BUF_DATA_SIZE (128 * 2)typedef int32_t EEPROM_SOFT_INDEX; // 索引类型// eeprom 错误码
typedef enum{EPROM_ERR_NORMAL 0, // 正常EPROM_ERR_UNDEFINE, // 未知错误可能为传入的参数无效EPROM_ERR_MEMBUF, // 数据缓冲区设置出错EPROM_ERR_READ, // 读失败EPROM_ERR_WRITE, // 写错误EPROM_ERR_ERASE, // 擦除扇区错误EPROM_ERR_OVER_DATA, // 数据过大会超出页大小EPROM_ERR_PAGE_SIZE, // 分配的页大小不正确EPROM_ERR_ADDR, // 分配的 falsh 的 adrrStart 或 adrrEnd 不正确EPROM_ERR_FUNC, // 设置的函数指针无效EPROM_ERR_SOFT_NUM, // 分配的个数不足需设大 EPROM_SOFT_NUMEPROM_ERR_NUM_SET, // EPROM_SOFT_NUM 设置不符合要求EPROM_ERR_LOCK, // 加锁失败EPROM_ERR_INDEX, // 未知索引号EPROM_ERR_NUM
}EPROM_ERR;/* eeprom 基准信息数据结构 */
typedef struct{uint32_t adrrStart; // 分配的 flash 扇区起始地址(此地址必须为4的倍数且不能为0)uint32_t adrrEnd; // 分配的 flash 扇区结束地址(此地址必须为4的倍数)// 设置的页大小(该数值必须是 128 的倍数)进行 falsh 的页分配单位Byte // 页大小并不代码实际存放数据的最大长度每页里面会保存基准信息uint32_t pageSize; /* flash 读函数指针,// flashAddr,要读取数据的flash地址;// buf, 读取数据缓冲的指针// readLen, 要读取数据的长度(单位:字节)// 返回, 实际读取到的数据长度 */uint32_t (*fRead)(uint32_t flashAddr, uint8_t *buf, uint32_t readLen);/* flash 写函数指针(不带擦除扇区写入数据),// flashAddr,开始写入数据的flash地址;// data, 要写入的数据指针// len, 要写入的数据长度(单位:字节)// 返回, 0, 写入成功// 1, 写入失败*/uint8_t (*fWrite)(uint32_t flashAddr,const uint8_t *data, uint32_t len);/* flash 擦除函数指针,// flashAddr,要擦除flash数据的起始地址;// len, 要擦除数据的数据长度(单位:字节)// 返回, 0, 成功// 1, 失败*/uint8_t (*fErase)(uint32_t flashAddr, uint32_t len);}EPROM_SOFT_INFO;// 声明外部其他文件定义的 crc32校验函数 若只模拟一个eeprom 可进行简单求和校验 .
extern uint32_t AlgorithCrc32(const uint8_t* data, uint32_t len); /*!* * param[in] timeOutMs 毫秒超时时间* param[out] none* return 1 加锁成功* return 0 加锁失败* * brief 声明外部其他文件定义的 加锁保护机制.* note . 主要用于 EPROM_BUF_DATA_SIZE 分配的数据缓冲区资源保护;* */
extern uint8_t EepromSoftLock(uint32_t timeOutMs);extern void EepromSoftUnLock(void); // 释放锁/*!* * param[in] num eeprom 可模拟的个数取值 1 - 10;* param[in] pageBuf : 要分配的页缓冲区指针;* param[in] pageSize : 页缓冲区的大小(必须为 128的倍数单位字节);* param[out] none* return EPROM_ERR 错误码* * brief 模拟eeprom 公共资源分配设置* note . 必须在 EepromSoftInit() 函数使用前调用该函数执行一次;* */
EPROM_ERR EepromSoftSet(uint8_t num, uint8_t* pageBuf, uint32_t pageSize);/*!* * param[in] info : 要配置的基准信息结构指针* param[out] errCode EPROM_ERR 返回指针存放返回的错误码* return 0的数值 eeprom 索引号* return 其他值: 出错* * brief 初始化基准信息若成功就返回对应 eeprom 的索引号.* note . 该操作会检测分配的地址是否正确并获取上次写入有效数据的基准信息;* . 若未获取到有效基准信息就擦除扇区从起始地址开始读/写数据;* */
EEPROM_SOFT_INDEX EepromSoftInit(EPROM_SOFT_INFO* info, EPROM_ERR* errCode);/*!* * param[in] index eeprom索引号* param[in] buf 数据缓冲区存放读取到的数据* param[in] readLen 要读取的数据长度* param[out] errCode EPROM_ERR 返回指针存放返回的错误码* return 实际读取到的数据长度* * brief 读数据* note . 从上次成功写入数据的地址读取数据;* */
uint32_t EepromSoftRead(EEPROM_SOFT_INDEX index, uint8_t *buf, uint32_t readLen, EPROM_ERR* errCode);/*!* * param[in] index eeprom索引号* param[in] data 要写入的数据指针* param[in] len要写入的数据长度* param[out] none* return PROM_ERR 错误码* * brief 写入数据* note . 写数据之前会将上次成功写入的地址进行偏移若数据成功写入数据就记录该地址;* */
EPROM_ERR EepromSoftWrite(EEPROM_SOFT_INDEX index, uint8_t *data, uint32_t len);
使用方法 在其他文件实现函数 AlgorithCrc32()、 EepromSoftLock() 、 EepromSoftUnLock() EepromSoftSet() 分配模拟 eeprom的个数页缓冲区(多个eeprom的公共缓冲区) 该函数必须在 EepromSoftInit() 使用之前调用一次 EepromSoftInit() 初始化 eeprom 的基准信息初始化成功会返回 EEPROM_SOFT_INDEX 索引号 ; EepromSoftRead()、 EepromSoftWrite() 进行数据读、写操作; 4.2 接口应用
/* USER CODE BEGIN 4 */// 定义 crc32校验
uint32_t AlgorithCrc32(const uint8_t* data, uint32_t len)
{uint32_t val 0;for(int i 0; i len; i){val data[i];}return val;
}// 定义保护锁机制
uint8_t s_LockStatus 0;
uint8_t EepromSoftLock(uint32_t timeOutMs)
{s_LockStatus 1;return s_LockStatus;
}// 释放锁
void EepromSoftUnLock(void)
{s_LockStatus 0;
}// 定义模拟 eeprom 缓冲区
static uint8_t s_EepromBuf[EPROM_BUF_DATA_SIZE];EEPROM_SOFT_INDEX s_EepronIndex1 -1, s_EepronIndex2 -1; // 定义索引变量void TestFlashHandle(void)
{unsigned char buf[20 8] {0x11, 0x22, 0x33, 0x44, 0x55};EPROM_ERR errCode 0;uint32_t len 0;EPROM_SOFT_INFO eepromInfo;// 设置 eeprom 公共资源分配errCode EepromSoftSet(EPROM_SOFT_NUM, s_EepromBuf, EPROM_BUF_DATA_SIZE);// 模拟 第一个 eepromeepromInfo.adrrStart FLASH_ADDR_SECTOR_9; // 设置模拟eeprom 的扇区起始地址eepromInfo.adrrEnd FLASH_ADDR_SECTOR_10; // 设置模拟eeprom 的扇区结束地址eepromInfo.pageSize 128; // 每次写数据操作的flash大小(最小128)eepromInfo.fErase FlashHardErase;eepromInfo.fRead FlashHardRead;eepromInfo.fWrite FlashWriteNoErase;s_EepronIndex1 EepromSoftInit(eepromInfo, errCode); // 初始化基准信息if(s_EepronIndex1 0) {return ;}// 写数据buf[16] 0xAA;buf[17] 0xBB;buf[18] 0xCC;buf[19] 0xDD;errCode EepromSoftWrite(s_EepronIndex1, buf, 20);// 读数据memset(buf, 0, 20);len EepromSoftRead(s_EepronIndex1, buf, 20, errCode);// 模拟 第二个 eepromeepromInfo.adrrStart FLASH_ADDR_SECTOR_10; // 设置模拟eeprom 的扇区起始地址eepromInfo.adrrEnd FLASH_ADDR_SECTOR_11; // 设置模拟eeprom 的扇区结束地址eepromInfo.pageSize EPROM_BUF_DATA_SIZE; // 每次写数据操作的flash大小(最小128)eepromInfo.fErase FlashHardErase;eepromInfo.fRead FlashHardRead;eepromInfo.fWrite FlashWriteNoErase;s_EepronIndex2 EepromSoftInit(eepromInfo, errCode); // 初始化基准信息if(s_EepronIndex2 0) {return ;}// 写数据buf[16] 0xA1;buf[17] 0xB1;buf[18] 0xC1;buf[19] 0xD1;errCode EepromSoftWrite(s_EepronIndex2, buf, 20);// 读数据memset(buf, 0, 20);len EepromSoftRead(s_EepronIndex2, buf, 20, errCode);// 再读取 s_EepronIndex1 观察是否有变化memset(buf, 0, 20);len EepromSoftRead(s_EepronIndex1, buf, 20, errCode);}