1.uC/OS-III系统内部有提供了5个任务:空闲任务、时钟节拍任务、统计任务、中断服务管理任务和定时器任务。其中空闲任务和时钟节拍任务是必须创建的,而统计任务、定时器任务和中断服务管理任务是可选的。
2.空闲任务(OS_IdleTask()、os_core.c)
空闲任务是系统必须创建的。当其他所有的任务都未就绪时,就需要运行它。
(1)优先级–它的优先级比较特殊,总是设置为OS_CFG_PRIO_MAX-1,所以其他的任务就不能设置为该优先级
(2)栈大小–在os_cfg_app.h文件中定义,如果有需要的话可以更改它的大小
#define OS_CFG_IDLE_TASK_STK_SIZE 64u
(3)空闲任务的源代码位于os_core.c文件的748行,如下所示:
void OS_IdleTask (void *p_arg)
{
CPU_SR_ALLOC(); // 声明变量cpu_sr,临时存储CPU的状态寄存器的值
p_arg = p_arg;
while (DEF_ON) {
CPU_CRITICAL_ENTER(); // 进入临界区
OSIdleTaskCtr++; // 表示空闲任务的活跃度,它的递增的速度表示CPU执行应用代码的繁忙程度。递增越快,表示执行与应用相关的任务所花费的时间越少
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCtr++; // 在统计任务中用来统计程序运行时CPU的利用率
#endif
CPU_CRITICAL_EXIT(); // 退出临界区
OSIdleTaskHook(); // 调用用户定义的介入函数,可以在uC/OS-III空闲的时候做一些额外的工作
}
}
注:在空闲任务中不能调用任何会使其进入等待态的服务函数(包括用户自定义的介入函数)
3.时钟节拍任务(OS_TickTask()、os_tick.c)
每个操作系统都需要一个周期性的时钟源,称为时钟节拍(Clock Tick)或者系统节拍(System Tick)。在uC/OS-III中时钟节拍相关部分的处理放在时钟节拍任务OS_TickTask()中,它的功能是跟踪正在延时的任务,以及在指定时间内等待某个内核对象的任务。
(1)配置的部分放在os_cfg_app.h的文件中
#define OS_CFG_TICK_RATE_HZ 100u // 时钟频率,一般在10Hz-1000Hz之间
#define OS_CFG_TICK_TASK_PRIO 10u // 时钟节拍任务的优先级,在实际使用中应当只比最重要的任务的优先级低一点
#define OS_CFG_TICK_TASK_STK_SIZE 128u // 时钟节拍任务的栈的大小
#define OS_CFG_TICK_WHEEL_SIZE 17u // 时钟节拍轮的大小,建议它的大小不要与时钟节拍的频率成倍数关系,最好是素数
(2)时钟节拍任务OS_TickTask()的代码位于os_tick.c文件中,60行 - 79行
void OS_TickTask (void *p_arg)
{
OS_ERR err;
CPU_TS ts;
p_arg = p_arg;
while (DEF_ON) {
(void)OSTaskSemPend((OS_TICK )0,
(OS_OPT )OS_OPT_PEND_BLOCKING,
(CPU_TS *)&ts,
(OS_ERR *)&err); // 等待来自时钟节拍中断的信号
if (err == OS_ERR_NONE) {
if (OSRunning == OS_STATE_OS_RUNNING) {
OS_TickListUpdate(); // 更新时钟节拍列表中所有任务的等待时间
}
}
}
}
(4)时钟节拍轮OSCfg_TickWheel[]
个人感觉uC/OS-III关于时钟节拍轮的设计非常巧妙,很好玩。由于现在还没有了解到相关的代码,所以这里不再做过多说明。
4.统计任务(OS_StatTask()、os_stat.c)
统计任务,顾名思义就是在系统运行时做一些统计工作,比如总的CPU利用率、各任务的CPU利用率以及各任务的堆栈使用量等。
(1)统计任务的允许与禁止通过os_cfg.h文件中的宏定义OS_CFG_STAT_TASK_EN来控制
#define OS_CFG_STAT_TASK_EN 1u
(2)配置信息位于os_cfg_app.h文件中
#define OS_CFG_STAT_TASK_PRIO 11u // 统计任务的优先级
#define OS_CFG_STAT_TASK_RATE_HZ 10u // 统计任务的时钟频率,其值在1Hz - 10Hz之间
#define OS_CFG_STAT_TASK_STK_SIZE 128u // 统计任务的栈大小
(2)使用注意
如果要使用统计任务,必须在main()函数中创建的第一个也是唯一一个应用任务中调用OSStatTaskCPUUsageInit()函数,并且只能在该函数之后再创建其他的任务。
OSStatTaskCPUUsageInit()函数的作用是确定当系统中没有其他的任务运行时OSStatTaskCtr在(1/OS_CFG_STAT_TASK_RATE_HZ)秒的时间内能够到达的最大值。
5.定时任务(OS_TmrTask()、os_tmr.c)
uC/OS-III可以通过定时任务向用户提供定时服务。到目前为止,暂未使用到定时器任务,所以这里不再说具体实例。
(1)定时任务OS_TmrTask()的使能通过宏定义OS_CFG_TMR_EN(位于os_cfg.h中)来实现。
(2)定时任务的配置主要有任务优先级、任务频率、任务栈大小、定时器轮大小这几项,它们位于文件os_cfg_app.h中。
#define OS_CFG_TMR_TASK_PRIO 11u // 定时任务的优先级,一般设置为中等优先级
#define OS_CFG_TMR_TASK_RATE_HZ 10u // 任务的频率,一般设置成10Hz
#define OS_CFG_TMR_TASK_STK_SIZE 128u // 任务栈大小,这里需要注意一点的是回调函数是从定时器任务的环境中调用的,因此栈的大小还要考虑回调函数所占空间的大小
#define OS_CFG_TMR_WHEEL_SIZE 17u // 定时器轮大小
(3)任务函数的解析放在《uC/OS-III之定时器管理》中。
6.中断服务管理任务(OS_IntQTask()、on_int.c)
个人觉得这里不应该叫做中断服务管理任务,应该叫做中断队列处理任务(以后等深入了解直接发布模式和延时发布模式后,就会这样想了)。
(1)通过将os_cfg.h文件中的配置常量OS_CFG_ISR_POST_DEFERRED_EN设置成1,来允许创建OS_IntQTask()的任务。
(2)该任务的源代码放在os_int.c文件中,270行 - 305行
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u // 延迟发布模式
void OS_IntQTask (void *p_arg)
{
CPU_BOOLEAN done;
CPU_TS ts_start;
CPU_TS ts_end;
CPU_SR_ALLOC(); // 宏定义,声明变量cpu_sr,用来临时存储CPU的状态寄存器的值
p_arg = p_arg; //Not using 'p_arg', prevent compiler warning
while (DEF_ON) {
done = DEF_FALSE;
while (done == DEF_FALSE) {
if (OSIntQNbrEntries == (OS_OBJ_QTY)0u) {
CPU_CRITICAL_ENTER(); // 进入临界区
OSRdyList[0].NbrEntries = (OS_OBJ_QTY)0u; // 清空就绪表中优先级为0的表项:中断队列处理任务的优先级为0
OSRdyList[0].HeadPtr = (OS_TCB *)0;
OSRdyList[0].TailPtr = (OS_TCB *)0;
OS_PrioRemove(0u); // 从优先级位映射表中删除0
CPU_CRITICAL_EXIT(); // 退出临界区
OSSched(); // 任务调度
done = DEF_TRUE; // 中断队列为空,循环要结束
} else {
ts_start = OS_TS_GET(); // 获取时间戳
OS_IntQRePost();
ts_end = OS_TS_GET() - ts_start; // 计算发送的时间
if (ts_end > OSIntQTaskTimeMax) { // 统计最大时间
OSIntQTaskTimeMax = ts_end;
}
CPU_CRITICAL_ENTER(); // 进入临界区
OSIntQNbrEntries--;
CPU_CRITICAL_EXIT(); // 退出临界区
}
}
}
}
#endif
注:该任务的优先级为0。