目录
空闲任务:
引入:当任务需要延时,进入阻塞状态,那CPU去干什么事情了?
如果没有其他的任务可以运行,RTOS都会为CPU创建一个空闲任务这个时候CPU就运行空闲任务。在uCOSIII中,空闲任务是系统在初始化的时候创建的优先级最低的任务,空闲任务OSTaskIdle()什么也不做,只是在不停的给一个32位的OSIdleCtr的计数器加1。使用这个计数器以确定现行应用软件实际消耗的CPU时间。鉴于空闲任务的这种特性,在实际应用中,当系统进入空闲任务的时候,可在空闲任务中让单片机进入休眠或者低功耗等操作。
特点:
- 空闲任务是UCOSIII创建的第一个任务。
- 空闲任务是UCOSIII创建的,不需要手动创建,在调用OS_Init()初始化UCOS的时候就会被创建。
- 空闲任务优先级总是为OS_CFG_PRIO_MAK-1.
- 空闲任务中不能调用任何可是空闲任务进入等待的函数(比如延时函数)!!!
作用:
- 空闲任务可以降低CPU的使用率。
- 可以利用钩子函数实现低功耗相关功能。
为了更好的实现低功耗,空闲任务也很有必要,我们可以在空闲任务中实现睡眠,待机等低功耗措施。
空闲任务相关源码分析:
先进入OS初始化函数当中,可以看到在该函数当中进行好多初始化。
找到空闲函数初始化:
转跳进去:我们可以看到有一个OSTaskCreate()任务创建函数
继续转跳进入函数主体
CPU_CRITICAL_ENTER();CPU_CRITICAL_EXIT();临界段代码保护
● OSIdleTaskCtr++;每进入一次空闲任务,OSIdleTaskCtr 就加一,当该变量增加比较快时,证明空闲时间比较多,应用任务花费资源少。
● 宏 OS_CFG_STAT_TASK_EN 大于 0 说明开启了统计任务。
● OSStatTaskCtr 加一,统计任务中用到 OSStatTaskCtr,用来统计 CPU 的使用率。
● OSIdleTaskHook()叫做钩子函数,钩入用户自定义的钩子函数实现用户自定义的功能等,但是需要注意的是,在钩子函数中用户不允许调用任何可以使空闲任务阻塞的函数接口,空闲任务是不允许被阻塞的。
时钟节拍任务:
uCOS需要给用户提供周期性信号源,用于实现时间延时和确认超时。节拍频率应该在每秒10次到100次之间,或者说10到100Hz。时间节拍率越高系统额外负载就越重,时钟节拍的实际频率取决于用户应用程序的精度(重要)。
时钟节拍任务用来跟踪任务延时和任务等待超时,任务函数为OS_TickTask();,是UCOSIII必须创建的一个任务,任务优先级使用宏OS_CFG_TICK_TASK_PRIO来定义,一般时钟节拍的任务应该,设置一个相对较高的优先级。在OS_Init()中调用了一个函数OS_TickTaskInit()函数。
源码分析:
跳转进入创建的任务中:
● (void)OSTaskSemPend((OS_TICK )0,OSTaskSemPend()是请求任务内建信号量的。
● OS_TickListUpdate();信号量请求成功的话就调用函数 OS_TickListUpdate()函数初始化时钟节拍列表。
统计任务:
在uCOSIII中有一个提供运行时间统计的任务,也就是统计任务。默认情况下统计任务是不会创建的。如果要开启统计任务的话需要做如下步骤:
- 将宏OS_CFG_STAT_TASK_EN置1
- 必须在main函数创建的第一个任务也是唯一一个应用任务里边调用函数OSStatTaskCPUUsageInit();才能使用统计任务。
- 统计任务的优先级通过宏OS_CFG_STAT_TASK_PRIO来设置,一般设置为OS_CFG_PRIO_MAX-2,也就是倒数第二个优先级。
根据上述代码,OSStatTaskCPUUsageInit(&err);最先被调用的函数,其他任务均在该函数之后被创建。CPU的总的使用率会保存在变量OSStatTaskCPUUsage 中,我们可以通过读取这个值来获取CPU的使用率,值为0~10000之间的整数对应0.00~100.00%。
定时任务:
uCOSIII提供软件定时器功能,定时任务是可选的,将宏OS_CFG_TMR_EN设置为1就会使能定时任务。在OSInit()中将会调用OSTmriInit()来创建定时任务。
中断服务管理任务:
中断服务管理任务的优先级永远是最高的为0,把 os_cfg.h 文件中的宏 OS_CFG_ISR_POST_DEFERRED_EN 置 1 就会使能中断服务管理任务
钩子函数:
空闲任务的钩子函数:
上一节的空闲任务的时候提到了钩子函数OSIdleTaskHook(),本节我们先以空闲任务的钩子函数OSIdleTaskHook(),来学习一下钩子函数。函数代码如下:
从上边的代码可以看出要使用空闲任务钩子函数的话需要将宏定义OS_CFG_APP_HOOKS_EN置1,即允许使用空闲任务的钩子函数。当使能空闲任务的钩子函数以后每次进入空闲任务就会调用指针OS_AppIdleTaskHookPtr所指向的函数。
OS_AppIdleTaskHookPtr是什么???
这是一个函数指针本质上是个指针变量,指向这个函数。我们可以找到下边这个函数,
红框里的代码显示将指针OS_AppIdleTaskHookPtr指向App_OS_IdleTaskHook,那么问题又来了App_OS_IdleTaskHook是什么???
通过转跳进入函数可知:
所以空闲任务的钩子函数App_OS_IdleTaskHook是在OSIdleTaskHook中最终调用的是函数App_OS_IdleTaskHook();也就是说我们想在空闲函数的钩子任务中处理一些其他事情的话,就将代码写在App_OS_IdleTaskHook();函数中。
注意:在空闲任务的钩子函数中不能调用任何可以使空闲进入等待态的代码。
空闲任务钩子函数实验:
实验要求:
当空闲任务每执行 50000 就通过串口打印字符串“Idle Task Running 50000 times!”,测试任务。
实验步骤:
1、将宏定义OS_CFG_APP_HOOKS_EN 置 1 ,使能钩子函数。
2、main.c文件中添加头文件os_app_hooks.h,在os_app_hooks.c文件中添加usart.h文件,再开始任务中使用条件编译语句来设置App_OS_SetAllHooks()函数;
#if OS_CFG_APP_HOOKS_EN //使用钩子函数 App_OS_SetAllHooks(); #endif
3、编写钩子函数的内容:
void App_OS_IdleTaskHook (void) { static int num; num++; if(0==num%50000) { num=num%50000; printf("Idle Task Running 50000 times!!!\r\n"); } }
实验结果:
其他任务的钩子函数:
UCOSIIi一共有八个钩子函数,除了上边这个空闲任务的钩子函数之外还有其他七个:
- OSIdleTaskHook(),空闲任务调用这个函数,可以用来让CPU进入低功耗模式
- OSInitHook(),系统初始化函数OSInit()调用此函数。
- OSStatTaskHook(),统计任务每秒中都会调用这个函数,此函数允许你向统计任务中添加自己的应用函数。
- 、OSTaskCreateHook(),任务创建的钩子函数。
- OSTaskDelHook(), 任务删除的钩子函数。
- OSTaskReturnHook(),任务意外返回时调用的钩子函数,比如删除某个任务
- OSTaskSwHook(), 任务切换时候调用的钩子函数
- OSTimeTickHook(),滴答定时器调用的钩子函数