2.4任务就绪表及任务调度
2.4.1任务就绪表的结构
RAM中有一个记录表,每个任务通过1或0来表示其是否处于就绪状态。
ucosII用一个类型为INT8U的数组OSRdyTb1[]来充当任务就绪表,一任务优先级别高低为顺序,1为就绪状态,0为非就绪状态。为了方便就绪表的查找,又定义了一个变量OSRdyGrp,并是该变量的每一个位都对应OSRdyTb1[]的一个任务组(即数组的一个元素),任务组里有元素就绪,变量OSRdyGrp把对应位置置为1,否则为0.
2.4.2对任务就绪表的操作:
1.将优先级别为prio的任务置为就绪状态。
OSRdyGrp |= OSMapTbl[prio >> 3];
OSMapTbl[prio >> 3] |= OSMapTbl[prio & 0x07];
2.将任务脱离就绪状态:
If((OSMapTbl[prio>>3] &= -OSMapTbl[prio & 0x07]) == 0)
OSRdyGrp &= -OSMapTbl[prio >> 3];
3.获取优先级别最高的就绪任务:
y = OSUnMapTal[OSRdyGrp]; //获得优先级别的D5,D4,D3位
x = OSUnMapTal[OSRdyTbl[y]]; //获得D2,D1,D0位
prio = (y << 3) + x; //获得就绪任务的优先级别
或者
y = OSUnMapTal[OSRdyGrp];
prio = (y << 3) + OSUnMapTal[OSRdyTbl[y]];
2.4.3任务的调度:
中止任务而运行另一个任务叫任务的切换,按某种规则切换叫做任务的调度。
ucosII有两种调度器。一种是任务级的,另一种是中断级的调度器。两者分别与OSSched()和OSIntExt()函数来实现。
1.任务调度器的步骤:1.获得运行任务的指针;
2.进行断点数据的切换。
2.
3.任务切换宏OS_TASK_SW()
任务的切换靠函数OSCtxSw()完成的。任务的切换就是断点数据的切换,即cpu堆栈指针的切换。为了完成操作,OSCtxSw()完成下列7项工作:
(1)把被中止任务的断电指针保存到任务堆栈中
(2)把cpu通过寄存器的内容保存到任务堆栈中
(3)把被中止任务的任务堆栈指针当前值保存到该任务的任务控制块的OSTCBStkPtr中
(4)获得待运行任务的任务控制块
(5)使cpu通过任务控制块获得待运行的任务堆栈指针
(6)把待运行任务对战中通用寄存器的内容恢复大奥cpu的通用寄存器中
(7)使cpu获得运行任务的断点指针
ucosII是把当前正在运行任务的任务控制块的指针放到一个指针变量OSTCBCur 中,并且在调度器的前面代码中已经得到了待运行的任务控制块指针OSTCBHighRdy,所以第(2)~(6)项工作非常容易,其示意性代码如下:
OSTCBCur -> OSTCBStkPtr = sp; //把sp保存在中止任务控制块中
OSTCBCur = OSTCBHighRdy; //使系统获得运行任务控制块
Sp = OSTCBHighRdy -> OSTCBStkPtr; //把待运行任务堆栈指针赋给sp
第(1)和(7)项工作通过中断将断电指针推入cpu的pc寄存器的功能,恢复带运行任务的断点。中断服务函数要用汇编语言编写。
2.5任务的创建
2.5.2用函数OSTaskCreateExt()创建任务
2.6任务的挂起和恢复
2.6.1
挂起:即任务的停止
INT8U OSTaskSuspend(INT8U prio);
参数prio为优先级别,函数要挂起自身,参数为常数OS_PRIO_SEI,F,在uCOS_H.H中定义为0xFF。
流程:
先判断是否调用该函数的任务本身,如果是,则删除任务在就绪表中的就绪标志,做起挂起记录,引发任务调度;如果不是,则删除被挂起任务 的就绪标致,并做挂起记录
2.6.2
恢复任务:
原型:INT8U OSTaskResume(INT8U prio);
流程:判断任务是否挂起且不是一个等待任务,就清除挂起记录
其他任务管理函数
任务优先级别的修改:
OSTaskChangePrio()函数原型:
INTBU OSTaskChangePrio (
INTBU oldprio, //任务现在的优先级别
INTBU newprio, //要修改的优先级别
);
若调用函数成功,则函数返回OS_NO_ERR
任务的删除:
就是把该任务置于睡眠状态。
函数OSTaskDel()原型:
#if OS_TASK_DEL_EN
INTBU OSTaskDel(
INTBU prio,
);
如果删除任务自己,函数参数改为OS_PRIO_SELF
7.ucosII初始化和任务的启动
初始化是对所有的全局变量和数据结构进行初始化,同时创建空闲任务,使最低的优先级别处于就绪状态
任务的启动:
OSStart(void)
{
INTBU y;
INTBU x;
If(OSRunning == FALSE)
{
y = OSUnMapTbl[OSRdyGrp];
x = OSUnMapTbl[OSUnMapTbl[y]];
OSPrioHighRdy = (INTBU)((y << 3) + x);
OSPrioCur = OSPrioHighRdy;
OSTCBHighRdy = OSTCBPrioTb1[OSPrioHighRdy];
OSPrioCur = OSPrioHighRdy;
OSStartHighRdy();
}
}