1. 为什么STM8的延时函数这么重要?
如果你刚开始玩STM8单片机,肯定会遇到一个最基础但又绕不开的问题:怎么让程序“等一会儿”?比如,你想让一个LED灯闪烁,亮一秒灭一秒,这个“一秒”怎么实现?这就是延时函数要干的事儿。在STM8这种资源有限的8位MCU上,实现一个稳定、准确的毫秒级延时,看似简单,实则暗藏玄机。我刚开始做项目的时候,也在这上面踩过不少坑,比如用软件循环延时,结果发现按键反应迟钝,或者用定时器延时,又觉得配置起来太麻烦。
其实,STM8上实现毫秒级延时,主流就两种方法:软件循环延时和硬件定时器延时。前者就像你心里默数“1、2、3…”,数够了时间就到了;后者就像你设了个闹钟,闹钟响了时间才到,在这期间你还能干点别的。这两种方法,一个简单粗暴但“占着茅坑不拉屎”,一个稍微复杂但“精准高效”。这篇文章,我就结合自己多年的实战经验,带你彻底搞懂这两种方法的原理、优缺点,并给出具体的优化方案和代码,让你无论是做简单的玩具,还是稍微复杂点的控制板,都能游刃有余。
2. 软件循环延时:新手的第一把“瑞士军刀”
软件循环延时,绝对是嵌入式新手接触到的第一个延时方法。它的原理超级简单:让CPU执行一堆无意义的空操作指令,靠消耗固定的时钟周期来“磨”时间。
2.1 一个最基础的实现代码
下面这个函数,相信很多朋友都写过或用过:
#define F_CPU 16000000UL // 假设你的STM8主频是16MHz
void delay_ms(uint16_t ms) {
volatile uint32_t i, j;
for (i = 0; i < ms; i++) {
for (j = 0; j < 4200; j++) { // 这个“4200”是个经验值
__asm__("nop"); // 插入一个空操作汇编指令
}
}
}
这段代码干了啥?外层循环控制“多少毫秒”,内层循环和nop指令共同构成“1毫秒”的耗时。这里的volatile关键字很重要,它告诉编译器:“别优化我的循环变量!”,否则编译器一看你这i和j光循环啥也不干,可能直接给你优化没了,延时也就失效了。
2.2 软件延时的“阿喀琉斯之踵”:精度与CPU占用
软件延时最大的优点就是简单,不需要初始化任何外设,拿来就用。但它有几个致命的缺点,我一个个给你掰扯清楚。
第一,精度差,受时钟影响大。 上面代码里的4200这个魔法数字是怎么来的?它是基于16MHz主频,结合编译器优化级别、每条指令的执行周期,反复测试或计算出来的。如果你的主频不是16MHz,或者你换了编译器、改了优化等级(比如从-O0改成-Os),这个数字就得重新调。我遇到过最坑的情况是,代码在调试模式(无优化)下延时准确,一发布(高优化等级)时间就全乱了。更别提如果系统时钟源(HSI/HSE)本身有偏差,延时误差会进一步放大。
第二,CPU被完全霸占,效率极低。 这是软件延时最被人诟病的地方。在执行delay_ms(1000)这一秒钟里,CPU什么事都干不了,就在那傻傻地数数。这在只有一个任务的简单系统中勉强可以接受,但一旦你的系统需要同时响应按键、刷新显示、读取传感器,这种“阻塞式”延时就会让整个系统看起来“卡顿”甚至“死机”。比如,你正在用延时等待一个温度传感器稳定,这时用户按了按键,系统是没法响应的。
第三,难以实现长时间、高精度延时。 你想延时1小时怎么办?难道让for循环跑3600*1000次?先不说变量会不会溢出,这么长的阻塞时间,你的系统跟“死”了没区别。而且,由于循环本身有开销,微秒(us)级的短延时很难用纯软件循环精确实现。
所以,软件循环延时就像一把钝刀,切切豆腐还行,真要上硬菜,就得换工具了。
3. 硬件定时器延时:精准的“时间管家”
当你受够了软件延时的种种不便,就该请出更专业的工具——硬件定时器。STM8芯片内部通常集成了多个定时器(如TIM1, TIM2, TIM3, TIM4等),它们就像几个独立的小闹钟,不依赖CPU执行指令来计时,而是靠硬件时钟源自己走。
3.1 定时器延时的核心思想
定时器延时的原理是:配置一个定时器,让它每隔一个固定的时间(比如1ms)产生一个“时间到”
730




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



