||
好长时间没更新我的博客了,接着前两节的写,上次写到任务控制块的初始化。任务控制块是一个数据结构,当任务的CPU使用权被剥夺时,μC/OS-Ⅱ用它来保存该任务的状态。当任务重新得到CPU使用权时,任务控制块能确保任务从当时被中断的那一点丝毫不差地继续执行。OS_TCBs全部驻留在RAM中。
先看任务控制块的组织结构:
typedef struct os_tcb { |
OS_STK *OSTCBStkPtr; //指向当前任务栈顶的指针 |
|
#if OS_TASK_CREATE_EXT_EN //以下参数只有在任务控制块扩展标 //志 使能OS_TASK_CREATE_EXT_EN才有用 |
void *OSTCBExtPtr; |
OS_STK *OSTCBStkBottom; |
INT32U OSTCBStkSize; |
INT16U OSTCBOpt; |
INT16U OSTCBId; |
#endif |
//下面两个变量用于任务控制块OS_TCBs的双重链接,该链表在时钟节拍函数OSTimeTick()中使用,用于刷新各 //个任务的任务延迟变量.OSTCBDly,每个任务的任务控制块OS_TCB在任务建立的时候被链接到链表 //中,在任务删除的时候从链表中被删除。双重连接的链表使得任一成员都能被快速插入或删除。 |
struct os_tcb *OSTCBNext; |
struct os_tcb *OSTCBPrev; |
|
#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN || OS_SEM_EN |
OS_EVENT *OSTCBEventPtr;// OSTCBEventPtr是指向事件控制块的指针 |
#endif |
|
#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN |
void *OSTCBMsg;// OSTCBMsg是指向传给任务的消息的指针。 |
#endif |
|
INT16U OSTCBDly;//当需要把任务延时若干时钟节拍时要用到这个变量 |
INT8U OSTCBStat;// 任务的状态字 |
INT8U OSTCBPrio;// 任务优先级 |
// .OSTCBX, .OSTCBY, .OSTCBBitX和 .OSTCBBitY用于加速任务进入 //就绪态的过程或进入等待事件发生状态的过程(避免在运行中去计算这些 //值)。 |
INT8U OSTCBX; |
INT8U OSTCBY; |
INT8U OSTCBBitX; |
INT8U OSTCBBitY; |
|
#if OS_TASK_DEL_EN |
BOOLEAN OSTCBDelReq;// .OSTCBDelReq是一个布尔量,用于表示 //该任务是否需要删除 |
#endif |
} OS_TCB; |
|
下面来看新建任务的TCB初始化,先说该函数的七个参数:
INT8U prio, ……………..任务优先级
OS_STK *ptos, ……………..任务堆栈栈顶指针
OS_STK *pbos, ……………..任务堆栈栈低指针
INT16U id, ……………..任务ID号(以后扩展用)
INT16U stk_size, ……………..任务任务堆栈长度
void *pext, ……………..任务扩展指针
INT16U opt,…………….可选项
其中必不可少的是前两个参数,其他注释在程序里。
INT8U OSTCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT16U stk_size, void *pext, INT16U opt)
{
OS_TCB *ptcb; //定义TCB变量
OS_ENTER_CRITICAL(); //关中断
ptcb = OSTCBFreeList; //从空闲TCB列表中取出一个TCB(OSTCBFreeList
//指向的那个)
if (ptcb != (OS_TCB *)0) //检查上一步取到的TCB存不存在
{
OSTCBFreeList = ptcb->OSTCBNext;//让OSTCBFreeList指向下一个空
//闲TCB
OS_EXIT_CRITICAL();//关中断
ptcb->OSTCBStkPtr = ptos; //将传递进来的七个参数放入TCB中
ptcb->OSTCBPrio = (INT8U)prio;
ptcb->OSTCBStat = OS_STAT_RDY;
ptcb->OSTCBDly = 0;
#if OS_TASK_CREATE_EXT_EN //其中有五个参数用于任务扩展
ptcb->OSTCBExtPtr = pext;
ptcb->OSTCBStkSize = stk_size;
ptcb->OSTCBStkBottom = pbos;
ptcb->OSTCBOpt = opt;
ptcb->OSTCBId = id;
#else // 如果OS_TASK_CREATE_EXT_EN=0,执行下面为了防止编译器警告
pext = pext;
stk_size = stk_size;
pbos = pbos;
opt = opt;
id = id;
#endif
#if OS_TASK_DEL_EN //如果任务删除功能使能,对相应变量赋值,此语句可视//为为无关代码
ptcb->OSTCBDelReq = OS_NO_ERR;
#endif
//下面四个变量是用于加速任务进入就绪态的过程或进入等待事件发生状态的
//过程(避免在运行中去计算这些值)。这些值是在任务建立时算好的,或者是在//改变任务优先级时算出的
ptcb->OSTCBY = prio >> 3;
ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY];
ptcb->OSTCBX = prio & 0x07;
ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX];
//下面这几句也不是必须的,涉及到任务间的通讯,先不管
#if OS_MBOX_EN || (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_SEM_EN
ptcb->OSTCBEventPtr = (OS_EVENT *)0;
#endif
#if OS_MBOX_EN || (OS_Q_EN && (OS_MAX_QS >= 2))
ptcb->OSTCBMsg = (void *)0;
#endif
OS_ENTER_CRITICAL(); //关中断
OSTCBPrioTbl[prio] = ptcb; //将新建的TCB放到TCB优先级表中
//下面语句是将新建的任务TCB放到已建立的任务TCB链表中
ptcb->OSTCBNext = OSTCBList;
ptcb->OSTCBPrev = (OS_TCB *)0;
if (OSTCBList != (OS_TCB *)0) {
OSTCBList->OSTCBPrev = ptcb;
}
OSTCBList = ptcb;
//下面两句是将就绪表中相应位置位,表示该新建任务进入就绪状态
OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
} else {
OS_EXIT_CRITICAL();
return (OS_NO_MORE_TCB);
}
}
这样加上上面一篇文章,uC/OS II的空闲任务算是建立起来,总结一下任务的建立主要做两件事情:一是任务堆栈的初始化,二是任务控制块(TCB)的初始化。
这样《一》《二》《三》加起来就把uC/OS II的系统初始化完成了,下面就要说说系统的心率——时钟节拍了……下章再写。