找回密码
 立即注册
查看: 658|回复: 2

硬件延时与硬件休眠的两种方法介绍:单片机倒计时技术的典型应用

[复制链接]
  • 打卡等级:偶尔看看I
  • 打卡总天数:16
  • 最近打卡:2025-04-30 08:41:32

105

主题

1215

回帖

1万

积分

荣誉版主

积分
12882
发表于 2024-10-17 19:32:55 | 显示全部楼层 |阅读模式
本帖最后由 杨为民 于 2024-10-17 19:38 编辑

倒计时是日常生活常见的时间控制方式,电饭煲、微波炉、烤箱、沙漏和墙上的高考倒计时,比比皆是。
倒计时也是单片机编程的一种重要方法,本文通过实际构造硬件延时与硬件休眠的两种方法介绍单片机倒计时编程技术。

一、中断对软件延时精确性的影响
(1)软件延时存在的最大问题是软件延时的准确性问题。软件延时的准确性分为“静态准确性”和“动态准确性”两种。笔者前面的文章介绍软件延时的“静态准确性”问题:《C51语言中的微秒、毫秒软件延迟函数探讨》
https://www.stcaimcu.com/forum.php?mod=viewthread&tid=11218
(出处: 国芯技术交流网站)
本文将介绍软件延时的“动态准确性”问题和用硬件来解决问题的方法。
(2)本文将以笔者前一篇文章《中断阻塞与信号量:C51语言中的单片机硬件定时方法探讨》
https://www.stcaimcu.com/forum.php?mod=viewthread&tid=11250
(出处: 国芯技术交流网站)
的最后一个例子“四、前后台任务间信号量通讯同步方法”的程序来演示软件延时存在的问题。
(3)本节范例的任务A仍然是采用了软件延时的方法来控制LED闪光的速度的。下图是LED闪3下光的任务函数A的程序:
Fig_01_Task_A.jpg
其中Test_LED5、Test_LED6和Test_LED7对应左面的3个LED灯,低电平发光。整个过程无中断情况下的执行时间是750毫秒。
(4)任务A是运行在“main()”函数开始的“后台任务”中,如果没有中断(“前台任务”),那么这些经过校准的软件延时(“JSx51_BIOS_Delay_MS函数”)是准确的,具有“静态准确性”。
(5)但是如果有了中断,中断过程(至少包含寄存器现场的保存和恢复)需要花费一定的时间,在这些时间里,CPU执行前台任务程序,后台任务程序就会被停止,直到前台任务结束,被停止的后台任务程序才会接着继续执行。
如果中断发生时后台任务正在执行软件延迟函数程序,那么软件延迟函数的延迟时间就会被延长(需要加上中断的时间),造成软件延迟函数失去“动态准确性”。
由于任务A程序中LED端口的设置指令很少,超过99.99%的时间都是在执行软件延迟函数,所以它的“动态准确性”非常容易受到中断的影响。
(6)通过人为在中断服务程序中增加空循环语句,就可以增加中断过程的时间,观察中断对软件延时动态准确性的影响,定量测试这种影响的指标。
下图是定时器0中断服务程序中不加空循环语句的原始测试程序:
Fig_02_中断_不加.jpg
其中第91行到第95行的定时器0的中断服务程序中除了第93行提供信号给逻辑分析仪通道0外,没有其他程序。

(7)下图是定时器0中断服务程序中加了空循环语句的测试程序部分:
Fig_03_中断_加20.jpg
其中第91行到第102行的定时器0的中断服务程序中,在第98行增加了一个空循环语句,空循环次数为225。

增加后测试程序运行时的逻辑分析仪整体信号的截屏如下:
Fig_04_加20_截屏A.jpg
其中下方第5、6、7通道为任务A信号,低电平信号对应“JSx51_BIOS_Delay_MS(50);”软件延迟语句,高电平信号对应“JSx51_BIOS_Delay_MS(200);”软件延迟语句,

(8)将上面逻辑分析仪图中间部分放大可以看到定时器0的中断信号细节:
Fig_05_加20_截屏B.jpg
其中通道0的高电平部分是由于在第98行增加的空循环语句产生的,当空循环次数为225时,这个高电平脉冲宽度是0.2043ms。由于中断的重复周期是1ms,因此正脉冲的占空比为0.2043,代表了CPU有20%的时间是在处理中断前台任务,只有80%的时间是处理后台软件延迟程序任务。自然软件延迟的时间被延长了,经测量:
50ms-> 62.941ms    200ms -> 251.61ms
(9)下面是用4种循环次数进行测量的结果:
1) 循环次数为 0,占空比小于0.001

50ms->  50.096ms       200ms -> 200.28ms

2) 循环次数为 225,占空比等于0.204
50ms-> 62.941ms    200ms -> 251.61ms

3) 循环次数为 550,占空比等于0.497
50ms-> 99.23ms    200ms -> 406.18ms

4) 循环次数为 775,占空比等于0.702
50ms-> 168.80ms    200ms -> 617.95ms

从这个视频可以看出软件延迟时间加长,LED闪光的速度明显降低了。
(10)结论:当有中断时,软件延时函数的延迟时间多多少少都会加长,由于中断的发生和持续时间有随机性,因此软件延迟函数在实际运行时的动态精确性会受到影响,难以用校准的方法解决。

二、硬件延时函数的实现与应用:单片机倒计时器的基本方法
(11)定时器中断是一个动态的过程,定时器中断周期的精确性由硬件决定的,因此在单片机后台任务编程中采用硬件延时的方法来代替软件延时,必将具有很高的“动态精确性”。
(12)实现以毫秒为单位的硬件延时分两个部分,定义硬件延迟函数部分见下图程序:
Fig_06_硬件延时_定义.jpg
其中第88行程序定义一个代表“延时计数”的全局变量“JSx51_BIOS_Wait_Tick”,第89行到第97行是硬件延迟函数“JSx51_BIOS_Wait_MS”的定义。
函数只有两行程序,首先第92行将要延时的毫秒计数“MS”赋值给延时计数变量,然后第95行做空循环等待延时计数变量变为0后退出循环。

(13)延时计数变量当然不会自己凭空变为0,但可以利用一个1毫秒定时器中断来完成其倒计时器的功能,具体见下图程序:
Fig_07_硬件延时_中断.jpg
其中第101行到103行是硬件延时的中断程序部分。定时器0的中断每1毫秒发生一次,第101行程序检测延时计数变量是否大于0,如果大于,第102行将其减1,直到减为0为止。
很显然在硬件延时的实现过程中延时计数变量扮演了一个沟通前后台任务的信号量的作用,当它的值为0的时候,表示延时已经结束了。
(14)定义好了硬件延迟函数之后,就可以在需要延时的地方使用了。下图是采用硬件延时的TaskA程序:
Fig_08_硬件延时_应用.jpg
其中的第38、42、48、52、58、62行程序已经用硬件延时函数代替软件延时函数了。
(15)结论:由于硬件延时函数的延时计数变量的倒计时是由中断ISR执行的,因此只要不发生中断阻塞,其动态准确性肯定优于1毫秒,不受中断执行时间的影响。
注意:硬件延迟函数必须在中断已经打开(EA=1)之后才能使用。

三、硬件休眠函数的实现与应用:单片机倒计时器的扩展方法
(16)上面硬件延迟函数的第95行程序:
“while(JSx51_BIOS_Wait_Tick!=0);”
是原地踏步,傻傻地做空循环等待延时计数变量变为0。假如延迟时间较长,有没有可能像RTOS一样,利用这一段空闲执行一个耗时不超过等待时间的其他任务呢?结论是可以的,这就是本节要介绍的硬件休眠函数方法。
(17)硬件休眠函数的思路是将原来的硬件延迟函数分为两个部分,第一个部分设置休眠的时间计数,让中断去实现休眠时间计数的倒计时,然后利用这段时间去执行其他任务,等待其他任务执行完了以后,再回来等待休眠时间计数归零。
具体的硬件休眠函数定义如下图:
Fig_09_硬件休眠_定义.jpg
其中第100行程序定义一个代表主任务“休眠计数”的全局变量“JSx51_BIOS_Sleep_Tick”,第102行到第105行是硬件休眠开始函数“JSx51_BIOS_Sleep_Begin”的定义,第109行到第113行是硬件休眠结束函数“JSx51_BIOS_Sleep_End”的定义。
(18)硬件休眠的倒计时仍然需要在中断中进行,具体见下图程序:
Fig_10_硬件休眠_中断.jpg
其中除了第90行到第92行的硬件延时倒计时程序,第95行到第97行是硬件休眠倒计时程序。
由于硬件休眠倒计时是由中断实现的,因此其倒计时准确性与定时器中断一样,具有很高的精度。

(19)上篇文章提出的问题:如何只知道任务A的执行时间不超过1000毫秒,但是需要让主循环每1000毫秒准确地重复。上篇文章是用定时器11每1000毫秒中断一次驱动信号量来实现前后台任务同步的方法来解决。
(20)本文采用硬件休眠的方法来解决这个问题,还省了一个定时器11。具体的程序见下图:
Fig_11_硬件休眠_应用.jpg
其中在第54行程序主循环的开始的地方设置主任务的休眠时间为1000毫秒,然后从第56行到68行去执行任务A。
执行完任务A后,不管用多用少花了多少时间,在第71行程序处等待1000毫秒的休眠时间结束。在经过由中断执行的1000毫秒倒计时计数后,休眠变量计数归零,第74行程序转移主循环开始处,开始新一轮程序执行。

四、总结
(21)单片机倒计时技术是一种十分简单又十分有用也十分常见的编程技术,也是精通单片机必须掌握的一项重要技术。
单片机倒计时程序定义时:
1)首先定义一个新的倒计时全局变量作为前后台任务通讯信号量。
2)定义倒计时函数,在函数中设置和检测倒计时变量。
3)在中断ISR中加入进行倒计时变量减1的程序。
单片机倒计时程序应用时:
1)在需要精确倒计时开始的地方设置倒计时计数。
2)做其他任务,确保其他任务不超过休眠时间。
3)最后在需要的地方等待倒计时结束

(22)其实也可以不需要硬件延时函数,因为如果不做其他任务,把硬件休眠的两个函数在应用时连在一起执行,也就等于是一个硬件延时函数了。

附件:0300_硬件延时方法.rar (245.06 KB, 下载次数: 41)


回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:423
  • 最近打卡:2025-05-02 07:55:56
已绑定手机

19

主题

3190

回帖

4870

积分

论坛元老

积分
4870
发表于 2024-10-17 19:57:18 来自手机 | 显示全部楼层
学习了,休眠加唤醒来实现定时器效果,这个办法在低功耗要求情况下不是一个好办法,但是如果是人机交互等情况就不是很好了吧。看来延时也要根据需求去做相应的调节,适合自己才是最好的。

点评

人机交互应用也适用,其实“人”总是比“机”慢,除非“机”的设计太拉胯 对于响应速度依赖型应用,可以提高定时器中断频率,结合休眠加唤醒的话,那就调整唤醒定时器的周期,缩短唤醒时间即可。 实际中,很多针对低  详情 回复 发表于 2024-10-17 22:32
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:417
  • 最近打卡:2025-04-30 21:39:09
已绑定手机

34

主题

2096

回帖

2206

积分

荣誉版主

积分
2206
发表于 2024-10-17 22:32:33 | 显示全部楼层
so*** 发表于 2024-10-17 19:57
学习了,休眠加唤醒来实现定时器效果,这个办法在低功耗要求情况下不是一个好办法,但是如果是人机交互等情 ...

人机交互应用也适用,其实“人”总是比“机”慢,除非“机”的设计太拉胯
对于响应速度依赖型应用,可以提高定时器中断频率,结合休眠加唤醒的话,那就调整唤醒定时器的周期,缩短唤醒时间即可。
实际中,很多针对低功耗优化的单片机,唤醒时间仅需要1us,而且有多种低功耗模式(LPM),低功耗应用的框架中,主循环一般只有关于休眠的调用操作,其它业务都在具有睡眠唤醒的中断里写。
睁开眼睛做场梦~~~
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-2 10:40 , Processed in 0.126403 second(s), 71 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表