μCOS-II中的任务
任务的基本概念
任务和任务控制块
任务是一个独立运行单位, 有一个自己的私有堆栈——任务堆栈
在任务控制块中包含任务代码,但要注意,与普通程序块代码指针指向程序首地址不同,任务控制块的代码指针要指向认为的断点(任务函数的起始地址也是一个断点)
任务的管理
μCOS-II中任务分为用户任务和系统任务两种
任务链表也叫做任务注册表
μCOS-II中的所有任务都共同使用一个内存空间,故属于线程(?普遍意义上的进程)
任务的状态
用户任务代码的一般结构
OS_ENTER_CRITICAL()中封装了关中断的代码
OS_EXIXT_CRITICAL()中封装了开中断的代码
两个宏之间的受保护的代码段叫做临界段
用户应用程序的一般结构
可以被μCOS-II所管理的用户应用程序名字必须不能是main,而且不被main()函数调用的任务函数
系统任务
为与用户任务相区别,这种系统自己所需要的任务叫做系统任务
预定义两个系统任务:空闲任务(必须使用,不能通过程序来删除)和统计任务(根据需要选择使用)
若要使用统计任务,要配置参数并进行初始化
任务的优先级及优先级别
μCOS-II采用按优先级抢占式规则
OS_LOWEST_PRIO
任务堆栈
所有μCOS-II任务的任务控制块中都含有一个指向该任务堆栈的指针
任务堆栈的创建
【假设了使用了支持堆栈先改增长方式的处理器的条件下设置的ptos】
堆栈的增长方向是随系统所使用的处理器不同而不同的,一定要注意所使用的处理器所支持的堆栈在增长方向
为了提高应用程序可移植性,把两种方式都写出来,通过配置作为选择开关来适应需要
任务堆栈初始化
把任务初始数据(例如指向任务的指针、程序状态字PSW等)存在到任务堆栈的工作就叫做任务堆栈的初始化
μCOS-II提供了任务堆栈初始化函数OSTaskInit(),通常用户不会直接接触到这个函数,该函数由μCOS-II所提供的任务创建函数来调用。
任务控制块及其链表
系统通过任务控制块来感知和管理任务,没有任务控制块的任务不能被系统承认和管理
μCOS-II把系统所有任务的控制块连接为两条链表,并通过它们管理各个任务
任务控制块结构
任务控制块链表
在任务控制块的管理上,μCOS-II需要两条链表:一条空任务块链表和一条任务快链表
其中,定义在文件OS.CFG.H中的常数OS_MAX_TASKS指明了用户任务的最大数目
而定义在文件UCOS_II.H中的常数OS_N_SYS_TASKS指明了系统任务的数目
OSPrioTbl[]以任务的优先级别为顺序在各个元素里存放了指向各个任务控制块的指针
空任务块链表和任务块链表的结构示意图(图中阴影部分为任务块链表)
OSTCBCur当前任务控制块是μCOS-II访问频度最高的控制块
任务控制块的初始化
该函数的主要任务如下
- 为被创建任务从空任务控制块链表获取一个任务控制块
- 用任务的谁能够对任务控制块各个成员进行赋值
- 把这个任务控制块链入到任务控制块链表
任务就绪表及任务调度
调度器(程序模块)
任务就绪表结构
在μCOS-II中,就绪表(登记系统中所有处于就绪这状态的任务)就是一个位图
OSRdyTbl[]一个元素可表达8个任务的任务组,OSRdyGrp变量每一位对应一个任务组
对任务就绪表的操作
- 登记:将处于就绪状态的任务登记在任务就绪表中
- 注销:将脱离就绪状态的任务对应位设置为0
- 最高优先级就绪任务的查找
其中OSUn-MapTbl是为提高查找速度定义的一个数组
任务调度
μCOS-II任务调度思想是:“近似地每时每刻让优先级最高的就绪任务处于运行状态”
在具体做法上,μCOS-II在系统或用户任务调用系统函数及执行中断服务程序结束时调用调度器,以确定应该运行的任务并运行它 \
调度器的主要工作
任务的调度:按某种规则进行任务切换
μCOS-II有两种调度器:一种是任务级的调度器、另一种是中断级的调度器
调度器把任务切换的工作分为两个步骤:第一步是获得待运行任务的TCB指针;第二步是进行断点数据的切换
获得待运行就绪任务控制块的指针
任务级调度器OSSched():
应用程序通过调用OSSchedLock()和OSSchedUnlock()给调度器上锁和解锁,变量OSLockNesting记录调度器上锁的嵌套次数
任务切换宏OS_TASK_SW()
其实任务切换的工作是靠OSCtxSw()来完成的
断点、断点数据(各寄存器中的数据)
任务的切换就是断点数据的切换,断点数据的切换也就是CPU堆栈指针的切换,被中止运行任务的任务堆栈指针要保护到该任务控制块中,待运行任务的任务堆栈指针要由该任务控制块转存到CPU的SP中。
为完成上述操作,OSCtxSw()要依次做如下7项工作:
- 把被中止任务的断点指针保存到任务堆栈中
- 把CPU通用寄存器的内容保存到任务堆栈中
- 把被中止任务的任务堆栈指针当前值保存到该任务的任务控制块的OSTCBStkPtr中
- 获得待运行任务的任务控制块
- 使CPU通过任务控制块获得待运行任务的任务堆栈指针
- 把待运行任务堆栈中通用寄存器的内容恢复到CPU的通用寄存器中
- 使CPU获得待运行任务的断点栈指针(该指针是待运行任务在上一次被调度器中止运行时保留在任务堆栈中的)
一般情况下,中断服务程序OSCtxSw()都要用汇编语言来编写,示意性代码如下:
宏OS_TASK_SW()引发中断:宏中封装一个软中断指令(使用的微处理器具有软中断指令,或者封装其他可以使PC等相关寄存器压栈的指令,例如调用指令)
任务的创建
OSTaskCreate()和OSTaskCreateExt()
用函数OSTaskCreate()创建任务
用函数OSTaskCreateExt()创建任务
用OSTaskCreateExt()来创建任务将更为灵活,但也会增加一些额外的开销
创建任务的一般方法
μCOS-II规定:在调用启动任务函数OSStart()之前,必须已经创建了至少一个任务——人们习惯先创建一个最高优先级的任务(起始任务)。在起始任务中,再创建其他各任务。
μCOS-II不允许在中断服务程序中创建任务
任务的挂起和恢复
挂起任务就是停止这个任务的运行
用户任务通过OSTaskSuspend()来挂起自身或其他任务(除空闲任务之外),之后只能通过OSTaskResume()使其恢复
挂起任务
INT8U OSTaskSuspend(INT8U prio); prio=OS_PRIO_SELF(0xFF)挂起自身
恢复任务
INT8U OSTaskResume(INT8U prio);
函数判断任务是一个已存在的挂起任务,同时它又不是等待任务(OSTCBDly==0)
其他任务管理函数
任务优先级别的修改
任务的删除
把被删除任务的任务控制块从任务控制块链表中删除,并归还给空任务控制块链表,然后在任务就绪表中把该任务的就绪状态位设置为0
被删除的任务的删除工作由被删除任务自己来完成,这样,被删除任务就可以删除自身之前把占用的资源释放掉。
OSTCBDelReq作为被删除任务的联络信号
被删除任务方一定要用OS_PRIO_SELF作为参数来调用OSTaskDelReq()
查询任务的信息
OSTaskQuery()了解一个任务的指针、堆栈等信息
μCOS-II的初始化和任务的启动
μCOS-II的初始化
初始化函数OSInit()对数据结构进行初始化时,主要是创建包括空任务控制块链表在内的5个空数据缓冲区
μCOS-II的启动
OSStart()
OSStartHighPdy()在多任务系统启动函数OSStart()中调用。完成的功能是:设置系统运行标志位OSRunning=TRUE,将就绪表中最高优先级任务的栈指针Load到SP中,并强制中断返回。