第二章 Uc/OS-II中的任务
3.1任务的基本概念
3.1.1
从代码上看:Uc/OS-II中的任务就是一个函数
从任务的存储结构上看:任务分成三个组成:
任务程序代码(函数)
任务堆栈 (保存任务的工作环境)
任务控制块 (关联任务代码的程序控制块,记录各个任务的属性)
任务组成(Uc/OS-II中的任务都没有定义私有空间,属于线程)
任务管理:任务控制块链表
任务分类:用户任务 由应用程序设计者编写,解决应用程序问题
系统任务由系统提供,为应用程序提供某种服务或为系统本身服务
3.1.2
任务状态:睡眠状态就绪状态 运行状态 等待状态 中断服务状态
3.1.3
用户任务代码的一般结构—— 超循环结构
用户应用程序的一般结构—— 在main函数中初始化与创建任务,由操作系统进行管理和调度
3.1.4系统任务 (系统自己需要的任务)
空闲任务:系统无用户任务可运行而处于空闲状态,执行空闲任务
统计任务:计算CPU被使用的时间,以百分比的形式存放于变量中
3.1.5任务的优先权及优先级别
任务的优先级别最多有64级,每个级别用一个整数数字表示。
数字越小,优先级别越高。
显示定义每个任务唯一的优先级别,调用系统函数OSTaskCreate()创建
3.2任务堆栈
3.2.1任务堆栈的创建 ——OSTaskCreate
例#define MyTaskStkN 64
OS_STK MyTaskStk[MyTaskStkN ];
void main(void)
{
…….
#if OS_STK_GROWTH == 1 //堆栈向下增长
OSTaskCreate(
MyTask, //任务的指针
& MyTaskAgu, //传递给任务的参数
& MyTaskStk[MyTaskStkN - 1], //任务堆栈栈顶的地址
20 //任务的优先级别
);
#else //堆栈向上增长
OSTaskCreate(
MyTask, //任务的指针
& MyTaskAgu, //传递给任务的参数
& MyTaskStk[0], //任务堆栈栈顶的地址
20 //任务的优先级别
);
#endif
}
3.2.2任务堆栈的初始化——OSTaskStkInit
初始化:将任务初始化数据(任务指针,任务堆栈指针及程序状态字)存放到任务堆栈
3.3任务控制块及任务控制块链表
3.3.1 任务控制块结构
3.3.2任务控制块链表
空任务控制块链表(所有任务控制块未分配任务)
包含元素共用户任务最大数目+系统任务数目(2)个
任务块链表(任务控制块已分配任务)
双向链表 ----à加快对任务控制块的访问速度
定义一个数据类型为OS_TCB*的数组OSPrioTbl[]
3.3.3任务控制块的初始化——OSTaskInit
函数主要任务:
为被创建任务从空任务控制块链表获取一个任务控制块
用任务的属性对任务控制块各个成员
3.4任务就绪表及任务调度
多任务操作系统的核心工作是任务调度(通过一个算法确定哪个任务来运行)
3.4.1任务就绪表的结构
任务就绪表 ——OSRdyTbl[]
变量OSRdyGrp的每一个位对应OSRdyTbl[]的一个任务组(即数组的一个元素)
如果某任务组中有任务就绪,则在变量OSRdyGrp里把该任务组所对应的位置置1
优先级别——一个6位二进制数
高3位(D5D4D3)—— 指明变量OSRdyGrp的具体数据位,并用来确定就绪表数组元素的下标
低3位(D2D1D0)—— 该数组元素的具体数据位
3.4.2对任务就绪表的操作
1.登记 (将优先级别为prio的任务置为就绪状态)
OSRdyGrp |= OSMapTbl[prio >> 3];
OSRdyTbl[prio >> 3] |= OSMapTbl[prio& 0x07];
2.注销 (将优先级别为prio的任务脱离就绪状态)
If((OSRdyTbl[prio >> 3] &= -OSMapTbl[prio & 0x07]) == 0)
{
OSRdyGrp&= - OSMapTbl[prio >> 3]
}
3.*别的就绪任务获取
y = OSUnMapTal[OSRdyGrp]; //获取优先级别的D5D4D3位
x = OSUnMapTal[OSRdyTbl[y]]; //获取优先级别的D2D1D0位
prio = (y << 3) + x; //获取就绪任务的优先级别
3.4.3任务的调度 ——按某种规则进行任务切换
1.任务调度器工作:1.在任务就绪表中查找具有最高优先级别的就绪任务
2.实现任务的切换
任务级调度器——OSSched()
中断级调度器——OSIntExt()
2.获得待运行就绪任务控制块的指针
void OSSched(void)
{
#ifOS_CRITICAL_METSOD == 3 //确认未被上锁 且 不是中断服务程序调用
OS_CPU_SR cpu_sr; 调度器
#endif
INT8U y;
OS_ENTER_ CRITICAL();
If((OSLockNesting |OSIntNesting) == 0)
{
y = OSUnMapTbl[OSRdyGrp];
//得到*优先任务
OSPrioHighRdy = (INT8U)((y << 3) + UnMapTbl[OSRdyTbl[y]]);
if(OSPrioHighRdy != OSPrioCur)
{
//统计人切换次数的计数器加1
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++;
OS_TASK_SW();
}
}
OS_EXIT_CRITICAL();
}
确认未被上锁且不是中断服务程序调用调度器——>从任务就绪表中查得的最高优先级别就绪任务的优先级别OSTCBHighRdy——>确认是否是正在运行的任务——>用OSPrioHighRd做下标去访问数组OSTCBPrioTbl[],将数组元素OSTCBPrioTbl[OSPrioHighRdy]的值赋给指针变量OSTCBHighRdy——>依据指向待运行任务控制块和当前任务控制块的指针在宏OS_TASK_SW中实施任务切换
3.任务切换宏OS_TASK_SW
任务切换:中止正在运行的任务,转而去运行另外一个任务
在任务被中止时把任务的断点数据保存到堆栈中,重新运行时把堆栈中的断点数据再恢复到CPU的各寄存器中——> 无缝接续运行
CPU的堆栈指针SP指向正确——> 正确回复断点数据——>任务在断点处恢复运行
调度器任务切换操作:
1. 被终止任务的断点指针保存到任务堆栈
2. CPU通用寄存器内容保存到任务堆栈
3. 被终止任务的任务堆栈指针当前值保存到该任务控制块的OSTCBStkPtr
4. 获得待运行的任务控制块
5. 使CPU通过任务控制块获得待运行任务的任务堆栈指针
6. 把待运行任务的任务堆栈中的通用寄存器内容恢复到CPU通用寄存器
7. 使CPU获得待运行任务的断点指针
流程图如下:
宏封装一个软中断指令——> 引发中断——>跳转到中断服务程序,把断点指针存入堆栈
3.5任务的创建
创建任务==创建一个任务控制块
3.5.1用函数OSTaskCreaate()创建任务
判断创建任务的优先级别——>确认优先级别合法且未被使用——>初始化任务堆栈和任务控制块——>任务计数器加1——>判断Uc/OS-II是否在运行——>在运行,则进行任务调度——>创建任务成功,返回OS_NO_ERR;失败,返回其他
3.5.2用函数OSTaskCreaateExt()创建任务——更灵活,增加额外的开销
3.5.3创建任务的一般方法
Uc/OS-II初始化——>创建起始任务——>在起始任务中,初始化统计任务,创建其他任务——>开始多任务调度
不允许在中断服务程序中创建任务
3.6任务的挂起与恢复
挂起——> 停止这个任务的运行
3.6.1挂起任务
待挂起的任务调用函数的任务本身——>删除任务就绪表中的就绪标志——>挂起记录——>引发任务调度
待挂起的任务不调用函数的任务本身——>删除任务就绪表中的就绪标志——>挂起记录
3.6.2恢复任务
判断任务确实是已存在的挂起任务,且不是等待任务——>清除挂起任务——>任务调度——>返回成功
3.7其他任务管理函数
3.7.1任务优先级别的修改——>OSTaskChangPrio()
3.7.2任务的删除——> OSTaskDel()
删除 = 将任务置于睡眠,把被删除任务的任务控制块从任务控制块链表中删除,并归还给空任务控制块链表
提出删除任务请求的任务只负责提出删除任务请求,删除工作由被删除任务自己完成——>OSTaskDelReq()
提出删除任务请求的任务调用函数时,函数参数是被删除任务的优先级别
被删除任务调用函数时,函数参数是OS_PRIO_SELF
提出删除任务请求的任务调用OSTaskDelReq():
被删除任务调用OSTaskDelReq():
3.7.3查询任务的信息——>OSTaskQuery()
3.8 UC/OS-II的初始化和任务的启动
3.8.1UC/OS-II的初始化——>OSInit()
初始化所有全局变量和数据结构(创建包括空任务块控制链表在内的5个空数据缓冲区及创建一个数组),创建空闲任务,赋以最低的优先级别和永远的就绪状态。若需用统计任务,赋统计任务优先级别为OS_LOWEST_PRIO – 1
3.8.2 UC/OS-II的启动——>OSStart()