出问题 初始化ucosiii_ucos-iii关于初始化

本文详细介绍了UCOSIII操作系统初始化的过程,包括OSInit函数的各个组件和作用,如中断处理、任务调度锁、时间片轮转等功能的初始化。在中断处理中,OSIntNestingCtr用于记录中断嵌套级别,确保中断处理期间不会进行任务调度。文章还讨论了任务创建和调度的条件,以及如何启用和禁用时间片轮转。此外,还提及了勾子函数的使用和优先级链的初始化方法。
摘要由CSDN通过智能技术生成

void  OSInit (OS_ERR  *p_err)

{

CPU_STK      *p_stk;

CPU_STK_SIZE  size;

#ifdef OS_SAFETY_CRITICAL

/*这个定义我没找到,可能是留给以后的,或是留给我们自己写*/

if (p_err == (OS_ERR *)0) {

OS_SAFETY_CRITICAL_EXCEPTION();

return;

}

#endif

OSInitHook();

/* 这个函数是留给用户写的,编程的人可根据自己情况写,当然空的也行*/

OSIntNestingCtr                 = (OS_NESTING_CTR)0;

/* 中断计数器,每来一个硬件中断这个就加1,                     */

OSRunning                       =  OS_STATE_OS_STOPPED;

/* OSRunning是说明是否要启动多任务切换功能,很明显初始化时是不启动这个功能*/

OSSchedLockNestingCtr           = (OS_NESTING_CTR)0;

/* 这个是为了给任务上锁,开始为0,如果在某个任务某个段不想让别的

任务打断就用上锁函数,这个参数会被加上,这样,别的任务就不能被切换,因为负责任务调度的函数

会是否不为0,不为0就不会调度*/

#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u

OSSchedLockTimeBegin            = (CPU_TS)0;

/*上锁时,硬件定时器的时间,直接读定时器的寄存器*/

OSSchedLockTimeMax              = (CPU_TS)0;

/*上锁的最长时间是多少,这个时间会影响实时性(好像是这样,因为我没用过这个系统做过什么太大的项目,通过说系统代码来理解)*/

OSSchedLockTimeMaxCur           = (CPU_TS)0;

/*看程序,个人认为功能同上*/

#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508

OSSafetyCriticalStartFlag       =  DEF_FALSE;

/*这个为1的话,就不能建新的任务了*/

#endif

#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u

/*这个ucos3一个优先级可以带任意多个任务,每次只运行该优先级的第一个任务,用这个可以在每个固定时间将最前面的任务调到最后,总觉得这样会影响实时性,下面细说*/

OSSchedRoundRobinEn             = DEF_FALSE;

OSSchedRoundRobinDfltTimeQuanta = OSCfg_TickRate_Hz / 10u;

#endif

if (OSCfg_ISRStkSize > (CPU_STK_SIZE)0) {

p_stk = OSCfg_ISRStkBasePtr;

/* Clear exception stack for stack checking.              */

if (p_stk != (CPU_STK *)0) {

/*关于OSCfg_ISRStkBasePtr我也不是很清楚,不用也行*/

size  = OSCfg_ISRStkSize;

/*在os_cfg_app.c中有定义CPU_STK* const  OSCfg_ISRStkBasePtr= (CPU_STK*)&OSCfg_ISRStk[0];*/

while (size > (CPU_STK_SIZE)0) {

/*CPU_STK OSCfg_ISRSt[OS_CFG_ISR_STK_SIZE]这也是在os_cfg_app.c定义的*/

size--;

/*#define  OS_CFG_ISR_STK_SIZE 128u 在os_cfg_app.h中定义*/

*p_stk = (CPU_STK)0;

p_stk++;

}

}

}

#if OS_CFG_APP_HOOKS_EN > 0u

OS_AppTaskCreateHookPtr = (OS_APP_HOOK_TCB )0;

/* 这是勾子函数指针,我们希望在任务调度时做一些我们希望它做的事,

就写个函数,让这个指针指向那个函数,然后让相应的勾子函数去运行它,下面会细说。以下同样*/

OS_AppTaskDelHookPtr    = (OS_APP_HOOK_TCB )0;

OS_AppTaskReturnHookPtr = (OS_APP_HOOK_TCB )0;

OS_AppIdleTaskHookPtr   = (OS_APP_HOOK_VOID)0;

OS_AppStatTaskHookPtr   = (OS_APP_HOOK_VOID)0;

OS_AppTaskSwHookPtr     = (OS_APP_HOOK_VOID)0;

OS_AppTimeTickHookPtr   = (OS_APP_HOOK_VOID)0;

#endif

OS_PrioInit();

/* 初始化优先级                  */

OS_RdyListInit();

/* 初始化就绪任务列表                              */

OS_TaskInit(p_err);

/* 初始化任务管理                    */

if (*p_err != OS_ERR_NONE) {

return;

}

#if OS_CFG_ISR_POST_DEFERRED_EN > 0u

OS_IntQTaskInit(p_err);

/* 初始化中断队列函数          */

if (*p_err != OS_ERR_NONE) {

return;

}

#endif

OS_IdleTaskInit(p_err);

/* 初始化空任务,一般没有别的任务工作的话,就由它来占CPU,空任务的优先级要最低*/

if (*p_err != OS_ERR_NONE) {

return;

}

OS_TickTaskInit(p_err);

/* 初始化时钟节拍函数                              */

if (*p_err != OS_ERR_NONE) {

return;

}

#if OS_CFG_STAT_TASK_EN > 0u

/* 初始化统计任务                         */

OS_StatTaskInit(p_err);

if (*p_err != OS_ERR_NONE) {

return;

}

#endif

#if OS_CFG_FLAG_EN > 0u

/* ucos的资源有FLAG控制,sem控制,Mem管理,Msg消息管理,Mutx互斥信号管理,队列管理,软定时器管理*/

OS_FlagInit(p_err);

if (*p_err != OS_ERR_NONE) {

return;

}

#endif

#if OS_CFG_MEM_EN > 0u

/* Initialize the Memory Manager module                   */

OS_MemInit(p_err);

if (*p_err != OS_ERR_NONE) {

return;

}

#endif

#if (OS_MSG_EN) > 0u

/* Initialize the free list of OS_MSGs                    */

OS_MsgPoolInit(p_err);

if (*p_err != OS_ERR_NONE) {

return;

}

#endif

#if OS_CFG_MUTEX_EN > 0u

/* Initialize the Mutex Manager module                    */

OS_MutexInit(p_err);

if (*p_err != OS_ERR_NONE) {

return;

}

#endif

#if OS_CFG_Q_EN > 0u

OS_QInit(p_err);

/* Initialize the Message Queue Manager module            */

if (*p_err != OS_ERR_NONE) {

return;

}

#endif

#if OS_CFG_SEM_EN > 0u

/* Initialize the Semaphore Manager module                */

OS_SemInit(p_err);

if (*p_err != OS_ERR_NONE) {

return;

}

#endif

#if OS_CFG_TMR_EN > 0u

/* Initialize the Timer Manager module                    */

OS_TmrInit(p_err);

if (*p_err != OS_ERR_NONE) {

return;

}

#endif

#if OS_CFG_DBG_EN > 0u

OS_Dbg_Init();

#endif

OSCfg_Init();

}

使用这个操作系统首先要初始化这个系统的资源,OSInit来初始化这些资源的。

OSIntNestingCtr这个变量,在来中断时,这个就加1,说明这时还在处理外部中断

事情,这时候可能有任务进入就绪状态,但也不会被调用。OSSched这个调度函数会去看这个变量是否为0,为0

就可以调度,不然不能。这个是在自己编写移植函数时调用处理中断函数前调用下OSIntEnter,然后在调用

处理中断函数后调用OSIntExit就好了。

/*************************************************************************************************************************

void  OSIntEnter (void)

{

if (OSRunning != OS_STATE_OS_RUNNING) {                 /* Is OS running?                                         */

return;                                             /* No                                                     */

}

if (OSIntNestingCtr >= (OS_NESTING_CTR)250u) {          /* Have we nested past 250 levels?                        */

return;                                             /* Yes                                                    */

}

OSIntNestingCtr++;                                      /* 这里就把OSIntNestingCtr+1了                            */

}

****************************************************************************************************************************/

/****************************************************************************************************************************

void  OSIntExit (void)

{

CPU_SR_ALLOC();

if (OSRunning != OS_STATE_OS_RUNNING) {

/* Has the OS started?                                    */

return;

/* No                                                     */

}

CPU_INT_DIS();

if (OSIntNestingCtr == (OS_NESTING_CTR)0) {

/* Prevent OSIntNestingCtr from wrapping                  */

CPU_INT_EN();

return;

}

OSIntNestingCtr--;

/*看这,每退出一个中断处理就减1,中断处理是会嵌套的*/

if (OSIntNestingCtr > (OS_NESTING_CTR)0) {

/* ISRs still nested?                                     */

CPU_INT_EN();

/* Yes                                                    */

return;

}

if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {

/* Scheduler still locked?                                */

CPU_INT_EN();

/* Yes                                                    */

return;

}

OSPrioHighRdy   = OS_PrioGetHighest();

/* Find highest priority                                  */

OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;

/* Get highest priority task ready-to-run                 */

if (OSTCBHighRdyPtr == OSTCBCurPtr) {

/* Current task still the highest priority?               */

CPU_INT_EN();

/* Yes                                                    */

return;

}

#if OS_CFG_TASK_PROFILE_EN > 0u

OSTCBHighRdyPtr->CtxSwCtr++;

/* Inc. # of context switches for this new task           */

#endif

OSTaskCtxSwCtr++;

/* Keep track of the total number of ctx switches         */

OSIntCtxSw();

/* Perform interrupt level ctx switch                     */

CPU_INT_EN();

}

*****************************************************************************************************************************/

我们也看到了,在这两个函数中都查看了OSRunning,因为只有这个变量为1时,这个系统才真正能启动多任务处理能力,我们这样看一下

int maint()/*这只是为了举例*/

{

OS_ERRp_err;

。。。。。。

OSInit (&p_err);

/*OSTaskCreate这个函数以后会细说的,这里的每个参数这里就不说了*/

OSTaskCreate (OS_TCB        task1,

CPU_CHAR      "fisrt_tsk",

OS_TASK_PTR    task_func1,

void          *p_arg,

OS_PRIO        prio1,

CPU_STK       *p_stk_base,

CPU_STK_SIZE   stk_limit,

CPU_STK_SIZE   stk_size,

OS_MSG_QTY     q_size,

OS_TICK        time_quanta,

void          *p_ext,

OS_OPT         opt,

OS_ERR        *p_err);

OSTaskCreate (OS_TCB        task2,

CPU_CHAR      "second_tsk",

OS_TASK_PTR    task_func2,

void          *p_arg,

OS_PRIO        prio1,

CPU_STK       *p_stk_base,

CPU_STK_SIZE   stk_limit,

CPU_STK_SIZE   stk_size,

OS_MSG_QTY     q_size,

OS_TICK        time_quanta,

void          *p_ext,

OS_OPT         opt,

OS_ERR        *p_err);

OSStart (&p_err);

}

这里建了两个任务,而且其实OSTaskCreate这里是有调用OSSched,但在这之前会先看OSRunning,因这在这里

这个两个任务建立时很明显,OSRunning还为0,这时是在OSTaskCreate运行不到OSSched就会退出,所以不会有

任务动作,直到OSStart (&p_err)这时OSRunning为1,会在这个两任务中找一个优先级最大的运行,然后以后再

建什么任务,就可以在OSTaskCreate调用到OSSched,如果你这个新建的任务优先级最高,那么就会直接调度到

这个新建的任务。如果没调用OSStart,那么这个系系统也就不能真正启动。

OSSchedLockTimeBegin这个是给任务上锁时读取,定时寄存器的值,

OSSchedLockTimeMax   当解锁时会计算下这次上锁的时间多长,如果比这个值大,就把这次的上锁时间给这个变量

OSSchedLockTimeMaxCur看代码,功能好像同上

/*********************************************************************************************************

/*

下面说的是上锁函数,OSSchedLockNestingCtr这变量会在OSSched中被检查,只要这个变量不为0就不会进行调度了

OSSchedLock会使OSSchedLockNestingCtr加1,OSSchedUnlock会使OSSchedLockNestingCtr减1。至于OSSched先不说以后会说的。

*/

void  OSSchedLock (OS_ERR  *p_err)

{

CPU_SR_ALLOC();/*CPU_CRITICAL_ENTER(),CPU_CRITICAL_EXIT()和这两个函数一起用的,看到了我说完上锁就说它们吧*/

#ifdef OS_SAFETY_CRITICAL

if (p_err == (OS_ERR *)0) {

OS_SAFETY_CRITICAL_EXCEPTION();

return;

}

#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u

if (OSIntNestingCtr > (OS_NESTING_CTR)0) {

/* Not allowed to call from an ISR                        */

*p_err = OS_ERR_SCHED_LOCK_ISR;

return;

}

#endif

if (OSRunning != OS_STATE_OS_RUNNING) {

/* Make sure multitasking is running                      */

*p_err = OS_ERR_OS_NOT_RUNNING;

return;

}

if (OSSchedLockNestingCtr >= (OS_NESTING_CTR)250u) {

/*带个问题,这是能上多少层锁啊?这有点不懂因为只要这个由不变0,就不能调度了,这是要给一个任务上几层锁有毕要吗?*/

*p_err = OS_ERR_LOCK_NESTING_OVF;

return;

}

/**********************************************************************************************************************

**

*以上是检查功能,真正的功能从下面开始*

**

**********************************************************************************************************************/

CPU_CRITICAL_ENTER();/*禁中断*/

OSSchedLockNestingCtr++;

/* 把这个标志加1,就表示上锁了                          */

#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u

OS_SchedLockTimeMeasStart();

/*读取当前上锁时间,下面就说它,这个很简单的*/

#endif

CPU_CRITICAL_EXIT(); /*开中断*/

*p_err = OS_ERR_NONE;

}

************************************************************************************************************************/

/***********************************************************************************************************************

/*解锁函数*/

void  OS_SchedLockTimeMeasStart (void)

{

if (OSSchedLockNestingCtr == 1u) {

OSSchedLockTimeBegin = CPU_TS_TmrRd();

/*读取当前时间,也就是定时寄存器的值,CPU_TS_TmrRd()是留给我们写*/

}

}

************************************************************************************************************************/

/************************************************************************************************************************

void  OSSchedUnlock (OS_ERR  *p_err)

{

CPU_SR_ALLOC();

#ifdef OS_SAFETY_CRITICAL

if (p_err == (OS_ERR *)0) {

OS_SAFETY_CRITICAL_EXCEPTION();

return;

}

#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u

if (OSIntNestingCtr > (OS_NESTING_CTR)0) {

/* Not allowed to call from an ISR                        */

*p_err = OS_ERR_SCHED_UNLOCK_ISR;

return;

}

#endif

if (OSRunning != OS_STATE_OS_RUNNING) {

/* Make sure multitasking is running                      */

*p_err = OS_ERR_OS_NOT_RUNNING;

return;

}

if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) {

/* See if the scheduler is locked                         */

*p_err = OS_ERR_SCHED_NOT_LOCKED;

return;

}

CPU_CRITICAL_ENTER();

OSSchedLockNestingCtr--;

/* 这里就解了一层锁,是不是上锁就看这个变量是不是>0       */

if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {

CPU_CRITICAL_EXIT();

/* 我想要是能进这里说明你在一个任务里多次调用OSSchedLock,会返回一个错误   */

*p_err = OS_ERR_SCHED_LOCKED;

return;

}

#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u

OS_SchedLockTimeMeasStop();/*这里就计算咱给任务上锁时间,并看是不是比以前上锁最长时间还长。*/

#endif

CPU_CRITICAL_EXIT();

/* Scheduler should be re-enabled                         */

OSSched();

/* 解锁正常之后就看是不是在上锁的时候有更高优先级任务就绪,有的话就切换任务*/

*p_err = OS_ERR_NONE;

}

*************************************************************************************************************************/

/************************************************************************************************************************

void  OS_SchedLockTimeMeasStop (void)

{

CPU_TS_TMR  delta;

if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) {

/* Make sure we fully un-nested scheduler lock            */

delta = CPU_TS_TmrRd()

/* 上锁结束就再读一次定时器,但这个上锁时间应该不能长,不然定时器寄存器会溢出我想最好在一次           */

- OSSchedLockTimeBegin;

if (delta > OSSchedLockTimeMax) {

/* 看这次上锁时间是不是比以前最长的上锁时间还长,要长就给OSSchedLockTimeMax赋值       */

OSSchedLockTimeMax    = delta;

}

if (delta > OSSchedLockTimeMaxCur) {

/* 我总觉得这个同上,也许我对这个系统还了解的还不够                */

OSSchedLockTimeMaxCur = delta;

}

}

}

*************************************************************************************************************************/

下面就说这三个,这三个函数都是留给我们写的

CPU_SR_ALLOC()

CPU_CRITICAL_ENTER()

CPU_CRITICAL_EXIT()

先说CPU_SR_ALLOC()的写法,就是定义一个32位的cpu_sr变量,开始为0,这就是用来保存硬件状态寄存器的

#define  CPU_SR_ALLOC()             CPU_SR  cpu_sr = (CPU_SR)0

再说CPU_CRITICAL_ENTER(),这个用汇编写,两件事,先把当前的状态寄存器的值保存到cpu_sr中,然后在状态

寄存器中设置禁中断。(不同的单片机写移植函数会有不同,这里先不说,要是什么是说移植代码再细说)

CPU_CRITICAL_EXIT()这个就是把cpu_sr保存的值赋给状态寄存器。

/******************************************************************************************************

#ifdef OS_SAFETY_CRITICAL_IEC61508

OSSafetyCriticalStartFlag       =  DEF_FALSE;/*这个为1的话,就不能建新的任务了*/

#endif

再说下这个,OSSafetyCriticalStartFlag这个变量要是为1的话,就不能建新的任务,

如果调用下面这个函数OSSafetyCriticalStartFlag就会被置位,

void  OSSafetyCriticalStart (void)

{

OSSafetyCriticalStartFlag = DEF_TRUE;

}

然后我们看一下这段代码,这是OSTaskCreate里的代码,我们先就看这一部分,由这个可以看出要是OSSafetyCriticalStartFlag

为真,那么就会直接退出OSTaskCreate,不会建任务了。

*****************************************************

if (OSSafetyCriticalStartFlag == DEF_TRUE) {

*p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;

return;

}

******************************************************

*******************************************************************************************************/

/******************************************************************************************************

好吧,再说下面这两个变量。

#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u

OSSchedRoundRobinEn             = DEF_FALSE;/*初始化时是不用这个功能 的*/

OSSchedRoundRobinDfltTimeQuanta = OSCfg_TickRate_Hz / 10u;/*这个是默认时间间隔,你可以不用的*/

#endif

ucos-iii可以带无限个任务,首先ucos-iii提供的优先级不是无限的,能带无限个任务的原因是每个优先级可以带

无限个任务。这个原理就留到创建任务时讲。

TCB1       TCB2                  TCBn

+------------+       +------------+        +------------+

| NextPtr    |------>| NextPtr    | ...... | NextPtr    |->0

+------------+       +------------+        +------------+

0

+------------+       +------------+        +------------+

:            :       :            :        :            :

:            :       :            :        :            :

+------------+       +------------+        +------------+

(说明:这个链上的任务是就绪的,如果不是就绪态的话就会从这个链上移除,还有一点这个链我没用完整的)

同一优先级上的就绪任务就是如图连在一起的,假设这些任务的优先级是40,如果40之前的优先级任务都休息了当前就绪

的任务优先级最高的就是40的话,那个调度时就会把这里的TCB1管理的任务拿出来执行,这个优先级上其他的任务

虽然是就绪,但CPU就是不让它们干活。

每次调度的时候先做TCB1管理的任务。如果OSSchedRoundRobinEn置位的话

那么每过OSSchedRoundRobinDfltTimeQuanta(当然这是默认时间间隔,是你不自己设置的话才会用它,当说到任务创建时

就明白了)时间就会把第一个调到最后,这样这里的TCB2就变成第一个了,这样,CPU再找这个优先级上的就绪任务时就会

找到TCB2管理的任务。TCB1得等,直到它前面的任务,自动放弃(也就是说,这个任务自己将自己移到这个链最后)或是

从就绪态变成别的状态(从这个链上移除)。

然后说下相关的三个函数。

/******************************************************************************************************

第一个

这个是我们自己调用的,只调用一次就好了,所以别放到任务的while(1)里

void  OSSchedRoundRobinCfg (CPU_BOOLEAN  en,/*是否启用同优先级任务轮转功能,也就是上面解释的*/

OS_TICK      dflt_time_quanta,/*时间间隔,OSSInit中已设,这里我们可以改*/

OS_ERR      *p_err)

{

CPU_SR_ALLOC();

#ifdef OS_SAFETY_CRITICAL

if (p_err == (OS_ERR *)0) {

OS_SAFETY_CRITICAL_EXCEPTION();

return;

}

#endif

CPU_CRITICAL_ENTER();

if (en != DEF_ENABLED) {

OSSchedRoundRobinEn = DEF_DISABLED;

} else {

OSSchedRoundRobinEn = DEF_ENABLED;/*这是设置使能*/

}

if (dflt_time_quanta > (OS_TICK)0) {

OSSchedRoundRobinDfltTimeQuanta = dflt_time_quanta;/*这是设置时间间隔*/

} else {

OSSchedRoundRobinDfltTimeQuanta = (OS_TICK)(OSCfg_TickRate_Hz / (OS_RATE_HZ)10);

/*如果我们传的dflt_time_quanta=0的话*/

}

CPU_CRITICAL_EXIT();

*p_err = OS_ERR_NONE;

}

*******************************************************************************************************/

下面的是在任务中调用的,用于任务自己将自己从本优先级的最前面调到最后面。要想看懂这个代码得先知道任务在

系统的组织。这先放一下,等说完任务建立时再说它吧(在代码中我用了中文注示,看一下吧)

/*******************************************************************************************************

void  OSSchedRoundRobinYield (OS_ERR  *p_err)

{

OS_RDY_LIST  *p_rdy_list;

OS_TCB       *p_tcb;

CPU_SR_ALLOC();

#ifdef OS_SAFETY_CRITICAL

if (p_err == (OS_ERR *)0) {

OS_SAFETY_CRITICAL_EXCEPTION();

return;

}

#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u

if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              /* Can't call this function from an ISR                   */

*p_err = OS_ERR_YIELD_ISR;

return;

}

#endif

if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {

/* Can't yield if the scheduler is locked                 */

*p_err = OS_ERR_SCHED_LOCKED;

return;

}

if (OSSchedRoundRobinEn != DEF_TRUE) {

/* Make sure round-robin has been enabled                 */

*p_err = OS_ERR_ROUND_ROBIN_DISABLED;

return;

}

CPU_CRITICAL_ENTER();

p_rdy_list = &OSRdyList[OSPrioCur];

/* Can't yield if it's the only task at that priority     */

if (p_rdy_list->NbrEntries < (OS_OBJ_QTY)2) {

CPU_CRITICAL_EXIT();

*p_err = OS_ERR_ROUND_ROBIN_1;

return;

}

OS_RdyListMoveHeadToTail(p_rdy_list);

/* 将当前优先级的最前面任务移到这个优先级链的最后             */

p_tcb = p_rdy_list->HeadPtr;

/* 取新的当前优先级最前面的任务                */

if (p_tcb->TimeQuanta == (OS_TICK)0) {

/* 给它一个时间片,到时间它会被移到这个优先级链的最后           */

p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta;

} else {

/*记住,这里我一直强调的是当前优先级链。也不知道前面我有说明白没*/

p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta;

/* Load time slice counter with new time                  */

}

CPU_CRITICAL_EXIT();

OSSched();

/* Run new task                                           */

*p_err = OS_ERR_NONE;

}

********************************************************************************************************/

下面的函数是在OSTimeTick(时钟节拍)中调用的,传入的是当前有任务活动的优先级的任务链,它会把时间戳减1

减到0就把最前面的任务移到这个优先级任务链的最后。p_tcb->TimeQuanta建任务时给的,当前面的任务被移到最后时

这个任务就变成最前面了,同时TimeQuanta给p_tcb->TimeQuantaCtr赋值。如果TimeQuanta=0,那就用OSSchedRoundRobinDfltTimeQuanta

/*******************************************************************************************************

void  OS_SchedRoundRobin (OS_RDY_LIST  *p_rdy_list)

{

OS_TCB   *p_tcb;

CPU_SR_ALLOC();

if (OSSchedRoundRobinEn != DEF_TRUE) {

/* Make sure round-robin has been enabled                 */

return;

}

CPU_CRITICAL_ENTER();

p_tcb = p_rdy_list->HeadPtr;

/* Decrement time quanta counter                          */

if (p_tcb == (OS_TCB *)0) {

CPU_CRITICAL_EXIT();

return;

}

if (p_tcb == &OSIdleTaskTCB) {

CPU_CRITICAL_EXIT();

return;

}

if (p_tcb->TimeQuantaCtr > (OS_TICK)0) {

p_tcb->TimeQuantaCtr--;

}

if (p_tcb->TimeQuantaCtr > (OS_TICK)0) {

/* Task not done with its time quanta                     */

CPU_CRITICAL_EXIT();

return;

}

if (p_rdy_list->NbrEntries < (OS_OBJ_QTY)2) {

/* See if it's time to time slice current task            */

CPU_CRITICAL_EXIT();

/* ... only if multiple tasks at same priority            */

return;

}

if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {

/* Can't round-robin if the scheduler is locked           */

CPU_CRITICAL_EXIT();

return;

}

OS_RdyListMoveHeadToTail(p_rdy_list);

/* Move current OS_TCB to the end of the list             */

p_tcb = p_rdy_list->HeadPtr;

/* Point to new OS_TCB at head of the list                */

if (p_tcb->TimeQuanta == (OS_TICK)0) {

/* See if we need to use the default time slice           */

p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta;

} else {

p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta;

/* Load time slice counter with new time                  */

}

CPU_CRITICAL_EXIT();

}

********************************************************************************************************/

/*******************************************************************************************************

OS_AppTaskCreateHookPtr = (OS_APP_HOOK_TCB )0;

OS_AppTaskDelHookPtr    = (OS_APP_HOOK_TCB )0;

OS_AppTaskReturnHookPtr = (OS_APP_HOOK_TCB )0;

OS_AppIdleTaskHookPtr   = (OS_APP_HOOK_VOID)0;

OS_AppStatTaskHookPtr   = (OS_APP_HOOK_VOID)0;

OS_AppTaskSwHookPtr     = (OS_APP_HOOK_VOID)0;

OS_AppTimeTickHookPtr   = (OS_APP_HOOK_VOID)0;

********************************************************************************************************/

下面说下这些勾子函数,这些是在os.h中定义的举一例

OS_EXT           OS_APP_HOOK_TCB         OS_AppTaskCreateHookPtr

typedef  void                      (*OS_APP_HOOK_TCB)(OS_TCB *p_tcb);

这样用OS_APP_HOOK_TCB声明的是函数指针,这个指针指向一个返回值为空,并有一个输入参数的函数

在os_app_hooks.c中有App_OS_SetAllHooks(void)函数。在这个函数里

。。。。。。

OS_AppTaskCreateHookPtr = App_OS_TaskCreateHook

。。。。。。

而在os_app_hooks.c中

void  App_OS_TaskCreateHook (OS_TCB  *p_tcb)

{

(void)&p_tcb;

}

最后在大家写移植函数时就这样写

void  OSTaskCreateHook (OS_TCB  *p_tcb)

{

#if OS_CFG_APP_HOOKS_EN > 0u

if (OS_AppTaskCreateHookPtr != (OS_APP_HOOK_TCB)0) {

(*OS_AppTaskCreateHookPtr)(p_tcb);

}

#else

(void)p_tcb;

#endif

}

然后再说OS_AppTaskCreateHookPtr这些在App_OS_SetAllHooks(void)设置

void  App_OS_ClrAllHooks (void)清理

这个我们可以自己调用在一个任务中调用,我想一般是在我们写个初始化任务中调用这些。用过ucos的话就知道,一

必要的资源在OSInit()里初始化了,但有些是开发人员认为客观必要的,那么就会在第一个任务中去初始化,如果定时

中断,和这些勾子函数。

******************************************************************************************************/

下面是优先级链的初始化,在调用OSInit运行到这时,还没有任务建立,所以优先级链为空的。还是看下代码:

/*****************************************************************************************************

void  OS_PrioInit (void)

{

CPU_DATA  i;

/*在os.h中定义了OS_PRIO_TBL_SIZE大小。

#define  OS_PRIO_TBL_SIZE          (((OS_CFG_PRIO_MAX - 1u) / DEF_INT_CPU_NBR_BITS) + 1u)

OS_CFG_PRIO_MAX是优先级值的最大数,是在os_cfg.h中定义的,os_cfg.h是配置文件,我们可以根据我们实际所需,

在这个文件中定制内核。目前在os_cfg.h中定义为64:

#define OS_CFG_PRIO_MAX                64u

至于DEF_INT_CPU_NBR_BITS我们可以定义(在lib_def.h中定义),这个值可以是8,16,32。说到这,可以有人会迷茫,好了这时就不得不

说下在内核中优先级的管理方式,这样大家就能看懂这段代码了,这段代码很简单。*/

for (i = 0u; i < OS_PRIO_TBL_SIZE; i++) {

OSPrioTbl[i] = (CPU_DATA)0;

}

}

这里说下优先级的管理方式,

我们定义OS_CFG_PRIO_MAX=64

DEF_INT_CPU_NBR_BITS=8(OSPrioTbl[]这个数组里的数据也是定义为8位长)

现在我们建了第一个任务,优先级是20,这时我们看一下优先级插入代码

。。。。。。

void  OS_PrioInsert (OS_PRIO  prio)

{

CPU_DATA  bit;

CPU_DATA  bit_nbr;

OS_PRIO   ix;

ix             = prio / DEF_INT_CPU_NBR_BITS;

bit_nbr        = (CPU_DATA)prio & (DEF_INT_CPU_NBR_BITS - 1u);

bit            = 1u;

bit          <<= (DEF_INT_CPU_NBR_BITS - 1u) - bit_nbr;

OSPrioTbl[ix] |= bit;

}

。。。。。。

因为我们假设本次优先级为20,也就是说prio=20,DEF_INT_CPU_NBR_BITS=8;

ix=2,

bit_nbr = 20 & 7=4(二进制计算是00010100&00000111=00000100)其实这就是相当于20除以8求余数。这是为了得到一个8以下的数。

bit_nbr        = (CPU_DATA)prio & (DEF_INT_CPU_NBR_BITS - 1u);这句其实是以前的方法

看过ucosiir 就知道

{ix=(prio>>3)

bit_nbr=(prio&7)}

bit=1

bit<<= (DEF_INT_CPU_NBR_BITS - 1u) - bit_nbr;左移3位

OSPrioTbl[ix] |= bit

这样就是20分成两部分,一部分是8的部数2,一部分是8的余数4,

然后就会在OSPrioTbl[2]=|8,

OSPrioTbl[2]看成二进制,

|+|+|+|+|+|+|+|+|

|0|0|0|0|1|0|0|0|

|+|+|+|+|+|+|+|+|

我们可以这么看,一个数num如果16<=num<24,那么这个优先级就一定会在OSPrioTbl[2]的某一位设个1,如果num越大

就会在OSPrioTbl[2]更低的位置设1,如果我们又建一个任务用的优先级是21的话那么就会在现在这个1后面再设一个1。

优先级prio的数值越小,优先级越高。当任务是就绪的,也就是可以工作的时候才会去设OSProTbl[]中的位。好了,

先不说了,等下次说完任务的建立和调度时再细说。

OS_RdyListInit();这是初始化就绪任务链,一个任务就绪时,不只在OSPrioTbl中设置一下,这里也要设置,这个也

留到建任务时说。

剩下的这回也不说了,等说到相应资源时再说,下面说任务建立与调度。

******************************************************************************************************/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值