阅读 32

OS_CORE.C(8)

本篇介绍的是OSStart()函数和OSStatInit()函数和OSTimeTick()函数。

OSStart()多任务开始函数:

/*$PAGE*/
/*
*********************************************************************************************************
*                                          START MULTITASKING
*											启动多个任务
* Description: This function is used to start the multitasking process which lets uC/OS-II manages the
*              task that you have created.  Before you can call OSStart(), you MUST have called OSInit()
*              and you MUST have created at least one task.
*				该功能用来开始多任务进程,使UC/OS-II管理你所创建的任务。在调用OSStart()之前必须先调用OSInit()并且必须创建至少一个任务
* Arguments  : none
*
* Returns    : none
*
* Note       : OSStartHighRdy() MUST:
*                 a) Call OSTaskSwHook() then,调用OSStartHighRdy()之后就调用OSTaskSwHook()函数
*                 b) Set OSRunning to OS_TRUE.将OSRunning设置为真,指出多任务已经开始
*                 c) Load the context of the task pointed to by OSTCBHighRdy.加载高优先级就绪任务启动函数中指出的任务的上下文
*                 d_ Execute the task.执行任务
*********************************************************************************************************
*/

void  OSStart(void)								/*启动多个任务*/
{
	if (OSRunning == OS_FALSE) {				/*此时没有多任务*/
		OS_SchedNew();                           /* Find highest priority's task priority number 找到最高优先级的任务优先级号  */
		OSPrioCur = OSPrioHighRdy;				 /*将最高优先级任务的优先级号作为当前要执行任务的优先级号*/
		OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; /* Point to highest priority task ready to run 指向将要运行的最高优先级任务   */
		OSTCBCur = OSTCBHighRdy;				 /*将高优先级任务的TCB作为当前TCB*/
		OSStartHighRdy();                        /* Execute target specific code to start task执行代码开始任务     */
	}
}
复制代码

将上述代码总结为如图所示流程:
\

\

OSStatInit()统计任务初始化函数:

/*$PAGE*/
/*
*********************************************************************************************************
*                                        STATISTICS INITIALIZATION
*											统计任务初始化
* Description: This function is called by your application to establish CPU usage by first determining
*              how high a 32-bit counter would count to in 1 second if no other tasks were to execute
*              during that time.  CPU usage is then determined by a low priority task which keeps track
*              of this 32-bit counter every second but this time, with other tasks running.  CPU usage is
*              determined by:
*			 统计初始化函数OSStatInit()决定在没有其它应用任务运行时,空闲计数器(OSIdleCtr)的计数有多快。
			这个任务每秒执行一次,以确定所有应用程序中的任务消耗了多少CPU时间。当用户的应用程序代码加入以后,
			运行空闲任务的CPU时间就少了,OSIdleCtr就不会像原来什么任务都不运行时有那么多计数。要知道,
			OSIdleCtr的最大计数值是OSStatInit()在初始化时保存在计数器最大值OSIdleCtrMax中的。
*                                             OSIdleCtr
*                 CPU Usage (%) = 100 * (1 - ------------)
*                                            OSIdleCtrMax
				 CPU使用率(百分比形式)=100*(1-空闲计数值/设定最大空闲计数值)
*
* Arguments  : none
*
* Returns    : none
*********************************************************************************************************
*/

#if OS_TASK_STAT_EN > 0u						
void  OSStatInit(void)							/*统计任务初始化*/
{
#if OS_CRITICAL_METHOD == 3u                     /* Allocate storage for CPU status register 中断函数被设定为模式3          */
	OS_CPU_SR  cpu_sr = 0u;
#endif


	OSTimeDly(2u);                               /* Synchronize with clock tick调用延迟函数OSTimeDly()将自身延时2个时钟节拍以停止自身的运行,
												 这是为了使OSStatInit()与时钟节拍同步                        */
	OS_ENTER_CRITICAL();						 /*关闭中断(进入中断)*/
	OSIdleCtr = 0uL;							 /* Clear idle counter 执行OSStartInit()时,空闲计数器OSIdleCtr被清零*/
	OS_EXIT_CRITICAL();							 /*打开中断*/
	OSTimeDly(OS_TICKS_PER_SEC / 10u);           /* Determine MAX. idle counter value for 1/10 second确定最大空闲计数值为1或10s  */
	OS_ENTER_CRITICAL();						 /*关闭中断*/
	OSIdleCtrMax = OSIdleCtr;                    /* Store maximum idle counter count in 1/10 second 存储最大空闲计数值   */
	OSStatRdy = OS_TRUE;						 /*将统计任务就绪标志OSStatRdy设为"真",以此来允许两个时钟节拍以后OSTaskStat()开始计算CPU的利用率*/
	OS_EXIT_CRITICAL();							 /*打开中断*/
}
#endif
复制代码

OSTimeTick()时钟节拍函数:\

/*$PAGE*/
/*2018/2/3~2/7
*********************************************************************************************************
*                                         PROCESS SYSTEM TICK
*											时钟节拍函数
* Description: This function is used to signal to uC/OS-II the occurrence of a 'system tick' (also known
*              as a 'clock tick').  This function should be called by the ticker ISR but, can also be
*              called by a high priority task.
*该功能是用来给uc/os发送时钟信号。该功能称为时钟中断,也叫做高优先级任务
* Arguments  : none
*
* Returns    : none
*********************************************************************************************************
*/

void  OSTimeTick(void)									/*时钟节拍函数*/
{
	OS_TCB    *ptcb;									/*指向TCB列表的的指针*/
#if OS_TICK_STEP_EN > 0u
	BOOLEAN    step;									/*设置一个布尔型变量*/
#endif
#if OS_CRITICAL_METHOD == 3u                               /* Allocate storage for CPU status register中断函数被设定为模式3     */
	OS_CPU_SR  cpu_sr = 0u;
#endif



#if OS_TIME_TICK_HOOK_EN > 0u							   /*可以生成时钟钩子函数OS_TIME_TICK_HOOK()*/
	OSTimeTickHook();                                      /* Call user definable hook 调用用户自定义钩子函数                    */
#endif
#if OS_TIME_GET_SET_EN > 0u								   /*可以生成OS_TIME_GET_SET()函数*/
	OS_ENTER_CRITICAL();                                   /* Update the 32-bit tick counter  更新32位节拍数,关中断             */
	OSTime++;											   /*/累加从开机以来的时间,用的是一个无符号32位变量*/
	OS_EXIT_CRITICAL();									   /*开中断*/
#endif
	if (OSRunning == OS_TRUE) {
#if OS_TICK_STEP_EN > 0u
		switch (OSTickStepState) {                     /* Determine whether we need to process a tick步进的状态:决定我们是否需要处理节拍  */
		case OS_TICK_STEP_DIS:                         /* Yes, stepping is disabled 步进被禁用 */
			step = OS_TRUE;								
			break;

		case OS_TICK_STEP_WAIT:                        /* No,  waiting for uC/OS-View to set ...步进等待状态:
													   等待uC/OS-View将步进状态设置成进一步*/
			step = OS_FALSE;                          
			break;

		case OS_TICK_STEP_ONCE:                        /* Yes, process tick once and wait for next ...步进一次等待下一步命令 */
			step = OS_TRUE;								/*... step command from uC/OS-View步进命令来自于uc/os-view*/
			OSTickStepState = OS_TICK_STEP_WAIT;		/*将步进状态设置为步进等待状态*/
			break;

		default:                                       /* Invalid case, correct situatio无效的情况或者正确的情况下*/
			step = OS_TRUE;							
			OSTickStepState = OS_TICK_STEP_DIS;		   /*将步进状态设置为禁止状态*/
			break;
		}
		if (step == OS_FALSE) {                            /* Return if waiting for step command如果正在等待步进命令,返回*/
			return;
		}
#endif
		ptcb = OSTCBList;                                  /* Point at first TCB in TCB list 指向TCB列表的第一个*/
		while (ptcb->OSTCBPrio != OS_TASK_IDLE_PRIO) {     /* Go through all TCBs in TCB list 浏览TCB列表的所有TCB*/
			OS_ENTER_CRITICAL();							/*进入中断*/
			if (ptcb->OSTCBDly != 0u) {                    /* No, Delayed or waiting for event with TO等待任务时的最多节拍数不为0*/
				ptcb->OSTCBDly--;                          /* Decrement nbr of ticks to end of delay时间延迟项减1*/
				if (ptcb->OSTCBDly == 0u) {                /* Check for timeout减1后检查是否到时间了。时间延迟项等于0,就转为就绪态(外部条件准备就绪)*/
					if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {	/*(检查内部条件是否准备就绪)
															如果TCB状态和挂起状态进行位与运算之后不等于准备好的状态,简单来说就是任务没有准备好*/
						ptcb->OSTCBStat &= (INT8U)~(INT8U)OS_STAT_PEND_ANY;          /* Yes, Clear status flag清除状态标志*/
						ptcb->OSTCBStatPend = OS_STAT_PEND_TO;                 /* Indicate PEND timeout将TCB挂起状态设置为超时状态*/
					}
					else {										/*如果是已准备好的状态(内部条件准备就绪)*/
						ptcb->OSTCBStatPend = OS_STAT_PEND_OK;/*就将TCB挂起状态设置为挂起结束(正常结束)状态*/
					}

					if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {  /* Is task suspended? 查看任务是否为挂起状态*/
						OSRdyGrp |= ptcb->OSTCBBitY;             /* No,  Make ready如果不是(即已为就绪态),在就绪表中找到具体的任务控制块*/
						OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
					}
				}
			}
			ptcb = ptcb->OSTCBNext;                        /* Point at next TCB in TCB list指向TCB列表的下一个 */
			OS_EXIT_CRITICAL();								/*退出中断(开中断)*/
		}
	}
}
复制代码

同时介绍一下相关的时间管理方面的内容:blog.csdn.net/adam_embedd…

\

1.1 时钟节拍

UCOSii通过时钟节拍OSTimeTick()来定期进行任务调度,一般来说这个频率是10-100HZ,频率越高,系统的开销也就越大。

1.2 任务延时函数

OSTimeDly()

任务可以调用OSTimeDly()来对自身延时一段时间。延时时,任务被挂起。任务被延时的时间必须是时钟节拍的倍数。与延时有关的变量在Tcb结构体中。

Tcb.OSTCBDly表示任务自己延时挂起的时间。

这样,当任务调用OSTimeDly()来进行延时时,该函数会修改修改OSTCBDly的值,把要延时的次数写入该变量,最后进行任务调度即可。

每次时钟节拍发生的时候,OSTCBDly的值都会被减去一,当该值为0的时候,内核就会把它放入就绪队列。

NOTE: 当调用OSTimeDly(1)只延时一个时钟节拍的时候,由于任务可能运行在一个时钟节拍的中后期,此时经过不到半个时钟节拍的时间,OSTCBDly的值就会被修改。因此,如果用户的应用程序至少得延时一个节拍,必须要调用 OSTimeDly(2),指定延时两个节拍。(即指定延时1,延时可能不足1,但是指定延时为2,至少可以保证延时一个节拍)。

来看一下OSTimeDly()的结构和原型:

结构:

void OSTimeDly(OS_TICK dly,//指定延时的长度,单位为时间节拍
                OS_OPT opt,//延时模式
                OS_ERR *p_err//错误信息复制代码
  • 如果延时时间dly>0,则会发生任务调度;0表示不延时
  • OSTimeDly()函数延时模式有四种:OS_OPT_TIME_DLY;OS_OPT_TIME_TIMEOUT;OS_OPT_TIME_PERIODIC;OS_OPT_TIME_MATCH;

函数原型:

void OSTimeDly (INT16U ticks)
{
    if (ticks > 0) {
        OS_ENTER_CRITICAL();
        if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {
            OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
        }   

        OSTCBCur->OSTCBDly = ticks;
        OS_EXIT_CRITICAL();
        OSSched();
    }
}
复制代码

可以看到该函数将延时次数传递给了OSTCBDly。

OSTimeDly()有一些缺点:一是只能延时65535次时钟节拍,二是不能换算成时间。\

1.3 结束任务延时函数

OSTimeDlyResume()函数可以被用来强制某一任务结束延时,它的主要作用是支持任务之间的通讯和同步。

OSTimeDlyResume()要做的就是将OSTCBDly清0,然后进行任务调度。

1.4 系统时间

每次发生时钟节拍时,UCOS都会将一个32位的计数器加1。

OSTimeGet()和 OSTimeSet()用来获取或者设置这个计数器的值。

\

文章分类
代码人生
文章标签