我们先看我们的任务代码 TEST.C
1 /******************************Test*******************************/ 2 #include "includes.h" 3 #define TASK_STK_SIZE 512 //任务堆栈长度 4 5 OS_STK MyTaskStk[TASK_STK_SIZE]; //定义任务堆栈区 6 OS_STK YouTaskStk[TASK_STK_SIZE]; //定义任务堆栈区 7 INT16S key; //用于退出uCOS_II的键 8 INT8U x=0,y=0; //字符显示位置 9 void MyTask(void *data); //声明任务 10 void YouTask(void *data); 11 char* s_M="M"; 12 /************************主函数*********************************/ 13 void main (void) 14 { 15 //定义要显示的字符 16 OSInit( ); //初始化uCOS_II 17 PC_DOSSaveReturn( ); //保存Dos环境 18 PC_VectSet(uCOS, OSCtxSw); //安装uCOS_II中断 19 OSTaskCreate( 20 MyTask, //创建任务MyTask 21 s_M, //给任务传递参数 22 &MyTaskStk[TASK_STK_SIZE - 1], //设置任务堆栈栈顶指针 23 4 //任务的优先级别为0 24 ); 25 OSStart( ); //启动多任务管理 26 } 27 28 /*******************任务MyTask**********************************/ 29 30 void MyTask (void *pdata) 31 { 32 33 34 char* s_Y="Y"; //定义要显示的字符 35 #if OS_CRITICAL_METHOD == 3 36 OS_CPU_SR cpu_sr; 37 #endif 38 pdata = pdata; 39 OS_ENTER_CRITICAL( ); 40 PC_VectSet(0x08, OSTickISR); //安装时钟中断向量 41 PC_SetTickRate(OS_TICKS_PER_SEC); //设置时钟频率 42 OS_EXIT_CRITICAL( ); 43 OSStatInit( ); //初始化统计任务 44 OSTaskCreate( 45 YouTask, //创建任务MyTask 46 s_Y, //给任务传递参数 47 &YouTaskStk[TASK_STK_SIZE - 1], //设置任务堆栈栈顶指针 48 5 // MyTask的优先级别为2 49 ); 50 for (;;) 51 { 52 if (x>50) 53 { 54 x=0; 55 y+=2; 56 } 57 PC_DispChar(x, y, //字符的显示位置 58 *(char*)pdata, 59 DISP_BGND_BLACK+DISP_FGND_WHITE ); 60 x += 1; 61 //如果按下Esc键则退出uCOS_II 62 if (PC_GetKey(&key) == TRUE) 63 { 64 if (key == 0x1B) 65 { 66 debug31(); 67 PC_DOSReturn( ); //恢复Dos环境 68 } 69 } 70 OSTimeDlyHMSM(0, 0, 3, 0); //等待3秒 71 } 72 } 73 74 /************************任务YouTask******************************/ 75 76 void YouTask (void *pdata) 77 { 78 #if OS_CRITICAL_METHOD == 3 79 OS_CPU_SR cpu_sr; 80 #endif 81 pdata = pdata; 82 for (;;) 83 { 84 if (x>50) 85 { 86 x=0; 87 y+=2; 88 } 89 PC_DispChar( 90 x, y, //字符的显示位置 91 *(char*)pdata, 92 DISP_BGND_BLACK+DISP_FGND_WHITE 93 ); 94 x += 1; 95 OSTimeDlyHMSM(0, 0, 1, 0); //等待1秒 96 } 97 } 98 99 /************************End************************************/
OK,让我们从 MAIN 函数里面,的 OSStart();开始吧······
1 void OSStart (void) 2 { 3 INT8U y; 4 INT8U x; 5 6 7 if (OSRunning == FALSE) { 8 y = OSUnMapTbl[OSRdyGrp]; /* Find highest priority's task priority number */ 9 x = OSUnMapTbl[OSRdyTbl[y]]; 10 OSPrioHighRdy = (INT8U)((y << 3) + x); 11 OSPrioCur = OSPrioHighRdy; 12 OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; /* Point to highest priority task ready to run */ 13 OSTCBCur = OSTCBHighRdy; 14 OSStartHighRdy(); /* Execute target specific code to start task */ 15 } 16 }
第零拍(0 Tick)
1 分析MyTask代码发现初始化Stat Task,<OSStatInit()> 中OSTimeDly(2),第一次切换Mytask->OS_TaskStat(统计任务)
2 OS_TaskStat也不省心,他发现还不知道IDLEtask到底全速运行一秒中能记多少数,OSTimeDly(2ticks),第二次切换OS_TaskStat->OS_TaskIdle(空闲任务)
1 #if OS_TASK_STAT_EN > 0 2 void OSStatInit (void) 3 { 4 #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ 5 OS_CPU_SR cpu_sr; 6 #endif 7 8 9 OSTimeDly(2); /* Synchronize with clock tick */ 10 OS_ENTER_CRITICAL(); 11 OSIdleCtr = 0L; /* Clear idle counter */ 12 OS_EXIT_CRITICAL(); 13 OSTimeDly(OS_TICKS_PER_SEC); /* Determine MAX. idle counter value for 1 second */ 14 OS_ENTER_CRITICAL(); 15 OSIdleCtrMax = OSIdleCtr; /* Store maximum idle counter count in 1 second */ 16 OSStatRdy = TRUE; 17 OS_EXIT_CRITICAL(); 18 } 19 #endif
note:
OK,利己利人····贴上OSTimeDly的代码
1 void OSTimeDly (INT16U ticks) 2 { 3 #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ 4 OS_CPU_SR cpu_sr; 5 #endif 6 7 8 if (ticks > 0) { /* 0 means no delay! */ 9 OS_ENTER_CRITICAL(); 10 if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { /* Delay current task 取消就绪态 */ 11 OSRdyGrp &= ~OSTCBCur->OSTCBBitY; 12 } 13 OSTCBCur->OSTCBDly = ticks; /* Load ticks in TCB */ 14 OS_EXIT_CRITICAL(); 15 OS_Sched(); /* Find next task to run! */ 16 } 17 }
第二拍(2 Tick)
3 Idle Task会执行到第二个Tick,此时MyTask醒来,故OS_TaskIdle->MyTask:虽然ostimedly(2)以后,有好多行的初始化OS_TaskIdle的代码,但是我们 呀相信,计算机一个tick能完成很多事情,所以忽略不计,大概认为,OS_TaskIdle运行了2 ticks ;
4 很不幸,OSStatInit()又要求延时一秒去计算IDLE全速运行的计数值,即 OSTimeDly(OS_TICKS_PER_SEC); 这句话。MyTask->OS_TaskIdle,接下来的一秒中, 只有IDLE task在运行,而且傻傻地干一件事情,去加它视为宝贝的OSIdleCtr(以上还得详见 OSStatInit)
第202 Tick (OSTimeDly(2)+OSTimeDly(OS_TICKS_PER_SEC))
5 MyTask醒来,OS_TaskIdle->MyTask
6 干完自己事,创建了Youtask,显示了一个M,OSTimeDly(3秒),MyTask->YouTask
7 Youtask显示了一个Y,OSTimeDly(1秒),YouTask->OS_TaskIdle
OK,说了这么半天OS_TaskStat
1 #if OS_TASK_STAT_EN > 0 2 void OS_TaskStat (void *pdata) 3 { 4 #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ 5 OS_CPU_SR cpu_sr; 6 #endif 7 INT32U run; 8 INT32U max; 9 INT8S usage; 10 11 12 pdata = pdata; /* Prevent compiler warning for not using 'pdata' */ 13 while (OSStatRdy == FALSE) { 14 OSTimeDly(2 * OS_TICKS_PER_SEC); /* Wait until statistic task is ready 也就说等到2秒哦亲··· */ 15 } 16 max = OSIdleCtrMax / 100L; 17 for (;;) { 18 OS_ENTER_CRITICAL(); 19 OSIdleCtrRun = OSIdleCtr; /* Obtain the of the idle counter for the past second */ 20 run = OSIdleCtr; 21 OSIdleCtr = 0L; /* Reset the idle counter for the next second */ 22 OS_EXIT_CRITICAL(); 23 if (max > 0L) { 24 usage = (INT8S)(100L - run / max); 25 if (usage >= 0) { /* Make sure we don't have a negative percentage */ 26 OSCPUUsage = usage; 27 } else { 28 OSCPUUsage = 0; 29 } 30 } else { 31 OSCPUUsage = 0; 32 max = OSIdleCtrMax / 100L; 33 } 34 OSTaskStatHook(); /* Invoke user definable hook */ 35 OSTimeDly(OS_TICKS_PER_SEC); /* Accumulate OSIdleCtr for the next second */ 36 } 37 } 38 #endif
第400 Tick
8 在0tick睡去的OS_TaskStat终于醒来了(初始化会后会等待,SStatRdy 为 true 哦),OS_TaskIdle->OS_TaskStat
9 OS_TaskStat做完统计后,OSTimeDly(1秒),OS_TaskStat->OS_TaskIdle
第402 Tick
10 在202tick睡去的YouTask醒来,OS_TaskIdle->YouTask
11 显示了一个Y,OSTimeDly(1秒),YouTask->OS_TaskIdle
402 ticks 已经很接近500 ticks了,后面的先不管了,至少分析出了第一个500tick。
我是用仿造直尺刻度的方法,在白纸上画了三遍时间轴分析出的这个结果。
,具体的继续分析,见任哲的 3-1 现象分析 txt·····然后,结论里面,有几个特别重要的·····
NOTE:1 从上面的两处时间轴,和11次与10的讨论,不难发现,Stat执行时,不会有其他任务执行的,除非MyTask或Youtask故意延时比如198Ticks,但是用户一般会用正秒数的延时也许这正是OSStatInit中OSTimeDly(2)的好处,避免和其他任务冲撞而影响stat任务的执行。其实上面画的时间轴是系统时间轴和用户时间轴的重合,用户时间轴的刻度上总有个尾数2。 OS_TaskStat 不会和其他任务重合的
2.
(任务切换时OSPrioHighRdy会大于OSPrioCur,我曾经有思维定势,OSPrioHighRdy肯定是最小的)!!!!!!!
任务切换时OSPrioHighRdy是不是总是小于OSPrioCur要分情况考虑中断级任务调度时,肯定是优先级高任务的取代当先被中断的任务。即OSPrioHighRdy<OSPrioCur。但任务级调度时,一般是先执行优先级高的,高的执行完延时或挂起时让给优先级低的去执行,此时OSPrioHighRdy>OSPrioCur