DIY USB 电流表(9):Flash 模拟 EEPROM 存储累计电量
在前一篇 《DIY USB 电流表(8):检测按键和绘制功率曲线》 中,整个 USB 电流表的固件开发已经进入尾声,目前我们已经完成了电压电流数据显示、功率计算、多页面切换、历史功率曲线绘制等功能.
为了更好地保持数据,在 USB 电流表重新上电的情况下,也可以恢复之前测量的数据,例如在测试充电宝容量时,中间会断开并重新连上负载,这个时候我们需要将之前记录的数据保存下来,继续累计负载消耗的电量。
但是在之前的原理图设计中,整个电路并没有添加 EEPROM,CH32V003 也没有自带 EEPROM,这时我们可以使用 CH32V003 的代码存储区域来模拟 EEPROM 保存数据,这次就来完成这个功能吧。
PS. 我也还是一个初学者,如果文章中有一些错误或不足,还请多多指教。
CH32V003 存储器结构
根据 CH32V003 的数据手册可以知道,CH32V003 拥有 16KB 的用户代码区域。
在 USB 电流表的固件编译之后,可以看到固件的大小,目前整个固件只占用约 12K 左右的空间,那可以就可以尝试使用剩余的空间来当作数据存储,模拟一下 EEPROM。
存储器特性
在使用 Flash 来模拟 EEPROM 时,需要通过数据手册关注一下 Flash 的一些特性,例如擦写时间和擦写寿命等。
存储器特性
从数据手册中可以看到,CH32V003 的 Flash 擦写 64 字节需要 2~3 毫秒的时间,如果在固件中太过频繁操作 Flash,会影响数据的统计和刷新,因此我们需要间隔一点的时间再来保存数据。
存储器寿命
同时,CH32V003 的内置存储器是有擦写寿命限制的,擦写次数超过限制可能会导致 Flash 的损坏,从而丢失数据,因此我们保存数据的频率也不能太高。
保存策略
一般来说,如果每分钟保存一次数据,在 20W 充电的情况,如果丢失一分钟数据,大约会丢失 20 * 1 / 60 = 0.33Wh
的统计数据,对于 10000 毫安时的充电宝来说,大概占比约为 0.33 / (10A * 3.7V) = 0.009
,不到 1% 的比例,也算可以接受的。
另外如果按最低擦写次数 10K 来计算,每分钟保存一次数据,那么理论上持续运行 10K 分钟就会将擦写次数消耗完,大约是 166 小时。
当然我们也可以采取额外的保存策略来减缓数据写入,例如在总消耗电量没有变化时,就不写入 Flash,这样即使 USB 电流表一直插着电,也不会增加 Flash 擦写次数。
Flash 擦写方式
CH32V003 的 Flash 提供了多种擦写方式,从数据手册里面可以看到,它可以标准编程和快速编程。
对于我们的使用场景来说,因为只需要保存累计电量一个数据,理论上只需要 4 个字节即可应对大多数情况,因此这里使用快速编程擦写 64 字节的方式来进行 Flash 读写。
模拟存储
首先需要完成使用 Flash 模拟 EEPROM 的相关库方法,这里我们只使用一个页 64 字节来模拟存储。
定义头文件
对于累计电量这个简单数据来说,我们只需要 3 个方法来完成 EEPROM 相关的操作,包括加载、读取和写入。
在 flash_eeprom.h
中完成相关方法的定义。
定义地址
在 flash_eeprom.c
中,先定义一个 64 字节的内存缓存,用于存放模拟 EEPROM 中的数据,这样可以在读取和写入时都加速处理。
在这里,使用了 Flash 中用户代码的最后一页,即起始地址为 0x08003FC0
的 64 字节作为 EEPROM 存储区域。
实现读取和写入
读取 Flash
对于读取来说,实现起来非常简单,Flash 的地址已经映射到了内存地址 0x08003FC0
上,只需要直接将这一块内存区域复制到缓存中即可。
写入 Flash
写入 Flash 则稍微复杂一些,需要先执行擦除,再将 64 个字节写入 Flash 中。
在擦除和写入的前后,需要完成 Flash 的解锁和加锁操作。
读取和保存累计电量数据
有了模拟 EEPROM 相关的操作方法,就可以将 USB 电流表运行过程中的累计电量数据保存下来了,这样在断电后再次运行时,能继续延续上次统计的数据,实现更长周期的统计。
累计电量数据的读取和保存都将在 data_manager.hpp
中完成。
定义变量
这里定义了几个变量,用来确定数据保存的策略:
CAPACITY_SAVE_PERIOD 定义了 60000 毫秒保存一次,即每分钟保存一次
EEPROM_OFFSET_CAPACITY 定义了累计电量数据保存在模拟 EEPROM 中偏移为 0 的位置
capacity_last_saved_ms 用来保存上次保存累计电量的时间戳,用于判断是否到达时间间隔
capacity_last_save_val 用来保存上次保存累计电量的值,仅在数据有变化时才保存
加载数据
adc_setup
方法在系统启动时就会被调用,这个时候可以顺便将之前保存的累计电量数据加载出来。
保存数据
根据之前确定的数据保存策略,判断时间间隔和数据是否变化之后,调用 ch32v_eeprom_write
方法将数据保存到 Flash 中。
测试
这个时候,将固件编译完成,并烧录进入 DIY USB 电流表,在 USB 电流表后接上负载,并且等 Cap 字段有数据变化之后,将 USB 电流表从电源上断开,再重新连接上电源,就可以看到累计电量数据正确保存并重新加载了。
小结
至此,我们已经完成了 DIY USB 电流表固件的全部功能开发,对于 USB 电流表常见的使用场景,数据测量、历史曲线、数据保存等都已经很好地支持了。
这里再留一个小作业吧,上面的累计电量保存功能,只有读取和写入,没有清零,如果在测试完一个充电宝的容量之后,想要重新测试,就需要将之前保存的数据清零,那么在固件代码中该如何完成呢?
完成 DIY USB 的整体固件开发之后,为了让我们的 DIY USB 电流表更像一个正式产品,可以给它设计一个外壳,更美观的同时,还可以防止裸露的 PCB 接触到导体之后可能存在的短路风险。
那么,下一篇就来完成 DIY USB 电流表的外壳和面板设计吧。
USB 电流表开源地址
这个 USB 电流表所有资料已经开源,可以在以下仓库中获取,包含固件代码、PCB 生产 Gerber 文件、原理图和外壳 STL 文件。
https://github.com/ohdarling/CH32V003-USBMeter
硬件相关的源文件已经在立创开源平台开源,访问以下地址可以进行一键 PCB 下单和一键 BOM 配单操作:
https://oshwhub.com/wandaeda/ji-yu-ch32v003-de-usb-dian-liu-biao
DIY USB 电流表系列
其他 DIY 项目
30 元 DIY 一个柔性灯丝氛围灯
教程地址:https://xujiwei.com/blog/2024/04/diy-ambient-light/
参考资料
https://github.com/ohdarling/CH32V003-USBMeter
https://oshwhub.com/wandaeda/ji-yu-ch32v003-de-usb-dian-liu-biao
https://www.wch.cn/products/CH32V003.html
如果这个文章对你有帮助的话,可以关注、点赞、转发或分享,非常感谢 😃。