UCOSII OS_CORE.c

在下这项有礼了!

1.就绪任务表

INT8U const OSMapTbl[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};

OSUnMapTbl[]:最高优先级任务查找表;对应OSRdy Grp和OSRbyTbl[i]的位值(0~7)

2.初始化函数

void OSInit (void) //初始化UCOS-II函数
{
INT16U i; //定义一个16位变量i
INT8U *prdytbl; //定义一个就绪态最高级任务列表指针

OS_TCB *ptcb1; //定义任务控制块优先级表指针1
OS_TCB *ptcb2; //定义任务控制块优先级表指针2
#if (OS_EVENT_EN > 0) && (OS_MAX_EVENTS > 1) //如果有消息事件,并且最大消息事件值>1
OS_EVENT *pevent1; //定义事件指针1
OS_EVENT *pevent2; //定义事件指针2
#endif

#if OS_VERSION >= 204 //如果版本大于2.04版
OSInitHookBegin(); //调初始化钩子函数,可加入用户代码
#endif


#if OS_TIME_GET_SET_EN > 0 //允许生成 OSTimeGet() 和 OSTimeSet() 函数代码
OSTime = 0L; //清除32的系统时钟
#endif
OSIntNesting = 0; //清除中断嵌套计数器
OSLockNesting = 0; //清除上锁嵌套计数器
OSTaskCtr = 0; //清除任务计数器
OSRunning = FALSE; //任务处于不运行状态
OSIdleCtr = 0L; //清除32位空闲任务的计数器
//允许生成OSTaskCreate()函数和OSTaskCreateExt()函数
#if (OS_TASK_STAT_EN > 0) && (OS_TASK_CREATE_EXT_EN > 0)
OSIdleCtrRun = 0L; //空闲任务计数器每秒的计数值清0
OSIdleCtrMax = 0L; //每秒空闲任务计数的最大值清0
 OSStatRdy = FALSE; //统计任务是否就绪的标志为空
 #endif
 OSCtxSwCtr = 0; //上下文切换的次数(统计任务计数器)清0
 OSRdyGrp = 0x00; //清除OSRdyTbl[i]组对应的任务就绪列表
 prdytbl = &OSRdyTbl[0];
 for (i = 0; i < OS_RDY_TBL_SIZE; i++) {
 *prdytbl++ = 0x00; //所有的就绪列表指针内容全部清0
 }

 OSPrioCur = 0; //正在运行的任务的优先级
 OSPrioHighRdy = 0; //具有最高优先级别的就绪任务的优先级
 OSTCBHighRdy = (OS_TCB *)0; //指向最高级优先级就绪任务控制块的指针清0
 OSTCBCur = (OS_TCB *)0; //指向正在运行任务控制块的指针清0
 OSTCBList = (OS_TCB *)0; //任务控制块链接表的指针清0
 //清除所有的优先级控制块优先级列表e
 for (i = 0; i < (OS_LOWEST_PRIO + 1); i++) {
 OSTCBPrioTbl[i] = (OS_TCB *)0;
 }
 ptcb1 = &OSTCBTbl[0]; //查找任务控制块列表(0)的对应地址
 ptcb2 = &OSTCBTbl[1]; //查找任务控制块列表(1)的对应地址
 //释放所有的任务控制块列表
 for (i = 0; i < (OS_MAX_TASKS + OS_N_SYS_TASKS - 1); i++) {
 ptcb1->OSTCBNext = ptcb2;
 ptcb1++;
 ptcb2++;
 }
 ptcb1->OSTCBNext = (OS_TCB *)0; //将最后的任务块双向链接表的后链接为0
 OSTCBFreeList = &OSTCBTbl[0]; //空任务控制块地址为当前任务控制块列表的首地址

 #if (OS_EVENT_EN > 0) && (OS_MAX_EVENTS > 0) //如果有消息事件,并且最大消息事件数>0
 #if OS_MAX_EVENTS == 1 //如果最大消息事件数>1
 //只能拥有单独的一个消息事件
 OSEventFreeList = &OSEventTbl[0]; //空余事件管理列表=任务等待表首地址
 OSEventFreeList->OSEventType = OS_EVENT_TYPE_UNUSED; //事件的类型=空闲
 OSEventFreeList->OSEventPtr = (OS_EVENT *)0; //消息或消息队列的指针为空
 #else
 pevent1 = &OSEventTbl[0]; //查找任务等待表(0)对应首地址
 pevent2 = &OSEventTbl[1]; //查找任务等待表(1)对应地址
 //释放所有的任务等待表,并将事件的类型=空闲
 for (i = 0; i < (OS_MAX_EVENTS - 1); i++) {
 pevent1->OSEventType = OS_EVENT_TYPE_UNUSED;
 pevent1->OSEventPtr = pevent2;
 pevent1++;
 pevent2++;
 }
 pevent1->OSEventType = OS_EVENT_TYPE_UNUSED; //首地址的事件的类型=空闲
 pevent1->OSEventPtr = (OS_EVENT *)0; //首地址的消息或消息队列的指针为空
 OSEventFreeList = &OSEventTbl[0]; //空余事件管理列表=任务等待表首地址
 #endif
 #endif
 //条件编译:UCOS版本>= 251 且 OS_FLAG_EN 允许产生事件标志程序代码 且 最大事件标志>0
 #if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
:\SOURCE中文源代码\OS_CORE.C
 OS_FlagInit(); //初始化事件标志结构
 #endif
 //条件编译:OS_Q_EN 允许 (1)产生消息队列相关代码 并且 应用中最多对列控制块的数目 > 0
 #if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
 OS_QInit(); //初始化事件队列结构
 #endif
 //条件编译:若两个条件满足时,产生以下代码
 //OS_MEM_EN允许 (1) 或者禁止 (0) 产生内存相关代码
 //OS_MAX_MEM_PART 最多内存块的数目
 #if (OS_MEM_EN > 0) && (OS_MAX_MEM_PART > 0)
 OS_MemInit(); //初始化内存块结构
 #endif

 /* ---------------------- 产生一个空闲的任务(CREATION OF 'IDLE' TASK) ----------------------- */
 #if OS_TASK_CREATE_EXT_EN > 0 // 允许生成OSTaskCreateExt()函数
 #if OS_STK_GROWTH == 1 // 堆栈生长方向向下
 // 建立扩展任务[...
 (void)OSTaskCreateExt(OS_TaskIdle, // 空闲任务
 (void *)0, // 没有(传递参数指针)
 &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1], // 分配任务堆栈栈顶指针
 OS_IDLE_PRIO, // 分配任务优先级
 OS_TASK_IDLE_ID, // (未来的)优先级标识(与优先级相同)
 &OSTaskIdleStk[0], // 分配任务堆栈栈底指针
 OS_TASK_IDLE_STK_SIZE, // 指定堆栈的容量(检验用)
 (void *)0, // 没有(指向用户附加的数据域的指针)

 OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
 #else // 建立扩展任务[... //堆栈生长方向向上
 (void)OSTaskCreateExt(OS_TaskIdle, // 空闲任务
 (void *)0, // 没有(传递参数指针)
 &OSTaskIdleStk[0], // 分配任务堆栈栈底指针
 OS_IDLE_PRIO, // 分配任务优先级
 OS_TASK_IDLE_ID, // (未来的)优先级标识(与优先级相同)
 // 分配任务堆栈栈顶指针
 &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1],
 OS_TASK_IDLE_STK_SIZE, // 指定堆栈的容量(检验用)
 (void *)0, // 没有(指向用户附加的数据域的指针)
 // 没有(指向用户附加的数据域的指针)
 OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
 #endif
 #else //否则只能生成OSTaskCreate()函数
 #if OS_STK_GROWTH == 1 // 堆栈生长方向向下
 (void)OSTaskCreate(OS_TaskIdle, // 建立任务[空闲任务、
 (void *)0, // 没有(传递参数指针)
 // 分配任务堆栈栈顶指针
 &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1],
 OS_IDLE_PRIO); // 分配任务优先级
 #else // 否则堆栈生长方向向上
 (void)OSTaskCreate(OS_TaskIdle, // 建立任务[空闲任务、
 (void *)0, // 没有(传递参数指针)
 &OSTaskIdleStk[0], // 分配任务堆栈栈底指针
 OS_IDLE_PRIO); // 分配任务优先级
 #endif
 #endif

 /* -------------------产生一个统计任务(CREATION OF 'STATISTIC' TASK) ---------------------- */
 #if OS_TASK_STAT_EN > 0
 #if OS_TASK_CREATE_EXT_EN > 0 // 允许生成OSTaskCreateExt()函数
 #if OS_STK_GROWTH == 1 // 堆栈生长方向向下
 // 建立扩展任务[...
 (void)OSTaskCreateExt(OS_TaskStat, // 产生一个统计任务
 (void *)0, // 没有(传递参数指针)
 &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1], // 分配任务堆栈栈顶指针
 OS_STAT_PRIO, // 分配任务优先级
 OS_TASK_STAT_ID, // (未来的)优先级标识(与优先级相同)
 &OSTaskStatStk[0], // 分配任务堆栈栈底指针
 OS_TASK_STAT_STK_SIZE, // 指定堆栈的容量(检验用)
 (void *)0, // 没有(指向用户附加的数据域的指针)
 OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
 #else // 建立扩展任务[... //堆栈生长方向向上
 (void)OSTaskCreateExt(OS_TaskStat, // 产生一个统计任务
 (void *)0, // 没有(传递参数指针)
 &OSTaskStatStk[0], // 分配任务堆栈栈底指针
 OS_STAT_PRIO, // 分配任务优先级
 OS_TASK_STAT_ID, // (未来的)优先级标识(与优先级相同)
 &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1], // 分配任务堆栈栈顶指针


 OS_TASK_STAT_STK_SIZE, // 指定堆栈的容量(检验用
 (void *)0, // 没有(指向用户附加的数据域的指针)
 OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
 #endif
 #else //否则只能生成OSTaskCreate()函数
 #if OS_STK_GROWTH == 1 // 堆栈生长方向向下
 (void)OSTaskCreate(OS_TaskStat, // 产生一个统计任务
 (void *)0, // 没有(传递参数指针)
 &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1], // 分配任务堆栈栈顶指针
 OS_STAT_PRIO); // 分配任务优先级
 #else // 否则堆栈生长方向向上
 (void)OSTaskCreate(OS_TaskStat, // 产生一个统计任务
 (void *)0, // 没有(传递参数指针)
 &OSTaskStatStk[0], // 分配任务堆栈栈底指针
 OS_STAT_PRIO); // 分配任务优先级
 #endif
 #endif
 #endif

 #if OS_VERSION >= 204 // 判断版本是否是大于或等于2.41版
 OSInitHookEnd(); // 调用OSInitHookEnd()钩子程序
 #endif
 }

3.中断函数正在处理

void OSIntEnter (void) //中断函数正在执行()
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif

OS_ENTER_CRITICAL(); //关闭中断
if (OSIntNesting < 255) { //如果中断嵌套小于255
OSIntNesting++; //中断嵌套计数变量加1
}
OS_EXIT_CRITICAL(); //打开中断
}

4.中断函数已经执行完成

void OSIntExit (void) //脱离中断函数
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif
OS_ENTER_CRITICAL(); //关闭中断
if (OSIntNesting > 0) { //如果中断嵌套大于0
OSIntNesting--; //中断嵌套计数变量减1
}
//1)中断嵌套层数计数器和锁定嵌套计数器(OSLockNesting)二者都必须是零
//2)OSRdyTbl[]所需的检索值Y是保存在全程变量OSIntExitY中
//3)检查具有最高优先级别的就绪任务的优先级是否是正在运行的任务的优先级
//4)将任务控制块优先级表保存到指向最高级优先级就绪任务控制块的指针
//5)上下文切换的次数(统计任务计数器)
//6)做中断任务切换
if ((OSIntNesting == 0) && (OSLockNesting == 0)) { //1)
OSIntExitY = OSUnMapTbl[OSRdyGrp]; //2)
OSPrioHighRdy = (INT8U)((OSIntExitY << 3) + OSUnMapTbl[OSRdyTbl[OSIntExitY]]);
if (OSPrioHighRdy != OSPrioCur) { //3)
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];//4
OSCtxSwCtr++; //5)
OSIntCtxSw(); //6)
}
}
OS_EXIT_CRITICAL(); //打开中断
}

5. 给调度器上锁(禁止调度)

#if OS_SCHED_LOCK_EN > 0 //允许生产OSSchedLock()函数
void OSSchedLock (void) //给调度器上锁函数
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif
if (OSRunning == TRUE) { //如果有多个任务在期待
OS_ENTER_CRITICAL(); //关闭中断
if (OSLockNesting < 255) { //上锁嵌套是否大于255
OSLockNesting++; //给上锁嵌套加1
}
OS_EXIT_CRITICAL(); //打开中断
}
}
#endif

6.给调度器解锁 (放开调度)

#if OS_SCHED_LOCK_EN > 0 //允许生产OSSchedUnlock()函数
void OSSchedUnlock (void) //给调度器解锁函数
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif

if (OSRunning == TRUE) { //如果有多个任务在期待
OS_ENTER_CRITICAL(); //关闭中断
if (OSLockNesting > 0) { //上锁嵌套是否大于0
OSLockNesting--; //给上锁嵌套减1
//如果函数不是在中断服务子程序中调用的,且调度允许的,
if ((OSLockNesting == 0) && (OSIntNesting == 0)) {
OS_EXIT_CRITICAL(); //打开中断
OS_Sched(); //进入任务调度
} else {
OS_EXIT_CRITICAL(); //打开中断
}
} else {
OS_EXIT_CRITICAL(); //打开中断
}
}
}
#endif

7.启动多个任务(首先开启最高优先级任务)

void OSStart (void) //启动多个任务
{
INT8U y;
INT8U x;

if (OSRunning == FALSE) { //OSRunning已设为“真”,指出多任务已经开始
y = OSUnMapTbl[OSRdyGrp]; //查找最高优先级别任务号码
x = OSUnMapTbl[OSRdyTbl[y]];
OSPrioHighRdy = (INT8U)((y << 3) + x); //找出就绪态最高级任务控制块
OSPrioCur = OSPrioHighRdy;
//OSPrioCur和OSPrioHighRdy存放的是用户应用任务的优先级
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSTCBCur = OSTCBHighRdy;
OSStartHighRdy(); //调用高优先级就绪任务启动函数
}
}

8.统计任务初始化(计算CPU的利用率)

#if OS_TASK_STAT_EN > 0 //允许生产OSStatInit()函数
void OSStatInit (void) //统计任务初始化
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif

OSTimeDly(2); //调用延迟函数OSTimeDly()将自身延时2个时钟节拍以停止自身的运行
//这是为了使OSStatInit()与时钟节拍同步
OS_ENTER_CRITICAL(); //关闭中断
OSIdleCtr = 0L; //执行OSStartInit()时,空闲计数器OSIdleCtr被清零
OS_EXIT_CRITICAL(); //打开中断
OSTimeDly(OS_TICKS_PER_SEC); //将自身延时整整一秒
//(因为没有其它进入就绪态的任务,OSTaskIdle()又获得了CPU的控制权)
OS_ENTER_CRITICAL(); //关闭中断
OSIdleCtrMax = OSIdleCtr; //空闲计数器将1秒钟内计数的值存入空闲计数器最大值OSIdleCtrMax中
OSStatRdy = TRUE; //将统计任务就绪标志OSStatRdy设为"真",以此来允许两个时钟节拍
//以后OSTaskStat()开始计算CPU的利用率
OS_EXIT_CRITICAL(); //打开中断
}
#endif

9.时钟节拍函数

 void OSTimeTick (void) //时钟节拍函数
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif
OS_TCB *ptcb; //定义任务控制块优先级表变量

OSTimeTickHook(); //调用户·自定义函数(钩子函数)
#if OS_TIME_GET_SET_EN > 0 //允许生成OSTimeGet() 函数代码
OS_ENTER_CRITICAL(); //关闭中断
OSTime++; //累加从开机以来的时间,用的是一个无符号32位变量
\SOURCE中文源代码\OS_CORE.C
OS_EXIT_CRITICAL(); //打开中断
#endif
ptcb = OSTCBList; //保存任务控制块列表首地址

//从OSTCBList开始,沿着OS_TCB链表做,一直做到空闲任务
while (ptcb->OSTCBPrio != OS_IDLE_PRIO) {
OS_ENTER_CRITICAL(); //关闭中断
if (ptcb->OSTCBDly != 0) { //如果任务等待时的最多节拍数不为0
if (--ptcb->OSTCBDly == 0) { //如果任务等待时的最多节拍数为0

//而确切被任务挂起的函数OSTaskSuspend()挂起的任务则不会进入就绪态
//执行时间直接与应用程序中建立了多少个任务成正比
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == 0x00) {
//当某任务的任务控制块中的时间延时项OSTCBDly减到了零,这个任务就进入了就绪态
OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
} else {
ptcb->OSTCBDly = 1; //否则
} //允许任务等待时的最多节拍数为1
}
}
ptcb = ptcb->OSTCBNext; //指向任务块双向链接表的后链接
OS_EXIT_CRITICAL(); //打开中断
}
}

10. 任务进入就绪态

#if OS_EVENT_EN > 0 //各类消息事件是否允许
//使一个任务进入就绪态
INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk)
{
OS_TCB *ptcb;
INT8U x;
INT8U y;
INT8U bitx;
INT8U bity;
INT8U prio;

//1)首先计算HPT任务在.OSEventTbl[]中的字节索引,其结果是一个从0到OS_LOWEST_PRIO/8+1之间的数
//2)并利用该索引得到该优先级任务在.OSEventGrp中的位屏蔽码
//3)判断HPT任务在.OSEventTbl[]中相应位的位置
//4)其结果是一个从0到OS_LOWEST_PRIO/8+1之间的数,以及相应的位屏蔽码
//5)根据以上结果,OSEventTaskRdy()函数计算出HPT任务的优先级
//6)然后就可以从等待任务列表中删除该任务了
y = OSUnMapTbl[pevent->OSEventGrp]; //1)
bity = OSMapTbl[y]; //2)
x = OSUnMapTbl[pevent->OSEventTbl[y]]; //3)
bitx = OSMapTbl[x]; //4)
prio = (INT8U)((y << 3) + x); //5)
if ((pevent->OSEventTbl[y] &= ~bitx) == 0x00) { //6)
pevent->OSEventGrp &= ~bity;
}
//7)任务的TCB中包含有需要改变的信息。知道了HPT任务的优先级,就可得到指向该任务的TCB的指针
//8)因为最高优先级任务运行条件已经得到满足,必须停止OSTimeTick()函数对.OSTCBDly域的递减操作,
// 所以OSEventTaskRdy()直接将该域清澈0
//9)因为该任务不再等待该事件的发生,所以本函数将其任务控制块中指向事件控制块的指针指向NULL
//10)如果OSEventTaskRdy()是由OSMboxPost()或者OSQPost()调用的,该函数还要将相应的消息传递给
// HPT,放在它的任务控制块中
ptcb = OSTCBPrioTbl[prio]; //7)
ptcb->OSTCBDly = 0; //8)
ptcb->OSTCBEventPtr = (OS_EVENT *)0; //9)
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
ptcb->OSTCBMsg = msg; //10)
#else
msg = msg;
#endif
//11)当OSEventTaskRdy()被调用时,位屏蔽码msk作为参数传递给它。该参数是用于对任务控制块中的
// 位清零的位屏蔽码,和所发生事件的类型相对应
//12)根据.OSTCBStat判断该任务是否已处于就绪状态
//13)如果是, 则将HPT插入到uC/OS-II的就绪任务列表中。注意,HPT任务得到该事件后不一定进入就绪
// 状态,也许该任务已经由于其它原因挂起了
ptcb->OSTCBStat &= ~msk; //11)
if (ptcb->OSTCBStat == OS_STAT_RDY) { //12)
OSRdyGrp |= bity; //13)
OSRdyTbl[y] |= bitx; //返回就绪态任务的优先级
}
return (prio);
}
#endif

11.使一个任务进入等待某事件发生状态

 #if OS_EVENT_EN > 0 //各类消息事件是否允许
void OS_EventTaskWait (OS_EVENT *pevent) //使一个任务进入等待某事件发生状态(ECB指针)
{ //将指向事件控制块ECB的指针放到任务的任务控制块TCB中,建立任务与事件控制块ECB之间的链接
OSTCBCur->OSTCBEventPtr = pevent;
//将任务从就绪任务表中删除
if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0x00) {
OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
}
//把该任务放到事件控制块ECB的等待事件的任务列表中
pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;
pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;
}
#endif

12.由于超时而将任务置为就绪态

#if OS_EVENT_EN > 0 //消息事件是否 > 0
void OS_EventTO (OS_EVENT *pevent) //由于超时而将任务置为就绪态(ECB指针)
{ //本函数必须从事件控制块ECB中等待任务列表中将该任务删除
if ((pevent->OSEventTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0x00) {
pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY;
}
OSTCBCur->OSTCBStat = OS_STAT_RDY; //该任务被置为就绪态
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; //从任务控制块TCB中将事件控制块ECB的指针删除
}
#endif

13.任务调度

void OS_Sched (void) //任务调度函数
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif
INT8U y; //定义一个8位整数y

OS_ENTER_CRITICAL(); //关闭中断
//如果中断嵌套次数>0,且上锁(调度器)嵌套次数>0,函退出,不做任何调度
if ((OSIntNesting == 0) && (OSLockNesting == 0)) {
//如果函数不是在中断服务子程序中调用的,且调度允许的,则任务调度函数将找出进入就绪态的
//最高优先级任务,进入就绪态的任务在就绪表中OSRdyTbl[ ]中相应位置位.
y = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
//找到最高优先级任务后,函数检查这个优先级最高的任务是否是当前正在运行的任务,以避免不
//必要的任务调度,多花时间
if (OSPrioHighRdy != OSPrioCur) {
//为实现任务切换,OSTCBHighRdy必须指向优先级最高的那个任务控制块OS_TCB,这是通过将
//以OSPrioHighRdy为下标的OSTCBPrioTbl[]数组中的那个元素赋给OSTCBHighRdy来实现的
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++; //统计计数器OSCtxSwCtr加1,以跟踪任务切换次数
OS_TASK_SW(); //最后宏调用OS_TASK_SW()来完成实际上的任务切换
}
}
OS_EXIT_CRITICAL(); //打开中断

14.空闲任务

 void OS_TaskIdle (void *pdata) //空闲任务函数(指向一个数据结构)
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif

pdata = pdata; //参数等于本身,防止一些编译器不能编译
for (;;) { //无限循环
OS_ENTER_CRITICAL(); //关闭中断
OSIdleCtr++; //32位空闲计数器加1,提供给统计任务消耗CPU事件
OS_EXIT_CRITICAL(); //打开中断
OSTaskIdleHook(); //空闲任务钩子程序
}
}

15.统计任务

#if OS_TASK_STAT_EN > 0 //允许生产OS_TaskStat()函数
void OS_TaskStat (void *pdata) //统计任务(指向一个数据结构)
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif
INT32U run; //定义一个运算变量
INT8S usage; //定义一个使用变量

pdata = pdata; //数据结构指针等于本身,防止编译器不能编译
while (OSStatRdy == FALSE) { //判断统计任务就绪标志OSStatRdy设为"假"
OSTimeDly(2 * OS_TICKS_PER_SEC); //延时2秒钟,等待统计任务做好准备
}
for (;;) { //无限循环
OS_ENTER_CRITICAL(); //关闭中断
OSIdleCtrRun = OSIdleCtr; //获得当前的空闲计数值
run = OSIdleCtr; //并保存到运算变量中,以便运算
OSIdleCtr = 0L; //空闲计数器OSIdleCtr被清零
OS_EXIT_CRITICAL(); //打开中断
if (OSIdleCtrMax > 0L) { //如果最大空闲计数值 > 0
usage = (INT8S)(100L - 100L * run / OSIdleCtrMax); 求CPU利用率
if (usage >= 0) { //不能是负的百分值
OSCPUUsage = usage; //如果是正的值,保存它
} else {
OSCPUUsage = 0; //如果是负值,设为0
}
} else { //如果最大空闲计数值不 > 0
OSCPUUsage = 0; //如果是负值,设为0
}
OSTaskStatHook(); //调用钩子函数,可添加自己的代码
OSTimeDly(OS_TICKS_PER_SEC); //调用延迟函数OSTimeDly()将自身延时1个时钟节拍以停止自身的运
}
}

16.任务控制块初始化

//初始化任务控制块TCB(优先级指针、栈顶指针、栈底指针、任务标志符、堆栈容量、扩展指针、选择项)
INT8U OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size,
void *pext, INT16U opt)
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif

OS_TCB *ptcb; //定义一个PCB变量

OS_ENTER_CRITICAL(); //关闭中断
ptcb = OSTCBFreeList; //分配一个空任务控制块给ptcb
if (ptcb != (OS_TCB *)0) { //如果缓冲池有空余TCB,这个TCB被初始化
OSTCBFreeList = ptcb->OSTCBNext; //指向TCB的双向链接的后链接
OS_EXIT_CRITICAL(); //打开中断
ptcb->OSTCBStkPtr = ptos; //指向当前TCB的栈顶指针(输入的数据)
ptcb->OSTCBPrio = (INT8U)prio; //保存当前TCB的优先级别(输入的数据)
ptcb->OSTCBStat = OS_STAT_RDY; //设定当前TCB的状态字(内容为(准备完毕))
ptcb->OSTCBDly = 0; //允许任务等待的最大字节节拍为0

#if OS_TASK_CREATE_EXT_EN > 0 //允许生成OSTaskCreateExt()函数
ptcb->OSTCBExtPtr = pext; //指向用户定义的任务控制块(扩展指针)
ptcb->OSTCBStkSize = stk_size; //设定堆栈的容量
ptcb->OSTCBStkBottom = pbos; //指向指向栈底的指针
ptcb->OSTCBOpt = opt; //保存OS_TCB的选择项
ptcb->OSTCBId = id; //保存任务标志符
#else //否则使用旧的参数
pext = pext; //扩展指针
stk_size = stk_size; //堆栈的容量
pbos = pbos; //栈底的指针
opt = opt; //选择项
id = id; //任务标志符
#endif


#if OS_TASK_DEL_EN > 0 //允许生成 OSTaskDel() 函数代码函数
ptcb->OSTCBDelReq = OS_NO_ERR; //如果可以删除任务本身,可以从每个
//OS_TCB中节省出一个布尔量
#endif
//对一些参数提前运算,为了节省CPU的操作事件
ptcb->OSTCBY = prio >> 3;
ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY];
ptcb->OSTCBX = prio & 0x07;
ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX];


#if OS_EVENT_EN > 0 //如果不打算在应用程序中使用各类事件
ptcb->OSTCBEventPtr = (OS_EVENT *)0; //OS_TCB中OSTCBEventPt就不会出现
#endif //针对的事件为信号量,互斥型信号量、消息邮箱、消息队列
//当满足 版本大于2.51 且 事件标志允许 且 有最大事件标志 及 允许删除任务
#if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) && (OS_TASK_DEL_EN > 0)
ptcb->OSTCBFlagNode = (OS_FLAG_NODE *)0;//则向事件标志节点的指针被初始化为空指针
#endif

#if (OS_MBOX_EN > 0) || ((OS_Q_EN > 0) && (OS_MAX_QS > 0))
ptcb->OSTCBMsg = (void *)0; //满足以上条件,指向传递给任务的消息指针为0空指针
#endif

#if OS_VERSION >= 204 //如果版本大于2.04
OSTCBInitHook(ptcb); //允许使用OSTCBInitHook(ptcb)函数,可对其加代码
#endif //主要增加OS_TCB扩展,浮点运算、MMU寄存器、与任务相关内容,调用此程序时中断开着的

OSTaskCreateHook(ptcb); //调用户建立任务钩子程序
//该函数能够扩展[OSTaskCreate()或OSTaskCreateExt()函数]
//当OS_CPU_HOOKS_EN为1时,OSTaskCreateHook()可以在OS_CPU.C中定义
//若OS_CPU_HOOKS_EN为0时,则可以在任何其它地方定义
//调用此程序时中断开着的。
OS_ENTER_CRITICAL();
OSTCBPrioTbl[prio] = ptcb;
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); //调用成功,最后让此函数返回到调用函数[OSTaskCreate()或
} //OSTaskCreateExt()函数],返回值表示分配到任务控块,并初始化了
OS_EXIT_CRITICAL(); //打开中断
return (OS_NO_MORE_TCB); //没有更多的任务控制块被分配,将无法创建新的任务
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值