实时操作系统UCOS学习笔记8----UCOSIII 五个系统内部任务

在UCOSII中我们知道有两个系统任务:统计任务和空闲任务,在UCOSIII中系统内部任务扩展到了5个,本章我们就详细的讲解一下UCOSIII中的这5个系统任务。

1、空闲任务

首先来看一下空闲任务:OS_IdleTask(),在os_core.c文件中定义。任务OS_IdleTask()是必须创建的,不过不需要手动创建,在调用OS_Init()初始化UCOS的时候就会被创建。打开OS_Init()函数,可以看到,在OS_Init()中调用了函数OS_IdleTaskInit(),打开函数OS_IdleTaskInit(),函数代码如下:
实时操作系统UCOS学习笔记8----UCOSIII 五个系统内部任务_第1张图片

OSIdleTaskCtr在文件os.h中定义,是一个32位无符号整型变量。这里将OSIdleTaskCtr清零。
从上面的代码可以看出,函数OS_IdleTaskInit()很简单,只是调用了OSTaskCreate()来创建一个任务,这个任务就是空闲任务。任务优先级为OS_CFG_PRIO_MAX-1,OS_CFG_PRIO_MAX是一个宏,在文件os_cfg.h中定义,OS_CFG_PRIO_MAX定义了UCOSIII可用的任务数。前面我们说过UCOSIII的任务数是无数的,但是在实际使用中考虑到硬件资源(ROM和RAM)等因素,不可能真的使用无数的任务,在UCOSIII中可以使用宏OS_CFG_PRIO_MAX来定义可使用的任务数,默认情况下OS_CFG_PRIO_MAX为64。空闲任务优先级为OS_CFG_PRIO_MAX-1,说明空闲任务的优先级为最低的。
空闲任务堆栈大小为OSCfg_IdleTaskStkSize,OSCfg_IdleTaskStkSize也是一个宏,在os_cfg_app.c文件中定义,默认为128,则空闲任务堆栈默认为128*4=512字节。
空闲任务的任务函数为OS_IdleTask(),OS_IdleTask()函数代码如下:
实时操作系统UCOS学习笔记8----UCOSIII 五个系统内部任务_第2张图片

  1. 1和5是临界段代码保护。
  2. OSIdleTaskCtr加一,每进入一次空闲任务,OSIdleTaskCtr就加一。我们可以通过查看OSIdleTaskCtr变量的递增速度来判断CPU执行应用任务的繁忙程度,如果递增的快的话说明应用任务花费时间少,很快就执行完了。
  3. 宏OS_CFG_STAT_TASK_EN大于0说明开启了统计任务。
  4. OSStatTaskCtr默认也是一个32位的无符号整型变量,在文件os.h中定义。这里将OSStatTaskCtr加一,统计任务中用到OSStatTaskCtr,用来统计CPU的使用率。
  5. OSIdleTaskHook()叫做钩子函数,我们可以在钩子函数中干一些其他的事情。

2、时钟节拍任务

我们再看另一个必须创建的任务——时钟节拍任务:OS_Ticktask(),在OS_Init()中调用了一个函数OS_TickTaskInit(),函数代码如下:
实时操作系统UCOS学习笔记8----UCOSIII 五个系统内部任务_第3张图片

实时操作系统UCOS学习笔记8----UCOSIII 五个系统内部任务_第4张图片

可以看到在函数OS_TickTaskInit()的最后调用OSTaskCreate()来创建了一个任务,任务函数为OS_TickTask(),所以说时钟节拍任务是UCOSIII必须创建的,同样,不需要我们手工创建。时钟节拍任务的任务优先级为OSCfg_TickTaskPrio,时钟节拍任务的优先级尽可能的高一些,战舰默认设置时钟节拍任务的任务优先级为1.
时钟节拍任务的作用是跟踪正在延时的任务,以及在指定时间内等待某个内核对象的任务,OS_TickTask()任务函数代码如下:
实时操作系统UCOS学习笔记8----UCOSIII 五个系统内部任务_第5张图片
实时操作系统UCOS学习笔记8----UCOSIII 五个系统内部任务_第6张图片

  1. 请求信号量,OSTaskSemPend()是请求任务内建信号量的,信号量会在OSTimeTick()中POST,这里的信号量是用来做任务同步的、前面我们讲过OSTimeTick()会在滴答定时器中断服务函数中调用。
  2. 信号量请求成功的话就调用函数OS_TickListUpdate()函数,在了解OS_TickListUpdate()函数之前我们先来了解时钟节拍任务中一个重要的概念:时钟节拍列表。
    时钟节拍列表是由一个数据表OSCfg_TickWheel(在os_cfg_app.c中定义)和一个计数器OSTickCtr组成,表OSCfg_TickWheel是一个数组,数组元素个数由宏OS_CFG_TICK_WHEEL_SIZE定义,宏OS_CFG_TICK_WHEEL_SIZE在os_cfg_app.h中定义了。表OSCfg_TickWheel中的元素为os_tick_spoke类型的,os_tick_spoke是一个结构体,结构体定义如下:
    实时操作系统UCOS学习笔记8----UCOSIII 五个系统内部任务_第7张图片

在使用时钟节拍列表时需要先初始化时钟节拍列表,在OS_TickTaskInit()函数中会调用OS_TickListInit()来初始化时钟节拍列表,函数OS_TickListInit()代码如下:
实时操作系统UCOS学习笔记8----UCOSIII 五个系统内部任务_第8张图片

实时操作系统UCOS学习笔记8----UCOSIII 五个系统内部任务_第9张图片

3、统计任务

在UCOSIII中统计任务可用来统计CPU的使用率、各个任务的CPU使用率和各个任务的堆栈使用情况,默认情况下统计任务是不会创建的,如果要使能统计任务的话需要将宏OS_CFG_STAT_TASK_EN置1,宏OS_CFG_STAT_TASK_EN在os_cfg.h文件中有定义。当我们将宏OS_CFG_STAT_TASK_EN置1以后,OSInit()函数中有关统计任务的代码就可以编译了。OS_StatTaskInit()函数用来创建统计任务,统计任务的优先级通过宏OS_CFG_STAT_TASK_PRIO设置,战舰将统计任务的优先级设置为OS_CFG_PRIO_MAX-2,也就是倒数第二。
如果要使用统计任务的话就需要在main函数创建的第一个也是唯一一个应用任务中调用OSStatTaskCPUUsageInit()函数。注意OSStart()之前只能创建一个任务,在我们提供的所有例程中,在main函数中只创建了一个任务,就是start_task()开始任务,start_task()函数示例代码如下:
实时操作系统UCOS学习笔记8----UCOSIII 五个系统内部任务_第10张图片

实时操作系统UCOS学习笔记8----UCOSIII 五个系统内部任务_第11张图片

从上面代码中可以看出最先调用了函数OSStatTaskCPUUsageInit(),创建其他任务只能在OSStatTaskCPUUsageInit()函数之后。CPU的总的使用率会保存在变量OSStatTaskCPUUsage中,我们可以通过读取这个值来获取CPU的使用率。从V3.03.00版本起,CPU的使用率用一个0-10000之间的整数表示(对应0.00-100.00%),在这之前的版本,CPU使用率是0-100之间的整数表示。
如果将宏OS_CFG_STAT_TASK_STK_CHK_EN置1的话表示检查任务堆栈使用情况,那么统计任务就会调用OSTaskStkChk()函数来计算所有已创建任务的堆栈使用量,并将检测结果写入到每个任务的OS_TCB中的StkFree和StkUsed中。

4、定时任务

UCOSIII提供软件定时器功能,定时任务是可选的,将宏OS_CFG_TMR_EN设置为1就会使能定时任务,在OSInit()中将会调用函数OS_TmrInit()来创建定时任务。定时任务的优先级通过宏OS_CFG_TMR_TASK_PRIO定义,战舰默认将定时器任务优先级设置为2.

5、中断服务管理任务

当把os_cfg.h文件中的宏OS_CFG_ISR_POST_DEFERRED_EN置1就会使能中断服务管理任务,UCOSIII会创建一个名为OS_IntQTask()的任务,该任务负责“延迟”在ISR中调用的系统post服务函数的行为。中断服务管理任务的任务优先级永远是最高的,为0!
在UCOS中可以通过关中断和任务调度器上锁2种方式来管理临界段代码,如果采用后一种,即调度器上锁的方式来管理临界段代码的话,那么在中断服务函数中调用的“post”类函数就不允许操作诸如任务就绪表、等待表等系统内部数据结构。
当ISR(中断服务函数)调用UCOSIII提供的“post”函数时,要发送的数据和发送的目的地都会存入一个特别的缓冲队列,当所有嵌套的ISR都执行完成以后UCOSIII会做任务切换,运行中断服务管理任务,该任务会把缓存队列中存放的信息重发给相应的任务。这样做的好处就是可以减少关中断的时间,否则,在ISR中还需要把任务从等待列表中删除,并把任务放入就绪表,以及做一些其他的耗时操作。

6、钩子函数

空闲钩子函数
上一小节中我们简单的提了一下空闲任务的钩子函数OSIdleTaskHook(),本节我们以空闲任务的钩子函数OSIdleTaskHook()为例来学习一下钩子函数,函数OSIdleTaskHook()代码如下:
实时操作系统UCOS学习笔记8----UCOSIII 五个系统内部任务_第12张图片

从上面的函数代码中可以看出要使用空闲任务钩子函数的话需要将宏OS_CFG_APP_HOOKS_EN置1,即允许使用空闲任务的钩子函数。当使能空闲任务的钩子函数以后每次进入空闲任务就会调用指针OS_AppIdleTaskHookPtr所指向的函数。OS_AppIdleTaskHookPtr是何方神圣?打开os_app_hooks.c文件,在文件中有个函数App_OS_SetAllHooks(),函数代码如下:
实时操作系统UCOS学习笔记8----UCOSIII 五个系统内部任务_第13张图片

红色代码显示将App_OS_IdleTaskHook复制给OS_AppIdleTaskHookPtr。那么问题来了,OS_AppIdleTaskHookPtr又是何方神圣?我们仔细查看os_app_hooks.c文件,会发现App_OS_IdleTaskHook是一个函数,代码如下:
在这里插入图片描述

到这里我们基本就懂了空闲任务的钩子函数OSIdleTaskHook()是怎么工作了,在OSIdleTaskHook中最终调用的是函数App_OS_IdleTaskHook(),也就是说如果我们要想在空闲任务的钩子函数中做一些其他处理的话就需要将程序代码写在App_OS_IdleTaskHook()函数中。

注意:在空闲任务的钩子函数中不能调用任何可以使空闲进入等待态的代码,原因很简单,CPU总是在不停的运行,需要一直工作,不能让CPU停下来,哪怕是执行一些对应用没有任何用的代码,比如简单的将一个变量加一。在UCOS中为了让CPU一直工作,在所有应用任务都进入等待态的时候CPU会执行空闲任务,我们可以从空闲任务的任务函数OS_IdleTask()看出,在OS_IdleTask()中没有任何可以让空闲任务进入等待态的代码。如果在OS_IdleTask()中有可以让空闲任务进入等待态的代码的话有可能会在同一时刻所有任务(应用任务和空闲任务)同时进入等待态,此时CPU就会无所事事了,所以在空闲任务的钩子函数OSIdleTaskHook()中不能出现可以让空闲任务进入等待态的代码!这一点很重要,一定要谨记!!

实时操作系统UCOS学习笔记8----UCOSIII 五个系统内部任务_第14张图片

其他任务钩子函数
UCOSIII中一个有8个钩子函数,除了上面讲的空闲任务的钩子函数以外,还有7个,分别为OSInitHook()、OSStatTaskHook()、OSTaskCreateHook()、OSTaskDelHook()、OSTaskRetumHook()、OSTaskSwHook()、OSTimeTickHook()这些钩子函数的使用方法和空闲任务的钩子函数的使用方法类似。

你可能感兴趣的:(操作系统,操作系统)