UCOSii_统计任务(CPU使用率)

        UCOSII在创建任务时,为任务分配堆栈空间,堆栈分配过多会出现浪费内存,但不影响功能。堆栈分配太小,就会出现HardFault异常数组访问越界等等问题,最终导致程序崩溃,因此为任务分配适当的内存非常重要。该任务统计的是实时的使用情况,不是最大的。

原理:

        在OSStatInit()前只能有空闲任务、启动任务、统计任务3个任务处于就绪态,保证在此期间不会有其它的任务运行,系统在OSStatInit()中计算得到的OSIdleCtrMax是准确的。

        先计算N个tick内,空闲任务执行的最大计数次数OSIdleCtrMax,然后当系统启动之后,系统的N个任务在正常运行,当执行到空闲任务时会对全局变量OSIdleCtr不停的递增,再实时统计N个tick内,空闲任务的计数次数OSIdleCtr。这样,cpu使用的使用率就等于:(100uL - OSIdleCtr * 100/ OSIdleCtrMax )%,这样计算后的结果直接以百分比形式体现。

eg.最大次数OSIdleCtrMax:200   闲时统计次数:100 ,

使用率 = 100  - (100  *  100 / 200)= 50%

使用步骤:

1.确定 OS_TASK_STAT_EN 为1 。OS_TASK_STAT_EN 在 os_cfg.h 文件中。main()主函数中确保首先调用了函数OSInit()。

2. main()主函数中确保首先调用了函数OSInit()。因为OSInit()会调用 OS_InitTaskStat()函数。OS_InitTaskStat()用于创建统计任务,它是我们所需要的。

3.在一个用户任务中设置完Systick后,手动调用 OSStatInit();因为OSStatInit()函数,负责初始化统计任务的各计数值。

4.将mcu 使用率值OSCPUUsage 串口打印输出或者显示输出等。OSCPUUsage是一个全局 unsigned char 变量,以百分比形式显示,CPU使用率。想要实现任务堆栈的统计必须使用OSTaskCreateExt()创建任务,且OS_TASK_CREATE_EXT_EN置1

统计任务详解:

         在使用查看CPU使用率功能之前,要将OS_TASK_STAT_EN(在OS_CFG.h)设置为1,也就是使用这个功能。只要使用UCOSII就必须会有空闲任务,无需在用户代码里调用,此时uCOS-II在调用函数OSInit()初始化的时候,不仅要创建必备的空闲任务OS_TaskIdle(),还会创建另外一个系统任务OS_TaskStat()

        由于OS_TASK_STAT_EN使能,OSInit()里编译了OS_InitTaskStat();,OS_InitTaskStat()函数里根据创建任务方式OSTaskCreate ()  、OSTaskCreateExt () ;堆栈方向(cfg,h)创建了OS_TaskStat()

空闲任务源码:1.可利用钩子函数实现低功耗 2.永远处于就绪态

/*
*****************************************************************************************
* 空闲任务 IDLE TASK
*
* 描述: 这个函数是uC/OS-II内部函数,uC/OS-II总要建立一个空闲任务,这个任务在没有其它任务进入
* 就绪态时投入运行。这个空闲任务永远设为最低优先级,即OS_LOWEST_PRIO.空闲任务不可能被应
* 用软件删除。
*
* 参数: 无
*
* 返回: 无
*
* 注意: 1) OSTaskIdleHook()可以允许用户在函数中写入自己的代码,可以借助OSTaskIdleHook(),让
* CPU执行STOP指令,从而进入低功耗模式,当应用系统由电池供电时,这种方式特别有用。
* 2) 这个函数永远处于就绪态,所以不要在OSTaskIdleHook()中调用可以使任务挂起的PEND函数、
* OSTineDly???()函数和OSTaskSuspend()函数
******************************************************************************************/

void OS_TaskIdle (void *pdata) //空闲任务函数(指向一个数据结构)
{
 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
 OS_CPU_SR cpu_sr;
 #endif 
 
 
 pdata = pdata; //参数等于本身,防止一些编译器不能编译
 for (;;) { //无限循环
 OS_ENTER_CRITICAL(); //关闭中断
 OSIdleCtr++; //32位空闲计数器加1,提供给统计任务消耗CPU事件
 OS_EXIT_CRITICAL(); //打开中断
 OSTaskIdleHook(); //空闲任务钩子程序
 }
 }

OSInit()源码:根据cfg.h的配置进行初始化

void  OSInit (void)
{
    OSInitHookBegin();                                           /* Call port specific initialization code   */

    OS_InitMisc();                                               /* Initialize miscellaneous variables       */

    OS_InitRdyList();                                            /* Initialize the Ready List                */

    OS_InitTCBList();                                            /* Initialize the free list of OS_TCBs      */

    OS_InitEventList();                                          /* Initialize the free list of OS_EVENTs    */

#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u)
    OS_FlagInit();                                               /* Initialize the event flag structures     */
#endif

#if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u)
    OS_MemInit();                                                /* Initialize the memory manager            */
#endif

#if (OS_Q_EN > 0u) && (OS_MAX_QS > 0u)
    OS_QInit();                                                  /* Initialize the message queue structures  */
#endif

    OS_InitTaskIdle();                                           /* Create the Idle Task                     */
#if OS_TASK_STAT_EN > 0u
    OS_InitTaskStat();                                           /* Create the Statistic Task                */
#endif

#if OS_TMR_EN > 0u
    OSTmr_Init();                                                /* Initialize the Timer Manager             */
#endif

    OSInitHookEnd();                                             /* Call port specific init. code            */

#if OS_DEBUG_EN > 0u
    OSDebugInit();
#endif
}

OS_TaskStat()源代码:OSCPUUsage储存最终得到的使用率数据

/****************************************************************************************
 * 统计任务 STATISTICS TASK
 *
 * 描述: uC/OS-II有一个提供运行时间统计的任务。这个任务叫做OSTaskStat(),如果用户将系统定义常
 * 数OS_TASK_STAT_EN(见文件OS_CFG.H)设为1,这个任务就会建立。一旦得到了允许,OSTaskStat()
 * 每秒钟运行一次(见文件OS_CORE.C),计算当前的CPU利用率。换句话说,OSTaskStat()告诉用户
 * 应用程序使用了多少CPU时间,用百分比表示,这个值放在一个有符号8位整数OSCPUsage中,精读
 * 度是1个百分点。
 * 如果用户应用程序打算使用统计任务,用户必须在初始化时建立一个唯一的任务,在这个任务中
 * 调用OSStatInit()(见文件OS_CORE.C)。换句话说,在调用系统启动函数OSStart()之前,用户初
 * 始代码必须先建立一个任务,在这个任务中调用系统统计初始化函数OSStatInit(),然后再建立
 * 应用程序中的其它任务
 *
 * OSIdleCtr
 * OSCPUUsage = 100 * (1 -OSIdleCtr/OSIdleCtrMax) (units are in %)
 * OSIdleCtrMax
 *
 * 参数: pdata 指向一个数据结构,该结构用来在建立统计任务时向任务传递参数
 *
 * 返回: 无
 *
 * 注意: 1) uC/OS-II已经将空闲任务的优先级设为最低,即OS_LOWEST_PR10,统计任务的优先级设为次
 * 低,OS_LOWEST_PR10-1.
 * 2) 因为用户的应用程序必须先建立一个起始任务TaskStart()。在使用统计任务前,用户必须首
 * 先调用的是uC/OS-II中的系统初始化函数OSInit(),
 * 3) 在创建统计任务之前,为了保持系统达到稳定状态,需要延迟5秒钟,你必须至少延时2秒钟
 * 以设定最大空闲计数值
 * 3) We delay for 5 seconds in the beginning to allow the system to reach steady state
 * and have all other tasks created before we do statistics. You MUST have at least
 H:\SOURCE中文源代码\OS_CORE.C
 * a delay of 2 seconds to allow for the system to establish the maximum value for 
 * the idle counter. ****************************************************************************************/

#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(2u * OS_TICKS_PER_SEC / 10u);  //等待统计任务做好准备
    }
    OSIdleCtrMax /= 100uL;
    if (OSIdleCtrMax == 0uL) {
        OSCPUUsage = 0u;
#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为全局变量。                    
                                        //定义在ucosII.h文件中    
        OSIdleCtr    = 0uL;               //空闲计数器OSIdleCtr被清零
        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

使用实例eg.

int main(void)
{
    LCD_Ili9341_PortInit();
    GUI_Init();
    GUI_SetFont(&GUI_Font24_ASCII);
    GUI_DispStringAt("uC/OS Version: V",,*);
    GUI_DispFloat(OSVersion()*0.01,);
 
    OSInit();//UCOS系统初始化
    OSTaskCreate(Task1_Start, (void *), &task1_start_stk[TASK1_START_STKSIZE-], TASK1_START_PRIO);//创建起始任务
    OSStart();//启动OS
    return ;
}
 
void Task1_Start(void *p_arg)
{
    OS_CPU_SR  cpu_sr;
 
    p_arg = p_arg;
    OS_ENTER_CRITICAL();
    SysTick_Config(SystemCoreClock / OS_TICKS_PER_SEC);//初始化时钟
    OS_EXIT_CRITICAL();
    OSStatInit();//初始化统计函数的参数
 //创建用户任务
    OSTaskCreate(Task2, (void *), &task2_stk[TASK2_STKSIZE-], TASK2_PRIO);
    OSTaskCreate(Task3_GUI, (void *),&task3_gui_stk[TASK3_GUI_STKSIZE-], TASK3_GUI_PRIO);
    OSTaskDel(OS_PRIO_SELF);
}
 
void Task3_GUI(void *p_arg)
{
    p_arg = p_arg;
    GUI_SetFont(&GUI_Font13_ASCII);
 
    while()
    {
        GUI_DispStringAt("CPU Usage: ",,*);
        GUI_DispDec(OSCPUUsage,);
        GUI_DispString("%");
        GUI_X_ExecIdle();
    }
}

        在一个用户任务中设置完Systick后,手动调用 OSStatInit();因为OSStatInit()函数,负责初始化统计任务的各计数值。

        在使用上述应用实例的时候,要严格按照模板中代码出现的先后顺序进行移植编写,不可更改顺序,否则会出现一些列错误。比如说本来应在第13行创建一个应用程序任务,假设它的优先级比启动任务的还要高。但是用户却将其提前到第12行之前,就会导致在创建这个应用程序的时候剥夺了TaskStart()的CPU占有权,导致OSStatInit()不能正常初始化。OSStatInit()在执行的时候,只允许系统有三个任务TaskStart()OS_TaskStat()OS_TaskIdle()

        uCOS-II的系统时钟是在TaskStart()中才正式开始跳动的,不要在main()函数中启动系统时钟。之所以这样做,是因为“用户并不希望在多任务还没有开始时就接收到时钟节拍中断”。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值