uCOS-II的移植及使用_第1頁
uCOS-II的移植及使用_第2頁
uCOS-II的移植及使用_第3頁
uCOS-II的移植及使用_第4頁
uCOS-II的移植及使用_第5頁
已閱讀5頁,還剩145頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

uCOS-II的移植及使用報告人:日期:2016.1.181425uC/OS-II的任務3uC/OS-II的移植uC/OS-II同步與通信uC/OS-II概述uC/OS-III簡介目錄uC/OS-II概述C/OS——MicroControllerOS,微控制器操作系統

美國人JeanLabrosse1992年完成應用面覆蓋了諸多領域,如照相機、醫療器械、音響設備、發動機控制、高速公路電話系統、自動提款機等1998年出C/OS-II,目前的版本C/OS-IIV2.912000年,得到美國航空管理局(FAA)的認證,可以用于飛行器中網站uC/OS-II概述-性能特點源代碼公開可移植(Portable)大部分代碼用ANSIC寫,與處理器無關,移植時不需修改少量與微處理器硬件相關的部分用C與匯編編寫,移植時需修改:OS_CPU.H//與硬件相關,移植時需修改OS_CPU_A.ASM//集中了所有與處理器相關的匯編語言代碼OS_CPU.C//集中了所有與處理器相關的匯編語言代碼uC/OS-II概述-性能特點可裁剪(Scalable)可以只使用

C/OS-II中應用程序需要的那些系統服務。也就是說某產品可以只使用很少幾個

C/OS-II調用,而另一個產品則使用了幾乎所有

C/OS-II的功能,這樣可以減少產品中的

C/OS-II所需的存儲器空間(RAM和ROM)。可剪裁性通過條件編譯實現。uC/OS-II概述-性能特點可剝奪性(Preemptive)與可確定性內核可剝奪、函數調用或系統服務的執行時間具有可確定性,是硬實時操作系統。支持多任務C/OS-II可以管理255個任務任務棧每個任務有自己單獨的棧,

C/OS-II允許每個任務有不同的棧空間,以便壓低應用程序對RAM的需求。uC/OS-II概述-性能特點系統服務C/OS-II提供很多系統服務,例如郵箱、消息隊列、信號量、塊大小固定的內存的申請與釋放、時間相關函數等。中斷管理中斷可以使正在執行的任務暫時掛起,如果優先級更高的任務被該中斷喚醒,則高優先級的任務在中斷嵌套全部退出后立即執行,中斷嵌套層數可達255層。uC/OS-II概述--文件結構體系結構1425uC/OS-II的任務3uC/OS-II的移植uC/OS-II同步與通信uC/OS-II概述uC/OS-III簡介目錄uC/OS-II的任務2.1任務組成部分2.2任務的結構2.3任務存儲結構2.4任務狀態2.5任務優先級2.6任務就緒表及任務調度2.7任務操作2.8uC/OS-II的初始化一個完整的任務應該有如下三部分:任務代碼(程序)任務的私有堆棧(用以保護運行環境)任務控制塊(提供私有堆棧也是虛擬處理器的位置)2.1uC/OS-II的任務—組成前一個任務控制塊的指針后一個任務控制塊的指針指向任務的指針指向任務堆棧的指針任務的優先級別……voidmytask(void*pdata){……for(;;){……}}

任務的代碼

任務控制塊……

任務堆棧

任務圖2-4任務的組成從應用程序設計的角度來看,任務就是一個線程。就是一個用來解決用戶問題的C語言函數和與之相關聯的一些數據結構而構成的一個實體從任務存儲結構來看,由三部分構成:任務程序代碼、任務堆棧和任務控制塊。任務控制塊用來保存任務屬性,任務堆棧用來保存任務工作環境,任務程序代碼是任務的執行部分2.1uC/OS-II的任務—組成uCOS中的任務是一個線程,其代碼通常是一個無限循環結構/超循環結構,看起來像其它C函數一樣。2.1.1uC/OS-II的任務—代碼結構voidMyTask(void*pdata) { for(;;) {

可以被中斷的任務代碼;

OS_ENTER_CRITICAL(); //進入臨階段(關中斷) 不可以被中斷的任務代碼;

OS_EXIT_CRITICAL(); //退出臨階段(開中斷)

可以被中斷的任務代碼;

}}根據嵌入式系統任務的工作特點,任務的執行代碼通常是一個無限循環結構,并且在這個循環中可以響應中斷,這種結構也叫超循環結構。為了有效的對中斷進行控制,在任務的代碼里可使用UC/OS-II定義的宏OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()來控制何時響應中斷,何時屏蔽中斷。在運行這兩個宏之間的代碼時是不會響應中斷的,這種受保護的代碼段叫臨界段。一旦任務建立,一個任務控制塊OS_TCB就被賦值。任務控制塊是一個數據結構,保存該任務的相關參數,包括任務堆棧指針,任務的當前狀態,任務的優先級等。任務CPU使用權被剝奪時,TCB保存該時刻任務狀態;任務重新得到CPU控制權時,TCB確保任務從當時被中斷的那一點絲毫不差地繼續執行。OS_TCB全部駐留在RAM中。任務控制塊就相當于是一個任務的身份證,沒有任務控制塊的任務是不能被系統承認和管理的。

2.1.2uC/OS-II的任務—任務控制塊(TCB)任務控制塊的結構typedefstructos_tcb{OS_STK*OSTCBStkPtr;//指向當前任務堆棧棧頂的指針。每個任務的堆棧容量可以是任意的。#ifOS_TASK_CREATE_EXT_ENvoid*OSTCBExtPtr;//指向任務控制塊擴展的指針,擴展功能:任務執行時間、任務切換次數、任務堆棧使用情況等。OS_STK*OSTCBStkBottom;//指向當前任務堆棧棧底的指針。INT32UOSTCBStkSize;//任務堆棧的長度INT16UOSTCBOpt;//創建任務時的選擇項INT16UOSTCBId;//用于存儲任務的識別碼。保留。#endifstructos_tcb*OSTCBNext;//指向后一個任務控制塊的指針structos_tcb*OSTCBPrev;//指向前一個任務控制塊的指針#if(OS_Q_EN&&(OS_MAX_QS>=2))||OS_MBOX_EN||OS_SEM_ENOS_EVENT*OSTCBEventPtr;//指向事件控制塊的指針#endif#if(OS_Q_EN&&(OS_MAX_QS>=2))||OS_MBOX_ENvoid*OSTCBMsg;//指向傳遞給任務消息的指針#endifINT16UOSTCBDly;//任務等待的時限INT8UOSTCBStat;//任務的當前狀態標志

INT8UOSTCBPrio;//任務的優先級別INT8UOSTCBX;//用于快速訪問就緒表的數據INT8UOSTCBY;//用于快速訪問就緒表的數據INT8UOSTCBBitX;//用于快速訪問就緒表的數據INT8UOSTCBBitY;//用于快速訪問就緒表的數據#ifOS_TASK_DEL_EN

BOOLEANOSTCBDelReq;//請求刪除任務時用到的標志

#endif}OS_TCB;任務控制塊結構的主要成員typedefstructos_tcb{OS_STK*OSTCBStkPtr;//指向任務堆棧棧頂的指針

……

structos_tcb*OSTCBNext;//指向后一個任務控制塊的指針

structos_tcb*OSTCBPrev;//指向前一個任務控制塊的指針

……INT16U OSTCBDly; //任務等待的時限(節拍數)

INT8U OSTCBStat; //任務的當前狀態標志

INT8U OSTCBPrio; //任務的優先級別

……}

OS_TCB;任務控制塊的初始化當用戶程序調用函數OSTaskCreate()創建一個任務時,這個函數會調用系統函數OSTCBInit()來為任務控制塊進行初始化。這個函數首先為被創建任務從空任務控制塊鏈表獲取一個任務控制塊,然后利用任務的屬性對任務控制塊各個成員進行賦值,最后再把這個任務控制塊鏈入到任務控制塊鏈表的頭部。初始化任務控制塊函數OSTCBInit()的原型如下:INT8UOSTCBInit(){ INT8U Prio, //任務的優先級別,保存在OSTCBPrio中

OS_STK *ptos, //任務堆棧棧頂指針,保存在OSTCBStkPtr中

OS_STK*pbos, //任務堆棧棧底指針,保存在OSTCBStkBottom中

INT16U id, //任務的標示符,保存在OSTCBId中

INT16U stk_size, //任務堆棧的長度,保存在OSTCBStkSize中

void *pext, //任務控制塊的擴展指針,保存在OSTCBExtPtr中

INT16U opt //任務的控制塊的選擇項,保存在OSTCBOpt中};所謂堆棧,就是在存儲器中按數據“后進先出(LIFO)”的原則組織的連續存儲空間。為了滿足任務切換和響應中斷時保存CPU寄存器中的內容及存儲任務私有數據的需要,每個任務都應該配有自己的堆棧。任務堆棧是任務的重要組成部分。2.1.3uC/OS-II的任務—任務堆棧任務堆棧的創建為方便定義任務堆棧,在文件OS_CPU.H中專門定義了一個數據類型OS_STK:TypedefunsignedintOS_STK;

//該類型長度為16位這樣,在應用程序中定義任務堆棧的棧區就非常簡單,即定義一個OS_STK類型的一個數組即可。例如:#defineTASK_STK_SIZE512//定義堆棧長度(1024字節)OS_STKTaskStk[TASK_STK_SIZE];//定義一個數組來作為任務堆棧

創建任務函數OSTaskCreate()原型如下:

INT8UOSTaskCreate( void(*task)(void*pd), //指向任務的指針

void*pdata, //傳遞給任務的參數

OS_STK*ptos, //任務堆棧棧頂的指針

INT8Uprio); //指定任務優先級別的參數

當調用函數OSTaskCreate()來創建一個任務時,把數組的指針傳遞給函數OSTaskCreate()中的堆棧棧頂參數ptos,就可以把該數組與任務關聯起來而成為該任務的任務堆棧。任務堆棧的創建堆棧的增長方向是隨系統所使用的處理器不同而不同。因此在使用函數OSTaskCreate()創建任務時,一定要注意所使用的處理器對堆棧增長方向的支持是向上的還是向下的。低地址高地址堆棧增長的方向向下堆棧增長的方向向上圖3-7堆棧的不同增長方向上一練習時假設使用了支持堆棧向下增長方式的處理器設置參數ptos。如果使用的處理器支持堆棧的增長方向向上,則應該為: OSTaskCreate(MyTask,&ttt,&MyTaskStk[0],20);為了提高應用程序的移植性,在編寫代碼時可兼顧兩種情況,利用OS_CFG.H文件中的常數OS_STK_GROWTH作為選擇開關,使用戶可通過定義該常數的值來選擇相應代碼段,以適應不同的堆棧增長方向的需要。試改寫上一練習代碼。任務堆棧的初始化

uC/OS-II在創建任務函數OSTaskCreat()中通過調用任務堆棧初始化函數OSTaskStkInit()來完成任務堆棧初始化工作的,其原型如下:

OS_STK*OSTaskStkInit(

void(*task)(void*pd),

void*pdata,

OS_STK*ptos,

INIT16Uopt

);

由于各處理器的寄存器及對堆棧的操作方式不同,因此該函數需要用戶在進行uC/OS-II的移植時,按所使用的處理器由用戶來編寫。當CPU啟動運行一個任務時,CPU的各寄存器總是需要預置一些初始數據,例如指向任務的指針、任務堆棧指針、程序狀態字等。#defineOS_TASK_OPT_STK_CHK0x0001/*Enablestackcheckingforthetask*/#defineOS_TASK_OPT_STK_CLR0x0002/*Clearthestackwhenthetaskiscreate*/#defineOS_TASK_OPT_SAVE_FP0x0004/*Savethecontentsofanyfloating-pointregisters*/最方便的方法就是讓CPU從這個任務的任務堆棧里獲得這些數據!任務堆棧voidmytask(){…..

for(;;){…..}}任務代碼任務控制塊指向任務堆棧的指針…..指向前一個任務控制塊的指針指向后一個任務控制塊的指針……..任務的優先級別……任務2.2uC/OS-II的任務--存儲結構指向任務代碼任務控制塊任務代碼任務堆棧任務1……任務控制塊鏈表任務控制塊任務代碼任務堆棧任務2任務控制塊任務代碼任務堆棧任務n2.2uC/OS-II的任務--存儲結構uC/OS-II的任務有5種狀態睡眠態(DORMANT):任務駐留在程序空間,還沒有交給uCOS管理,即還沒有配備任務控制塊,還沒有被創建。就緒態(READY):

任務一旦建立,就進入就緒態準備運行,“萬事具備,只欠CPU”。運行態(RUNNING):正在使用CPU的狀態稱運行態。等待態(WAITING):等待某事件發生的狀態.中斷服務態(ISR):正在運行的任務被中斷時就進入了中斷服務態(ISR)。2.3uC/OS-II的任務—工作狀態正在運行的任務,需要等待一段時間或需要等待一個事件發生再運行時,該任務就會把CPU的使用權讓給別的任務而使任務進入等待狀態。任務在沒有被配備任務控制塊或被剝奪了任務控制塊時的狀態叫做任務的睡眠狀態

系統為任務配備了任務控制塊且在任務就緒表中進行了就緒登記,這時任務的狀態叫做就緒狀態。

處于就緒狀態的任務如果經調度器判斷獲得了CPU的使用權,則任務就進入運行狀態

一個正在運行的任務一旦響應中斷申請就會中止運行而去執行中斷服務程序,這時任務的狀態叫做中斷服務狀態

COSII(V2.91版)

支持255個任務,每個任務有一個特定的優先級。任務的優先級別用數字表示,0表示的任務的優先級最高,數字越大表示的優先級越低。通過常數OS_LOWEST_PRIO(在OS_CFG.H中)定義系統的最低優先級別,同時限定系統能容納的最多任務數量。OS_LOWEST_PRIO給空閑任務,OS_LOWEST_PRIO-1給統計任務。2.4uC/OS-II的任務—優先級

多任務操作系統的核心:任務調度。調度定義:就是通過一個算法在多個任務中確定那個任務來運行。做這項工作的就是調度器。任務調度的思想:總是讓優先級最高的就緒任務處于運行狀態。

uC/OS-I進行任務調度的依據:任務就續表。為了能使系統清楚地知道系統中哪些任務已經就緒,那些還沒有就緒,UC/OS-II在RAM中設立了一個記錄表,系統中的每個任務都在這個表占據一個位置,并用這個位置的狀態(1或者0)來表示任務是否處于就緒狀態。這個表就叫做任務就緒表。2.5uC/OS-II的任務—任務就緒表及調度每個就緒的任務都放入就緒表中,就緒表有兩個變量:OSRdyGrp、OSRdyTbl[]OSRdyGrp1207654300XXXYYY任務優先級2017654310891514131211181617232221201926242531302928273432333938373635424041474645444350484955545352515856576362616059[0][1][2][3][4][5][6][7]XY優先級最低任務優先級最高任務任務優先級號(idletask)任務就緒表的結構圖2-10就緒表的結構由于每個任務的就緒狀態只占一位,因此OSRdyTbl[]數組的一個元素可表達8個任務的就緒狀態。即每一個數組元素描述了8個任務的就緒狀態,于是這8個任務就可以看成一個任務組。數據類型為INT8U的變量OSRdyGrp,該變量的每一個位都對應OSRdyTbl[]的一個任務組(即數組的一個元素)。任務就緒表的結構如何根據任務的優先級別查找任務在就緒表的位置呢?例:已知某一個已經就緒的任務優先級別為prio=30,試判斷應該在就緒表的哪一位置上置1。分析:由于優先級別是一個單字節的數字,而且最大值不會超過63,即二進制00111111,因此,可以把優先級別看成是一個6位的二進制數,這樣就可以用高3位(D5、D4、D3)來指明變量OSRdyGrp的具體數據位,并用來確定就緒表數組元素的下標;用低3位(D2、D1、D0)來指明該數組元素的具體數據位。答:30的二進制形式為00011110,其低6位為011110,于是可知應該在OSRdyTbl[3]的D6位上置1,同時要把變量OSRdyGrp的D3位置1。對任務就緒表的操作在程序中,可用類似于下面的代碼把優先級為prio的任務置為就緒態。OSRdyGrp|=OSMapTbl[prio>>3];OSRdyTbl[prio>>3]|=OSMapTbl[prio&0x07];其中,OSMapTbl[]是uC/OS-II為加快運算速度定義的一個數組,各元素為: OSMapTbl[0]=00000001B OSMapTbl[1]=00000010B OSMapTbl[2]=00000100B OSMapTbl[3]=00001000B OSMapTbl[4]=00010000B OSMapTbl[5]=00100000B OSMapTbl[6]=01000000B OSMapTbl[7]=10000000B如果要使一個優先級為prio的任務脫離就緒態,則可使用如下代碼:If((OSRdyTbl[prio>>3]&=OSMapTbl[prio&0x07])==0)OSRdyGrp&=OSMapTbl[prio>>3];將任務就緒表OSRdyTbl[prio>>3]相應元素的相應位清零,而且當OSRdyTbl[prio>>3]中的所有位都為零時,即全組任務中沒有一個進入就緒態時,OSRdyGrp的相應位才為零。對任務就緒表的操作(續)例:欲使優先級為12的任務進入就緒態,設置就緒表。答:優先級為12,即00001100B。OSRdyGrp|=OSMapTbl[prio>>3]=OSMapTbl[1]=00000010;OSRdyTbl[1]|=OSMapTbl[prio&0x07]=OSMapTbl[4]=00010000;例:欲使優先級為12的任務脫離就緒態,設置就緒表。答:優先級為12,即00001100B。OSMapTbl[prio&0x07]=OSMapTbl[4]=11101111OSMapTbl[prio>>3]=OSMapTbl[1]=11111101由于OSRdyTbl[prio>>3]&=OSMapTbl[prio&0x07]=0

則OSRdyGrp=OSRdyGrp&OSMapTbl[prio>>3]=0從任務就緒表中獲取優先級別最高的就緒任務可用如下代碼:采用查表法確定高優先級任務Y=OSUnMapTbl[OSRdyGrp]; //獲得優先級別的D5、D4、D3位X=OSUnMapTbl[OSRdyTbl[Y]];//獲得優先級別的D2、D1、D0位Prio=(Y<<3)+X; //獲得就緒任務的優先級別其中,OSUnMapTbl[]同樣是uC/OS-II為加快運算速度定義的一個數組,共有256個元素:INT8UconstOSUnMapTbl[]={0,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};舉例:如OSRdyGrp的值為01101000B,即104,則查得OSUnMapTbl[OSRdyGrp]的值是3。如OSRdyTbl[3]的值是11100100B,即228,則查OSUnMapTbl[OSRdyTbl[3]]的值是2。則進入就緒態的最高任務優先級。

Prio=3*8+2=26

UC/OS-II經常使用類似于就緒表的形式來記錄任務的某種狀態,因此一定要熟悉這種表的結構以及對這種表的基本操作。任務切換:在多任務系統中,令CPU中止當前正在運行的任務而去運行另一個任務的工作。任務調度:按某種規則進行任務切換的工作。任務調度由任務調度器完成,調度器主要工作:

1.在任務就緒表中查找具有最高優先級別的就緒任務。

2.實現任務切換。uC/OS-II有兩種調度器:

任務級調度器(由OSSched()實現)、中斷級調度器(由OSIntExt()實現)。任務切換的兩個步驟:

1.獲得待運行任務的TCB指針。

2.進行斷點數據的切換。任務的調度任務切換過程獲得待運行任務的任務控制塊恢復待運行任務的運行環境處理器的PC=任務堆棧中的斷點地址處理器的SP=任務塊中保存的SP如何獲得待運行任務的任務控制塊?根據就緒表獲得待運行任務的任務控制塊指針其實,調度器在進行調度時,在這個位置還要進行一下判斷:究竟是待運行任務是否為當前任務,如果是,則不切換;如果不是才切換,而且還要保存被中止任務的運行環境。任務代碼任務堆棧內存處理器PCSP處理器通過兩個指針寄存器(PC和SP)來與任務代碼和任務堆棧建立聯系并運行它寄存器組程序運行環境運行環境包括了兩部分:處理器中的運行環境和內存中的運行環境任務運行時與處理器之間的關系任務代碼任務堆棧內存處理器PCSP多任務時的問題任務代碼任務堆棧內存任務代碼任務堆棧內存?當有多個任務時,處理器中的運行環境應該怎么辦?寄存器組程序運行環境程序

虛擬處理器PCSP

虛擬處理器PCSP

虛擬處理器PCSP

虛擬處理器PCSP調度器多任務時任務與處理器之間關系的處理程序處理器PCSP在內存中為每個任務創建一個虛擬的處理器(處理器部分的運行環境由操作系統的調度器按某種規則來進行這兩個復制工作復制當需要運行某個任務時就把該任務的虛擬處理器復制到實際處理器中復制當需要中止當前任務時,則把任務對應的虛擬處理器復制到內存復制再把另一個需要運行的任務的虛擬處理器復制到實際處理器中寄存器組寄存器組也就是說,任務的切換是任務運行環境的切換任務切換宏OS_TASK_SW()

任務切換就是中止正在運行的任務(當前任務),轉而去運行另外一個任務的操作,當然這個任務應該是就緒任務中優先級別最高的那個任務。需要由宏OS_TASK_SW()

來引發一次中斷或者一次調用來使OSCtxSw()執行任務切換工作,任務切換OSCtxSw()是一個中斷服務程序。任務的調度(續)1.獲得待運行任務的TCB指針voidOSSched(void){INT8Uy;OS_ENTER_CRITICAL();if((OSLockNesting|OSIntNesting)==0)//未被上鎖且不是中斷服務程序調用

{

y=OSUnMapTbl[OSRdyGrp]; OSPrioHighRdy=(INT8U)((y<<3)+OSUnMapTbl[OSRdyTbl[y]]);//得到最高優先級任務

if(OSPrioHighRdy!=OSPrioCur)//不是當前運行任務

{

OSTCBHighRdy=OSTCBPrioTbl[OSPrioHighRdy];//得到待運行任務控制塊指針OSCtxSwCtr++;//統計任務切換次數的計數器加1OS_TASK_SW();//實施任務切換

}}OS_EXIT_CRITICAL();}由于操作系統是通過任務的任務控制塊TCB來管理任務的,因此調度器真正實施任務切換之前的主要工作是要獲得待運行任務的任務控制塊指針和當前任務的任務控制塊指針。任務的調度(續)2.任務切換宏OS_TASK_SW()SPR1R2……RnPCPSWR1R2……RnPCPSWR1R2……RnPCPSWCPU的各寄存器被中止任務TCB待運行任務TCBOSTCBStkPtrOSTCBStkPtr被中止任務堆棧待運行任務堆棧圖2-11調度器進行任務切換時的動作斷點:任務被中止運行時的位置。斷點數據:當時存放在CPU的各寄存器中的數據。“無縫”接續:當任務恢復運行時,必須在斷點處以斷點數據作為初始數據接著運行。正確地恢復斷點數據的關鍵:CPU的堆棧指針SP是否有正確的指向。在系統中存在多個任務時,如果在恢復斷點數據使用另一個任務的任務堆棧指針(存放在TCB的OSTCBStkPtr中)來改變CPU的堆棧指針SP,那么CPU運行的就不是剛才被中止運行的任務,而使另一個任務了,也就是實現任務切換了。為了了解調度器是如何進行任務切換的,探討一下一個被中止運行的任務,將來又要“無縫”地恢復運行應該滿足的條件2.7任務的操作—創建uC/OS-II是通過任務控制塊來管理任務的。

uC/OS-II有兩個用來創建任務的函數:TaskCreate()、OSTaskCreateExt()OSTaskCreate()向下兼容,OSTaskCreateExt()是前一函數的擴展,提供了一些附加功能。任務可以在多任務調度開始前建立,也可以在其他任務執行過程中建立。任務不能由中斷服務程序建立。創建任務的一般方法

可在調用函數OSStart()啟動任務調度之前來創建。在任務中來創建。

uC/OS-II的規定:在OSStart()啟動任務調度之前必須創建至少一個任務。這樣,在OSStart()之前先創建一個任務,并賦予它最高的優先級,從而使它成為起始任務,然后在這個起始任務中,在創建其它各任務。如果要使用系統提供的統計任務,則統計任務的初始化函數必須在這個起始任務中來調用。

uC/OS-II不允許在中斷服務程序中創建任務!創建任務的一般方法/*****************************主函數**********************************/voidmain(void){

…… OSInit(); //對uC/OS-II初始化

…… OSTaskCreate(TaskStart,……); //創建起始任務

OSStart(); //開始多任務調度}/*****************************起始任務*********************************/voidTaskStart(void*pdata){

…… //在這個位置安裝并啟動uC/OS-II時鐘

OSStatInit(); //初始化統計任務

…… //在這個位置創建其它任務

For(;;) {

起始任務的代碼

}}

所謂掛起一個任務,就是停止這個任務的運行。在uC/OS-II中,用戶任務可通過調用系統提供的函數OSTaskSuspend()來掛起自身或者除空閑任務之外的其他任務。用函數OSTaskSuspend()掛起的任務,只能在其它任務中通過調用恢復函數OSTaskResume()使其恢復為就緒狀態。等待狀態就緒狀態運行狀態OS_TASK_SW()OSTaskResume()OSTaskSuspend()

任務的CPU使用權被剝奪圖任務的掛起和恢復2.7任務的操作—掛起與恢復

刪除任務,就是把該任務處于休眠狀態。并不是說任務的代碼真的被刪除了,只是任務的代碼不再被操作系統調用。通過調用OSTaskDel()就可以完成刪除任務自身或除了空閑任務之外的其他任務。

函數OSTaskDel()的原型如下:

#ifOS_TASK_DEL_ENINT8UOSTaskDel( INT8Uprio //要刪除任務的優先級

);

如果任務刪除自己,則應在調用函數時令函數的參數prio為OS_PRIO_SELF。

刪除任務具體做法是,把被刪除任務的任務控制塊從任務控制塊鏈表中刪除,并歸還給空任務控制塊鏈表,然后在任務就緒表中把該任務的就緒狀態位置0,于是該任務就不能再被調度器調用了。2.7任務的操作—刪除請求刪除任務函數OSTaskDelReq()的原型如下:

INT8UOSTaskDelReq( INT8Uprio //要刪除任務的優先級

);

如果任務請求刪除自己,則應在調用函數時令函數的參數prio為OS_PRIO_SELF。

進入Prio是空閑任務?

返回OS_TASK_NOT_EXIST

返回OS_TASK_IDLE_PRIO返回被刪除任務TCB的成員OSTCBDelReq的值NOYESYESYES

返回OS_NO_ERRNOPrio是合法優先級?

返回OS_PRIO_INVALIDNOPrio=OS_PRIO_SELF?Prio任務的TCB不存在?NOYES圖2-15函數OSTaskDelReq()流程圖提出刪除請求任務的執行路徑被刪除任務的執行路徑有時任務會占用一些動態分配的資源,這時如果有其他任務把這個任務刪除了,那么被刪除任務所占用的一些資源就會因為沒有被釋放而丟失,這是任何系統都無法接受的。具體辦法是:提出刪除任務請求的任務只負責刪除任務請求,而刪除工作則由被刪除任務自己來完成。這樣,被刪除任務就可以根據自身的具體情況來決定何時刪除自身,同時也有機會在刪除自身之前把占用的資源釋放掉。2.7任務的操作—請求刪除任務在用戶建立任務的時候會分配給任務一個優先級。在程序運行期間,用戶可以通過調用OSTaskChangePrio()來改變任務的優先級。換句話說,就是μC/OS-Ⅱ允許用戶動態的改變任務的優先級。函數OSTaskChangePrio()的原型如下:

INT8UOSTaskChangePrio( INT8Uoldprio, //任務現在的優先級

INT8Unewprio//要修改的優先級

);

2.7任務的操作—改變任務優先級INT8UOSTaskQuery( INT8Uprio, //待查詢任務的優先級

OS_TCB*pdata //存儲任務信息的結構

);函數OSTaskQuery()的原型如下:

有時,在應用程序運行中需要了解一個任務的指針、堆棧等信息,這時可通過調用函數OSTaskQuery()來獲取選定的任務的信息。若調用函數OSTaskQuery()查詢成功,則返回OS_NO_ERR,并把查詢得到的任務信息存放在結構OS_TCB類型的變量中。2.7任務的操作—查詢任務信息系統首先調用初始化函數OSIint()。OSIint()初始化μC/OS-Ⅱ所有的變量和數據結構。OSInit()建立空閑任務idletask,這個任務總是處于就緒態的。空閑任務OSTaskIdle()的優先級總是設成最低,即OS_LOWEST_PRIO。如果統計任務允許OS_TASK_STAT_EN和任務建立擴展允許都設為1,則OSInit()還得建立統計任務OSTaskStat()并且讓其進入就緒態。OSTaskStat的優先級總是設為OS_LOWEST_PRIO-1。

初始化時主要是創建包括空任務控制塊鏈表在內的5個空數據緩沖區,及按任務優先級存放任務控制塊指針的數組OSTCBPrioTbl[OS_LOWEST_PRIO+1]。2.8uC/OS-II的初始化uC/OS-II初始化后的數據結構000000000000000000000000000000000000000000000000000000001100000000000001圖2-16uC/OS-II初始化后的數據結構任務就緒表

OSRdyGrp任務就緒表

OSRdyTbl[]●●[OS_LOWEST_PRIO-1][OS_LOWEST_PRIO]OSTCBPrioTbl[][0][1][2]

空任務控制塊

空任務控制塊

空任務控制塊……OSTCBStkBottom……OSTCBStkPtr…………OSTCBStkBottom……OSTCBStkPtr……統計任務的控制塊空閑任務的控制塊OSTCBFreeList

任務控制塊鏈表OSTCBList

統計任務堆棧

空閑任務堆棧

其余4個鏈表1425uC/OS-II的任務3uC/OS-II的移植uC/OS-II同步與通信uC/OS-II概述uC/OS-III簡介目錄uC/OS-II的移植3.1基于Cortex-M3內核的移植3.2基于ARM7內核的移植μC/OS-II移植應用程序(用戶代碼)μC/OS-II(與處理器無關代碼)OS_CORE.cOS_FLAG.c...μC/OS-II配置(與應用無關)OS_CFG.HINCLUDES.H

μC/OS-II移植(與處理器相關代碼)CPU定時器硬件軟件——μC/OS-II硬件軟件體系結構用于產生系統時鐘移植時需要編寫的代碼54User目錄Main.CMain.HIncludes.HOS_Cfg.HμC/OS-II

Source目錄OS_CORE.COS_FLAG.COS_MBOX.COS_MEM.COS_MUTEX.COS_Q.COS_SEM.COS_TASK.COS_TIME.COS_TMR.CuCOS_II.HμC/OS-II

Ports目錄CortexM3

OS_CPU_C.COS_CPU_A.ASMOS_CPU.HBSP(板級支持包)Startup.STarget.CTarget.H

ARMCortex-M3

目標板與處理器無關操作系統內核代碼與處理器有關需要移植代碼開發板相關代碼3.1基于ARMCortex-M3的移植55內核文件移植的部分用戶代碼配置代碼主任務56ARMCortex-M3的寄存器模型在移植之前,先簡述ARMCortex-M3寄存器模型。ARMCortex-M3總共有20個寄存器,每個都是32位寬度。R0-R12通用寄存器,可存儲數據也可存放指針R13用于存放堆棧指針。實際上有兩個堆棧指針SP_process(進程堆棧)和

SP_main(主堆棧),但任何時候只有一個是可見的。在本移植中,

SP_process用于任務代碼(即線程模式),SP_main用于異常代碼(即處理模式)。R14連接寄存器LR。在執行分支鏈接指令(BL)或帶交換的分支鏈接指令(BLX)時,存儲來自PC的返回地址;也用作異常的返回。R15程序計數寄存器PC。用于指示當前正被執行的指令。根據不同的指令,每執行一條,PC增加2或增加4。5758狀態中斷59控制寄存器603.1.1移植條件移植μC/OS-II到處理器上必須滿足以下條件:(1)處理器的C編譯器能產生可重入代碼μC/OS是多任務內核,函數可能會被多個任務調用,代碼的重入性是保證完成多任務的基礎。可重入代碼指的是可被多個體任務同時調用,而不會破壞數據的一段代碼,或者說代碼具有在執行過程中打斷后再次被調用的能力。舉例說明:Swap1函數代碼:Inttemp;voidswap1(int*x,int*y){temp=*x;*x=*y;*y=temp;}舉例說明:Swap2函數代碼:voidswap2(int*x,int*y){inttemp;temp=*x;*x=*y;*y=temp;}可重入不可重入編譯器還得支持,MDK開發環境,可生成可重入代碼61(2)用C語言可打開和關閉中斷ARM處理器核包含一個CPSR寄存器,該寄存器包括一個全局的中斷禁止位,控制它便可打開和關閉中斷。PRIMASK(3)處理器支持中斷并且能產生定時中斷μC/OS-II通過處理器產生的定時器中斷來實現多任務之間的調度。ARMCortex-M3的處理器都支持中斷并能產生定時器中斷,專門有一個SysTick定時器來實現。(4)處理器支持能夠容納一定量數據的硬件堆棧(通常需要幾十KByte字節)

比如AT98C51處理器,內部只有128字節的RAM,要運行,需外擴RAM。CM3的芯片,內部可多達128KByte的容量,因此可直接使用。(5)處理器有將堆棧指針和其他CPU寄存器讀出和存儲到堆棧(或內存)的指令

μC/OS-II進行任務調度時,會把當前任務的CPU寄存器存到此任務的堆棧中,然后,再從另一個任務的堆棧中恢復原來的工作寄存器,繼續運行另一個任務。所以,寄存器的入棧和出棧是μC/OS-II多任務調度的基礎。運行TCP、UDP需要的內存會更大,通常要100K左右62

所謂移植,就是使一個實時操作系統能夠在某個微處理器平臺上或微控制器平臺上運行。由μC/OS-II的文件系統可知,在移植過程中,用戶需要關注的就是與處理器相關的代碼。這部分包括一個頭文件OS_CPU.H、一個匯編文件OS_CPU_A.ASM和一個C代碼文件OS_CPU_C.C。OS_CPU.HOS_CPU_C.COS_CPU_A.ASM#define設置一個常量的值聲明10個數據類型用#define聲明三個宏用C語言編寫六個簡單的函數編寫四個匯編語言函數移植實際中,寫一個就行3.1.2移植步驟631、INCLUDES.HINCLUDES.H是一個頭文件,它在所有.C文件的第一行被包含。#include"includes.h"INCLUDES.H使得用戶項目中的每個.C文件不用分別去考慮它實際上需要哪些頭文件。使用INCLUDES.H的唯一缺點是它可能會包含一些實際不相關的頭文件。這意味著每個文件的編譯時間可能會增加。但由于它增強了代碼的可移植性,所以我們還是決定使用這一方法。用戶可以通過編輯INCLUDES.H來增加自己的頭文件,但是用戶的頭文件必須添加在頭文件列表的最后。2、基本配置和定義OS_CPU.H(1)用#define設置一個常量的值#ifdefOS_CPU_GLOBALS#defineOS_CPU_EXT#else#defineOS_CPU_EXTextern#endif64(2)定義與編譯器相關的數據類型

為了保證可移植性,程序中沒有直接使用C語言中的short、int和long等數據類型的定義,因為它們與處理器類型有關,隱含著不可移植性。程序中自己定義了一套數據類型,如INT16U表示16位無符號整型。對于ARM這樣的32位內核,INT16U是unsignedshort型;如果是16位處理器,則是unsingedint型。typedefunsignedcharBOOLEAN;/*Boolean布爾變量*/typedefunsignedcharINT8U;/*無符號8位實體*/typedefsignedcharINT8S;/*有符號8位實體*/typedefunsignedshortINT16U;/*無符號16位實體*/typedefsignedshortINT16S;/*有符號16位實體*/typedefunsignedintINT32U;/*無符號32位實體*/typedefsignedintINT32S;/*有符號32位實體*/typedeffloatFP32/*單精度浮點數*/typedefdoubleFP64;/*雙精度浮點數*/typedefunsignedintOS_STK;/*堆棧是32位寬度*/typedefunsignedintOS_CPU_SR;/*申明狀態寄存器是32位*/μC/OS-II內核的代碼需要與處理器位有關65(3)定義臨界段(允許和禁止中斷宏)

與所有實時內核一樣,μC/OS-II需要先禁止中斷,再訪問代碼的臨界區,并且在訪問完畢后,重新允計中斷。這就是μC/OS-II能夠保護臨界段代碼免受多任務或中斷服務例程ISR的破壞。中斷禁止時間是商業實時內核公司提供的重要指標之一,因為它將影響到用戶的系統對實時事件的響應能力。雖然μC/OS-II盡量使中斷禁止時間達到最短,但是μC/OS-II的中斷禁止時間還主要依賴于處理器結構和編譯器產生的代碼的質量。通常每個處理器都會提供一定的指令來禁止/允許中斷,因此用戶的C編譯器必須由一定的機制來直接從C中執行這些操作。OS_ENTER_CRITICAL()OS_EXIT_CRITICAL()μC/OS-II定義了兩個宏來禁止和允許中斷:#defineOS_CRITICAL_METHOD3#defineOS_ENTER_CRITICAL(){cpu_sr=OS_CPU_SR_Save();}#defineOS_EXIT_CRITICAL(){OS_CPU_SR_Restore(cpu_sr);}μC/OS-II定義了三種方法關閉和打開中斷(OS_CRITICAL_METHED=1,2,3),通常情況下,我們都是選用的方法3。66OS_CPU_SR_SaveMRSR0,PRIMASKCPSIDIBXLROS_CPU_SR_RestoreMSRPRIMASK,R0BXLR關中斷開中斷(4)定義棧的增長方向μC/OS-II使用結構常量OS_STK_GROWTH來指定堆棧的增長方式:置OS_STK_GROWTH為0,表示堆棧從下往上增長;置OS_STK_GROWTH為1,表示堆棧從上往下增長。Cortex-M3支持從上往下增長的方式。因此,我們在移植時,需將OS_STK_GROWTH=1,如果是51系列單片機,則OS_STK_GROWTH=0。#defineOS_STK_GROWTH1

67(5)定義OS_TASK_SW()宏,任務級上下文切換

任務級上下文切換(即任務切換)調用宏定義OS_TASK_SW()。因為上下文切換跟處理器有密切關系,OS_TASK_SW()實質上是調用匯編函數OSCtxSW(),它在OS_CPU_A.ASM文件中定義。#defineOS_TASK_SW()OSCtxSw()OSCtxSwPUSH{R4,R5}LDRR4,=NVIC_INT_CTRL;觸發軟件中斷

LDRR5,=NVIC_PENDSVSETSTRR5,[R4]POP{R4,R5}BXLR原型如下:打開MDK查看原始代碼NVIC_INT_CTRLEQU0xE000ED04NVIC_PENDSVSETEQU0x10000000當執行完這段代后,自運的產生PendSV中斷,也即14號異常,自動跳到14號異常服務程序執行。在本移植中則會直接去執行:OSPendSV部分內容68中斷控制及狀態寄存器ICSR0xE000_ED04設置1將掛起中斷693、移植匯編語言編寫的4個與處理器相關的函數OS_CPU_A.ASM(1)OSStartHighRdy():運行優先級最高的就緒任務OSStartHighRdy()OSCtxSw()OSIntCtxSw()OSTickISR()OSStartHighRdy()函數是在OSStart()多任務啟動之后,負責從最高優先級任務的TCB控制中獲得該任務的堆棧指針SP,并通過SP依次將CPU現場恢復。這時系統就將控制權交給用戶創建的任務進程,直到該任務被阻塞或都被其他更高優先級的任務搶占CPU。該函數僅僅在多任務啟動時被執行一次,用來啟動最高優先級的任務執行。移植該函數的原因是,它涉及將處理器寄存器保存到堆棧的操作。70OSStartHighRdyLDRR4,=NVIC_SYSPRI2;setthePendSVexception;priority設置PendSV優先級

LDRR5,=NVIC_PENDSV_PRI STRR5,[R4]

MOVR4,#0;setthePSPto0forinitial;contextswitchcall使PSP等于0MSRPSP,R4

LDRR4,=OSRunning;OSRunning=TRUEMOVR5,#1STRBR5,[R4]LDRR4,=NVIC_INT_CTRL;triggerthePendSVexception;觸發軟件中斷

LDRR5,=NVIC_PENDSVSETSTRR5,[R4]CPSIEI;enableinterruptsatprocessor;level使能所有優先級的中斷OSStartHangBOSStartHang71(2)OSCtxSw():任務優先級切換函數

該函數由OS_TASK_SW()宏調用,OS_TASK_SW()由OSSched()函數調用,OSSched()函數負責任務之間的調度。OSCtxSw()函數的工作是,先將當前任務的CPU現場保存到該任務的堆棧中,然后獲得最高優先級任務的堆棧指針,并從該堆棧中恢復此任務的CPU現場,使之繼續執行,該函數就完了一次任切換。OSCtxSwPUSH{R4,R5}LDRR4,=NVIC_INT_CTRL;觸發軟件中斷

LDRR5,=NVIC_PENDSVSETSTRR5,[R4]POP{R4,R5}BXLR產生PendSV異常PendSV并沒有馬上執行,因為OS_TASK_SW()(實際是OSCtxSw())被調用前中斷是關閉的。PednSV只能在中斷使能后才能執行。OS_TASK_SW()總是被OS_Sched()調用(見OS_CORE.C文件)72(3)OSInitCtxSw():中斷級的任務切換函數

該函數由OSIntExit()調用。由于中斷可能會使更高優先級的任務進入就緒態,因此,為了讓更高優先級的任務能立即運行,在中斷服務子程序的最后,OSInitExit()函數會調用OSInitCtxSw()做任務切換。這樣做的目的主要是能夠盡快地讓高優先級的任務得到響應,保證系統的實時性能。OSInitCtxSw()與OSCtxSw()都是用于任務切換函數,其區別在于,在OSIntCtxSw()中無需再保存CPU寄存器,因為在調用OSIntCtxSw()之前已發生了中斷,OSIntCtxSw()已將默認的CPU寄存器保存到被中斷的任務堆棧中。OSIntCtxSwPUSH{R4,R5}LDRR4,=NVIC_INT_CTRL;觸發軟件中斷

LDRR5,=NVIC_PENDSVSETSTRR5,[R4]POP{R4,R5}BXLRNOPOSCtxSw()OSIntCtxSw()這兩個函最終都會觸發PendSV異常73OSPendSV()函數OSPendSV()是PendSV(可掛起中斷服務)的中斷處理函數,它負責μC/OS-II的全部上下文切換。這是ARMCortex-M3提倡的上下文切換方法。使用這程方法的好處理當發生任何的異常時,Cortex-m3自動保存CPU的一半通用寄存器到預先指定的堆棧中,并且在退出異常前按順序恢復寄存器。OSPendSV()只需保存剩下的R4-R11寄存器并且調整好堆棧指針。這種方法速度快,充分體現了ARMCortex-M3的優勢,而且無論是任務還是異常均可觸發此函數切換上下文。注意使用前應在Startup.S中申明。7475ARMCortex-M3任務切換示意圖76(4)OSTickISR():時鐘節拍中斷服務函數

時鐘節拍是特定的周期性中斷,是由硬件定時器產生的。時鐘節拍式中斷使得內核可將任務延時若干個整數時鐘節拍,以及當任務等待事件發生時,提供等待超時的依據。時鐘節拍頻率越高,系統的額外開銷越大。中斷間的時間間隔取決于不同的應用。

OSTickISR()首先將CPU寄存器的值保存在被中斷任務的堆棧中,之后調用OSIntEnter()。隨后,OSTickISR()調用OSTimeTick,檢查所有處于延時等待狀態的任務,判斷是否有延時結束就緒的任務。OSTickISR()最后調用OSIntExit()。如果在中斷中(或其他嵌套的中斷)有更高優先級的任務就緒,并且當前中斷為中斷嵌套的最后一層,那么OSIntExit()將進行任務調度。774、移植C語言編寫的6個與操作系統相關的函數OS_CPU_C.COS_CPU_C.C文件中包含6個和CPU相關的函數,這6個函數為:

這些函數中,唯一必須移植的是任務堆棧初始化函數OSTaskStkInit()。這個函數在任務創建時被調用,負責初始化任務的堆棧結構并返回新堆棧的指針stk。堆棧初始化工作結束后,返回新的堆棧棧頂指針。OSTaskStkInit()OSTaskDelHook()OSTaskSwHook()OSTaskStartHook()OSTimeHook()783.2基于ARM7的移植任務模式的取舍ARM7處理器核具有用戶、系統、管理、中止、未定義、中斷和快中斷七種

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論