OS_SchedNew(void)找到将要运行的最高优先级任务函数
和任务调度函数OS_Sched(void):
/*
*********************************************************************************************************
* FIND HIGHEST PRIORITY TASK READY TO RUN
* 找到将要运行的最高优先级任务
* Description: This function is called by other uC/OS-II services to determine the highest priority task
* that is ready to run. The global variable 'OSPrioHighRdy' is changed accordingly.
*描述: 该功能被其他服务调用,用来决定将要运行的最高优先级任务是什么。全局变量OSPrioHighRdy相应改变。
* Arguments : none
*参数:无
* Returns : none
*返回值:无
* Notes : 1) This function is INTERNAL to uC/OS-II and your application should not call it.
* 2) Interrupts are assumed to be disabled when this function is called.
注释: 1)该功能是内部函数,你的应用程序不能调用。
2)当这个功能被调用的时候不能被中断(原子函数)
*********************************************************************************************************
*/
static void OS_SchedNew(void) /*找到将要被调度的任务*/
{
#if OS_LOWEST_PRIO <= 63u /*优先级<=63,支持64位任务*/
INT8U y;
y = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((y << 3u) + OSUnMapTbl[OSRdyTbl[y]]);/*计算最高优先级任务的优先级*/
#else /* We support up to 256 tasks支持256个任务 */
INT8U y;
OS_PRIO *ptbl; /*ptb1是指向事件控制块的指针*/
if ((OSRdyGrp & 0xFFu) != 0u) /*如果就绪组不为0*/
{
y = OSUnMapTbl[OSRdyGrp & 0xFFu]; /*y为在表中查到的数*/
}
else {
y = OSUnMapTbl[(OS_PRIO)(OSRdyGrp >> 8u) & 0xFFu] + 8u;/*将y置为8*/
}
ptbl = &OSRdyTbl[y];
if ((*ptbl & 0xFFu) != 0u) /*计算出优先级*/
{
OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(*ptbl & 0xFFu)]);
}
else
{
OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(OS_PRIO)(*ptbl >> 8u) & 0xFFu] + 8u);
}
#endif
}
/*$PAGE*/
/*2018/2/8
*********************************************************************************************************
* SCHEDULER
* 调度
* Description: This function is called by other uC/OS-II services to determine whether a new, high
* priority task has been made ready to run. This function is invoked by TASK level code
* and is not used to reschedule tasks from ISRs (see OSIntExit() for ISR rescheduling).
*描述:该功能被其他服务调用,用来决定是否一个新的、高优先级任务已经准备好运行了。任务级的调度是由函数OSSched()完成的。
中断级的调度是由另一个函数OSIntExt()完成的).
* Arguments : none
*参数:无
* Returns : none
*返回值:无
* Notes : 1) This function is INTERNAL to uC/OS-II and your application should not call it.
* 2) Rescheduling is prevented when the scheduler is locked (see OS_SchedLock())
注释: 1)该功能为内部函数,你的应用程序不能调用
2) 给调度器上锁用于禁止任务调度 (查看 OSSchedLock()函数)
*********************************************************************************************************
*/
void OS_Sched(void) /*任务调度函数*/
{
#if OS_CRITICAL_METHOD == 3u /*中断函数被设定为模式3*/
OS_CPU_SR cpu_sr = 0u;
#endif
OS_ENTER_CRITICAL(); /*关中断*/
if (OSIntNesting == 0u) { /*如果所有的中断都完成了 */
if (OSLockNesting == 0u) { /* 并且调度器没有被锁 */
OS_SchedNew(); /*找到要运行的任务*/
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; /*为实现任务切换,OSTCBHighRdy必须指向优先级最高的那个任务控制块OS_TCB,
这是通过将以OSPrioHighRdy为下标的OSTCBPrioTbl[]数组中的那个元素赋给OSTCBHighRdy来实现的*/
if (OSPrioHighRdy != OSPrioCur) { /*找到最高优先级任务后,函数检查这个优先级最高的任务是否是当前正在运行的任务,
以避免不必要的任务调度,多花时间*/
#if OS_TASK_PROFILE_EN > 0u
OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */
#endif
OSCtxSwCtr++; /*任务切换计数值加1,统计切换次数 */
OS_TASK_SW(); /*进行实际的任务交换 */
}
}
}
OS_EXIT_CRITICAL(); /*开中断*/
}
这两个函数中让人费解的还是计算优先级那一块。回头看了(9)中介绍的有关知识,感觉描述的还是不够清楚。有时间重新梳理一下,尽量描述详尽。
OS_StrLen(INT8U *psrc)确定一个ASCII字符串的长度的函数:
/*$PAGE*/
/*2018/2/8
*********************************************************************************************************
* DETERMINE THE LENGTH OF AN ASCII STRING
* 确定一个ASCII字符串的长度
* Description: This function is called by other uC/OS-II services to determine the size of an ASCII string
* (excluding the NUL character).
*描述:该功能被其他服务调用,用来确定一个ASCII字符串的长度,包括最后的null字符。
* Arguments : psrc is a pointer to the string for which we need to know the size.
*参数: --psrc指向字符串
* Returns : The size of the string (excluding the NUL terminating character)
*返回值: 返回字符串的大小(包括最后空终止字符)。
* Notes : 1) This function is INTERNAL to uC/OS-II and your application should not call it.
* 2) The string to check must be less than 255 characters long.
注释: 1)该功能是内部函数,你的应用程序不能调用它;
2)要确定的字符串必须小于255字符。
*********************************************************************************************************
*/
#if (OS_EVENT_NAME_EN > 0u) || (OS_FLAG_NAME_EN > 0u) || (OS_MEM_NAME_EN > 0u) || (OS_TASK_NAME_EN > 0u) || (OS_TMR_CFG_NAME_EN > 0u)
INT8U OS_StrLen(INT8U *psrc)
{
INT8U len;
len = 0u; /*刚开始初始化len为0*/
while (*psrc != OS_ASCII_NUL) /*字符串没有到结尾*/
{
psrc++; /*指针后移*/
len++; /*长度加1*/
}
return (len); /*返回长度len*/
}
#endif
这个函数不需要多说。
OS_TaskIdle(void *p_arg)空闲任务函数:
/*$PAGE*/
/*2018/2/8
*********************************************************************************************************
* IDLE TASK
* 空闲任务
* Description: This task is internal to uC/OS-II and executes whenever no other higher priority tasks
* executes because they are ALL waiting for event(s) to occur.
*描述: 这个函数是uC/OS-II内部函数,uC/OS-II总要建立一个空闲任务,这个任务在没有其它任务进入就绪态时投入运行。
这个空闲任务永远设为最低优先级,即OS_LOWEST_PRIO.空闲任务不可能被应用软件删除。
* Arguments : none
*参数:无
* Returns : none
*返回值:无
* Note(s) : 1) OSTaskIdleHook() is called after the critical section to ensure that interrupts will be
* enabled for at least a few instructions. On some processors (ex. Philips XA), enabling
* and then disabling interrupts didn't allow the processor enough time to have interrupts
* enabled before they were disabled again. uC/OS-II would thus never recognize
* interrupts.
* 2) This hook has been added to allow you to do such things as STOP the CPU to conserve
* power.
注释:1)OSTaskIdleHook()......(自行百度)
2)让CPU执行STOP指令,从而进入低功耗模式,当应用系统由电池供电时,这种方式特别有用。
*********************************************************************************************************
*/
void OS_TaskIdle(void *p_arg)
{
#if OS_CRITICAL_METHOD == 3u /* 中断号设置为3 */
OS_CPU_SR cpu_sr = 0u;
#endif
p_arg = p_arg; /*赋值给自己本身,防止编译器出现错误*/
for (;;) {
OS_ENTER_CRITICAL(); /*关中断*/
OSIdleCtr++; /*空闲任务数量加1*/
OS_EXIT_CRITICAL(); /*开中断*/
OSTaskIdleHook(); /* 调用用户自定义的钩子函数 */
}
}
空闲任务函数主要是统计空闲任务数量,调用用户自定义的钩子函数。
OS_TaskStatStkChk(void)检查所有的任务堆栈函数:
/*$PAGE*/
/*2018/2/9
*********************************************************************************************************
* CHECK ALL TASK STACKS
* 检查所有的任务堆栈
* Description: This function is called by OS_TaskStat() to check the stacks of each active task.
*描述:该功能被OS_TaskStat()统计任务调用,用来家产每个活跃的任务的堆栈
* Arguments : none
*参数:无
* Returns : none
返回值:无
*********************************************************************************************************
*/
#if (OS_TASK_STAT_STK_CHK_EN > 0u) && (OS_TASK_CREATE_EXT_EN > 0u)
void OS_TaskStatStkChk(void)
{
OS_TCB *ptcb;
OS_STK_DATA stk_data;
INT8U err;
INT8U prio;
for (prio = 0u; prio <= OS_TASK_IDLE_PRIO; prio++)
{
err = OSTaskStkChk(prio, &stk_data); /*检测任务是否有问题*/
if (err == OS_ERR_NONE) /*如果没问题*/
{
ptcb = OSTCBPrioTbl[prio]; /*从优先级为0的任务开始检查*/
if (ptcb != (OS_TCB *)0)
{
if (ptcb != OS_TCB_RESERVED) /*确定任务是有效任务*/
{
#if OS_TASK_PROFILE_EN > 0u
#if OS_STK_GROWTH == 1u/*向下增长方式,就是从高地址向低地址增长,栈顶在高地址端。*/
ptcb->OSTCBStkBase = ptcb->OSTCBStkBottom + ptcb->OSTCBStkSize;/*改变栈底指针位置*/
#else
ptcb->OSTCBStkBase = ptcb->OSTCBStkBottom - ptcb->OSTCBStkSize;/*改变栈底指针位置*/
#endif
ptcb->OSTCBStkUsed = stk_data.OSUsed; /* 存储已经使用的字节数*/
#endif
}
}
}
}
}
#endif
上面的:
OS_STK_DATA stk_data;
这个语句中,解释一下OS_STK_DATA结构体,方便大家理解:
/*
*2018/1/30
*********************************************************************************************************
* TASK STACK DATA
* 任务堆栈数据
*********************************************************************************************************
*/
#if OS_TASK_CREATE_EXT_EN > 0u
typedef struct os_stk_data {
INT32U OSFree; /* Number of free bytes on the stack 堆栈中未使用的字节数 */
INT32U OSUsed; /* Number of bytes used on the stack 堆栈中已使用的字节数 */
} OS_STK_DATA;
#endif
OS_TaskStat(void *p_arg)统计任务函数:
/*$PAGE*/
/*2018/2/8
*********************************************************************************************************
* STATISTICS TASK
* 统计任务
* Description: This task is internal to uC/OS-II and is used to compute some statistics about the
* multitasking environment. Specifically, OS_TaskStat() computes the CPU usage.
* CPU usage is determined by:
*描述:这个任务是uc/os-ii内部任务,并且被用来计算一些关于多任务环境的统计数据。最关键的是用OS_TaskStat()函数计算CPU的使用率
* OSIdleCtr
* OSCPUUsage = 100 * (1 - ------------) (units are in %)
* OSIdleCtrMax
* cpu的使用率=100*(1-空闲任务数/设定的空闲任务总数)
* Arguments : parg this pointer is not used at this time.
*参数: --parg:这个时候不使用parg
* Returns : none
*返回值: 无
* Notes : 1) This task runs at a priority level higher than the idle task. In fact, it runs at the
* next higher priority, OS_TASK_IDLE_PRIO-1.
* 2) You can disable this task by setting the configuration #define OS_TASK_STAT_EN to 0.
* 3) You MUST have at least a delay of 2/10 seconds to allow for the system to establish the
* maximum value for the idle counter.
注释: 1) uC/OS-II已经将空闲任务的优先级设为最低,即OS_LOWEST_PR10,统计任务的优先级设为次低,OS_LOWEST_PR10-1.
2)你可以通过设置配置禁用该任务 #define OS_TASK_STAT_EN to 0.
3)你必须有至少0.2s(2个时钟节拍)的延迟来使系统能够为空闲任务计数器设置最大值
*********************************************************************************************************
*/
#if OS_TASK_STAT_EN > 0u
void OS_TaskStat(void *p_arg) /*任务统计函数*/
{
#if OS_CRITICAL_METHOD == 3u /*将中断类型设置为3*/
OS_CPU_SR cpu_sr = 0u;
#endif
p_arg = p_arg; /*自己给自己赋值,防止编译出现错误*/
while (OSStatRdy == OS_FALSE) /*如果统计任务状态不是就绪的,通过延迟函数OSTimeDly()等待*/
{
OSTimeDly(2u * OS_TICKS_PER_SEC / 10u); /* Wait until statistic task is ready*/
}
OSIdleCtrMax /= 100uL; /*将最大空闲计数值对100求整*/
if (OSIdleCtrMax == 0uL) /*如果最大空闲计数值为0*/
{
OSCPUUsage = 0u; /*CPU使用率为0*/
#if OS_TASK_SUSPEND_EN > 0u /*如果允许任务挂起*/
(void)OSTaskSuspend(OS_PRIO_SELF);/*调用任务挂起函数(参数为自身的优先级)*/
#else /*不允许任务挂起*/
for (;;)
{
OSTimeDly(OS_TICKS_PER_SEC); /*就通过延迟函数进行等待*/
}
#endif
}
for (;;)
{
OS_ENTER_CRITICAL(); /*关中断*/
OSIdleCtrRun = OSIdleCtr; /*将此时统计的空闲计数值赋给OSIdleCtrRun这个临时变量*/
OSIdleCtr = 0uL; /*将OSIdleCtr重新设置为0,然后进行下一秒钟的计数*/
OS_EXIT_CRITICAL(); /*开中断*/
OSCPUUsage = (INT8U)(100uL - OSIdleCtrRun / OSIdleCtrMax); /*计算CPU的使用率*/
OSTaskStatHook(); /*执行用户自定义的钩子函数*/
#if (OS_TASK_STAT_STK_CHK_EN > 0u) && (OS_TASK_CREATE_EXT_EN > 0u)
OS_TaskStatStkChk(); /*任务堆栈检测*/
#endif
OSTimeDly(OS_TICKS_PER_SEC / 10u); /*调用延迟函数OSTimeDly()将自身延时1个时钟节拍以停止自身的运行*/
}
}
#endif
在这个函数中想解释一下几点:
1.任务统计函数中最主要的几个语句是:
OSIdleCtrMax /= 100uL; /*将最大空闲计数值对100求整*/
OSIdleCtrRun = OSIdleCtr; /*将此时统计的空闲计数值赋给OSIdleCtrRun这个临时变量*/
OSIdleCtr = 0uL; /*将OSIdleCtr重新设置为0,然后进行下一秒钟的计数*/
OSCPUUsage = (INT8U)(100uL - OSIdleCtrRun / OSIdleCtrMax); /*计算CPU的使用率*/
2.在这个函数中:解释一下下面这个语句:
OSIdleCtrMax /= 100uL; /*将最大空闲计数值对100求整*/
大家可能看到这个语句时和我有着同样的疑问:为什么要对100取整?有什么必要性?
这里将最大值除以100是为了之后的计算。若是不除100,根据前面提到的公式来的话, OSIdleCtr / OSIdleCtrMax这里我们希望得到的是一个浮点数,也就是一个小于1的小数,但是因为OSIdleCtr、OSIdleCtrMax 都是整数,且OSIdleCtr < OSIdleCtrMax,则两个数相除就必定为0,则OSCPUUsage 始终会等于100。所以先OSIdleCtrMax /100,然后再OSIdleCtrRun / OSIdleCtrMax,这个结果就不会是一个小于0的数,这个时候就不会出现始终等于0的情况 。同时在算数逻辑上100 - OSIdleCtrRun / OSIdleCtrMax=100 -OSIdleCtrRun *100/ OSIdleCtrMax = 100(1 -OSIdleCtrRun / OSIdleCtrMax )。这样计算能够接近数学运算的结果。
3.第三个关于这个函数的疑问是:在for循环最后的一行语句:
OSTimeDly(OS_TICKS_PER_SEC / 10u); /*调用延迟函数OSTimeDly()将自身延时1个时钟节拍以停止自身的运行*/
我们知道这个语句是延迟函数。但是这里为什么要用呢?
实际上,OSTimeDly()函数可以看作一个延时函数,但是它真正的内涵是将CPU让给其他的任务。将自身的任务延时,在OSTimeDly(Ticks)这段时间内调用OS_Sched()函数找出任务就绪列表中优先级最高的任务并将当前CPU切换到该任务。
关于这个函数就介绍到这里。
OS_TCBInit(INT8U prio, OS_STK *ptos,OS_STK *pbos,INT16U id,INT32U stk_size,void *pext,INT16U opt)
初始化TCB函数:
/*$PAGE*/
/*2018/2/9
*********************************************************************************************************
* INITIALIZE TCB
* 初始化TCB
* Description: This function is internal to uC/OS-II and is used to initialize a Task Control Block when
* a task is created (see OSTaskCreate() and OSTaskCreateExt()).
*描述:该功能是内部函数,当有任务被创建时(详情见OSTaskCreate()函数和OSTaskCreateExt()函数),该函数被用来初始化任务控制块,
* Arguments : prio is the priority of the task being created
*参数: --prio是被创建任务的优先级
* ptos is a pointer to the task's top-of-stack assuming that the CPU registers
* have been placed on the stack. Note that the top-of-stack corresponds to a
* 'high' memory location is OS_STK_GROWTH is set to 1 and a 'low' memory
* location if OS_STK_GROWTH is set to 0. Note that stack growth is CPU
* specific.
* --ptos:假设CPU寄存器被堆栈占用,ptos就是指向栈顶的指针。
注意:如果内存增长方式被设定为1(从高地址到低地址),那么ptos(栈顶)指向的是高地址;
相反,如果增长方式被设定为0(从低地址到高地址),那么ptos(栈顶)指向的是低地址。
具体是什么增长方式取决于不同的CPU
* pbos is a pointer to the bottom of stack. A NULL pointer is passed if called by
* 'OSTaskCreate()'.
* --pbos:指向栈底的指针。如果是使用OSTaskCreate()创建任务,pbos被设定为null空。
* id is the task's ID (0..65535)
* --id是栈的ID号
* stk_size is the size of the stack (in 'stack units'). If the stack units are INT8Us
* then, 'stk_size' contains the number of bytes for the stack. If the stack
* units are INT32Us then, the stack contains '4 * stk_size' bytes. The stack
* units are established by the #define constant OS_STK which is CPU
* specific. 'stk_size' is 0 if called by 'OSTaskCreate()'.
* --stk_size:是栈的大小(或者准确讲师栈单元的大小)。
如果栈单元是8位的,stk_size值得就是8位可以表示的字节大小(2的8次方字节)。
如果栈单元室32位的,这个栈就有4*stk_size字节这么大。
栈单元是通过 #define constant OS_STK来定义的。与CPU类型相关
* pext is a pointer to a user supplied memory area that is used to extend the task
* control block. This allows you to store the contents of floating-point
* registers, MMU registers or anything else you could find useful during a
* context switch. You can even assign a name to each task and store this name
* in this TCB extension. A NULL pointer is passed if called by OSTaskCreate().
* --pext扩展指针:指向用户可使用的内存单元,该内存单元是为了扩大任务控制块。
这样可以存储浮点数寄存器、MMU寄存器或者其他在上下文交换时可用的寄存器中的内容。
甚至可以设定每个任务的名称,并将该名称存储在TCB扩展中。
* opt options as passed to 'OSTaskCreateExt()' or,
* 0 if called from 'OSTaskCreate()'.
* --opt:如果是OSTaskCreateExt()调用,代表OS_TCB的选择项,如果是OSTaskCreate()调用,opt为0
* Returns : OS_ERR_NONE if the call was successful
* OS_ERR_TASK_NO_MORE_TCB if there are no more free TCBs to be allocated and thus, the task cannot
* be created.
*返回值:OS_ERR_NONE:调用成功返回该值
OS_ERR_TASK_NO_MORE_TCB:如果没有空闲的TCB了,任务不能被创建,返回该值
* Note : This function is INTERNAL to uC/OS-II and your application should not call it.
注释: 该功能是内部函数,你的应用程序不能调用
*********************************************************************************************************
*/
INT8U OS_TCBInit(INT8U prio,
OS_STK *ptos,
OS_STK *pbos,
INT16U id,
INT32U stk_size,
void *pext,
INT16U opt)
{
OS_TCB *ptcb; /*指向TCB的指针*/
#if OS_CRITICAL_METHOD == 3u /*将中断类型设置为3*/
OS_CPU_SR cpu_sr = 0u;
#endif
#if OS_TASK_REG_TBL_SIZE > 0u
INT8U i;
#endif
OS_ENTER_CRITICAL(); /*关中断*/
ptcb = OSTCBFreeList; /*ptcb指针指向空闲TCB列表,来获得一个空闲的TCB*/
if (ptcb != (OS_TCB *)0) /*如果ptcb不为0,即还有空闲的TCB*/
{
OSTCBFreeList = ptcb->OSTCBNext; /* Update pointer to free TCB list更新一下空闲TCB列表指针(起始指针后移一个)*/
OS_EXIT_CRITICAL(); /*关中断*/
ptcb->OSTCBStkPtr = ptos; /*将栈顶指针存储在ptch中的OSTCBStkPtr */
ptcb->OSTCBPrio = prio; /*将优先级存储在OSTCBPrio中*/
ptcb->OSTCBStat = OS_STAT_RDY; /*将TCB的状态设置为就绪态*/
ptcb->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status将挂起状态设置为OS_STAT_PEND_OK*/
ptcb->OSTCBDly = 0u; /* Task is not delayed无任务延迟,直接执行*/
#if OS_TASK_CREATE_EXT_EN > 0u /*如果创建的是扩展型任务,存储有关的信息*/
ptcb->OSTCBExtPtr = pext;
ptcb->OSTCBStkSize = stk_size;
ptcb->OSTCBStkBottom = pbos;
ptcb->OSTCBOpt = opt;
ptcb->OSTCBId = id;
#else /*不是扩展型任务*/
pext = pext; /*pext只针对扩展型任务,所以这里自己给自己赋值,防止编译出错*/
stk_size = stk_size;
pbos = pbos;
opt = opt;
id = id;
#endif
#if OS_TASK_DEL_EN > 0u
ptcb->OSTCBDelReq = OS_ERR_NONE;/*将删除TCB的请求设置为OS_ERR_NONE*/
/*如果可以删除任务本身,可以从每个OS_TCB中节省出一个布尔量*/
#endif
/*提前进行相关计算,为了节省CPU的操作事件*/
#if OS_LOWEST_PRIO <= 63u
ptcb->OSTCBY = (INT8U)(prio >> 3u);
ptcb->OSTCBX = (INT8U)(prio & 0x07u);
#else
ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 4u) & 0xFFu);
ptcb->OSTCBX = (INT8U)(prio & 0x0Fu);
#endif
/* Pre-compute BitX and BitY */
ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY);/*提前计算位掩码*/
ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);
#if (OS_EVENT_EN)
ptcb->OSTCBEventPtr = (OS_EVENT *)0; /* 如果不打算在应用程序中使用各类事件,OS_TCB中OSTCBEventPt就不会出现
任务就不会被挂起Task is not pending on an event*/
#if (OS_EVENT_MULTI_EN > 0u)
ptcb->OSTCBEventMultiPtr = (OS_EVENT **)0; /* Task is not pending on any events任务不会因为任何事件被挂起*/
#endif
#endif
#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u) && (OS_TASK_DEL_EN > 0u)
ptcb->OSTCBFlagNode = (OS_FLAG_NODE *)0; /* Task is not pending on an event flag任务不会因为事件标志被挂起 */
#endif
#if (OS_MBOX_EN > 0u) || ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u))
ptcb->OSTCBMsg = (void *)0; /* No message received消息数设为0*/
#endif
#if OS_TASK_PROFILE_EN > 0u
ptcb->OSTCBCtxSwCtr = 0uL; /* Initialize profiling variables初始化分析变量 */
ptcb->OSTCBCyclesStart = 0uL;
ptcb->OSTCBCyclesTot = 0uL;
ptcb->OSTCBStkBase = (OS_STK *)0;
ptcb->OSTCBStkUsed = 0uL;
#endif
#if OS_TASK_NAME_EN > 0u
ptcb->OSTCBTaskName = (INT8U *)(void *)"?";/*初始化TCB任务名称*/
#endif
#if OS_TASK_REG_TBL_SIZE > 0u /* Initialize the task variables初始化任务变量*/
for (i = 0u; i < OS_TASK_REG_TBL_SIZE; i++)
{
ptcb->OSTCBRegTbl[i] = 0u;
}
#endif
OSTCBInitHook(ptcb); /*初始化钩子函数*/
OSTaskCreateHook(ptcb); /* Call user defined hook调用用户自定义的钩子函数*/
OS_ENTER_CRITICAL(); /*关中断*/
OSTCBPrioTbl[prio] = ptcb;
ptcb->OSTCBNext = OSTCBList; /* Link into TCB chain链接到任务控制块链接串*/
ptcb->OSTCBPrev = (OS_TCB *)0;
if (OSTCBList != (OS_TCB *)0)
{
OSTCBList->OSTCBPrev = ptcb;
}
OSTCBList = ptcb;
OSRdyGrp |= ptcb->OSTCBBitY; /*通过掩码计算就绪组号*/
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;/*通过掩码计算在就绪表中的位置*/
OSTaskCtr++; /* 任务数目加1*/
OS_EXIT_CRITICAL(); /*开中断*/
return (OS_ERR_NONE);
}
OS_EXIT_CRITICAL(); /*开中断*/
return (OS_ERR_TASK_NO_MORE_TCB);
}
相关介绍:http://blog.csdn.net/m0_37411189/article/details/72967962
解析在创建任务时对该任务控制块的初始化过程(三步走):
- 被创建任务从空闲任务控制链表(OSTCBFreeList)中获取一个任务控制块
2.用任务的属性对任务控制块各个成员进行赋值
3.把这个任务控制块链入到任务控制块链表(OSTCBList),并在任务就绪表中登记该任务
个人感觉源代码读起来有些费神,但是这三个图表现的很清楚。
到这里,OS_CORE.C文件读完。