ucos(二)时间管理
一、时间管理
UCOSIII提供了一系列的时间管理函数,延时以时钟节拍(例如1000个节拍,就是进行1000个计数就是1秒时间的到达)为基准。
1.时钟节拍
时钟节拍可谓是实时操作系统的心脏,它若不跳动,整个系统都将会瘫痪。时钟节拍就是操作系统的时基,操作系统要实现时间上的管理,必须依赖于时基(时间基准)。
时钟节拍就是系统以固定的频率产生中断(时基中断),并在中断中处理与时间相关的事件,推动所有任务向前运行。时钟节拍需要依赖于硬件定时器,在 STM32 裸机程序中经常使用的 SysTick 时钟作为产生操作系统的时钟节拍。
用户需要先在“os_cfg_app.h”中设定时钟节拍的频率,该频率越高,操作系统检测事件就越频繁,可以增强任务的实时性,但太频繁也会增加操作系统内核的负担加重,所以用户需要权衡该频率的设置。
配置头文件:os_cfg_app.h
#define OS_CFG_TICK_RATE_HZ 1000u
2.任务睡眠延时n个时钟节拍【推荐】
void OSTimeDly (OS_TICK dly, OS_OPT opt, OS_ERR *p_err)
参数:
dly:睡眠的时钟节拍数
opt:决定任务的唤醒时刻,默认OS_OPT_TIME_PERIODIC(周期模式);其他模式为OS_OPT_TIME_DLY(相对模式)、OS_OPT_TIME_MATCH(绝对模式)。
p_err:返回错误码,没有错误的就返回OS_ERR_NONE
返回值:无
3、相对模式
(1)一个时钟节拍中断来,内核执行相关的中断服务。
(2)中断结束后,所有高优先级的任务得到运行。这些高优先级任务的运行时间是未知的,而且是变化的。
(3)当高优先级的任务执行完时,内核切换到相对低优先级的任务,任务将调用OSTimeDly(),实现相对模式延时2个时钟节拍。
(4)任务调用OSTimeDly(),以“相对模式”延时2个时钟节拍。这时,内核将该任务放入一个等待列表中,它将等待2个时钟节拍。在等待延时结束的任务并不会占用CPU的处理时间。
(5)下一个时钟节拍来到。如果有高优先级的任务在等待这个时钟节拍,那么内核将会在节拍中断结束后调度它们执行。
(6)高优先级的任务得到执行。
(7)又一个时钟节拍到来。这是低优先级的任务在等待的时钟节拍,在这个时钟节拍到来后它将会转入就绪态。
(8)因为在这个时钟节拍没有高优先级的任务需要执行,内核将切换到这个低优先级的任务。
(9)因为受高优先级运行时间的影响,这个低优先级的任务的延时并不精确地等于预期2个时钟节拍。
实际上,要想精确地获得和预期的时钟节拍是几乎不可能的。例如,用户可能需要延时2个节拍,但下一个时钟节拍有可能在用户调用OSTimeDly()后马上就到来。如果高优先级的任务的执行时间更长,那么(3)和(4)在时间轴上还会进一步右移,这时任务的延时更像是一个节拍,而不是2个。
“相对”这个关键字,意思会有参考对象。例如物理学中的相对静止,该物体的运行速度参考另外一个物体的运行速度是相对静止的,参考其他物体是运动的。在UCOSIII中,就是低任务优先级的相对延时的参考对象为高优先级任务运行的结束开始延时。
4、周期模式
内核将根据指定的周期确定一系列的“匹配值”,当时钟计数器OSTickCtr达到这些“匹配值”时,任务将被唤醒。
“相对模式”和“周期模式”也许看不出区别,但实际上两者是不同的。“在相对模式”下,当系统负荷较重时有可能延时会少一个节拍,甚至偶尔差多个节拍。“在周期模式”下,任务仍然可能被延迟执行,但它总会和预期的的“匹配值”同步。因此,推荐使用“周期模式”来实现长时间运行的周期性延时。
最后,绝对模式可以用来在上电后指定的时间执行具体的动作。例如,在产品上电10秒后关闭某盏灯,这时使用OS_OPT_TIME_MATCH选项,而参数dly对应的是预期时刻时钟节拍计数器OSTickCtr的值。
5.任务延时指定的时间,采用“时:分:秒:毫秒”的方式【少用】
#if OS_CFG_TIME_DLY_HMSM_EN > 0u void OSTimeDlyHMSM (CPU_INT16U hours, CPU_INT16U minutes, CPU_INT16U seconds, CPU_INT32U milli, OS_OPT opt, OS_ERR *p_err)
尽管UCOSIII允许任务延时很长时间,但实际上并不推荐这种做法。这样做,没有任何标识可以获知是否真正处于“存活”状态,除非可以监控任务剩余的等待时间。更好的做法是,让任务每大约1min唤醒一次,并且告诉该任务处于正常状态。
6.恢复被延时的任务【少用】
#if OS_CFG_TIME_DLY_RESUME_EN > 0u void OSTimeDlyResume (OS_TCB *p_tcb, OS_ERR *p_err)
该函数用于恢复调用了OSTimeDly或OSTimeDlyHMSM的任务,延时的任务并不知道它是被其他任务恢复的,它会认为是延时结束而得到恢复的。因此,请谨慎使用该函数。
7.获取当前时钟节拍计数器
OS_TICK OSTimeGet (OS_ERR *p_err)
利用该函数,程序可以进行粗略的时间测量,并大概地知道上电后已运行的时间。
8.设置时钟节拍的计数值
void OSTimeSet (OS_TICK ticks, OS_ERR *p_err)
该函数允许用户改变当前时钟节拍计数器的值,尽管UCOSIII允许这么做,但务必要谨慎使用。
9.触发一次时钟节拍服务
void OSTimeTick (void)
该函数在SysTick_Handler被调用,用于更新任务的延时和超时。