来自:http://blog.youkuaiyun.com/michaelyue526/article/details/8443796
时间管理服务函数是以系统节拍为处理单位的,实际的时间与希望的时间是有误差的,最坏的情况下误差接近一个系统节拍。因此时间管理服务函数只能用在对时间精度要求不高的场合,或者时间间隔较长的场合。
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]; //空任务控制块地址为当前任务控制块列表的首地址
- }