UI展示
主菜单(滚动3.94V 2.5mA):
二级菜单(滚动3.94V 4.3mA):
三级菜单:
TV模式(时钟显示界面):
TV模式(环境显示界面):
TV模式(电源显示界面):
休眠屏显模式:
指南针UI:
UI操作逻辑:
低功耗思路
熟悉PC设备的朋友应该都知道,我们的电脑在闲置的时候,功耗一般比较低,这是因为CPU降频了,处于一种“怠速”的状态。同样,在降低设备功耗的时候,大多数人会采用降频的策略。很多朋友看到我用30M的主频时都会发出疑问:为什么不降频?
不分情况的一味降频,反而会增加设备的功耗。下图测试了STC32G12K128单片机在各个主频下的运行电流
之前想移植到STC8051U上运行,也移植好了,但测试发现8051U的功耗比32G大一些,只好作罢
这里我测试了各个主频下单片机运行65535次while(i--)所需的时间,这个是想证明,单片机在处理固定任务量的任务时,所需时间和主频成固定反比,35M主频是5M主频的7倍,那么5M主频处理任务需要的时间也应该是35M主频处理任务需要的时间的7倍,事实上也是如此:79200/11340 = 6.984
但5M主频下消耗的电流却不是35M主频下消耗电流的1/7(0.1428),而是2.287/10.88 = 0.21,这就说明低频执行同样任务量的任务反而会更耗电,也就是uA/MHz更大。
像本项目需要执行的UI刷新,UI刷新的点阵计算就是固定的任务量,uA/MHz越低,就越省电,所以需要高主频去执行这些任务或者计算,完成后无任务,这个时候就进入休眠模式。
软件介绍
软件部分,一些底层的配置采用了STC厂家范例代码,OLED初始化参考了淘宝附赠代码,反三角函数Atan的CORDIC算法参考了红石电路吧的代码,其余部分均为本人自行开发,程序框图如下,使用任务号栈+任务等待时间栈进行任务的预约与执行,中间的等待时间进入掉电模式进行过渡
之所以可以这么省电的缘故是因为MCU不会干多余的事情,有任务的时候才会运行,其他时间都在休眠。因为之前做第一代第二代时钟的时候,就发现一个事情,就是MCU在执行任务的时候,很多时候都在delay,例如滚动数字的时候,平移32格像素,需要平移32次,每次平移后间隔6毫秒才能执行下一次的平移,这个时候,空跑的的时间就是31x6=186ms,这是非常致命的,如果一秒刷新一次,就有18.6%的时间浪费在等待上。再例如给传感器发送测量指令后,需要等待一段时间才能读取测量后的值,这一段时间也是需要等待的。
为了解决MCU在等待时摸鱼的情况,可以让MCU在等待的时候进入掉电模式,从而降低功耗
但这样又不得不面临一个新的问题,就是MCU怎么知道自己什么时候醒过来?因为MCU在进入掉电模式之后主时钟停震,就真的睡死了,怎么知道自己下一次什么时候起来上班就成为一个问题
针对这个问题,像打工人可以预定一个闹钟一样,可以使用掉电唤醒定时器,通过设置掉电唤醒定时器的时间,控制MCU休眠后在我们指定的时间醒过来,然后我们可以再进一步,例如平移32格像素,就定下31个闹钟
为此,我引入两个数组,一个是“休眠时间数组”,一个是“任务号数组”(每个bit代表一个任务),两个数组的值一一对应。例如执行一个32格像素的平移,要执行32次,我就先在“休眠时间数组”和“任务号数组”中预约32个任务,如下图所示。
每次MCU检测数组“休眠时间数组”[0]和“任务号数组”[0]中的数值,如果不等于0,则将“休眠时间数组”[0]的值装入掉电唤醒寄存器,进行休眠,唤醒后再根据“任务号数组”[0]的值匹配相应的任务。任务完成后整个数组的值向左移动一位。当检测到“休眠时间数组”[0]和“任务号数组”[0]中的数值为0时,说明UI刷新任务已经完成,掉电唤醒寄存器关闭,彻底进入休眠,等待外部按键中断任务的唤醒。
但项目中并非只有一个OLED屏幕刷新的任务,对于传感器测量等待的任务,为了尽可能保证时效性,不可能排在UI刷新完成之后再测量,我们当然希望能两不误,这时就需要写插入算法将任务插入任务队列中,例如在队列中插入一个气压测量的任务(“任务号数组”bit1 =1),需要等待15ms(6+6+3),插入上图的队列中,如下图。可以看到当数值不可以重合时,需要打断队列插入数值,3为bit0和bit1都为1
通过上文的描述,我们知道单片机在刷新UI动画的时候,并不会一直刷新,像素每一次移动之间,一定是有一定的间隔时间的,否则就会运动过快。例如主菜单模式中,会显示3个32X32尺寸的图标,屏幕长128,图标之间间隔16,所以要完成一次滚动就需要平移48个像素,也就是平移48次,按照每次移动之间等待6ms,完成一次平移需要282ms(不算其他执行的时间),那这282ms的时间,如果单片机没有其他工作的话,那就是在空转。那么我们将等待空转的时间,用休眠代替,就可以把功耗降低了。这个时候就需要将48个间隔的UI刷新任务(任务号0x0001)和 6ms的间隔时间分布压进任务号栈、任务等待时间栈中,由任务休眠等待模块处理,那么单片机就会在接下来的时间里,按照6ms的间隔,从休眠中唤醒48次,每次执行一次UI刷新任务。
下列图片为测试PCB采集到的数据,测试环境为电源板+测试主板(只焊接FFC座子、MCU、按键),测试接入点为电池输出两端:
由于MCU供电是降压2.7V提供,实际2.7V电流最好*1.4换算,当然,最终是电池在供电,使用原始数据也是没什么毛病的
while(1)测试,模拟单片机全运行,可以看到电流大概在7mA左右
主菜单滚动测试,每隔1~2秒让主菜单UI移动一次,可以看到,电流均值在1mA左右,放大可以看到,电流为48个有间隔的尖峰,说明单片机间歇工作48次,完成48次像素移动,然后继续休眠
二级菜单滚动测试,每隔1~2秒让主菜单UI移动一次,可以看到,电流均值在2.9mA左右,放大可以看到,电流为24个有间隔的尖峰,说明单片机间歇工作24次,完成24次像素移动,然后继续休眠,由于需要计算的东西比主菜单移动多,所以看到电流尖峰的脉宽较大,所以耗电较多
由此可以证明,设计的低功耗UI架构已经满足设计的初衷,只有在有任务的时候才干活,而且整个程序中,几乎没有delay,避免了单片机空转,提高了效率。 之前的代码中,该框架存在一个比较严重的bug,就是插队算法,插了,但任务等待休眠的子模块不买账,并不会终止当前任务的休眠,会堵塞到当前任务结束为止。这就导致在等待一些预约时间较长的任务时,整个系统的阻塞会被察觉。例如开启光控后需要每秒获取环境光数据,每次测量后200mS后读数,如果此时位于菜单界面,而且正在进行读取传感器数据的等待中,按下按键,需要等待当前预约的等待时间完成后才能进行UI的滚动,宏观表现上就是按下按键之后会时不时有卡顿感。正确的效果应该是,按键按下后,如果任务等待休眠的子模块正在进行其他任务的休眠,则需要中止,将剩余时间读回并填入任务等待时间栈栈顶,然后再根据中断来源进行任务的插队。之前发现这个bug之后怎么改都不正常,结果2024年6月24号凌晨不死心随便改了一下,竟然改好了,目前测试没发现异常
事情还没有结束,为了进一步降低功耗,还需要进一步降低功耗,MCU最耗电的任务其实是在刷屏的时候,这时候使用8080总线发送数据,需要MCU参与其中,不能去干别的事情,这个时候我们可以使用DMA功能,使用双缓冲区,先装填1区,DMA发送1区的数据,在1区发送的时候,装填2区,轮流发送,循环往复,提高MCU的工作效率。
但单纯DMA发送数据的话,其实还是会更耗电,因为需要将数据从flash搬到XRAM里面,再通过DMA发出去是需要时间的,效率上不如把flash的数据直接发送出去,这个时候可以利用MCU进入停IDLE模式时,MCU停止工作,但外设还在可以工作的特点,如果在2区填充完成,但1区还没发完的情况下,还可以让MCU进入停IDLE模式,这个时候MCU停止工作,但外设还在可以工作,在IDLE模式等待LCM DMA 发送完成后再唤醒执行别的程序。这样功耗就可以进一步降低。除此之外,还有各种优化局部刷新,一点点抠功耗
主要硬件介绍
MCU
最大主频35M,本项目最大稳定主频为30M,超过就会随机莫名其妙重启,这个问题曾困扰我两个星期
功耗大概在310uA/MHz,,休眠实测在2个uA左右,IO口中断在掉电模式下边缘触发有点硬件上的问题,触发一个可能联动另一个,很难绷得住
供电使用3.7V 1000mA 软包锂电池进行供电
主回路供电
MCU、传感器、蜂鸣器、OLED逻辑供电由ETA3425 DC-DC同步整流降压提供,供电电压设置为2.7V,该电压受限于还要给RTC电池充电,所以不能降的太低
OLED显示供电
OLED自带的电荷泵效率极其拉胯,推荐使用DC-DC升压,并且不推荐同步整流升压,因为效率少有超过80%的
OLED显示供电由MT3608L DC-DC异步整流升压提供,供电电压为5V、6V、7V、8V可选,由MCU控制OLEDV1(开漏)、OLEDV2(开漏)引脚切换
MT9700为限流芯片,防止输出短路
OLEDV1 1 OLEDV2 1 5V
OLEDV1 0 OLEDV2 1 6V
OLEDV1 1 OLEDV2 0 7V
OLEDV1 0 OLEDV2 0 8V
OLEDV1(准双向) 1 OLEDV2 (准双向) 1 13V+ 禁止,原本有隔离mos的,后来降本去掉了
MT3608L(纹波72mV)10uf |
输出电压(V) | 输出电流(mA) | 输出功率(mW) | 输入电压(V) | 输入电流(mA) | 输入功率(mW) | 效率 |
5.018 | 1.521 | 7.630 | 3.873 | 2.230 | 8.637 | 88.35% |
4.986 | 3.030 | 15.108 | 3.873 | 4.360 | 16.886 | 89.47% |
5.037 | 156.250 | 787.031 | 3.740 | 247.000 | 923.780 | 85.20% |
锂电池充电
锂电池充电由ME4059ASPG-N负责,使用DC-DC同步整流降压进行充电,充电电流约为550mA,可大幅度降低线性充电带来的温升,预留控制脚位EN_2和GHRG
EN_2为ME4059ASPG-N使能脚,可以在充电中测量电池电源的时候,短暂关闭使能,获取真实电池电压
GHRG为充电状态指示端口,可以判断电池状态、有无电池
锂电池保护
完全依赖电池自带的保护板,未预留保护器件焊盘,降本降掉了
锂电池充电电流检测
由INA181A2IDBVT芯片提供50倍差分放大,采样电阻放在低侧,防止漏电(放在高侧会产生11uA左右的漏电流)
其余查看开源原理图即可
目前功能介绍
标准模式
休眠模式
- 时间显示
- 温湿气压
- 电源状态
- 整点报时
- 深度休眠
- 休眠屏显
- 设置
环境信息
亮度设置
- 屏幕亮度
- 电压档位
- 自动调节
- UI动态
- UI静态
- TV动态
- TV静态
- 联动电压
- 亮度倍率
指南针
水平尺
时间设置
闹钟(10个闹钟)
- 秒
- 分
- 时
- 日
- 月
- 周六休
- 周天休
- 闹钟时长
- 开关
增量闹钟
秒表
声音设置
手电筒
电源管理
- 外部供电
- 内部供电
- 供电电压
- 充电电流
- 剩余电量
- 寿命保护(暂无功能)
系统设置
- 保存参数
- 防误触(暂无功能)
- 12时制(暂无功能)
- 屏幕翻转(暂无功能)
- 休眠计划(暂无功能)
- 开始休眠 (暂无功能)
- 结束休眠(暂无功能)
系统信息
- 主控型号
- 温湿度计
- 气压计
- 光强计
- 加速度计
- 磁强计
- 时钟芯片
- 屏幕主控
- 按键数
- 版本号
- 机器型号
- 作者
工厂模式
结构介绍
重新建模外壳,复位按键改到屏幕下面,按下屏幕复位,装配稍微有些难度,后面会出作业手册供参考
3D打印使用嘉立创的光固化,半透明树脂
开源地址与资料下载:
https://oshwhub.com/yq-qvq/low-power-consumption-for-24-day