原型出自内核OS_CORE.C
//统计任务的初始化
#if OS_TASK_STAT_EN > 0
void OSStatInit (void)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
//调用这个函数要注意,主要原因就是因为在OSStatInit()中调用OSTimeDly发生了任务的调度,而这一点特别容易被忽略掉
//ucosii时钟频率200hz,即1m 200个ticks时钟节拍
//延时2个ticks,也就是2/200=10ms
OSTimeDly(2); /* Synchronize with clock tick */
OS_ENTER_CRITICAL();
OSIdleCtr = 0L; /* Clear idle counter */
OS_EXIT_CRITICAL();
OSTimeDly(OS_TICKS_PER_SEC); /* Determine MAX. idle counter value for 1 second */
OS_ENTER_CRITICAL();
OSIdleCtrMax = OSIdleCtr; /* Store maximum idle counter count in 1 second */
OSStatRdy = TRUE;
OS_EXIT_CRITICAL();
}
#endif
原型出自OS_TIME.C
//uC/OS-Ⅱ提供了这样一个系统服务:申请该服务的任务可以延时一段时间,这段时间的长短是用时钟节拍的数目来确定的.
//实现这个系统服务的函数叫做OSTimeDly().调用该函数会使uC/OS-Ⅱ进行一次任务调度,并且执行下一个优先级最高的就绪态任务.
//任务调用OSTimeDly()后,一旦规定的时间期满或者有其它的任务通过调用OSTimeDlyResume()取消了延时,它就会马上进入就绪状态.
//注意,只有当该任务在所有就绪任务中具有最高的优先级时,它才会立即运行
void OSTimeDly (INT16U ticks)//延迟指定时钟节拍
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
/*
任务控制块中定义的
优先级低3位,即prio&0x07
INT8U OSTCBX; /* Bit position in group corresponding to task priority (0..7) */
优先级高3位,即prio>>3
INT8U OSTCBY; /* Index into ready table corresponding to task priority */
OSMapTbl[prio&0x07],任务所在的列OSRdyTbl[OSTCBY]
INT8U OSTCBBitX; /* Bit mask to access bit position in ready table */
OSMapTbl[prio>>3],任务所在的组OSRdyGrp
INT8U OSTCBBitY; /* Bit mask to access bit position in ready group */
//优先级位图
extern INT8U const OSMapTbl[]; /* Priority->Bit Mask lookup table */
//优先级索引
extern INT8U const OSUnMapTbl[]; /* Priority->Index lookup table */
*/
if (ticks > 0) { /* 0 means no delay! */
OS_ENTER_CRITICAL();
//确定为当前任务延时
if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { /* Delay current task */
//从就绪队列中剔除当前任务.对相应的行号取反相与,即清除任务
OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
}
//这个延时节拍数会被保存在当前任务的OS_TCB中,并且通过OSTimeTick()每隔一个时钟节拍就减少一个延时节拍数.
OSTCBCur->OSTCBDly = ticks; /* Load ticks in TCB */
OS_EXIT_CRITICAL();
//最后,既然任务已经不再处于就绪状态,任务调度程序会执行下一个优先级最高的就绪任务
//执行任务级调度
OS_Sched(); /* Find next task to run! */
}
}
//在延时函数中,会取消任务的就绪状态而进入延时等待状态,调用OSSched()函数实现任务的调度,实现处理器使用权的让出
原型出自内核OS_CORE.C
//uC/OS-II有两种任务调度器:任务级的调度器和中断级的调度器.
//任务级的调度器由函数OSSched()来实现;中断级的调度器由函数OSIntExit()来实现
void OS_Sched (void)//其职责就是寻找优先级别最高的就绪任务作为待运行任务
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
INT8U y;
OS_ENTER_CRITICAL();
if ((OSIntNesting == 0) && (OSLockNesting == 0)) { /* Sched. only if all ISRs done & not locked */
//获得最高优先级行号-与任务多少无关,总是找到最高优先级行号
/*
OSUnMapTbl[]共0xFF个元素,0x00~0xFF为索引,而OSUnMapTbl[]里的值就是通过分析索引得到的.
eg:索引0x50,二进制表示为0101 0000,然后从右边数,看第几位首先为1,则OSUnMapTbl[0x50]的值就为几.0101 0000从右起,第4位首先为1,所以有OSUnMapTbl[0x50]=4
eg:索引0x51,二进制为0101 0001,右起第0位为1,所以OSUnMapTbl[0x51]=0
优先级是从右至左,从上至下越来越低的,最低优先级给了空闲任务.
*/
y = OSUnMapTbl[OSRdyGrp]; /* Get pointer to HPT ready to run */
/*
OSRdyTbl[OSRdyGrp]通过行号找到最高优先级任务
原理同上
*/
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++; /* Increment context switch counter */
//任务切换宏OS_CPU.H中定义
//#define OS_TASK_SW() asm INT uCOS
//通过用户设置的软中断0x80进入任务切换
/*
1. 任务切换都做了哪些事情:CPU寄存器内容切换.
2. ucos实现任务切换的方法:“通过执行软中断指令,或者依据处理器的不同,执行TRAP(陷阱)指令来实现的.
3. 为什么要通过”软中断“呢?通常的,处理器支持2种模式对应2种权限:用户级和特权级.”以提供一种存储器访问的保护机制,使得普通的用户程序不能意外地,甚至是恶意地执行涉及要害的操作.
简言之:任务A切换到B时需要保存cpu的”现场数据“使系统能够返回A;同时需要加载B的”现场数据“到cpu中,以使B回到被切换时的状态.而只有cpu的特权模式允许上述操作,由用户级进入特权级的惟一途径是触发异常(或中断).
*/
OS_TASK_SW(); /* Perform a context switch */
}
}
OS_EXIT_CRITICAL();
}