UCOSIII系统初始化
在使用UCOSIII之前我们必须先初始化UCOSIII,函数OSInit()用来完成UCOSIII的初始化,而且OSInit()必须先于其他UCOSIII函数调用,包括OSStart()。
一般UCOSIII的main函数遵循以下的格式编写:
int main(void) { OS_ERR err; …… //其他函数,一般为外设初始化函数 …… OSInit(&err); …… //其他函数,一般为创建任务函数 …… OSStart(&err); }
也就是说:
- 最先肯定是要调用OSInit()初始化UCOSIII;
- 创建任务,一般我们在main()函数中只创建一个start_task任务,其他任务都在start_task任 务 中 创 建, 在 调 用OSTaskCreate()函 数 创 建 任 务 的 时 候 一 定 要 调 用OS_CRITICAL_ENTER()函数进入临界区,任务创建完以后调用OS_CRITICAL_EXIT()函数退出临界区;
- 最后调用OSStart()函数开启UCOSIII。
需要注意:我们在调用OSStart()开启UCOSIII之前一定要至少创建一个任务,其实我们在调用OSInit()函数初始化UCOSIII的时候已经创建了一个空闲任务和时钟节拍任务。
接下来,我们看一下UCOSIII的初始化函数OSInit()函数:
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; /* Clear the interrupt nesting counter */ OSRunning = OS_STATE_OS_STOPPED; /* UCOSIII正在运行的标志 */ OSSchedLockNestingCtr = (OS_NESTING_CTR)0; /* Clear the scheduling lock counter */ OSTCBCurPtr = (OS_TCB *)0; /* 指向正在运行任务控制块的指针 */ OSTCBHighRdyPtr = (OS_TCB *)0; //指向最高优先级就绪任务控制块的指针 OSPrioCur = (OS_PRIO)0; /* 正在运行任务的优先级 */ OSPrioHighRdy = (OS_PRIO)0; //最高优先级别的就绪任务的优先级 OSPrioSaved = (OS_PRIO)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; #endif #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u 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) { size = OSCfg_ISRStkSize; while (size > (CPU_STK_SIZE)0) { size--; *p_stk = (CPU_STK)0; p_stk++; } } } #if OS_CFG_APP_HOOKS_EN > 0u OS_AppTaskCreateHookPtr = (OS_APP_HOOK_TCB )0; /* Clear application hook pointers */ 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 #if OS_CFG_TASK_REG_TBL_SIZE > 0u OSTaskRegNextAvailID = (OS_REG_ID)0; #endif OS_PrioInit(); /* 优先级初始化 */ OS_RdyListInit(); /* 任务就绪列表初始化 */ #if OS_CFG_FLAG_EN > 0u /* Initialize the Event Flag module */ 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 defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) OS_TLS_Init(p_err); /* Initialize Task Local Storage, before creating tasks */ if (*p_err != OS_ERR_NONE) { return; } #endif OS_TaskInit(p_err); /* Initialize the task manager */ if (*p_err != OS_ERR_NONE) { return; } #if OS_CFG_ISR_POST_DEFERRED_EN > 0u OS_IntQTaskInit(p_err); /* Initialize the Interrupt Queue Handler Task */ if (*p_err != OS_ERR_NONE) { return; } #endif OS_IdleTaskInit(p_err); /* 空闲任务初始化 */ 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 /* Initialize the Statistic Task */ OS_StatTaskInit(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()主要负责建立任务控制链表、就绪任务表等一些数据结构,并对系统使用的全局变量进行初始化。
我们之前讲5个系统任务的时候说到,空闲任务、时钟节拍任务是必须创建的任务;而统计任务、定时任务、中断服务管理任务则是可选任务。怎么保证这一点呢?
在这里就得到解答了。在UCOSIII的系统初始化函数OSInit()中,前两个任务OS_IdleTaskInit()和OS_TickTaskInit()都是一定要运行的,而后三个任务OS_StatTaskInit()、OS_TmrInit()和OS_IntQTaskInit()都采用条件编译的方式。只有在OS_CFG.h文件中配置开启后,才会运行这些任务。
既然是任务,那么就一定有优先级。那么这5个系统任务的优先级有事怎么分布的呢?
UCOSIII中以下优先级用户程序不能使用,因为这些优先级分配给了UCOSIII的5个系统内部任务:
- 优先级0:中断服务服务管理任务 OS_IntQTask();
- 优先级1:时钟节拍任务 OS_TickTask();
- 优先级2:定时任务 OS_TmrTask();
- 优先级OS_CFG_PRIO_MAX-2:统计任务 OS_StatTask();
- 优先级OS_CFG_PRIO_MAX-1:空闲任务 OS_IdleTask()。
UCOSIII系统启动
使用函数OSStart()来启动UCOSIII,函数如下:
void OSStart (OS_ERR *p_err) { #ifdef OS_SAFETY_CRITICAL if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return; } #endif if (OSRunning == OS_STATE_OS_STOPPED) { OSPrioHighRdy = OS_PrioGetHighest(); /* 寻找有就绪任务的最高优先级 */ OSPrioCur = OSPrioHighRdy; OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr; //寻找该优先级的任务控制块 OSTCBCurPtr = OSTCBHighRdyPtr; OSRunning = OS_STATE_OS_RUNNING; OSStartHighRdy(); /* Execute target specific code to start task */ *p_err = OS_ERR_FATAL_RETURN; /* OSStart() is not supposed to return */ } else { *p_err = OS_ERR_OS_RUNNING; /* OS is already running */ } }
在函数OSStart()中,用到了表示内核是否处于运行状态的变量OSRunning。若该变量为FALSE,则意味着内核处于未运行状态;若该变量为TRUE,则意味着内核处于运行状态。
由于在调用函数OSInit()进行初始化之后,已经将该值初始化为FALSE,所以在OSStart()函数中首先对OSRunning进行判断。如果该值为假,则查找最高优先级的就绪任务开始运行,并将OSRunning赋值为TRUE;否则,意味着内核已经处于运行状态了,函数OSInit()就什么工作也不做地返回。