1 声明堆栈大小 在uc/os-ii操作系统的任务切换和中断处理过程中,需要保存处理器的内部寄存器和变量的值,这就 要求每个任务都有自己的堆栈空间。堆栈必须声明为OS_STK类型,并且由连续的内存空间组成,可以静态 分配空间(在编译时分配),也可以动态分配堆栈空间(在运行时分配)。由于采用动态分配方式,会导致 内存中含有大量内存碎片,因此不推荐使用动态分配方式。其两种声明方式如下: 静态分配方式: static OS_STK TaskStk[StkSize]; 或者 OS_STK TaskStk[StkSize]; 动态分配方式: OS_STK *pstk; pstk = (OS_STK*)malloc(StkSize); if(pstk != (OS_STK*)0) //判断堆栈分配是否成功 { printf("Create TaskStk Success"); } 2 设置堆栈生产方向 uc/os-ii操作系统支持2中堆栈生长方向。即可从高地址往低地址生长,也可以由低地址往高地址生长。 在调用OSTaskCreate()或者OSTaskCreateExt()创建任务的时候由于必须知道堆栈的生长方向,所以要在OS_CPU.H 文件中设置任务堆栈的生长方向。 #define OS_STK_GROWTH 1 //设置堆栈是从上往下长的 OSTaskCreate(Task,pdata,&TaskStk[StkSize - 1],prio); 或者 #define OS_STK_GROWTH 0 //设置堆栈是从下往上长的 OSTaskCreate(Task,pdata,&TaskStk[0],prio); 当然也可以这样编写创建任务的以支持堆栈的从上往下和从下往上生长 #if OS_STK_GROWTH == 1 OSTaskCreate(Task,pdata,&TaskStk[StkSize - 1],prio); #else OSTaskCreate(Task,pdata,&TaskStk[0],prio); #endif 3 堆栈检验 为控制产品成本,有时需要确定任务实际需要的堆栈空间的大小,避免为任务分配过多的对战空间,从而 减少应用程序代码所需的RAM数量。uc/os-ii系统提供OSTaskStkChk()函数用以确定任务实际需要的堆栈空间。 使用堆栈检验功能必须做一下几点: 1.在OS_CFG.H文件中设置OS_TASK_CREATE_EXT为 1 2.使用OSTaskCreateExt()创建任务,并且赋予任务比实际需要多一点的空间。可以在任何任务中调用STaskStkChk()函数,对任何用OSTaskCreateExt()建立的任务进行堆栈检验。 3.在OSTaskCreateExt()中,将参数opt设置为:OS_TASK_OPT_STK_CHK + OS_TASK_OPT_STK_CLR 4.把需要进行检测的任务的优先级作为OSTaskStkChk()的参数并调用 应使自己的应用程序运行足够长的时间,并且经历最坏的堆栈使用情况,这样才能得到正确的树木。一旦得到所需要的对单需求,就可以重新设置堆栈的最终大小了。在堆栈检验中,所得到的只是一个大智的堆栈使用情况,并不能说明堆栈的使用全部实际情况。 4 堆栈溢出 在实际的项目中,由于产品的升级需要可能一个任务会经常修改,所需要的实际堆栈大小并不能很好的确定,即便使用堆栈检验功能后,在后续产品的升级过程中变量的增加会导致堆栈不够用。而在调试的过程中,如果没有堆栈溢出的报警机制,一旦堆栈出现溢出,这个问题是很难一时被发现的。在这里,我建议在系统开始运行前,把每个任务的堆栈栈顶初始化一个值,每次出现任务切换的时候就读取对应栈顶的值,如果和初始化栈顶值相同的话就说明没有问题,如果值出现改变的话那么出现堆栈溢出的概率至少达到90%以上,这样可以避免出现堆栈溢出而不能发现的尴尬。下面是个项目的一部分,删了一些,可供参考。
#include "user/lc_sqce_aj.h" #include "include_all.h"
/* size of each task's stacks (# of WORDs) */ #define TASK_START_STK_SIZE 128 #define BUZZER_STK_SIZE 128 #define CTRLMSG_STK_SIZE 128 #define STORDEV_MOUNT_STK_SIZE 512 #define MODE_SWITCH_STK_SIZE 512 #define MODE_EXE_STK_SIZE 2000 #define TWO_CHANNEL_REC_SIZE 512 #define ALARM_STK_SIZE 128 #define TASK_STK_SIZE 512
/* application tasks */ #define TASK_START_ID 0 #define TASK_1_ID 1 #define TASK_2_ID 2 #define TASK_3_ID 3 #define TASK_4_ID 4 #define TASK_5_ID 5 #define TASK_6_ID 6 #define TASK_7_ID 7 #define TASK_8_ID 8 #define TASK_9_ID 9 #define TASK_10_ID 10 #define TASK_11_ID 11 #define TASK_12_ID 12 #define TASK_13_ID 13 #define TASK_14_ID 14 #define TASK_15_ID 15
/* application tasks priorities */ #define TASK_START_PRIO 0 #define TASK_1_PRIO 1 #define TASK_2_PRIO 2 #define TASK_3_PRIO 3 #define TASK_4_PRIO 4 #define TASK_5_PRIO 5 #define TASK_6_PRIO 6 #define TASK_7_PRIO 7 #define TASK_8_PRIO 8 #define TASK_9_PRIO 9 #define TASK_10_PRIO 10 #define TASK_11_PRIO 11 #define TASK_12_PRIO 12 #define TASK_13_PRIO 13 #define TASK_14_PRIO 14 #define TASK_15_PRIO 15
/*see task stacks*/ OS_STK TaskStartStk[TASK_START_STK_SIZE]; OS_STK BuzzerStk[BUZZER_STK_SIZE]; OS_STK CtrlmsgStk[CTRLMSG_STK_SIZE]; OS_STK StorDevStk[STORDEV_MOUNT_STK_SIZE]; OS_STK ModeSwitchStk[MODE_SWITCH_STK_SIZE]; OS_STK ModeExeStk[MODE_EXE_STK_SIZE];
static void TaskStart(void *p_arg); //函数声明 static void TaskStartCreateTasks(void); void InitStackMark(void);
//************************************************************************************ //* 函数名 :main //* 返回值 :N/A //* 参数 :N/A //* 函数说明:主函数 //* 作 者:啊呆 //***********************************************************************************
void main(void) { INT8U err;
// initialize uC/OS-II OSInit(); // install uC/OS-II's context switch vector IRQSetVect(uCOS, OSCtxSw);
OSTaskCreateExt(TaskStart, (void *)0, &TaskStartStk[TASK_START_STK_SIZE - 1], TASK_START_PRIO, TASK_START_ID, &TaskStartStk[0], TASK_START_STK_SIZE, (void *)0, OS_TASK_OPT_STK_CLR + OS_TASK_OPT_STK_CHK);
OSTaskNameSet(TASK_START_PRIO, "Start Task", &err); // start multitasking OSStart();
}
//********************************************************************************* //* 函数名 :TaskStart //* 返回值 :N/A //* 参数 :void *p_arg //* 函数说明:创建TaskStart任务 //* 作 者:啊呆 //******************************************************************************** static void TaskStart(void *p_arg) { #if OS_CRITICAL_METHOD == 3 OS_CPU_SR cpu_sr; #endif // prevent compiler warning p_arg = p_arg;
// install uC/OS-II's clock tick ISR OS_ENTER_CRITICAL(); IRQSetVect(TMR1_VEC, OSTickISR); OSSetTickRate(lc_clk_get_freq(CLK_SYS_SEL), OS_TICKS_PER_SEC); OS_EXIT_CRITICAL(); // initialize uC/OS-II's statistics OSStatInit();
TaskStartCreateTasks();
for (;;) { // clear the context switch counter OSCtxSwCtr = 0; // wait one second OSTimeDly(OS_TICKS_PER_SEC); } }
//******************************************************************************* //* 函数名 :TaskStartCreateTasks //* 返回值 :N/A //* 参数 :N/A //* 函数说明:创建任务 //* 作 者:啊呆 //****************************************************************************** static void TaskStartCreateTasks(void) { //初始化,创建每个任务对应需要的信号量 init_buzzer_proc(); init_ModeEXE_proc(); init_ctrlmsg_get_proc(); init_twoChRec_proc(); InitStackMark();
//创建任务 OSTaskCreate(buzzer_proc, (void *)0, &BuzzerStk[BUZZER_STK_SIZE-1], TASK_3_PRIO); OSTaskCreate(ctrlmsg_get_proc, (void *)0, &CtrlmsgStk[CTRLMSG_STK_SIZE-1], TASK_5_PRIO); OSTaskCreate(stordev_mount_proc, (void *)0, &StorDevStk[STORDEV_MOUNT_STK_SIZE-1], TASK_6_PRIO); OSTaskCreate(mode_switch_proc, (void *)0, &ModeSwitchStk[MODE_SWITCH_STK_SIZE-1], TASK_7_PRIO); OSTaskCreate(ModeEXE_proc, (void *)0, &ModeExeStk[MODE_EXE_STK_SIZE-1], TASK_11_PRIO); }
//************************************************************************** //* 函数名 :InitStackMark //* 返回值 :N/A //* 参数 :N/A //* 函数说明:初始化堆栈栈顶 //* 作 者:啊呆 //************************************************************************** void InitStackMark(void) { //初始化每个堆栈栈顶 BuzzerStk[0]=0x5153; BuzzerStk[1]=0xAA55; CtrlmsgStk[0]=0x5153; CtrlmsgStk[1]=0xAA55; StorDevStk[0]=0x5153; StorDevStk[1]=0xAA55; ModeSwitchStk[0]=0x5153; ModeSwitchStk[1]=0xAA55; ModeExeStk[0]=0x5153; ModeExeStk[1]=0xAA55; }
//***************************************************************************** //* 函数名 : CheckStkOverFlow //* 返回值 :BOOLEAN //* 参数 :INT8U TaskName //* 函数说明:初检测堆栈溢出 //* 作 者:啊呆 //****************************************************************************** BOOLEAN CheckStkOverFlow(INT8U TaskName) { //判断是否堆栈溢出 if(TaskName==buzzer) { if(BuzzerStk[0]==0x5153 && BuzzerStk[1]==0xAA55) return FALSE; } else if(TaskName==ctrlmsg) { if(CtrlmsgStk[0]==0x5153 && CtrlmsgStk[1]==0xAA55) return FALSE; } else if(TaskName==stordev_mount) { if(StorDevStk[0]==0x5153 && StorDevStk[1]==0xAA55) return FALSE; } else if(TaskName==mode_switch) { if(ModeSwitchStk[0]==0x5153 && ModeSwitchStk[1]==0xAA55) return FALSE; } else if(TaskName==ModeEXE) { if(ModeExeStk[0]==0x5153 && ModeExeStk[1]==0xAA55) return FALSE; } return TRUE; }