1. 从“傻等”到“聪明睡”:为什么你的单片机还在空转耗电?
大家好,我是老张,一个在单片机圈子里摸爬滚打了十多年的老工程师。今天想和大家聊聊一个几乎所有单片机项目都会遇到,但又常常被忽视的问题:延时。
回想我刚入行那会儿,写个延时函数,十有八九就是下面这种“祖传”写法:
void Delay_ms(unsigned int ms) {
unsigned int i, j;
for(i=0; i<ms; i++)
for(j=0; j<114; j++); // 根据主频调整这个“魔法数字”
}
这种循环等待的方式,我称之为“傻等”。程序确实停在那里了,时间也过去了,但单片机的内核(CPU)在干嘛?它在疯狂地执行空指令,一刻不停。对于STC8这类高性能单片机,在24MHz主频下,执行这种空循环的电流可能高达5mA甚至更高。如果你的设备是靠电池供电,比如一个需要每隔10分钟采集一次温湿度的传感器节点,那么绝大部分时间,电池的能量都浪费在了这种无意义的“空转”上。这就像你让一辆跑车一直挂着空挡踩油门,不仅费油,还伤发动机。
后来做低功耗项目多了,踩的坑也多了,我才彻底明白一个道理:在低功耗设计中,最省电的指令,就是让CPU停止执行任何指令。 而STC8单片机,恰恰为我们提供了这种“聪明睡”的能力。它内置了多种低功耗模式,比如空闲模式(Idle) 和掉电模式(Power Down, 简称PD模式)。在PD模式下,CPU核心、大部分时钟和外设都会停止工作,整颗芯片的电流可以降到微安(μA)级别,这和毫安(mA)级的运行电流相比,简直是天壤之别。
所以,我们今天要探讨的低功耗延时优化,其核心思想就是:把需要等待的时间,变成单片机深度睡眠的时间。 我们不再让CPU空转消耗能量,而是设置一个“闹钟”(定时器),然后让单片机“睡”过去,等“闹钟”响了再醒来继续工作。这个转变,是从“被动等待”到“主动休眠”的质变,是低功耗设计中最实用、也最容易被掌握的技巧之一。无论你是做物联网传感器、便携式设备,还是任何对电池寿命有要求的项目,掌握这个方法,都能让你的产品续航能力提升一个数量级。
2. 庖丁解牛:STC8的“睡眠闹钟”——掉电唤醒定时器(WKT)
想要实现“定时睡眠”,我们得请出STC8单片机里的一个关键角色:掉电唤醒定时器(Wake-up Timer, 简称WKT)。你可以把它想象成单片机内部一个专门为低功耗模式设计的“机械闹钟”。即使单片机进入了最深的PD模式,主时钟都停了,这个“闹钟”依然靠着一个独立的低速时钟源(通常是内部32KHz低频IRC)在滴答走时。
这个“闹钟”的配置,主要通过两个特殊功能寄存器来完成:WKTCH 和 WKTCL。它们是8位寄存器,但组合起来形成了一个16位的定时器。这里有个关键点需要特别注意,也是很多新手容易配置错误的地方:
- WKTCH (高字节寄存器):它的最高位(bit7)是这个“闹钟”的总开关。当这个位被设置为1时,WKT定时器才开始工作并准备唤醒单片机。 剩下的低7位(bit6-bit0)和整个WKTCL寄存器(8位)的15个位,共同决定了“闹钟”响起的间隔时间,也就是唤醒延时。
简单来说,WKTCH = 0x80; 这个操作,不仅仅是设置一个值,它实质上是做了两件事:1. 打开WKT定时器的使能开关;2. 同时设定了定时器初值的高7位。而WKTCL则用于设定初值的低8位。定时器启动后,会从这个初值开始向上计数,直到溢出,溢出事件就会触发单片机从PD模式中唤醒。
那么,这个“闹钟”能定多久呢?这取决于它的时钟源。STC8的WKT通常使用内部32KHz的低速时钟(LIRC)。计算公式是这样的:
唤醒时间(秒) = (65536 - [WKTCH:WKTCL]设定的初值) / 时钟频率
因为WKT是16位的,所以最大计数值是65536。如果我们把初值设为0,那么需要计数65536次才会溢出,在32KHz下,这个时间就是 65536 / 32768 ≈ 2秒。但注意,我们配置的初值是高7位加低8位共15位有效(因为WKTCH的最高位是使能位),所以实际可设置的最大延时大约是 32768 / 32768 = 1秒 吗?不对,这里有个细节:手册给出的典型最大延时是约 16秒。这是怎么来的呢?原来,WKT内部可能还有一个固定


326

被折叠的 条评论
为什么被折叠?



