第7章uCOS-II的移植.ppt_第1頁
第7章uCOS-II的移植.ppt_第2頁
第7章uCOS-II的移植.ppt_第3頁
第7章uCOS-II的移植.ppt_第4頁
第7章uCOS-II的移植.ppt_第5頁
已閱讀5頁,還剩45頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、,七、uCOS-II的移植,東軟IT人才實訓中心,Copyright 2008 By Neusoft Group. All rights reserved,第七章:uCOS-II的移植,目標: 本章旨在向學員介紹uC/OS-II的移植,通過本章的學習,學員應該掌握如下知識: 移植uC/OS-II的一般性問題 在MCS-51系統(tǒng)上移植uC/OS-II時的堆棧設計 移植的測試,學時:7.0學時 教學方法:講授ppt上機練習點評案例分析,7.1 uc/os-II 操作系統(tǒng)的移植,所謂操作系統(tǒng)的移植,是指使一個實時操作系統(tǒng)能夠在某個特定的微處理器平臺上運行。 COS-II的主要代碼都是由標準的C語言寫

2、成的,移植方便。但仍需要用匯編語言寫一些與處理器相關的代碼,這是因為C/OS-在讀寫處理器寄存器時只能通過匯編語言來實現。 移植的主要工作是修改部分與處理器硬件相關的代碼。,處理器的C編譯器能產生可重入代碼。 在程序中可以打開或者關閉中斷。 處理器支持中斷,并且能產生定時中斷(通常在10-100Hz之間)。 處理器支持能夠容納一定量數據的硬件堆棧(可能達幾KB) 處理器有將堆棧指針和其他CPU寄存器存儲和讀出到堆棧(或者內存)的指令。,7.1.1移植uC/OS-II滿足的條件,uC/OS-II是通過硬件中斷來實現系統(tǒng)時鐘,并在時鐘中斷服務程序中來處理與時間相關的問題的。因此,用戶所選用的處理器

3、必須具有響應中斷的能力。,一般情況下應該使用硬件定時器來作為時鐘中斷源,這個定時器可以是與微處理器集成在一個芯片上的,也可以是分立的。,可重入的代碼指的是一段代碼(比如:一個函數)可以被多個任務同時調用,而不必擔心會破壞數據。 也就是說,可重入型函數在任何時候都可以被中斷執(zhí)行,過一段時間以后又可以繼續(xù)運行,而不會因為在函數中斷的時候被其他的任務重新調用,影響函數中的數據。 可重入的代碼的實現主要是編程技術,所有嵌入式集成開發(fā)環(huán)境都能產生可重入的代碼。,7.1.2 什么是可重入代碼,int temp; void Swap(int *x, int *y) temp = *x; *x = *y; *

4、y = temp; ,例如,任務A和任務B都要調用函數Swap(),而該函數又使用了全局變量temp。于是當任務A調用Swap()函數期間,系統(tǒng)發(fā)生了任務切換而使任務B也調用了Swap(),那么任務B將要改變全局變量temp的值,使任務A傳遞給全局變量temp的值丟失而出現錯誤。,一般來說,一個可重入函數應該在函數中只使用局部變量,因為函數的局部變量存儲在任務的堆棧中,所以可保證不同的任務在調用同一個函數時不會發(fā)生沖突。,7.1.3 系統(tǒng)棧與任務棧的關系,被中止運行的任務堆棧,被運行的任務堆棧,系統(tǒng)堆棧,CPU,SP,圖7-1 系統(tǒng)棧與任務棧的關系,有些處理器對于堆棧的設置有特殊的要求,即要求

5、堆棧必須設置在一個特定的區(qū)域,比如片內RAM。由于片內的RAM極其有限,不可能把應用程序中所有任務的堆棧都設置在片內RAM中,所以就只能把應用程序中各個任務堆棧的內容存放在片外RAM中,而只在片內RAM中設置一個公用的堆棧。,片外的RAM用來存放任務堆棧,片內RAM中是系統(tǒng)的公共堆棧,當系統(tǒng)運行某個任務時,就要把該任務的堆棧映像復制到系統(tǒng)堆棧中;而在中止這個任務時,再把系統(tǒng)堆棧中的內容復制回任務堆棧映像中。,7.1.4 uC/OS-II文件結構,圖7-2 uC/OS-II的文件結構,表7-1 需要修改的關鍵函數和宏定義,7.1.5 需要修改的關鍵函數和宏定義,7.1.6 INCLUDES.H,

6、使得項目中的每個.c文件不用分別考慮它實際上需要那些頭文件。 它會包含一些不相關的頭文件 INCLUDES.H 是一個頭文件,它在所有的.c文件的第一行被包含。 #include “includes.h”,/* * uC/OS-II 實時內核 * (c) Copyright 1992-1998, Jean J. Labrosse, Plantation, FL * 版權所有 * MCU-51 專用代碼 KEIL C51大模式編譯 * * 文件名 : INCLUDES.H * 作者 : Jean J. Labrosse */ #include os_cpu.h #include os_cfg.h

7、 #include ucos_ii.h #include #include ,7.1.7 OS_CPU.H,/* 數據類型 (與編譯器相關的內容) */ typedef unsigned charBOOLEAN; typedef unsigned char INT8U; typedef signed char INT8S; typedef unsigned int INT16U; typedef signed intINT16S; typedef unsigned long INT32U; typedef signed long INT32S; typedef float FP32; type

8、def double FP64; typedef unsigned int OS_STK;,OS_CPU.H中包括與處理器相關的常量、宏以及類型。,7.1.7 OS_CPU.H(續(xù)),/ * 與處理器相關的代碼 */ #define OS_CRITICAL_METHOD ? #if OS_CRITICAL_METHOD = = 1 #define OS_ENTER_CRITICAL() ? #define OS_EXIT_CRITICAL() ? #endif #if OS_CRITICAL_METHOD = = 2 #define OS_ENTER_CRITICAL() ? #define

9、OS_EXIT_CRITICAL() ? #endif #if OS_CRITICAL_METHOD = = 3 #define OS_ENTER_CRITICAL() ? #define OS_EXIT_CRITICAL() ? #endif #define OS_STK_GROWTH1 #define OS_TASK_SW()?,7.1.8 OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL(),臨界代碼的概念。 uC/OS-II定義的兩個宏。 OS_ENTER_CRITICAL(); /* C/OS-II 臨界代碼段 */ OS_EXIT_CRITICAL(); 三

10、種實現方法。 方法1: 在OS_ENTER_CRITICAL()中調用處理器指令來禁止中斷,以及在 OS_EXIT_CRITICAL()中調用允許中斷指令。 方法2: 是先將中斷禁止狀態(tài)保存到堆棧中,然后禁止中斷。 方法3: 有些編譯器提供擴展功能,可以得到當前處理器狀態(tài)字的值。,#define OS_ENTER_CRITICAL() EA=0 #define OS_EXIT_CRITICAL() EA=1,#define OS_ENTER_CRITICAL() asm(“PUSH PSW”); asm(“DI”); #define OS_EXIT_CRITICAL() asm(“POP PS

11、W”);,void some_ucos_ii_service() OS_CPU_SR cpu_sr; cpu_sr = get_processor_psw(); disable_interrupts(); /* C/OS-II 臨界代碼段 */ set_processor_psw(cpu_sr); ,7.1.9 OS_STK_GROWTH,絕大多數的微處理器和微控制器的堆棧是從上往下長的。但是某些處理器是用另外一種方式工作的。C/OS-被設計成兩種情況都可以處理,只要在結構常量OS_STK_GROWTH(在OS_CPU.H中) 中指定堆棧的生長方式(如下所示)就可以了。,置OS_STK_GRO

12、WTH為0表示堆棧從下往上長。 置OS_STK_GROWTH為1表示堆棧從上往下長。,7.1.10 OS_TASK_SW(),OS_TASK_SW()是一個宏,它是在C/OS-從低優(yōu)先級任務切換到最高優(yōu)先級任務時被調用的。 在C/OS-中,處于就緒狀態(tài)的任務的堆棧結構看起來就像剛發(fā)生過中斷并將所有的寄存器保存到堆棧中的情形一樣。換句話說,C/OS-要運行處于就緒狀態(tài)的任務必須要做的事就是將所有處理器寄存器從任務堆棧中恢復出來,并且執(zhí)行中斷的返回。為了切換任務可以通過執(zhí)行OS_TASK_SW()來產生中斷。大部分的處理器會提供軟中斷或是陷阱(TRAP)指令來完成這個功能。 例如,在Intel或者

13、80 x86處理器上可以使用INT指令。但是中斷處理向量需要指向OSCtxSw()。 一些處理器并不提供軟中斷機制。在這種情況下,用戶需要盡自己的所能將堆棧結構設置成與中斷堆棧結構一樣,再用函數調用方式來實現任務切換,也就是說通過函數來模仿軟中斷指令。如#define OS_TASK_SW() OSCtxSw(),當多任務內核決定運行另外的任務時,它保存正在運行任務的當前狀態(tài),即CPU寄存器中的全部內容。這些內容保存在任務的當前狀態(tài)保存區(qū),也就是任務自己的堆棧區(qū)中。入棧工作完成后,就是把下一個將要運行任務的當前狀態(tài)從該任務的堆棧中重新裝入CPU寄存器,并開始下一個任務的運行,這個過程叫任務切換

14、。,7.1.11 OS_CPU_C.C,OSTaskStkInit() OSTaskCreateHook() OSTaskDelHook() OSTaskSwHook() OSTaskIdleHook() OSTaskStatHook() OSTimeTickHook() OSInitHookBegin() OSInitHookEnd() OSTCBInitHook(),OS_CPU_C.C文件包含10個C函數:,唯一必要的函數是OSTaskStkInit(),其它九個屬于鉤子函數,必須得聲明但沒必要包含代碼。,7.1.11.1 OSTaskStkInit(),OSTaskCreate()和O

15、STaskCreateExt()通過調用OSTaskStkInt()來初始化任務的堆棧結構,因此,堆??雌饋砭拖駝偘l(fā)生過中斷并將所有的寄存器保存到堆棧中的情形一樣。 編寫OSTaskStkInit()函數的第一步就是堆棧設計。需要考慮以下因素: CPU自動入棧的寄存器及壓棧順序。 需要額外保存哪些寄存器。 所采用的編譯器對形式參數的傳遞方法。 堆棧的增長方向。 堆棧指針是指向下一個可用空間還是指向上次入棧數據。 所采用的CPU是否存在系統(tǒng)堆棧。 堆棧深度。,任務按函數形式編寫,但永遠不被調用,而是通過模仿中斷的方式來運行其中的代碼。既然任務通過模仿中斷的方式來進行,而且擁有自己單獨的任務棧,那

16、么需要做的就是執(zhí)行中斷返回指令,讓任務中的內容出棧,讓系統(tǒng)覺得該任務(或者說是所謂的“函數”)剛剛被中斷過,現在需要繼續(xù)執(zhí)行。但在系統(tǒng)剛開始運行的時候,任務是沒有被系統(tǒng)中斷過的,也沒有被切換過,任務棧里沒有內容。所以需要通過OSTaskStkInit()來初始化任務棧,模擬一次壓棧動作,使得系統(tǒng)認為任務剛剛被中斷過。,7.1.11.2 HOOK類函數,OSTaskCreateHook() 當用OSTaskCreate()或OSTaskCreateExt()建立任務的時候就會調用OSTaskCreateHook()。 OSTaskDelHook() 當任務被刪除的時候就會調用OSTaskDelH

17、ook()。 OSTaskSwHook() 當發(fā)生任務切換的時候調用OSTaskSwHook()。 OSTaskStatHook() OSTaskStatHook()每秒鐘都會被OSTaskStat()調用一次。用戶可以用OSTaskStatHook()來擴展統(tǒng)計功能。 OSTimeTickHook() OSTaskTimeHook()在每個時鐘節(jié)拍都會被OSTaskTick()調用。,HOOK類函數主要的作用是擴展uC/OS-II的功能,可以不包含代碼,但必須聲明。一般在移植中不予考慮。,7.1.12 OS_CPU_A.ASM,C/OS-的移植要求用戶編寫四個簡單的匯編語言函數: OSSta

18、rtHighRdy() OSCtxSw() OSIntCtxSw() OSTickISR() 如果用戶的編譯器支持插入匯編語言代碼的話,用戶就可以將所有與處理器相關的代碼放到OS_CPU_C.C文件中,而不必再擁有一些分散的匯編語言文件。,這4個匯編函數幾乎占據了移植70%的工作量,也是移植最關鍵的部分。,7.1.12.1 OSStartHighRdy(),OSStartHighRdy()在OSStart()函數中調用,用來使就緒態(tài)任務中優(yōu)先級最高的任務開始運行。在用戶調用OSStart()之前,用戶必須至少已經通過OSTaskCreate()或OSTaskCreateExt()建立自己的一個

19、任務。因為OSStart()永不返回,在OSStartHighRdy()執(zhí)行完畢后,uC/OS-II正式開始接管系統(tǒng),不會再有機會創(chuàng)建任務。 OSStartHighRdy()與OSStart()一樣,永遠只運行一次。,void OSStart(void) INT8U x,y; if(OSRunning=FALSE) OSStartHighRdy(); ,7.1.12.2 OSCtxSw(),在uC/OS-II與處理器無關的代碼中,為了屏蔽不同的CPU帶來的不同的處理方法,使用OS_TASK_SW()宏實現任務切換。在uC/OS-II中,任務級的任務調度由OS_Sched()函數完成,該函數為了

20、實現任務級的任務切換,確定了等待調度的最高優(yōu)先級任務后,調用OS_TASK_SW()宏實現任務的切換。,7.1.12.3 OSIntCtxSw(),OSIntExit()通過調用OSIntCtxSw()來從ISR中執(zhí)行切換功能。因為OSIntCtxSw()是在ISR中被調用的,所以可以斷定所有的處理器寄存器都被正確地保存到了被中斷的任務的堆棧之中。實際上除了我們需要的東西外,堆棧結構中還有其它的一些東西。OSIntCtxSw()必須要清理堆棧,這樣被中斷的任務的堆棧結構內容才能滿足我們的需要。,OSIntCtxSw()函數的絕大多數代碼與OSCtxSw()是一樣的。在中斷服務子程序中已經保存了

21、CPU的寄存器,因此不需要在OSIntCtxSw()函數中保存CPU寄存器,其他的步驟幾乎都是一樣的。很多人在編寫這個函數的時候,基本上都跳轉到OSCtxSw()中執(zhí)行相同的代碼,可以減少一部分代碼量。,7.1.12.4 OSTickISR(),C/OS-要求用戶提供一個時鐘資源來實現時間的延時和期滿功能。時鐘節(jié)拍應該每秒鐘發(fā)生10100次。為了完成該任務,可以使用硬件時鐘,也可以從交流電中獲得50/60Hz的時鐘頻率。 用戶必須在開始多任務調度后(即調用OSStart()后)允許時鐘節(jié)拍中斷。換句話說,就是用戶應該在OSStart()運行后,C/OS-啟動運行的第一個任務中初始化節(jié)拍中斷。通

22、常所犯的錯誤是在調用OSInit()和OSStart()之間允許時鐘節(jié)拍中斷。,有可能在C/OS-開始執(zhí)行第一個任務前時鐘節(jié)拍中斷就發(fā)生了。在這種情況下,C/OS-的運行狀態(tài)不確定,用戶的應用程序也可能會崩潰。,7.1.13 測試移植代碼,當完成uC/OS-II的移植后,系統(tǒng)是否能夠正常工作,需要檢驗,只有通過了測試,uC/OS-II的移植才算完成。,#include “includes.h” void main(void) OSInit(); OSStart(); ,首先,不添加任務應用代碼,測試內核自身的運行狀況。這樣可以避免問題復雜化,同時可以排除應用代碼的問題,使反映出的問題清晰化。

23、在OS_CFG.H中允許所有的uC/OS-II功能,然后在主程序中不添加任何復雜代碼,列如:,7.1.13.1 測試OSTaskStkInit()與OSStartHighRdy(),采用源碼調試器 單步執(zhí)行main()程序-跳過OS_Init()函數-單步進入OSStart()函數-一直運行到OSStartHighRdy()應切換到匯編模式- OSStartHighRdy()會開始的一個任務,因為沒有任何應用任務,只有OS_TaskIdle()可以運行-單步執(zhí)行觀察堆棧內容及CPU寄存器內容變化- OSStartHighRdy()最后一條語句會中斷返回,指向OS_TaskIdle()第一條語句

24、。如果能夠在OS_TaskIdle()中循環(huán),則證明OSTaskStkInit()與OSStartHighRdy()是成功的。 運行/不運行測試法 如果目標系統(tǒng)存在LED,可以先關閉LED。如果OSTaskStkInit()與OSStartHighRdy()正常,再由OS_TaskIdle()點亮LED。,首先修改OS_CFG.H文件,設置OS_TASK_STAT_EN為0,禁止統(tǒng)計任務,仍然不添加用戶應用任務,此時運行的唯一任務就是空閑任務。,7.1.13.2 測試OSCtxSw(),# include “includes.h” OS_STK Task1Stk100; void main(v

25、oid) OSInit(); 關LED; OSTaskCreate(Task1,(void*)0, 可采用源碼調試器及運行/不運行測試法。,如果前兩節(jié)測試通過,證明堆棧結構正確,可以添加一個簡單的應用任務,從該任務切換到空閑任務。,7.1.13.3 測試OSIntCtxSw()和OSTickISR(),測試程序如下: #include “includes.h” OS_STK Task1Stk100; void main(void) OSInit(); 關LED; OSTaskCreate(Task1,(void*)0, ,7.2 uC/OS-II在MCS-51上的移植,要使uC/OS-II正常

26、運行,必須滿足以下要求: 處理器的C編譯器能產生可重入代碼。 在程序中可以打開或者關閉中斷。 處理器支持中斷,并且能產生定時中斷(通常在10-100Hz之間)。 處理器支持能夠容納一定量數據的硬件堆棧(可能達幾KB) 處理器有將堆棧指針和其他CPU寄存器存儲和讀出到堆棧(或者內存)的指令。 MCS-51與KEIL Cx51編譯器可以滿足以上條件。,移植與4個文件相關: 匯編文件 OS_CPU_A.ASM 處理器相關C文件 OS_CPU.H、OS_CPU_C.C 配置文件 OS_CFG.H,7.2.1 建立工程,首先建立一個工程,這里輸入的文件名也是工程名。Keil會在指定的目錄建立一個.uv2

27、文件,用來保存相關的工程信息。,圖7-3 建立工程-1,7.2.1 建立工程(續(xù)),Keil會要求選擇所使用的CPU,這里選擇WINBOND公司的W78E58B。,圖7-4 建立工程-2,7.2.1 建立工程(續(xù)),Keil會詢問是否添加標準的8051啟動代碼,一般來說都選擇添加,然后在此基礎上修改。,在完成以上3個步驟后,一個工程的框架就基本建立了,接下來向工程添加必要的代碼。,圖7-5 建立工程-3,7.2.1 建立工程(續(xù)),uC/OS-II分為與處理器相關代碼和與處理器無關代碼。首先將與處理器無關代碼復制到工程文件夾。將UCOS_II.C添加至源碼組,接下來將OS_CFG.H與INCL

28、UDES.H復制到工程文件夾。再將與移植相關的文件OS_CPU.H、OS_CPU_A.ASM與OS_CPU_C.C復制到主文件夾,并將OS_CPU_A.ASM、OS_CPU_C.C加入源碼組。最后再添加一個存放main()的C文件。,圖7-6 建立工程-4,7.2.1 建立工程(續(xù)),在完成以上步驟后,要選擇內存模式為大模式(Large),否則在編譯時會出現段過大的錯誤。,圖7-7 建立工程-5,7.2.1 建立工程(續(xù)),如果在程序中使用了嵌入匯編,就需要在源碼組打開相應的選項激活。,至此,工程的建立基本完成。下面需要進行具體代碼的編寫。,圖7-8 建立工程-6,7.2.2 OS_CPU.H

29、,OS_CPU.H中包括與處理器相關的常量、宏以及類型。這個文件大體分為兩部分-與編譯器相關的數據類型和與處理器相關的代碼。 首先,查詢Keil Cx51編譯器手冊,確定與編譯器相關的數據類型,選擇需要的數據類型,并用typedef關鍵字定義成uC/OS-II所需要的數據類型。在UC/OS-II與處理器無關的代碼中,至少需要使用以下8種數據類型: 無符號8位數(INT8U)無符號32位數(INT32U) 有符號8位數(INT8S)有符號32位數(INT32S) 無符號16位數(INT16U)布爾型(Boolean) 有符號16位數(INT16S)任務堆棧(OS_STK),7.2.2 OS_CP

30、U.H(續(xù)),/*與編譯器相關數據類型 */ typedef unsigned char BOOLEAN; typedef unsigned char INT8U; /無符號8位數 typedef signed char INT8S; /有符號8位數 typedef unsigned int INT16U; /無符號16位數 typedef signed int INT16S; /有符號16位數 typedef unsigned long INT32U; /無符號32位數 typedef signed long INT32S; /有符號32位數 typedef float FP32; /單精度

31、浮點數 typedef double FP64; /雙精度浮點數 typedef unsigned char OS_STK; /棧單元寬度為8比特 typedef unsigned char OS_CPU_SR; / Define size of CPU status register (PSW = 8 bits) #define BYTE INT8S /兼容以前版本的數據類型 #define UBYTE INT8U /uC/OS-II可以不用這些數據類型 #define WORD INT16S #define UWORD INT16U #define LONG INT32S #define

32、ULONG INT32U,7.2.2 OS_CPU.H(續(xù)),在完成與編譯器相關的數據類型的設定后,進行與處理器相關的代碼的編寫,分為以下幾個部分: 對臨階段的處理。 #define OS_ENTER_CRITICAL()EA=0 #define OS_EXIT_CRITICAL()EA=1 確定堆棧的增長方向。 MCS-51堆棧從低地址往高地址增長,因此將OS_STK_GROWTH定義為0。 #define OS_STK_GROWTH 0 定義OS_TASK_SW()宏。 MCS-51無軟中斷指令,只能通過函數調用模仿。 #define OS_TASK_SW() OSCtxSw(),7.2.

33、3 OS_CPU_C.C,堆棧設計時需要考慮的因素: CPU自動入棧的寄存器及壓棧順序。 需要額外保存哪些寄存器。 所采用的編譯器對形式參數的傳遞方法。 堆棧的增長方向。 堆棧指針是指向下一個可用空間還是指向上次入棧數據。 所采用的CPU是否存在系統(tǒng)堆棧。 堆棧深度。,OS_CPU_C.C文件包含10個C函數:OSTaskStkInit()、OSTaskCreateHook()、OSTaskDelHook()、OSTaskSwHook()、OSTaskIdleHook()、OSTaskStatHook()、OSTimeTickHook()、OSInitHookBegin()、OSInitHoo

34、kEnd()、OSTCBInitHook() 唯一必要的函數是OSTaskStkInit()。 OSTaskCreate()和OSTaskCreateExt()通過調用OSTaskStkInit()來初始化任務的堆棧結構。在編寫這個函數的時候,堆棧結構必須已知,設計堆棧結構勢在必行。,7.2.3 OS_CPU_C.C(續(xù)),查詢MCS-51相關資料,對以上因素加以分析: 傳統(tǒng)的8051處理器在中斷來臨時只將程序計數器PC的值壓入堆棧。 按照uC/OS-II的要求,保存全部寄存器,MCS-51的寄存器有PSW、ACC、B、 DPL、DPH、R0R7和SP。 Cx51編譯器允許用CPU寄存器傳遞3

35、個參數。 堆棧從低地指向高地址增長。 堆棧指針指向上次入棧地址。 MCS-51存在系統(tǒng)棧。 系統(tǒng)棧深度為256字節(jié)。 需要考慮: 系統(tǒng)棧的設計 任務棧的設計 仿真堆??臻g,MCS51系列處理器存在一個系統(tǒng)堆棧,堆棧在內存中的位置是固定的。uC/OS-II需要為每一個任務分配任務堆棧,MCS51處理器并不具備這個條件,需要在任務切換的時候進行堆棧的復制。 因為傳統(tǒng)的51處理器在中斷來臨時只將程序計數器PC的值壓入堆棧,所以系統(tǒng)棧保存的第一個內容就是PC,其余的寄存器保存的時候沒有太多要求,順序可以為:PCL、PCH、PSW、ACC、B、DPL、DPH、R0R7。,接下來進行任務棧的設計。OS_T

36、CB結構體中OSTCBStrPtr用來保存任務棧的堆棧指針,在任務切換時使用。在沒有系統(tǒng)棧的CPU中, OSTCBStrPtr用來保存任務棧棧頂指針,即SP的值。在MCS51這類存在任務棧的CPU中,保存SP值沒有意義,可以保存任務棧的起始地址,這樣執(zhí)行任務切換的時候,可以通過OSTCBStrPtr中保存的地址執(zhí)行任務棧與系統(tǒng)棧的復制。因為任務棧只是在內存中開辟的一段連續(xù)存儲空間,必須考慮邊界處理,所以在設計任務棧的時候,在OSTCBStrPtr指向的最低地址處存放長度。,7.2.3 OS_CPU_C.C(續(xù)),任務堆棧空間=系統(tǒng)堆??臻g+仿真堆棧空間,圖7-9 堆棧結構,uC/OS-II要求

37、所使用的編譯器能產生可重入代碼,與不可重入函數的參數傳遞和局部變量的存儲分配方法不同, Cx51編譯器為可重入函數生成一個模擬棧,通過這個模擬棧來完成參數傳遞和存放局部變量。模擬棧在的存儲空間根據可重入函數存儲器模式的不同,可以是DATA、PDATA或XDATA存儲器空間。為了函數重入,形參和局部變量必須保存在堆棧里。MCS51硬件堆棧太小, Keil將根據內存模式在相應內存空間仿真堆棧,增長方向由上向下,與硬件棧相反。對于大模式編譯,函數返回地址保存在硬件堆棧里,形參和局部變量放在仿真堆棧中,棧指針為?C_XBP。仿真堆棧效率低下, Keil建議盡量不用,但為了重入操作必須使用。 Keil可

38、以混合使用3種仿真堆棧(大、中、小模式)。為了提高效率,對MCS 51要使用大模式編譯。,在任務切換時首先保存當前任務堆棧內容。用SP-OSStkStart得出保存字節(jié)數,將其寫入用戶堆棧最低地址內,以用戶堆棧最低地址為起始地址,以OSStkStart為系統(tǒng)堆棧起始地址,由系統(tǒng)棧向用戶??截悢祿?循環(huán)SP-OSStkStart次,每次拷貝前先將各自棧指針增1。 其次,恢復最高級優(yōu)先級任務系統(tǒng)堆棧。獲得最高優(yōu)先級任務用戶堆棧最低地址,從中取出“長度”,以最高優(yōu)先級任務用戶堆棧最低地址為起始地址,以OSStkStart為系統(tǒng)堆棧起始地址,由用戶棧向系統(tǒng)??截悢祿?,循環(huán)“長度”數值指示的次數,每次

39、拷貝前先將各自棧指針增1。,用戶堆棧初始化時從下向上依次保存:用戶堆棧長度(15)、PCL、PCH、PSW、ACC、B、DPL、DPH、R0、R1、R2、R3、R4、R5、R6、R7。接下來保存仿真堆棧的內容,不保存SP,任務切換時可以根據用戶堆棧長度計算出。,OS_STK *OSTaskStkInit (void (*task)(void *pd), void *ppdata, OS_STK *ptos, INT16U opt) reentrant OS_STK *stk; ppdata = ppdata; opt = opt; /opt沒被用到,保留此語句防止告警產生 stk = (OS_

40、STK *)ptos; /必須通過*ptos參數獲得用戶堆棧最低有效地址 *stk+ = 15; /用戶堆棧長度 *stk+ = (INT16U)task ,7.2.3 OS_CPU_C.C(續(xù)),OSTaskStkInit()在一開始需要模擬帶參數(pdata)的函數調用,即將任務建立時所確定的參數傳遞給任務。所以在開始移植時需要確定所采用編譯器對形參的傳遞方法。CX51編譯器允許CPU寄存器傳遞3個參數。查詢KEIL手冊可知通用指針通過寄存器R1-R3傳遞, R3用來保存存儲類型,R2用來保存MSB,R用來保存LSB。在初始化堆棧的時候,需要將R1-R3的值保存在任務堆棧的指定位置,在任務

41、啟動的時候自動彈出至寄存器。,因為仿真堆棧并不通過壓棧與出棧指令操作,所以不必復制到系統(tǒng)棧,這也是保存長度為15的原因。但仿真堆棧的指針還是需要保存在堆棧中的。,按照KEIL編譯器的規(guī)定,idata/data/bdatata存儲類型值為0 x00,xdata的存儲類型值為0 x01,pdata的存儲類型值為0 xFE,code的存儲類型值為0 xFF。,7.2.4 OS_CPU_A.ASM,定義壓棧出棧宏,此部分并不是uC/OS-II所要求的,但為了方便編程,一般都定義壓棧出棧宏。,;定義壓棧宏 PUSHALL MACRO PUSH ACC PUSH B PUSH DPH PUSH DPL P

42、USH PSW MOV A,R0 ;R0-R7入棧 PUSH ACC MOV A,R1 PUSH ACC MOV A,R2 PUSH ACC MOV A,R3 PUSH ACC MOV A,R4 PUSH ACC MOV A,R5 PUSH ACC MOV A,R6 PUSH ACC MOV A,R7 PUSH ACC ENDM,;定義出棧宏 POPALL MACRO POP ACC ;R0-R7出棧 MOV R7,A POP ACC MOV R6,A POP ACC MOV R5,A POP ACC MOV R4,A POP ACC MOV R3,A POP ACC MOV R2,A POP

43、 ACC MOV R1,A POP ACC MOV R0,A POP PSW POP DPL POP DPH POP B POP ACC ENDM,7.2.4 OS_CPU_A.ASM(續(xù)),OSStartHighRdy() OSStartHighRdy()在OSStart()函數中調用,用來使就緒態(tài)任務中優(yōu)先級最高的任務開始運行。在用戶調用OSStart()之前,用戶必須至少已經通過OSTaskCreate()或OSTaskCreateExt()建立自己的一個任務。因為OSStart()永不返回,在OSStartHighRdy()執(zhí)行完畢后,uC/OS-II正式開始接管系統(tǒng),不會再有機會創(chuàng)建

44、任務。OSStartHighRdy()與OSStart()一樣,只運行一次。,RSEG ?PR?OSStartHighRdy?OS_CPU_A OSStartHighRdy: USING 0 ;固定使用寄存器組0 LCALL _?OSTaskSwHook MOV R0,#LOW (OSTCBCur) ;獲得OSTCBCur指針低地址,指針占3字節(jié) INC R0 MOV DPH,R0 INC R0 MOV DPL,R0 INC DPTR ;獲得OSTCBCur -OSTCBStkPtr的值,其指針占3字節(jié) MOVX A,DPTR MOV R0,A INC DPTR MOVX A,DPTR MOV

45、 R1,A MOV DPH,R0 MOV DPL,R1 MOVX A,DPTR ;已指向最高優(yōu)先級任務的堆棧起始地址 MOV R5,A ;R5=用戶堆棧長度,MOV R0,#OSStkStart ;在得到需要復制的長度后,將系統(tǒng)堆棧的起始地址復制到 R0,然后將任務棧中保存的寄存器值復制到系統(tǒng)棧 restore_stack: INC DPTR INC R0 MOVX A,DPTR MOV R0,A DJNZ R5,restore_stack MOV SP,R0 ;完成任務棧到系統(tǒng)棧的復制后,R0的值就是SP的值 INC DPTR ;恢復了SP的值后,DPTR加1,指向仿真堆棧指針?C_XBP

46、MOVX A,DPTR MOV ?C_XBP,A ;?C_XBP 仿真堆棧指針高8位 INC DPTR MOVX A,DPTR MOV ?C_XBP+1,A ;?C_XBP 仿真堆棧指針低8位 MOV R0,#LOW (OSRunning) MOV R0,#01 POPALL ;執(zhí)行出棧宏,將系統(tǒng)棧中存儲的內容恢復到寄存器,就像剛發(fā)生過中斷一樣 SETB EA ;允許中斷 RETI ;執(zhí)行中斷返回指令,uc/osii正式開始接管系統(tǒng),7.2.4 OS_CPU_A.ASM(續(xù)),OSCtxSw() 因為MCS-51沒有軟中斷指令,所以采用函數調用的方式完成OSCtxSw(),在OS_CPU.H中

47、把OS_TASK_SW()宏直接指定為OSCtxSw(): #define OS_TASK_SW() OSCtxSw(),RSEG ?PR?OSCtxSw?OS_CPU_A OSCtxSw: USING 0 PUSHALL MOV A,SP CLR C SUBB A,#OSStkStart MOV R5,A MOV R0,#LOW (OSTCBCur) INC R0 MOV DPH,R0 INC R0 MOV DPL,R0 INC DPTR MOVX A,DPTR MOV R0,A INC DPTR MOVX A,DPTR MOV R1,A MOV DPH,R0 MOV DPL,R1 MOV

48、A,R5 MOVX DPTR,A MOV R0,#OSStkStart save_stack_A:,INC DPTR INC R0 MOV A,R0 MOVX DPTR,A DJNZ R5,save_stack_A INC DPTR MOV A,?C_XBP MOVX DPTR,A INC DPTR MOV A,?C_XBP+1 MOVX DPTR,A LCALL _?OSTaskSwHook ;保存完要被掛起的任務后,需要將當前任務的指針指向要恢復運行的任務,注意指針占3字節(jié) MOV R0,#OSTCBCur MOV R1,#OSTCBHighRdy MOV A,R1 MOV R0,A IN

49、C R0 INC R1 MOV A,R1 MOV R0,A INC R0 INC R1 MOV A,R1 MOV R0,A,;將新任務的優(yōu)先級賦給當前任務優(yōu)先級 MOV R0,#OSPrioCur MOV R1,#OSPrioHighRdy MOV A,R1 MOV R0,A MOV R0,#LOW (OSTCBCur) INC R0 MOV DPH,R0 INC R0 MOV DPL,R0 INC DPTR MOVX A,DPTR MOV R0,A INC DPTR MOVX A,DPTR MOV R1,A MOV DPH,R0 MOV DPL,R1 MOVX A,DPTR MOV R5,A

50、 MOV R0,#OSStkStart restore_stack_B: INC DPTR INC R0,MOVX A,DPTR MOV R0,A DJNZ R5,restore_stack_B MOV SP,R0 INC DPTR MOVX A,DPTR MOV ?C_XBP,A INC DPTR MOVX A,DPTR MOV ?C_XBP+1,A MOV R0,#LOW (OSRunning) MOV R0,#01 POPALL SETB EA RETI,7.2.4 OS_CPU_A.ASM(續(xù)),OSIntCtxSw() OSIntExit通過調用OSIntCtxSw(),在中斷服務子

51、程序中執(zhí)行中斷級別任務切換。,RSEG ?PR?OSIntCtxSw?OS_CPU_A OSIntCtxSw: USING 0 LCALL _?OSTaskSwHook ; OSIntCtxSw ()由OSIntExit()調用,在執(zhí)行這個步驟的時候,系統(tǒng)堆棧已經壓入了2個返回地址,在MCS51中,PC值分高低地址壓入系統(tǒng)棧,所以在此SP應該減4,恢復改變之前的SP值來計算系統(tǒng)堆棧中數據的長度 MOV A,SP CLR C SUBB A,#4 MOV SP,A MOV A,SP CLR C SUBB A,#OSStkStart MOV R5,A MOV R0,#LOW (OSTCBCur) I

52、NC R0 MOV DPH,R0 INC R0 MOV DPL,R0,INC DPTR MOVX A,DPTR MOV R0,A INC DPTR MOVX A,DPTR MOV R1,A MOV DPH,R0 MOV DPL,R1 MOV A,R5 MOVX DPTR,A MOV R0,#OSStkStart save_stack_A: INC DPTR INC R0 MOV A,R0 MOVX DPTR,A DJNZ R5,save_stack_A INC DPTR MOV A,?C_XBP MOVX DPTR,A INC DPTR MOV A,?C_XBP+1 MOVX DPTR,A,LCALL

溫馨提示

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

評論

0/150

提交評論