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()/*这只是为了举例*/
{
。。。。。。
OSInit (&p_err);
/*OSTaskCreate 这个函数以后会细说的,这里的每个参数这里就不说了*/
OSTaskCreate (OS_TCB task1,
OS_ERR p_err;
OSTaskCreate (OS_TCB task2,
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);
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);
}
这里建了两个任务,而且其实 OSTaskCreate 这里是有调用 OSSched,但在这之
前会先看 OSRunning,因这在这里
这个两个任务建立时很明显,OSRunning 还为 0,这时是在 OSTaskCreate 运行不
到 OSSched 就会退出,所以不会有
任务动作,直到 OSStart (&p_err)这时 OSRunning 为 1,会在这个两任务中找一
个优先级最大的运行,然后以后再
建什么任务,就可以在 OSTaskCreate 调用到 OSSched,如果你这个新建的任务
优先级最高,那么就会直接调度到
这个新建的任务。如果没调用 OSStart,那么这个系系统也就不能真正启动。
OSSchedLockTimeBegin 这个是给任务上锁时读取,定时寄存器的
值,
OSSchedLockTimeMax 当解锁时会计算下这次上锁的时间多长,如果比这
个值大,就把这次的上锁时间给这个变量
OSSchedLockTimeMaxCur 看代码,功能好像同上
OSStart (&p_err);