时间管理服务函数是以系统节拍为处理单位的,实际的时间与希望的时间是有误差的,最坏的情况下误差接近一个系统节拍。因此时间管理服务函数只能用在对时间精度要求不高的场合,或者时间间隔较长的场合。
1. void OSSchedLock(void);
void OSSchedLock (void)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
if (OSRunning == OS_TRUE) { /* Make sure multitasking is running */
OS_ENTER_CRITICAL();
if (OSIntNesting == 0) { /* Can't call from an ISR */
if (OSLockNesting < 255u) { /* Prevent OSLockNesting from wrapping back to 0 */
OSLockNesting++; /* Increment lock nesting level */
}
}
OS_EXIT_CRITICAL();
}
}
这个函数又叫上锁函数,如果在一个任务里面调用了上锁函数,那么OSSched()这个任务切换函数就不会执行也就是说不会进任务调度。
调用OSSchedLock()以后,用户的应用程序不得使用任何能将现行任务挂起的系统调用。也就是说,用户程序不得调用OSMboxPend()、OSQPend()、OSSemPend()、OSTaskSuspend(OS_PR1O_SELF)、OSTimeDly()或OSTimeDlyHMSM(),直到OSLockNesting回零为止。因为调度器上了锁,用户就锁住了系统,任何其它任务都不能运行。
但是上锁了任务是可以中断,若任务遇到中断,则中断函数的执行会为OSIntNesting变量加1,当中断返回时又要判断OSLockNesting是否为0,如果不为0说明系统仍被锁,直接退出中断。如果OSLockNesting为0说明系统未被锁,CPU进入任务就绪表查找优先级最高的任务。所以上锁函数执行后,CPU一直处于当前任务与中断服务函数之间的运行,直到解锁函数将OSLockNesting和OSIntNesting的值减到0时,方可解除系统锁定。
OSSchedUnlock() 取消函数上锁。
2.void
OSTimeDly (INT16U ticks);
void
OSTimeDly (INT16U ticks)
{
INT8U y;
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
if (OSIntNesting > 0) { /* See if trying to call from an ISR */
return;
}
if (ticks > 0) { /* 0 means no delay! */
OS_ENTER_CRITICAL();
y = OSTCBCur->OSTCBY; /* Delay current task */
OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;
if (OSRdyTbl[y] == 0) {
OSRdyGrp &= ~OSTCBCur->OSTCBBitY; /*取消当前任务的就绪状态
}
OSTCBCur->OSTCBDly = ticks; /* 延时节拍数存入任务控制块TCB */
OS_EXIT_CRITICAL();
OS_Sched(); /* 调度函数 */
}
}
将一个任务延时若干个时钟节拍。如果延时时间大于0,系统将立即进行任务调度。延时时间的长度可从0到65535个时钟节拍。延时时间0表示不进行延时,函数将立即返回调用者。延时的具体时间依赖于系统每秒钟有多少时钟节拍(由文件OS_CFG.H中的常量OS_TICKS_PER_SEC设定):
#define OS_TICKS_PER_SEC 1000
调用该函数会使uCOS-II进行一次任务调度,并且执行下一个优先级最高的就绪态任务。任务调用OSTimeDly()后,一旦规定的时间期满或者有其它的任务通过调用OSTimeDlyResume()取消了延时,它就会马上进入就绪状态。注意,只有当该任务在所有就绪任务中具有最高的优先级时,它才会立即运行。
3.INT8U
OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U ms);
这个函数是以小时(H)、分(M)、秒(S)和毫秒(m)四个参数来定义延时时间的,函数在内部把这些参数转换为时钟节拍,再通过单次或多次调用OSTimeDly()进行延时和任务调度,所以延时原理和调用延时函数OSTimeDly()是一样的。
4.INT8U
OS_TCBInit(INT8U
prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt);
任务控制块初始化
描述:这个函数是uCOS-II内部函数,在建立任务时调用的初始化任务控制块OS_TCB函数,含7个参数,查看OSTaskCreate()和OSTaskCreateExt()
初始化任务控制块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
-
-
ptcb->OSTCBY = prio >> 3; //对一些参数提前运算,为了节省CPU的操作事件
-
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中OSTCBEventPtr就不会出现
-
#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); //调用户建立任务钩子程序
-
-
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; /* Make task ready to run */
-
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
-
OS_EXIT_CRITICAL(); //打开中断
-
return (OS_NO_ERR); //调用成功,最后让此函数返回到调用函数[OSTaskCreate()或OSTaskCreateExt()函数],
-
//返回值表示分配到任务控块,并初始化了
-
}
-
OS_EXIT_CRITICAL(); //打开中断
-
return (OS_NO_MORE_TCB); //没有更多的任务控制块被分配,将无法创建新的任务
-
}
5.INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio);
-
//建立一个新任务
-
#if OS_TASK_CREATE_EN > 0 //允许生成OSTaskCreate()函数
-
INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio)
-
{
-
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
-
OS_CPU_SR cpu_sr;
-
#endif
-
OS_STK *psp; //初始化任务堆栈指针变量,返回新的栈顶指针
-
INT8U err; //定义(获得并定义初始化任务控制块)是否成功
-
-
-
#if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内
-
if (prio > OS_LOWEST_PRIO) { //检查任务优先级是否合法
-
return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO
-
}
-
#endif
-
OS_ENTER_CRITICAL(); //关闭中断
-
if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { //确认优先级未被使用,即就绪态为0
-
OSTCBPrioTbl[prio] = (OS_TCB *)1; //保留这个优先级,将就绪态设为1
-
-
OS_EXIT_CRITICAL(); //打开中断
-
psp = (OS_STK *)OSTaskStkInit(task, pdata, ptos, 0); //初始化任务堆栈
-
err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0); //获得并初始化任务控制块
-
if (err == OS_NO_ERR) { //任务控制初始化成功
-
OS_ENTER_CRITICAL(); //关闭中断
-
OSTaskCtr++; //任务计数器加1
-
OS_EXIT_CRITICAL(); //打开中断
-
if (OSRunning == TRUE) { //检查是否有(某个)任务在运行
-
OS_Sched(); //任务调度,最高任务优先级运行
-
}
-
} else { //否则,任务初始化失败
-
OS_ENTER_CRITICAL(); //关闭中断
-
OSTCBPrioTbl[prio] = (OS_TCB *)0; //放弃任务,设此任务就绪态为0
-
OS_EXIT_CRITICAL(); //打开中断
-
}
-
return (err); //返回(获得并定义初始化任务控制块是否成功)
-
}
-
OS_EXIT_CRITICAL(); //打开中断
-
return (OS_PRIO_EXIST); //返回(具有该优先级的任务已经存在)
-
}
-
#endif
6.static void OS_InitTaskStat (void)
;
-
//创建统计任务
-
#if OS_TASK_STAT_EN > 0
-
static void OS_InitTaskStat (void)
-
{
-
#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); /* Enable stack checking + clear */
-
#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); /* Enable stack checking + clear */
-
#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
7.static void OS_InitTCBList (void);
-
//初始化空闲TCB链表
-
static void OS_InitTCBList (void)
-
{
-
INT8U i;
-
OS_TCB *ptcb1;
-
OS_TCB *ptcb2;
-
-
-
OSTCBList = (OS_TCB *)0; //任务控制块链接表的指针清0
-
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]; //空任务控制块地址为当前任务控制块列表的首地址
-
}