1.08 2


2使用了帶擴展功能的任務建立函數OSTaskCreateExt()和uCOS-II的堆疊檢查操作(要使用堆疊檢查操作必須用OSTaskCreateExt()建立任務—譯者注)。當用戶不知道應該給任務分配多少堆疊空間時,堆疊檢查功能是很有用的。在這個例子裏,先分配足夠的堆疊空間給任務,然後用堆疊檢查操作看看任務到底需要多少堆疊空間。顯然,任務要運行足夠長時間,並要考慮各種情況才能得到正確資料。最後決定的堆疊大小還要考慮系統今後的擴展,一般多分配10%,25%或者更多。如果系統對穩定性要求高,則應該多一倍以上。


uCOS-II的堆疊檢查功能要求任務建立時堆疊清零。OSTaskCreateExt()可以執行此項操作(設置選項OS_TASK_OPT_STK_CHKOS_TASK_OPT_STK_CLR打開此項操作)。如果任務運行過程中要進行建立、刪除任務的操作,應該設置好上述的選項,確保任務建立後堆疊是清空的。同時要意識到OSTaskCreateExt()進行堆疊清零操作是一項很費時的工作,而且取決於堆疊的大小。執行堆疊檢查操作的時候,uCOS-II從棧底向棧頂搜索非0元素(參看圖F 1.1),同時用一個計數器記錄0元素的個數。


2的磁片文件爲\SOFTWARE\uCOS-II\EX2_x86L,它包含9個任務。加上uCOS-II本身的兩個任務:空閒任務(idle task)和統計任務。與例1一樣TaskStart()由main()函數建立,其功能是建立其他任務並在螢幕上顯示如下的統計資料:






  • 每秒種任務切換的次數;



  • CPU利用率的百分比;



  • 當前日期和時間;



  • uCOS_II的版本號;



F 1.1 µC/OS-II stack checking.





1.08.01 main()


2main()函數和例1的看起來差不多(參看程式清單L1.11),但是有兩處不同。第一,main()函數調用PC_ElapsedInit()[程式清單L1.11(1)]來初始化計時器記錄OSTaskStkChk()的執行時間。第二,所有的任務都使用OSTaskCreateExt()函數來建立任務[程式清單L1.11(2)](替代老版本的OSTaskCreate()),這使得每一個任務都可進行堆疊檢查。














































程式清單 L 1.11 2中的Main()函數.



void main (void)



{



PC_DispClrScr(DISP_FGND_WHITE + DISP_BGND_BLACK);



OSInit();



PC_DOSSaveReturn();



PC_VectSet(uCOS, OSCtxSw);



PC_ElapsedInit(); (1)



OSTaskCreateExt(TaskStart, (2)



(void *)0,



&TaskStartStk[TASK_STK_SIZE-1],



TASK_START_PRIO,



TASK_START_ID,



&TaskStartStk[0],



TASK_STK_SIZE,



(void *)0,



OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);



OSStart();



}





除了OSTaskCreate()函數的四個參數外,OSTaskCreateExt()還需要五個參數(一共9個):任務的ID,一個指向任務堆疊棧底的指標,堆疊的大小(以堆疊單元爲單位,80X86中爲字),一個指向用戶定義的TCB擴展資料結構的指標,和一個用於指定對任務操作的變數。該變數的一個選項就是用來設定uCOS-II堆疊檢查是否允許。例2中並沒有用到TCB擴展資料結構指標。


1.08.02TaskStart()


程式清單L1.12列出了TaskStart()的虛擬碼。前五項操作和例1中相同。TaskStart()建立了兩個郵箱,分別提供給任務4和任務5[程式清單L1.12(1)]。除此之外,還建立了一個專門顯示時間和日期的任務。


























































程式清單 L 1.12 TaskStart()的虛擬碼。.



void TaskStart (void *data)



{



Prevent compiler warning by assigning ‘data’ to itself;



Display a banner and non-changing text;



Install uC/OS-II’s tick handler;



Change the tick rate to 200 Hz;



Initialize the statistics task;



Create 2 mailboxes which are used by Task #4 and #5; (1)



Create a task that will display the date and time on the screen; (2)



Create 5 application tasks;



for (;;) {



Display #tasks running;



Display CPU usage in %;



Display #context switches per seconds;



Clear the context switch counter;



Display uC/OS-II’s version;



If (Key was pressed) {



if (Key pressed was the ESCAPE key) {



Return to DOS;



}



}



Delay for 1 second;



}



}



1.08.03 TaskN()


任務1將檢查其他七個任務堆疊的大小,同時記錄OSTackStkChk()函數的執行時間[程式清單L1.13(1)–(2)],並與堆疊大小一起顯示出來。注意所有堆疊的大小都是以位元組爲單位的。任務1每秒執行10[程式清單L1.13(3)](間隔100ms)。
































































程式清單 L 1.13 2, 任務1



void Task1 (void *pdata)



{



INT8U err;



OS_STK_DATA data;



INT16U time;



INT8U i;



char s[80];









pdata = pdata;



for (;;) {



for (i = 0; i < 7; i++) {



PC_ElapsedStart(); (1)



err = OSTaskStkChk(TASK_START_PRIO+i, &data)



time = PC_ElapsedStop(); (2)



if (err == OS_NO_ERR) {



sprintf(s, "%3ld %3ld %3ld %5d",



data.OSFree + data.OSUsed,



data.OSFree,



data.OSUsed,



time);



PC_DispStr(19, 12+i, s, DISP_FGND_YELLOW);



}



}



OSTimeDlyHMSM(0, 0, 0, 100); (3)



}



}





程式清單L1.14所示的任務2在螢幕上顯示一個順時針旋轉的指標(用橫線,斜線等字元表示—譯者注),每200ms旋轉一格。






































程式清單 L 1.14 任務2



void Task2 (void *data)



{



data = data;



for (;;) {



PC_DispChar(70, 15, '|', DISP_FGND_WHITE + DISP_BGND_RED);



OSTimeDly(10);



PC_DispChar(70, 15, '/', DISP_FGND_WHITE + DISP_BGND_RED);



OSTimeDly(10);



PC_DispChar(70, 15, '-', DISP_FGND_WHITE + DISP_BGND_RED);



OSTimeDly(10);



PC_DispChar(70, 15, '\\', DISP_FGND_WHITE + DISP_BGND_RED);



OSTimeDly(10);



}



}





任務3(程式清單 L1.15)也顯示了與任務2相同的一個旋轉指標,但是旋轉的方向不同。任務3在堆疊中分配了一個很大的陣列,將堆疊填充掉,使得OSTaskStkChk()只需花費很少的時間來確定堆疊的利用率,尤其是當堆疊已經快滿的時候。
















































程式清單 L 1.15 任務3



void Task3 (void *data)



{



char dummy[500];



INT16U i;



data = data;



for (I = 0; i < 499; i++) {



dummy[i] = '?';



}



for (;;) {



PC_DispChar(70, 16, '|', DISP_FGND_WHITE + DISP_BGND_BLUE);



OSTimeDly(20);



PC_DispChar(70, 16, '\\', DISP_FGND_WHITE + DISP_BGND_BLUE);



OSTimeDly(20);



PC_DispChar(70, 16, '-', DISP_FGND_WHITE + DISP_BGND_BLUE);



OSTimeDly(20);



PC_DispChar(70, 16, '/', DISP_FGND_WHITE + DISP_BGND_BLUE);



OSTimeDly(20);



}



}





任務4(程式清單L1.16)向任務5發送消息並等待確認[程式清單L1.16(1)]。發送的消息是一個指向字元的指標。每當任務4從任務5收到確認[程式清單L1.16(2)],就將傳遞的ASCII碼加1再發送[程式清單L1.16(3)],結果是不斷的傳送“ABCDEFG....”












































程式清單 L 1.16 任務4



void Task4 (void *data)



{



char txmsg;



INT8U err;









data = data;



txmsg = 'A';



for (;;) {



while (txmsg <= 'Z') {



OSMboxPost(TxMbox, (void *)&txmsg); (1)



OSMboxPend(AckMbox, 0, &err); (2)



txmsg++; (3)



}



txmsg = 'A';



}



}





當任務5 [程式清單L1.17]接收消息後[程式清單L1.17(1)](發送的字元),就將消息顯示到螢幕上[程式清單L1.17(2)],然後延時1[程式清單L1.17(3)],再向任務4發送確認資訊。






































程式清單 L 1.17 任務5



void Task5 (void *data)



{



char *rxmsg;



INT8U err;







data = data;



for (;;) {



rxmsg = (char *)OSMboxPend(TxMbox, 0, &err); (1)



PC_DispChar(70, 18, *rxmsg, DISP_FGND_YELLOW+DISP_BGND_RED); (2)



OSTimeDlyHMSM(0, 0, 1, 0); (3)



OSMboxPost(AckMbox, (void *)1); (4)



}



}





TaskClk()函數[程式清單L1.18]顯示當前日期和時間,每秒更新一次。






































程式清單 L 1.18 時鐘顯示任務



void TaskClk (void *data)



{



Struct time now;



Struct date today;



char s[40];









data = data;



for (;;) {



PC_GetDateTime(s);



PC_DispStr(0, 24, s, DISP_FGND_BLUE + DISP_BGND_CYAN);



OSTimeDly(OS_TICKS_PER_SEC);



}



}



1.093


3中使用了許多uCOS-II提供的附加功能。任務3使用了OSTaskCreateExt()TCB的擴展資料結構,用戶定義的任務切換對外介面函數(OSTaskSwHook(),用戶定義的統計任務(statistic task )的對外介面函數(OSTaskStatHook()以及消息佇列。例3的磁片文件是\SOFTWARE\uCOS-II\EX3_x86L,它包括9個任務。除了空閒任務(idle task)和統計任務(statistic task ),還有7個任務。與例1,例2一樣,TaskStart()main()函數建立,其功能是建立其他任務,並顯示統計資訊。


1.09.01 main()


main()函數[程式清單L1.19]和例2中的相不多,不同的是在用戶定義的TCB擴展資料結構中可以保存每個任務的名稱[程式清單L1.19(1)](擴展結構的聲明在INCLUDES.H中定義,也可參看程式清單L1.20)。筆者定義了30個位元組來存放任務名(包括空格)[程式清單L1.20(1)]。本例中沒有用到堆疊檢查操作,TaskStart()中禁止該操作[程式清單L1.19(2)]
































































程式清單 L 1.19 3main()函數



void main (void)



{



PC_DispClrScr(DISP_FGND_WHITE + DISP_BGND_BLACK);



OSInit();



PC_DOSSaveReturn();



PC_VectSet(uCOS, OSCtxSw);



PC_ElapsedInit();






Strcpy(TaskUserData[TASK_START_ID].TaskName, "StartTask"); (1)



OSTaskCreateExt(TaskStart,



(void *)0,



&TaskStartStk[TASK_STK_SIZE-1],



TASK_START_PRIO,



TASK_START_ID,



&TaskStartStk[0],



TASK_STK_SIZE,



&TaskUserData[TASK_START_ID],



0); (2)



OSStart();



}



程式清單 L 1.20 TCB擴展資料結構。



typedef struct {



char TaskName[30]; (1)



INT16U TaskCtr;



INT16U TaskExecTime;



INT32U TaskTotExecTime;



} TASK_USER_DATA;





1.09.02任務


TaskStart()的虛擬碼

創作者介紹
創作者 立你斯 的頭像
立你斯

立你斯學習記錄

立你斯 發表在 痞客邦 留言(1) 人氣()