1、任务栈检测和任务栈清除
在创建任务时,也需要设置OSTaskCreateExt()传入opt参数。
当opt= (INT16U)(OS_TASK_OPT_STK_CLR | OS_TASK_OPT_STK_CHK),可以使用OSTaskStkChk()检查的任务栈的剩余空间,也可以使用OS_TaskStkClr()清除任务栈。
2、创建任务举例
#define LED0_TASK_PRIORITY 5 //设置LED0_TASK任务优先级为5
#define LED0_TASK_STACK_SIZE 88
//设置LED0_TASK任务堆栈大小为88, 为8的倍数
//如果任务中使用printf来打印浮点数据的话一点要8字节对齐
OS_STK LED0_TASK_STACK[LED0_TASK_STACK_SIZE];//LED0_TASK任务栈
//LED0_TASK任务
void LED0_TASK(void *pdata)
{
(void)pdata;
while(1)
{
OSTimeDlyHMSM(0,0,0,500);//延时500ms
}
}
OSTaskCreateExt(
LED0_TASK,/*任务函数指针*/
(void *)0,/*建立任务时,传递的参数*/
(OS_STK*)&LED0_TASK_STACK[LED0_TASK_STACK_SIZE-1],/*指向任务栈顶的指针*/
LED0_TASK_PRIORITY, /*任务优先级*/
LED0_TASK_PRIORITY,/*任务ID用优先级代替,2.52版本,无实际作用,保留作为扩展用*/
(OS_STK*)&LED0_TASK_STACK[0],/*指向栈底部的指针,用于OSTaskStkChk()函数*/
LED0_TASK_STACK_SIZE, /*指定任务堆栈的大小,由OS_STK类型决定*/
(void *)0, /*定义数据结构的指针,作为TCB的扩展*/
(INT16U)(OS_TASK_OPT_STK_CLR | OS_TASK_OPT_STK_CHK)/*允许任务栈检查*/
);
3、OSTaskStkChk()函数
1)、在使用OSTaskStkChk()之前,要先声明OS_STK_DATA结构变量,如下:
OS_STK_DATA TaskStackData;
2)、OSTaskStkChk()应用举例
OSTaskStkChk( LED0_TASK_PRIORITY, &TaskStackData);
3)、分析解析OSTaskStkChk()函数
函数功能:结构指针p_stk_data返回的数据就是该任务栈的使用情况
//prio表示任务优先级
INT8U OSTaskStkChk (INT8U prio, OS_STK_DATA *p_stk_data)
{
OS_TCB *ptcb; //任务控制块的指针
OS_STK *pchk;//任务栈的指针
INT32U nfree;//该任务栈的剩余空间大小,单位为OS_STK
INT32U size;//该任务栈的总空间大小,单位为OS_STK
//unsigned int重命名为OS_STK
#if OS_CRITICAL_METHOD == 3u
OS_CPU_SR cpu_sr = 0u;
#endif
参数检查开始//
#if OS_ARG_CHK_EN > 0u
if (prio > OS_LOWEST_PRIO)
{/*若任务优先级prio比最低优先级(空闲任务优先级)大,则表示任务优先级错误*/
if (prio != OS_PRIO_SELF)
{//自身优先级OS_PRIO_SELF为255
return (OS_ERR_PRIO_INVALID);//优先级无效
}
}
if (p_stk_data == (OS_STK_DATA *)0)
{/*p_stk_data结构指针为0*/
return (OS_ERR_PDATA_NULL);
}
#endif
p_stk_data->OSFree = 0u; /*假定任务栈的”可用空间”为0*/
p_stk_data->OSUsed = 0u; /*假定任务栈的”已用空间”为0*/
OS_ENTER_CRITICAL();//进入临界区(无法被中断打断),需要定义cpu_sr变量
if (prio == OS_PRIO_SELF)
{/*若任务优先级prio为自身优先级,需要读取当前任务的优先级*/
prio = OSTCBCur->OSTCBPrio;
//读取当前任务的优先级
// OSTCBCur指向“当前任务控制块”的指针
}
ptcb = OSTCBPrioTbl[prio];
//根据所给的任务优先级prio,读取任务控制块的指针
//*OSTCBPrioTbl[]为所有的任务控制块的指针
//OSTCBTbl[]任务控制块数组,所有的任务控制块都保存在这个数组中
if (ptcb == (OS_TCB *)0)
{/*任务控制块的指针ptcb为0 */
OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)
return (OS_ERR_TASK_NOT_EXIST);
}
if (ptcb == OS_TCB_RESERVED)
{/*任务控制块的指针ptcb为OS_TCB_RESERVED,OS_TCB_RESERVED =1 */
OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)
return (OS_ERR_TASK_NOT_EXIST);
}
if ((ptcb->OSTCBOpt & OS_TASK_OPT_STK_CHK) == 0u)
{
//调用OSTaskCreateExt()时会传入opt
//opt= (INT16U)(OS_TASK_OPT_STK_CLR | OS_TASK_OPT_STK_CHK)
//OS_TASK_OPT_STK_CHK允许任务栈检查
OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)
return (OS_ERR_TASK_OPT);
}
参数检查结束//
nfree = 0u; //假定该任务栈的剩余空间大小为0,单位为OS_STK
size = ptcb->OSTCBStkSize;//读取该任务栈的总空间大小,单位为OS_STK
pchk = ptcb->OSTCBStkBottom;//读取该任务栈的”栈底指针”
OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)
#if OS_STK_GROWTH == 1u
// OS_STK_GROWTH为栈的增长方向,1表示栈是向下增长
//CM3中,栈是由高地址向低地址增长的,所以OS_STK_GROWTH设置为1
while (*pchk++ == (OS_STK)0)
{
nfree++;
//计算”任务栈的剩余空间大小”,单位为OS_STK
//栈是由高地址向低地址增长的,所以栈底的地址较小,使用pchk++
}
#else
while (*pchk-- == (OS_STK)0)
{
nfree++;
//计算”任务栈的剩余空间大小”,单位为OS_STK
//栈是由低地址向高地址增长的,所以栈底的地址较大,使用pchk--
}
#endif
p_stk_data->OSFree = nfree * sizeof(OS_STK);
/* unsigned int重命名为OS_STK,计算该任务栈的可用空间大小,单位为字节数*/
p_stk_data->OSUsed = (size - nfree) * sizeof(OS_STK);
/*Compute number of bytes used on the stack*/
return (OS_ERR_NONE);
}
4、OS_TaskStkClr()函数
1)、警慎调用OS_TaskStkClr()函数,否则可能会导致系统崩溃。
注意:这个函数是给OSTaskCreateExt()调用的,在创建任务时,需要将任务栈初始化为0。在任务中不要随便调用。
2)、分析解析OS_TaskStkClr()函数
函数功能:清除任务栈
//pbos为指向栈底部的指针
//size为任务堆栈的大小
//opt= (INT16U)(OS_TASK_OPT_STK_CLR | OS_TASK_OPT_STK_CHK),该函数才会执行
void OS_TaskStkClr (OS_STK *pbos, INT32U size, INT16U opt)
{
if ((opt & OS_TASK_OPT_STK_CHK) != 0x0000u)
{ //调用OSTaskCreateExt()时会传入opt
//opt= (INT16U)(OS_TASK_OPT_STK_CLR | OS_TASK_OPT_STK_CHK)
//OS_TASK_OPT_STK_CHK允许任务栈检查
if ((opt & OS_TASK_OPT_STK_CLR) != 0x0000u)
{/*See if stack needs to be cleared*/
#if OS_STK_GROWTH == 1u
// OS_STK_GROWTH为栈的增长方向,1表示栈是向下增长
//CM3中,栈是由高地址向低地址增长的,所以OS_STK_GROWTH设置为1
while (size > 0u) //循环将任务栈清除
{/*Stack grows from HIGH to LOW memory*/
size--;
*pbos++ = (OS_STK)0;
//从栈底向上清除
//栈是由高地址向低地址增长的,所以栈底的地址较小,使用pchk++
}
#else
while (size > 0u)
{/*Stack grows from LOW to HIGH memory*/
size--;
*pbos-- = (OS_STK)0; /*Clear from bottom of stack and down*/
//从栈底向下清除
//栈是由低地址向高地址增长的,所以栈底的地址较大,使用pchk--
}
#endif
}
}
}
3)、OS_TaskStkClr()应用举例
这是给好奇心很强的人看的。再次强调,不要随便调用。
OS_TaskStkClr(
(OS_STK*)&LED0_TASK_STACK[0],/*指向栈底部的指针,用于OSTaskStkChk()函数*/
LED0_TASK_STACK_SIZE, /*指定任务堆栈的大小,由OS_STK类型决定*/
(INT16U)(OS_TASK_OPT_STK_CLR | OS_TASK_OPT_STK_CHK)/*允许任务栈清除*/
);
5、实际应用
const char CHECK_TASK_rn_REG[]="\r\n";
const char CHECK_TASK_Initialise_REG[]="CHECK_TASK Initialise";
const char LED0_TASK_used_Or_free_REG[]="LED0_TASK used/free:";
const char LED1_TASK_used_Or_free_REG[]="LED1_TASK used/free:";
const char KEY_TASK_used_Or_free_REG[]="KEY_TASK used/free:";
const char CHECK_TASK_used_Or_free_REG[]="CHECK_TASK used/free:";
const char Used_REG[]=" used%";
const char Err_REG[]=" err:";
void CHECK_TASK(void *pdata)
{
OS_STK_DATA pTaskStackData;
u8 err1 =0;//1079062528
(void)pdata;
printf("%s",CHECK_TASK_rn_REG);
printf("%s",CHECK_TASK_Initialise_REG);
while(1)
{
err1 = OSTaskStkChk( LED0_TASK_PRIORITY, &pTaskStackData);
printf("%s",CHECK_TASK_rn_REG);
printf("%s",LED0_TASK_used_Or_free_REG);
printf("%d/",pTaskStackData.OSUsed);
printf("%d",pTaskStackData.OSFree);
printf("%s",Used_REG);
printf( "%0.2f",(float)(pTaskStackData.OSUsed*100)/(float)(pTaskStackData.OSUsed+pTaskStackData.OSFree) );
printf("%s",Err_REG);printf("%d",err1);
printf("%s",CHECK_TASK_rn_REG);
err1 = OSTaskStkChk( LED1_TASK_PRIORITY, &pTaskStackData);
printf("%s",LED1_TASK_used_Or_free_REG);
printf("%d/",pTaskStackData.OSUsed);
printf("%d",pTaskStackData.OSFree);
printf("%s",Used_REG);
printf( "%0.2f",(float)(pTaskStackData.OSUsed*100)/(float)(pTaskStackData.OSUsed+pTaskStackData.OSFree) );
printf("%s",Err_REG);printf("%d",err1);
printf("%s",CHECK_TASK_rn_REG);
err1 = OSTaskStkChk( KEY_TASK_PRIORITY, &pTaskStackData);
printf("%s",KEY_TASK_used_Or_free_REG);
printf("%d/",pTaskStackData.OSUsed);
printf("%d",pTaskStackData.OSFree);
printf("%s",Used_REG);
printf( "%0.2f",(float)(pTaskStackData.OSUsed*100)/(float)(pTaskStackData.OSUsed+pTaskStackData.OSFree) );
printf("%s",Err_REG);printf("%d",err1);
printf("%s",CHECK_TASK_rn_REG);
err1 = OSTaskStkChk( CHECK_TASK_PRIORITY, &pTaskStackData);
printf("%s",CHECK_TASK_used_Or_free_REG);
printf("%d/",pTaskStackData.OSUsed);
printf("%d",pTaskStackData.OSFree);
printf("%s",Used_REG);
printf( "%0.2f",(float)(pTaskStackData.OSUsed*100)/(float)(pTaskStackData.OSUsed+pTaskStackData.OSFree) );
printf("%s",Err_REG);printf("%d",err1);
printf("%s",CHECK_TASK_rn_REG);
OSTimeDlyHMSM(0,0,5,0);//延时5s
}
}
输出结果:
LED0_TASK used/free:184/168 used%52.27 err:0
LED1_TASK used/free:212/172 used%55.21 err:0
KEY_TASK used/free:184/168 used%52.27 err:0
CHECK_TASK used/free:444/68 used%86.72 err:0