加入OSTaskCreateExt()创建拓展任务函数的使用。
加入OSTaskStkChk()堆栈检验函数的使用。
堆栈检验函数可检查任务堆栈的使用字节数量和空闲字节数量。
具体使用方法如下:
1.创建拓展任务OSTaskCreateExt()用于堆栈检验,堆栈检验必须用拓展任务OSTaskCreateExt()。如,
#define task1_PRIO 50 //这个是任务优先级,任务优先级的编号,1-63,且不能重复,它代表了任务的唯一性
#define task1_STK_NUM 40 //指任务的OS_STK的数量
OS_STK task1_STK[task1_STK_NUM]; //有task1_STK_NUM 个4个字节的空间,40*4
void task1(void* p_arg); //任务函数
#define task2_PRIO 60
#define task2_STK_NUM 40
OS_STK task2_STK[task2_STK_NUM];
void task2(void* p_arg);
OSTaskCreateExt(task1, NULL, \
&task1_STK[task1_STK_NUM - 1], task1_PRIO, task1_PRIO, \
task1_STK, task1_STK_NUM, NULL, OS_TASK_OPT_STK_CHK| OS_TASK_OPT_STK_CLR);
OSTaskCreateExt(task2, NULL, \
&task2_STK[task2_STK_NUM - 1], task2_PRIO, task2_PRIO, \
task2_STK, task2_STK_NUM, NULL, OS_TASK_OPT_STK_CHK| OS_TASK_OPT_STK_CLR);
void task1 (void *p_arg)
{
INT8U err1 = OSTaskStkChk(task1_PRIO,&StackBytes1);
GUI_Printf(0,40,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task1 FreeStack:%d",StackBytes1.OSFree);
GUI_Printf(0,60,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task1 UsedStack:%d",StackBytes1.OSUsed);
GUI_Printf(0,80,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task1 err:%d",err1);
while(1)
{
GUI_Printf(0,20,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"任务1");
// GUI_Printf(0,40,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task1 FreeStack:%d",StackBytes1.OSFree);
// GUI_Printf(0,60,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task1 UsedStack:%d",StackBytes1.OSUsed);
// GUI_Printf(0,80,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task1 err:%d",err1);
// OSTimeDlyHMSM(0, 0, 1, 0);
OSTimeDly(50);
}
}
void task2(void *p_arg)
{
INT8U err2 = OSTaskStkChk(task2_PRIO,&StackBytes2);
GUI_Printf(0,140,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task2 UsedStack:%d",StackBytes2.OSUsed);
GUI_Printf(0,120,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task2 FreeStack:%d",StackBytes2.OSFree);
GUI_Printf(0,160,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task2 err:%d",err2);
while(1)
{
GUI_Printf(0,100,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"任务2");
// GUI_Printf(0,120,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task2 FreeStack:%d",StackBytes2.OSFree);
// GUI_Printf(0,140,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task2 UsedStack:%d",StackBytes2.OSUsed);
// GUI_Printf(0,160,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task2 err:%d",err2);
// OSTimeDlyHMSM(0, 0, 1, 0);
OSTimeDly(50);
// 其他任务...
}
}
OSTaskCreateExt()创建拓展函数与OSTaskCreate()创建任务函数相比多了五个入口参数,它们的前四个参数task,pdata,ptos和prio(分别为:task是任务代码的指针,pdata是任务开始执行时传递给任务的参数的指针,ptos是分配给任务的堆栈的栈顶指针,prio是分配给任务的优先级)完全相同,先后顺序都一模一样,方便用户将OSTaskCreate()移植到OSTaskCreateExt()。后五个参数分别为:
id参数,为要建立的任务创建一个特殊的标识符,但是只要简单的将id设置的和人物的优先级一样就行。
pbos,是指向任务的堆栈的栈底指针,用于堆栈的检验。
stk_size,用于指定堆栈成员的数目,用于堆栈的检验。
pext,指向用户附加的数据域的指针,用来拓展任务的OS_TCB。
opt,用于设定OSTaskCreateExt()的选项,指定是否允许堆栈检验,是否将堆栈区域清零,任务是否要进行浮点操作等等。ucosii.h文件有一个所有选项的常数表,用户在使用时只需将选项常数进行位或操作即可。在堆栈检验时OSTaskCreateExt()的最后一个参数必须为OS_TASK_OPT_STK_CHK| OS_TASK_OPT_STK_CLR,用于开启堆栈检验。
2.定义结构体OS_STK_DATA XXX用于堆栈检验。如
OS_STK_DATA StackBytes1; /*定义结构体,用于堆栈检验*/
OS_STK_DATA StackBytes2; /*定义结构体,用于堆栈检验*/
结构体XXX中包含XXX.OSFree和XXX.OSUsed, 分别代表任务堆栈的使用字节数量和空闲字节数量。如
typedef struct os_stk_data {
INT32U OSFree; /* Number of free entries on the stack */
INT32U OSUsed; /* Number of entries used on the stack */
} OS_STK_DATA;
3.调用堆栈检验函数OSTaskStkChk(),两个输入参数分别为待检验任务的优先级和结构体XXX的地址。
void task1 (void *p_arg)
{
INT8U err1 = OSTaskStkChk(task1_PRIO,&StackBytes1);
GUI_Printf(0,40,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task1 FreeStack:%d",StackBytes1.OSFree);
GUI_Printf(0,60,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task1 UsedStack:%d",StackBytes1.OSUsed);
GUI_Printf(0,80,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task1 err:%d",err1);
while(1)
{
GUI_Printf(0,20,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"任务1");
// GUI_Printf(0,40,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task1 FreeStack:%d",StackBytes1.OSFree);
// GUI_Printf(0,60,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task1 UsedStack:%d",StackBytes1.OSUsed);
// GUI_Printf(0,80,GUI_WHITE,GUI_BLACK|GUI_FONT_16,"Task1 err:%d",err1);
// OSTimeDlyHMSM(0, 0, 1, 0);
OSTimeDly(50);
}
}
正常运行的堆栈检验函数OSTaskStkChk()的返回值是0,这里用
INT8U err1 = OSTaskStkChk(task1_PRIO,&StackBytes1);
也是为了观察返回值判断是否运行成功。运行结果如图
任务1和2均设置了40个OS_STK,使用了34,空闲6。用户应该使自己的应用程序运行足够长的时间,并且经历最坏的堆栈情况,这样才能得到正确的数,为了适应程序的多升级和拓展,应该多分配10%到100%的堆栈空间。