定位到uCOS-II/Source/os_time.c,该文件是系统时间相关。
由于嵌入式系统的任务是一个无限循环,而uCOS-II是一个抢占式内核,所以为了能让高优先级的任务不一直独占CPU,应该适当的让出CPU以给其他优先级较低的任务获得CPU得以执行。所谓“让出”即使任务进入延时,在延时期间让出CPU。
1. 延时函数OSTimeDly()
void OSTimeDly (INT32U ticks)
{
INT8U y;
#if OS_CRITICAL_METHOD == 3u /* 临界区保护,需要使用变量cpu_sr */
OS_CPU_SR cpu_sr =
0u;
#endif
if (OSIntNesting >
0u) {
return;
}
if (OSLockNesting >
0u) {
return;
}
if (ticks >
0u) {
OS_ENTER_CRITICAL();
y = OSTCBCur->OSTCBY;
OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
if (OSRdyTbl[y] ==
0u) {
OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
}
OSTCBCur->OSTCBDly = ticks;
OS_EXIT_CRITICAL();
OS_Sched();
}
}
函数的参数ticks是以系统节拍数为单位的延时时间设置值,延时期间会让出CPU供其他任务使用。一般我们设置硬件tick为10ms产生一次sysytick中断,所以此函数存在缺陷:不能延时小于10ms且延时的时间需是10ms的整数倍。
2. 延时函数OSTimeDlyHMSM()
#if OS_TIME_DLY_HMSM_EN > 0u
INT8U OSTimeDlyHMSM (INT8U hours,
INT8U minutes,
INT8U seconds,
INT16U ms)
{
INT32U ticks;
if (OSIntNesting >
0u) {
return (OS_ERR_TIME_DLY_ISR);
}
if (OSLockNesting >
0u) {
return (OS_ERR_SCHED_LOCKED);
}
#if OS_ARG_CHK_EN > 0u
if (hours ==
0u) {
if (minutes ==
0u) {
if (seconds ==
0u) {
if (ms ==
0u) {
return (OS_ERR_TIME_ZERO_DLY);
}
}
}
}
if (minutes >
59u) {
return (OS_ERR_TIME_INVALID_MINUTES);
}
if (seconds >
59u) {
return (OS_ERR_TIME_INVALID_SECONDS);
}
if (ms >
999u) {
return (OS_ERR_TIME_INVALID_MS);
}
#endif
ticks = ((INT32U)hours *
3600uL + (INT32U)minutes *
60uL + (INT32U)seconds) * OS_TICKS_PER_SEC
+ OS_TICKS_PER_SEC * ((INT32U)ms +
500uL / OS_TICKS_PER_SEC) /
1000uL;
OSTimeDly(ticks);
return (OS_ERR_NONE);
}
#endif
为了能使用日常习惯的方法来使任务延时,uCOS-II还提供了OSTimeDlyHMSM函数,该函数可以指定时分秒、毫秒进行延时。其中OS_TICKS_PER_SEC变量指明每秒钟发生几次systick,1ms产生一次systick,那么1秒就是1000次。
3. 中止任务继续延时函数OSTimeDlyResume()
#if OS_TIME_DLY_RESUME_EN > 0u
INT8U OSTimeDlyResume (INT8U prio)
{
OS_TCB *ptcb;
#if OS_CRITICAL_METHOD == 3u
OS_CPU_SR cpu_sr =
0u;
#endif
if (prio >= OS_LOWEST_PRIO) {
return (OS_ERR_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
ptcb = OSTCBPrioTbl[prio];
if (ptcb == (OS_TCB *)
0) {
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_NOT_EXIST);
}
if (ptcb == OS_TCB_RESERVED) {
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_NOT_EXIST);
}
if (ptcb->OSTCBDly ==
0u) {
OS_EXIT_CRITICAL();
return (OS_ERR_TIME_NOT_DLY);
}
ptcb->OSTCBDly =
0u;
if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {
ptcb->OSTCBStat &= ~OS_STAT_PEND_ANY;
ptcb->OSTCBStatPend = OS_STAT_PEND_TO;
}
else {
ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
}
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {
OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
OS_EXIT_CRITICAL();
OS_Sched();
}
else {
OS_EXIT_CRITICAL();
}
return (OS_ERR_NONE);
}
#endif
任务调用了OSTimeDly()/OSTimeDlyHMSM()函数,当规定的延时时间超时,或者其他任务调用OSTimeDlyResume()取消其延时,该任务就会进入就绪状态。参数prio用于指定被取消延时的任务的优先级。
在这里,总结PEND和SUSPEND状态的差别: (1) PEND为阻塞之意,任务在PEND过程中会释放CPU资源,其它任务可以得到执行。PEND一般在等待某个事件的出现。SUSPEND为暂停、挂起之意,任务在SUSPEND过程中不释放CPU资源。一般挂起用于程序调试中的条件中断,即出现某个条件的情况下挂起,然后进行单步调试。
(2) 挂起是一种主动行为,因此恢复也应该主动完成。阻塞是一种被动行为,被阻塞的任务不知道自己什么时候被挂起了,也不知道什么时候能恢复。
(3) PEND和NOTPEND/PEND_OK/PEND_TO对应
(4) SUSPEND和RDY对应
4. 读取时间函数OSTimeGet()
#if OS_TIME_GET_SET_EN > 0
INT32U OSTimeGet (
void)
{
INT32U ticks;
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr =
0;
#endif
OS_ENTER_CRITICAL();
ticks = OSTime;
OS_EXIT_CRITICAL();
return (ticks);
}
#endif
为了方便,系统定义了一个INT32U类型的全局变量OSTime来记录系统发生的时钟节拍数。OSTime在应用程序中调用的OSStart()时被初始化为0,之后每发生一个时钟节拍,OSTime的值就会被加1。OSTimeGet()的返回OSTimeGet的值。
5. 设置时间函数OSTimeSet()
#if OS_TIME_GET_SET_EN > 0
void OSTimeSet (INT32U ticks)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr =
0;
#endif
OS_ENTER_CRITICAL();
OSTime = ticks;
OS_EXIT_CRITICAL();
}
#endif
OSTimeSet()用于设置OSTime的值。
这5个函数还是比较简单,都是c语言基础,个人觉得关键主要还是在PEND和SUSPEND的理解。