🔥作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生,研究方向无线联邦学习
🎬擅长领域:驱动开发,嵌入式软件开发,BSP开发
❄️作者主页:一个平凡而乐于分享的小比特的个人主页
✨收录专栏:UCOS-III,本专栏为UCOS-III学习记录
欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖
UCOSIII笔记(十三)
CPU利用率及栈检测统计
CPU利用率的基本概念及作用
CPU利用率其实就是系统运行的程序占用的CPU资源,表示机器在某段时间程序运行的情况。一个系统设计的好坏,可以使用CPU利用率来衡量,一个好的系统必然是能完美响应急需的处理,并且系统的资源不会过于浪费。μC/OS提供的CPU利用率统计是一个可选功能,只有将OS_CFG_STAT_TASK_EN宏定义启用后用户才能使用CPU利用率统计相关函数,该宏定义位于os_cfg.h文件中
CPU利用率统计初始化
在统计CPU 利用率之前必须先调用OSStatTaskCPUUsageInit()函数进行相关初始化,这个函数的目的就是为了计算只有空闲任务时CPU在某段时间内的运算最大值,也就是OSStatTaskCtrMax

栈溢出检测概念及作用
如果处理器有MMU或者MPU,检测栈是否溢出是非常简单的,MMU和MPU是处理器上特殊的硬件设施,可以检测非法访问,如果任务企图访问未被允许的内存空间的话,就会产生警告
如果处理器有MMU或者MPU,检测栈是否溢出是非常简单的,MMU和MPU是处理器上特殊的硬件设施,可以检测非法访问,如果任务企图访问未被允许的内存空间的话,就会产生警告
如果需要使用栈溢出检测的功能,就需要用户自己在App_OS_TaskSwHook()钩子函数中自定义实现,需要使用μC/OS为我们提供的栈检测功能,想要使用该功能就需要在os_cfg_app.h文件中将OS_CFG_STAT_TASK_STK_CHK_EN宏定义配置为1。
某些处理器中有一些栈溢出检测相关的寄存器,当CPU的栈指针小于(或大于,取决于栈的生长方向)设置于这个寄存器的值时,就会产生一个异常(中断),异常处理程序就需要确保未允许访问空间代码的安全(可能会发送警告给用户,或者其他处理)。任务控制块中的成员变量StkLimitPtr就是为这种目的而设置的

栈溢出检测过程
以STM32的栈生长方向为例子(高地址向低地址生长),在任务初始化的时候先将任务所有的栈都置 0,使用后的栈不为 0,在检测的时候只需从栈的低地址开始对为0的栈空间进行计数统计

统计任务OS_StatTask()
μC/OS提供了统计任务的函数,该函数为系统内部函数(任务),在启用宏定义OS_CFG_STAT_TASK_EN后,系统会自动创建一个统计任务------OS_StatTask(),它会在任务中计算整个系统的CPU 利用率,各个任务的 CPU 利用率和各个任务的栈使用信息
栈检测OSTaskStkChk()
μC/OS提供OSTaskStkChk()函数用来进行栈检测,在使用之前必须将宏定义OS_CFG_STAT_TASK_STK_CHK_EN配置为1,对于需要进行任务栈检测的任务,在其被OSTaskCreate()函数创建时,选项参数 opt 还需包含 OS_OPT_TASK_STK_CHK。统计任务会以我们设定的运行频率不断更新栈使用的情况并且保存到任务控制块的StkFree和StkUsed成员变量中,这两个变量分别表示任务栈的剩余空间与已使用空间大小,单位为任务栈大小的单位(在STM32中采用4字节)
任务栈大小的确定
任务栈的大小取决于该任务的需求,设定栈大小时,我们就需要考虑:所有可能被栈调用的函数及其函数的嵌套层数,相关局部变量的大小,中断服务程序所需要的空间,另外,栈还需存入CPU寄存器,如果处理器有浮点数单元FPU寄存器的话还需存入FPU寄存器。
同时等待多个内核对象
UCOSIII如何同时等待多个内核对象,在 UCOSIII中只支持同时等待多个信号量和消息队列,不支持同时等待多个事件标志组和互斥信号量。
UCOSIII中一个任务可以同时等待任意数量的信号量或者消息队列,当只要等到其中的任意一个的时候就会导致该任务进入就绪态。

任务通过调用函数 OSPendMulti()来等待多个内核对象,我们可以设定一个等待超时值,如果在指定的时间内没有一个内核对象被发布,那么将返回一个错误码,表示等待超时。
OSPendMulti()函数
函数 OSPendMulti0用来等待多个内核对象,调用 OSPendMulti0时,如果这些对象中有多个可用,则所有可用的信号量和消息都将返回给调用者,如果没有任何对象可用,则OSPendMulti0将挂起当前任务,直到以下任一情况发生:
- 对象变为可用。
- 到达设定的超时时间。
- 一个或多个任务被删除或被终止。
- 一个或多个对象被删除。
如果一个对象变为可用,并且有多个任务在等待这个对象,则 UCOSII将恢复优先级最高的那个任务,函数 OSPendMulti0原型如下:
c
OS_OBI_QTY OSPendMulti(OS PEND DATA *p_pend_data_tbl,
OS OBI QTY tbl_size,
OS TICK timeout,
OS OPT opt,
OS ERR *p_err)
p_pend_data_tbl:指向 OS_PEND_DATA 表的指针,调用者通过该表来查询函数的调用结果。调用该函数的时候首先必须初始化 OS_PEND_DATA 表中的每个元素的PendobiPtr,使得各个指针指向被等待的对象。
tbl_siae:表p_pend_data_tbl的大小,也就是所等待的内核对象数量。
timeout:设定一个等待超时值(时钟节拍数),用来设置任务等待对象发送的时间,如果为 0,表示这个任务将一直等待下去,直到对象被发送。
opt:来选择是否使用阻塞模式,有两个选项可以选择:
- OS_OPT_PEND_BLOCKING 如果没有任何消息存在的话就阻塞任务一直等待,直到接收到消息。
- OS OPT PEND NON BLOCKING 如果消息队列没有任何消息的话任务就直接返回。
p_err:用来保存调用此函数后返回的错误码。