任务堆栈:
创建任务的时候除了需要配置任务的优先级以外,还需要对任务堆栈大小进行分配。而对于单片机这种RAM并不是非常大的微控制器来说,RAM显得格外珍贵,如果任务堆栈分配大了,会导致RAM不够用,分配小了任务运行又会受到影响,甚至系统的崩溃,所以在创建任务的时候合适的堆栈大小分配很重要。
uC/OS-II中任务堆栈的作用主要有两个,一是在任务运行的时候保存任务的一些局部变量,二是当任务挂起时,保存任务现场,也就是CPU寄存器的值。uC/OS-II系统是在OSTaskCreate();中的OSTaskStkInit();来确定堆栈地址的。虽然任务堆栈大小也可以通过设计者认为去测算出来,但是要考虑的东西太多,而且也不能十分精确。
任务堆栈----可以理解为-->RAM----->缓存寄存器;
实际上uC/OS-II在OS_TASK.C中提供了很多有关任务管理的功能函数,包括:
建立任务OSTaskCreate()、建立扩展任务OSTaskCreateExt()、删除任务OSTaskDel()等,其中还有一个关于堆栈的函数就是堆栈检验OSTaskStkChk(),这个函数的检测原理就是顺着堆栈的栈底开始计算空闲的堆栈空间大小,实现方法是统计存储值为0的连续堆栈入口的数量,直到发现存储值不为0的堆栈入口,这样就可以知道实际占用的堆栈大小了。
该函数的调用和运行需要将OS_TASK_STAT_STK_CHK_EN和OS_TASK_CREATE_EXT_EN进行使能,而检测的任务对象是通过任务的优先级来获取的,即:INT8U prio,并且需要定义一个OS_STK_DATA的结构体变量来存放堆栈情况的值,
其中的:
INT32U OSFree 就是剩余的堆栈大小
INT32U OSUsed 是已经使用的堆栈大小。
我们创建一个运行的任务(该任务优先级为5)中调用该函数并在该函数语句处打断点。
err = OSTaskStkChk(5, &stk_data);
待程序运行到此处时,通过观察&stk_data中的值,可以看到该任务栈的实际使用情况。下图为通过观测窗口观察到的使用情况。
可以看到OSFree的值为11,OSUsed的值为37,因为我定义的该任务堆栈大小为48,因此,此时CPU使用率为
usage = 37/48 = 77 %
也就是说当我定义栈空间为48时,能够保证任务运行且不会造成栈溢出,同时,有将近25%的栈空间剩余。
任务栈单位及设定原则
ucos规定,任务栈的单位为OS_STK,根据不同平台有不同的位宽定义,我是用的M0核定义为32位,也就是4字节宽度。因此,上面例子中定义的任务栈为48时,实际栈空间大小为
size = 48 * 4 = 192 Byte
关于定义栈空间原则,以任务使用率占用最大栈空间50%-80%为优,太小会造成空间浪费,太大会造成栈溢出。因此,上例中我们测试实际使用为37,则我们就可以定义该任务栈空间大小为
37 / 0.8 = 46.25
因此我定义为48。
这就是uC/OS-II自带检验任务堆栈大小的方法,但是由于任务运行受实际产品使用状态等很多方面的影响,必须在任务最大运行负载的情况下所测出来的使用率才是最可靠的,一般为了防止堆栈过小,在RAM空间够用的时候,建议最后可以将实际测出来的大小*2进行堆栈分配。