ucos-ii(源代碼開(kāi)放的確良嵌入式os)教程(1)new_第1頁(yè)
ucos-ii(源代碼開(kāi)放的確良嵌入式os)教程(1)new_第2頁(yè)
ucos-ii(源代碼開(kāi)放的確良嵌入式os)教程(1)new_第3頁(yè)
ucos-ii(源代碼開(kāi)放的確良嵌入式os)教程(1)new_第4頁(yè)
ucos-ii(源代碼開(kāi)放的確良嵌入式os)教程(1)new_第5頁(yè)
已閱讀5頁(yè),還剩26頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、第一章:范例在這一章里將提供三個(gè)范例來(lái)說(shuō)明如何使用 C/OS-II。筆者之所以在本書(shū)一開(kāi)始就寫(xiě)這一章是為了讓讀者盡快開(kāi)始使用 C/OS-II。在開(kāi)始講述這些例子之前,筆者想先說(shuō)明一些在這本書(shū)里的約定。這些例子曾經(jīng)用Borland C/C+ 編譯器(V3.1)編譯過(guò),用選擇項(xiàng)產(chǎn)生Intel/AMD80186處理器(大模式下編譯)的代碼。這些代碼實(shí)際上是在Intel Pentium II PC (300MHz)上運(yùn)行和測(cè)試過(guò),Intel Pentium II PC可以看成是特別快的80186。筆者選擇PC做為目標(biāo)系統(tǒng)是由于以下幾個(gè)原因:首先也是最為重要的,以PC做為目標(biāo)系統(tǒng)比起以其他嵌入式環(huán)境,如

2、評(píng)估板,仿真器等,更容易進(jìn)行代碼的測(cè)試,不用不斷地?zé)龑?xiě)EPROM,不斷地向EPROM仿真器中下載程序等等。用戶只需要簡(jiǎn)單地編譯、鏈接和執(zhí)行。其次,使用Borland C/C+產(chǎn)生的80186的目標(biāo)代碼(實(shí)模式,在大模式下編譯)與所有Intel、AMD、Cyrix公司的80x86 CPU兼容。 1.00 安裝 C/OS-II本書(shū)附帶一張軟盤(pán)包括了所有我們討論的源代碼。是假定讀者在80x86,Pentium,或者Pentium-II處理器上運(yùn)行DOS或Windows95。至少需要5Mb硬盤(pán)空間來(lái)安裝uC/OS-II。 請(qǐng)按照以下步驟安裝:1.進(jìn)入到DOS(或在Windows 95下打開(kāi)DOS窗口)

3、并且指定C:為默認(rèn)驅(qū)動(dòng)器。2.將磁盤(pán)插入到A:驅(qū)動(dòng)器。3.鍵入 A:INSTALL 【drive】注意drive是讀者想要將C/OSII安裝的目標(biāo)磁盤(pán)的盤(pán)符。INSTALL.BAT 是一個(gè)DOS的批處理文件,位于磁盤(pán)的根目錄下。它會(huì)自動(dòng)在讀者指定的目標(biāo)驅(qū)動(dòng)器中建立SOFTWARE目錄并且將uCOS-II.EXE文件從A:驅(qū)動(dòng)器復(fù)制到SOFTWARE并且運(yùn)行。C/OSII將在SOFTWARE目錄下添加所有的目錄和文件。完成之后INSTALL.BAT將刪除uCOS-II.EXE并且將目錄改為SOFTWAREuCOS-IIEX1_x86L,第一個(gè)例子就存放在這里。在安裝之前請(qǐng)一定閱讀一下READ.M

4、E文件。當(dāng)INSTALL.BAT已經(jīng)完成時(shí),用戶的目標(biāo)目錄下應(yīng)該有一下子目錄:l SOFTWARE這是根目錄,是所有軟件相關(guān)的文件都放在這個(gè)目錄下。l SOFTWAREBLOCKS子程序模塊目錄。筆者將例子中C/OS-II用到的與PC相關(guān)的函數(shù)模塊編譯以后放在這個(gè)目錄下。l SOFTWAREHPLISTC這個(gè)目錄中存放的是與范例HPLIST相關(guān)的文件(請(qǐng)看附錄D,HPLISTC和TO)。HPLIST.C存放在SOFTWAREHPLISTCSOURCE目錄下。DOS下的可執(zhí)行文件(HPLIST.EXE)存放在SOFTWARETOEXE中。l SOFTWARETO這個(gè)目錄中存放的是和范例TO相關(guān)的

5、文件(請(qǐng)看附錄D,HPLISTC和TO)。源文件TO.C存放在SOFTWARETOSOURCE中,DOS下的可執(zhí)行文件(TO.EXE)存放在SOFTWARETOEXE中。注意TO需要一個(gè)TO.TBL文件,它必須放在根目錄下。用戶可以在SOFTWARETOEXE目錄下找到TO.TBL文件。如果要運(yùn)行TO.EXE,必須將TO.TBL復(fù)制到根目錄下。l SOFTWAREuCOS-II與C/OS-II 相關(guān)的文件都放在這個(gè)目錄下。l SOFTWAREuCOS-IIEX1_x86L這個(gè)目錄里包括例1的源代碼(參見(jiàn) 1.07, 例1),可以在DOS(或Windows 95下的DOS窗口)下運(yùn)行。l SOF

6、TWAREuCOS-IIEX2_x86L這個(gè)目錄里包括例2的源代碼(參見(jiàn) 1.08, 例2),可以在DOS(或Windows 95下的DOS窗口)下運(yùn)行。l SOFTWAREuCOS-IIEX3_x86L這個(gè)目錄里包括例3的源代碼(參見(jiàn) 1.09, 例3),可以在DOS(或Windows 95下的DOS窗口)下運(yùn)行。l SOFTWAREuCOS-IIIx86L這個(gè)目錄下包括依賴于處理器類型的代碼。此時(shí)是為在80x86處理器上運(yùn)行uC/OS-II而必須的一些代碼,實(shí)模式,在大模式下編譯。l SOFTWAREuCOS-IISOURCE這個(gè)目錄里包括與處理器類型無(wú)關(guān)的源代碼。這些代碼完全可移植到其它

7、架構(gòu)的處理器上。1.01 INCLUDES.H用戶將注意到本書(shū)中所有的 *.C 文件都包括了以下定義:#include includes.hINCLUDE.H可以使用戶不必在工程項(xiàng)目中每個(gè)*.C文件中都考慮需要什么樣的頭文件。換句話說(shuō),INCLUDE.H是主頭文件。這樣做唯一的缺點(diǎn)是INCLUDES.H中許多頭文件在一些*.C文件的編譯中是不需要的。這意味著逐個(gè)編譯這些文件要花費(fèi)額外的時(shí)間。這雖有些不便,但代碼的可移植性卻增加了。本書(shū)中所有的例子使用一個(gè)共同的頭文件INCLUDES.H,3個(gè)副本分別存放在SOFTWAREuCOS-IIEX1_x86L,SOFTWAREuCOS-IIEX2_x8

8、6L,以及SOFTWAREuCOS-IIEX3_x86L 中。當(dāng)然可以重新編輯INCLUDES.H以添加用戶自己的頭文件。1.02不依賴于編譯的數(shù)據(jù)類型因?yàn)椴煌奈⑻幚砥饔胁煌淖珠L(zhǎng),C/OS-II的移植文件包括很多類型定義以確??梢浦残裕▍⒁?jiàn)SOFTWAREuCOS-IIIx86LOS_CPU.H,它是針對(duì)80x86的實(shí)模式,在大模式下編譯)。COS-II不使用C語(yǔ)言中的short,int,long等數(shù)據(jù)類型的定義,因?yàn)樗鼈兣c處理器類型有關(guān),隱含著不可移植性。筆者代之以移植性強(qiáng)的整數(shù)數(shù)據(jù)類型,這樣,既直觀又可移植,如表L1.1所示。為了方便起見(jiàn),還定義了浮點(diǎn)數(shù)數(shù)據(jù)類型,雖然C/OS-II中沒(méi)

9、有使用浮點(diǎn)數(shù)。程序清單 L1.1可移植型數(shù)據(jù)類型。Typedef unsigned char BOOLEAN;Typedef unsigned char INT8U;Typedef signed char INT8S;Typedef unsigned int INT16U;Typedef signed int INT16S;Typedef unsigned long INT32U;Typedef signed long INT32S;Typedef float FP32;Typedef double FP64;#define BYTE INT8S#define UBYTE INT8U#defi

10、ne WORD INT16S#define UWORD INT16U#define LONG INT32S#define ULONG INT32U以INT16U數(shù)據(jù)類型為例,它代表16位無(wú)符號(hào)整數(shù)數(shù)據(jù)類型。C/OS-II和用戶的應(yīng)用代碼可以定義這種類型的數(shù)據(jù),范圍從0到65,535。如果將CO/S-II移植到32位處理器中,那就意味著INT16U不再不是一個(gè)無(wú)符號(hào)整型數(shù)據(jù),而是一個(gè)無(wú)符號(hào)短整型數(shù)據(jù)。然而將無(wú)論C/OS-II用到哪里,都會(huì)當(dāng)作INT16U處理。 表1.1是以Borland C/C+編譯器為例,為80x86提供的定義語(yǔ)句。為了和C/OS兼容,還定義了BYTE,WORD,LONG以及

11、相應(yīng)的無(wú)符號(hào)變量。這使得用戶可以不作任何修改就能將C/OS的代碼移植到C/OS-II中。之所以這樣做是因?yàn)楣P者覺(jué)得這種新的數(shù)據(jù)類型定義有更多的靈活性,也更加易讀易懂。對(duì)一些人來(lái)說(shuō),WORD意味著32位數(shù),而此處卻意味著16位數(shù)。這些新的數(shù)據(jù)類型應(yīng)該能夠消除此類含混不請(qǐng)1.03全局變量以下是如何定義全局變量。眾所周知,全局變量應(yīng)該是得到內(nèi)存分配且可以被其他模塊通過(guò)C語(yǔ)言中extern關(guān)鍵字調(diào)用的變量。因此,必須在 .C 和 .H 文件中定義。這種重復(fù)的定義很容易導(dǎo)致錯(cuò)誤。以下討論的方法只需用在頭文件中定義一次。雖然有點(diǎn)不易懂,但用戶一旦掌握,使用起來(lái)卻很靈活。表1.2中的定義出現(xiàn)在定義所有全局變

12、量的.H頭文件中。程序清單 L 1.2定義全局宏。#ifdef xxx_GLOBALS#define xxx_EXT#else#define xxx_EXT extern#endif.H 文件中每個(gè)全局變量都加上了xxx_EXT的前綴。xxx代表模塊的名字。該模塊的.C文件中有以下定義:#define xxx_GLOBALS#include includes.h當(dāng)編譯器處理.C文件時(shí),它強(qiáng)制xxx_EXT(在相應(yīng).H文件中可以找到)為空,(因?yàn)閤xx_GLOBALS已經(jīng)定義)。所以編譯器給每個(gè)全局變量分配內(nèi)存空間,而當(dāng)編譯器處理其他.C文件時(shí),xxx_GLOBAL沒(méi)有定義,xxx_EXT被定義

13、為extern,這樣用戶就可以調(diào)用外部全局變量。為了說(shuō)明這個(gè)概念,可以參見(jiàn)uC/OS_II.H,其中包括以下定義:#ifdef OS_GLOBALS#define OS_EXT#else#define OS_EXT extern#endifOS_EXT INT32U OSIdleCtr;OS_EXT INT32U OSIdleCtrRun;OS_EXT INT32U OSIdleCtrMax;同時(shí),uCOS_II.H有中以下定義:#define OS_GLOBALS#include “includes.h”當(dāng)編譯器處理uCOS_II.C時(shí),它使得頭文件變成如下所示,因?yàn)镺S_EXT被設(shè)置為空。

14、INT32U OSIdleCtr;INT32U OSIdleCtrRun;INT32U OSIdleCtrMax;這樣編譯器就會(huì)將這些全局變量分配在內(nèi)存中。當(dāng)編譯器處理其他.C文件時(shí),頭文件變成了如下的樣子,因?yàn)镺S_GLOBAL沒(méi)有定義,所以O(shè)S_EXT被定義為extern。extern INT32U OSIdleCtr;extern INT32U OSIdleCtrRun;extern INT32U OSIdleCtrMax;在這種情況下,不產(chǎn)生內(nèi)存分配,而任何 .C文件都可以使用這些變量。這樣的就只需在 .H 文件中定義一次就可以了。1.04OS_ENTER_CRITICAL() 和 O

15、S_EXIT_CRITICAL()用戶會(huì)看到,調(diào)用OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()兩個(gè)宏,貫穿本書(shū)的所有源代碼。OS_ENTER_CRITICAL() 關(guān)中斷;而OS_EXIT_CRITICAL()開(kāi)中斷。關(guān)中斷和開(kāi)中斷是為了保護(hù)臨界段代碼。這些代碼很顯然與處理器有關(guān)。關(guān)于宏的定義可以在OS_CPU.H中找到。9.03.02節(jié)詳細(xì)討論定義這些宏的兩種方法。程序清單 L 1.3進(jìn)入正確部分的宏。#define OS_CRITICAL_METHOD 2#if OS_CRITICAL_METHOD = 1#define OS_ENTER_CRITICAL(

16、) asm CLI#define OS_EXIT_CRITICAL() asm STI#endif#if OS_CRITICAL_METHOD = 2#define OS_ENTER_CRITICAL() asm PUSHF; CLI#define OS_EXIT_CRITICAL() asm POPF#endif用戶的應(yīng)用代碼可以使用這兩個(gè)宏來(lái)開(kāi)中斷和關(guān)中斷。很明顯,關(guān)中斷會(huì)影響中斷延遲,所以要特別小心。用戶還可以用信號(hào)量來(lái)保護(hù)林階段代碼。1.05基于PC的服務(wù)PC.C 文件和 PC.H 文件(在SOFTWAREBLOCKSPCSOURCE目錄下)是筆者在范例中使用到的一些基于PC的服務(wù)程序

17、。與 C/OS-II 以前的版本(即 C/OS)不同,筆者希望集中這些函數(shù)以避免在各個(gè)例子中都重復(fù)定義,也更容易適應(yīng)不同的編譯器。PC.C包括字符顯示,時(shí)間度量和其他各種服務(wù)。所有的函數(shù)都以PC_為前綴。1.05.01字符顯示為了性能更好,顯示函數(shù)直接向顯示內(nèi)存區(qū)中寫(xiě)數(shù)據(jù)。在VGA顯示器中,顯示內(nèi)存從絕對(duì)地址0x000B8000開(kāi)始(或用段、偏移量表示則為B800:0000)。在單色顯示器中,用戶可以把#define constant DISP_BASE從0xB800改為0xB000。PC.C中的顯示函數(shù)用x和y坐標(biāo)來(lái)直接向顯示內(nèi)存中寫(xiě)ASCII字符。PC的顯示可以達(dá)到25行80列一共2,00

18、0個(gè)字符。每個(gè)字符需要兩個(gè)字節(jié)來(lái)顯示。第一個(gè)字節(jié)是用戶想要顯示的字符,第二個(gè)字節(jié)用來(lái)確定前景色和背景色。前景色用低四位來(lái)表示,背景色用第4位到6位來(lái)表示。最高位表示這個(gè)字符是否閃爍,(1)表示閃爍,(0)表示不閃爍。用PC.H中 #defien constants定義前景和背景色,PC.C包括以下四個(gè)函數(shù):PC_DispClrScr()Clear the screenPC_DispClrLine()Clear a single row (or line)PC_DispChar()Display a single ASCII character anywhere on the screenPC_

19、DispStr()Display an ASCII string anywhere on the screen1.05.02花費(fèi)時(shí)間的測(cè)量時(shí)間測(cè)量函數(shù)主要用于測(cè)試一個(gè)函數(shù)的運(yùn)行花了多少時(shí)間。測(cè)量時(shí)間是用PC的82C54定時(shí)器2。被測(cè)的程序代碼是放在函數(shù)PC_ElapsedStart()和PC_ElapsedStop()之間來(lái)測(cè)量的。在用這兩個(gè)函數(shù)之前,應(yīng)該調(diào)用PC_ElapsedInit()來(lái)初始化,它主要是計(jì)算運(yùn)行這兩個(gè)函數(shù)本身所附加的的時(shí)間。這樣,PC_ElapsedStop()函數(shù)中返回的數(shù)值就是準(zhǔn)確的測(cè)量結(jié)果了。注意,這兩個(gè)函數(shù)都不具備可重入性,所以,必須小心,不要有多個(gè)任務(wù)同時(shí)調(diào)用這

20、兩個(gè)函數(shù)。表1.4說(shuō)明了如何測(cè)量PC_DisplayChar()的執(zhí)行時(shí)間。注意,時(shí)間是以u(píng)S為單位的。程序清單 L 1.4測(cè)量代碼執(zhí)行時(shí)間。INT16U time;PC_ElapsedInit();.PC_ElapsedStart();PC_DispChar(40, 24, A, DISP_FGND_WHITE);time = PC_ElapsedStop();1.05.03其他函數(shù)C/OS-II的應(yīng)用程序和其他DOS應(yīng)用程序是一樣的,換句話說(shuō),用戶可以像在DOS下編譯其他單線程的程序一樣編譯和鏈接用戶程序。所生成的.EXE程序可以在DOS下裝載和運(yùn)行,當(dāng)然應(yīng)用程序應(yīng)該從main()函數(shù)開(kāi)始

21、。因?yàn)镃/OS-II 是多任務(wù),而且為每個(gè)任務(wù)開(kāi)辟一個(gè)堆棧,所以單線程的DOS環(huán)境應(yīng)該保存,在退出C/OS-II 程序時(shí)返回到DOS。調(diào)用PC_DOSSaveReturn()可以保存當(dāng)前DOS環(huán)境,而調(diào)用PC_DOSReturn()可以返回到DOS。 PC.C中使用ANSI C的setjmp(),longjmp()函數(shù)來(lái)分別保存和恢復(fù)DOS環(huán)境。Borland C/C+編譯庫(kù)提供這些函數(shù),多數(shù)其它的編譯程序也應(yīng)有這類函數(shù)。應(yīng)該注意到無(wú)論是應(yīng)用程序的錯(cuò)誤還是只調(diào)用exit(0)而沒(méi)有調(diào)用PC_DOSReturn()函數(shù)都會(huì)使DOS環(huán)境被破壞,從而導(dǎo)致DOS或WINDOWS95下的DOS窗口崩潰。

22、調(diào)用PC_GetDateTime()函數(shù)可得到PC中的日期和時(shí)間,并且以SACII字符串形式返回。格式是MM-DD-YY HH:MM:SS,用戶需要19個(gè)字符來(lái)存放這些數(shù)據(jù)。該函數(shù)使用了Borland C/C+的gettime()和getdate()函數(shù),其它DOS環(huán)境下的C編譯應(yīng)該也有類似函數(shù)。PC_GetKey() 函數(shù)檢查是否有按鍵被按下。如果有按鍵被按下,函數(shù)返回其值。這個(gè)函數(shù)使用了Borland C/C+的kbhit()和getch()函數(shù),其它DOS環(huán)境下的C編譯應(yīng)該也有類似函數(shù)。函數(shù)PC_SetTickRate()允許用戶為 C /OS-II定義頻率,以改變鐘節(jié)拍的速率。在DOS

23、下,每秒產(chǎn)生18.20648次時(shí)鐘節(jié)拍,或每隔54.925ms一次。這是因?yàn)?2C54定時(shí)器芯片沒(méi)有初始化,而使用默認(rèn)值65,535的結(jié)果。如果初始化為58,659,那么時(shí)鐘節(jié)拍的速率就會(huì)精確地為20.000Hz。筆者決定將時(shí)鐘節(jié)拍設(shè)得更快一些,用的是200Hz(實(shí)際是上是 199.9966Hz)。注意OS_CPU_A.ASM中的OSTickISR()函數(shù)將會(huì)每11個(gè)時(shí)鐘節(jié)拍調(diào)用一次DOS中的時(shí)鐘節(jié)拍處理,這是為了保證在DOS下時(shí)鐘的準(zhǔn)確性。如果用戶希望將時(shí)鐘節(jié)拍的速度設(shè)置為20HZ,就必須這樣做。在返回DOS以前,要調(diào)用PC_SetTickRate(),并設(shè)置18為目標(biāo)頻率,PC_SetTi

24、ckRate()就會(huì)知道用戶要設(shè)置為18.2Hz,并且會(huì)正確設(shè)置82C54。PC.C中最后兩個(gè)函數(shù)是得到和設(shè)置中斷向量,筆者是用Borland C/C+中的庫(kù)函數(shù)來(lái)完成的,但是PC_VectGet()和PC_VectSet()很容易改寫(xiě),以適用于其它編譯器。1.06 應(yīng)用 C/OS-II 的范例本章中的例子都用Borland C/C+編譯器編譯通過(guò),是在Windows95 的DOS窗口下編譯的??蓤?zhí)行代碼可以在每個(gè)范例的OBJ子目錄下找到。實(shí)際上這些代碼是在Borland IDE (Integrated Development Environment)下編譯的,編譯時(shí)的選項(xiàng)如表1.1所示:表

25、T1.1IDE中編譯選項(xiàng)。Code generationModel: LargeOptions: Treat enums as intsAssume SS Equals DS: Default for memory modelAdvanced code generationFloating point: EmulationInstruction set: 80186Options: Generate underbarsDebug info in OBJsFast floating pointOptimizationsOptimizationsGlobal register allocation

26、Invariant code motionInduction variablesLoop optimizationSuppress redundant loadsCopy propagationDead code eliminationJump optimizationIn-line intrinsic functionsRegister variablesAutomaticCommon subexpressionsOptimize globallyOptimize forSpeed筆者的Borland C/C+編譯器安裝在C:CPP目錄下,如果用戶的編譯器是在不同的目錄下,可以在Option

27、s/Directories的提示下改變IDE的路徑。C/OS-II是一個(gè)可裁剪的操作系統(tǒng),這意味著用戶可以去掉不需要的服務(wù)。代碼的削減可以通過(guò)設(shè)置OS_CFG.H中的#defines OS_?_EN 為0來(lái)實(shí)現(xiàn)。用戶不需要的服務(wù)代碼就不生成。本章的范例就用這種功能,所以每個(gè)例子都定義了不同的OS_?_EN。1.07例1第一個(gè)范例可以在SOFTWAREuCOS_IIEX1_x86L目錄下找到,它有13個(gè)任務(wù)(包括 C/OS-II 的空閑任務(wù))。C/OS-II 增加了兩個(gè)內(nèi)部任務(wù):空閑任務(wù)和一個(gè)計(jì)算CPU利用率的任務(wù)。例1建立了11個(gè)其它任務(wù)。TaskStart()任務(wù)是在函數(shù)main()中建立的

28、;它的功能是建立其它任務(wù)并且在屏幕上顯示如下統(tǒng)計(jì)信息:l 每秒鐘任務(wù)切換次數(shù);l CPU利用百分率;l 寄存器切換次數(shù);l 目前日期和時(shí)間;l C/OS-II的版本號(hào); TaskStart()還檢查是否按下ESC鍵,以決定是否返回到DOS。其余10個(gè)任務(wù)基于相同的代碼Task();每個(gè)任務(wù)在屏幕上隨機(jī)的位置顯示一個(gè)0到9的數(shù)字。1.07.01 main()例1基本上和最初C/OS中的第一個(gè)例子做一樣的事,但是筆者整理了其中的代碼,并且在屏幕上加了彩色顯示。同時(shí)筆者使用原來(lái)的數(shù)據(jù)類型(UBYTE, UWORD等)來(lái)說(shuō)明C/OS-II向下兼容。main()程序從清整個(gè)屏幕開(kāi)始,為的是保證屏幕上不留

29、有以前的DOS下的顯示L1.5(1)。注意,筆者定義了白色的字符和黑色的背景色。既然要請(qǐng)屏幕,所以可以只定義背景色而不定義前景色,但是這樣在退回DOS之后,用戶就什么也看不見(jiàn)了。這也是為什么總要定義一個(gè)可見(jiàn)的前景色。C/OS-II要用戶在使用任何服務(wù)之前先調(diào)用OSInit() L1.5(2)。它會(huì)建立兩個(gè)任務(wù):空閑任務(wù)和統(tǒng)計(jì)任務(wù),前者在沒(méi)有其它任務(wù)處于就緒態(tài)時(shí)運(yùn)行;后者計(jì)算CPU的利用率。程序清單 L 1.5main().void main (void) PC_DispClrScr(DISP_FGND_WHITE + DISP_BGND_BLACK); (1) OSInit(); (2) PC

30、_DOSSaveReturn(); (3) PC_VectSet(uCOS, OSCtxSw); (4) RandomSem = OSSemCreate(1); (5) OSTaskCreate(TaskStart, (6) (void *)0, (void *)&TaskStartStkTASK_STK_SIZE-1, 0); OSStart(); (7)當(dāng)前DOS環(huán)境是通過(guò)調(diào)用PC_DOSSaveReturn()L1.5(3)來(lái)保存的。這使得用戶可以返回到?jīng)]有運(yùn)行C/OS-II以前的DOS環(huán)境。跟隨清單L1.6中的程序可以看到PC_DOSSaveReturn()做了很多事情。PC_DOSS

31、aveReturn()首先設(shè)置PC_ExitFlag為FALSEL1.6(1),說(shuō)明用戶不是要返回DOS,然后初始化OSTickDOSCtr為1L1.6(2),因?yàn)檫@個(gè)變量將在OSTickISR()中遞減,而0將使得這個(gè)變量在OSTickISR()中減1后變?yōu)?55。然后,PC_DOSSaveReturn()將DOS 的時(shí)鐘節(jié)拍處理(tick handler)存入一個(gè)自由向量表入口中L1.6(3)-(4),以便為C/OS-II的時(shí)鐘節(jié)拍處理所調(diào)用。接著PC_DOSSaveReturn()調(diào)用jmp()L1.6(5),它將處理器狀態(tài)(即所有寄存器的值)存入被稱為PC_JumpBuf的結(jié)構(gòu)之中。保

32、存處理器的全部寄存器使得程序返回到PC_DOSSaveReturn()并且在調(diào)用setjmp()之后立即執(zhí)行。因?yàn)镻C_ExitFlag被初始化為FALSEL1.6(1)。PC_DOSSaveReturn()跳過(guò)if狀態(tài)語(yǔ)句 L1.6(6)(9) 回到main()函數(shù)。如果用戶想要返回到DOS,可以調(diào)用 PC_DOSReturn()(程序清單 L 1.7),它設(shè)置PC_ExitFlag為T(mén)RUE,并且執(zhí)行l(wèi)ongjmp()語(yǔ)句L1.7(2),這時(shí)處理器將跳回 PC_DOSSaveReturn()在調(diào)用 setjmp()之后 L1.6(5),此時(shí)PC_ExitFlag為T(mén)RUE,故if語(yǔ)句以后的

33、代碼將得以執(zhí)行。 PC_DOSSaveReturn()將時(shí)鐘節(jié)拍改為 18.2HzL1.6(6),恢復(fù)PC 時(shí)鐘節(jié)拍中斷服務(wù)L1.6(7),清屏幕L1.6(8),通過(guò)exit(0)返回DOS L1.6(9)。程序清單 L 1.6保存DOS環(huán)境。.void PC_DOSSaveReturn (void) PC_ExitFlag = FALSE; (1) OSTickDOSCtr = 8; (2) PC_TickISR = PC_VectGet(VECT_TICK); (3) OS_ENTER_CRITICAL(); PC_VectSet(VECT_DOS_CHAIN, PC_TickISR);

34、(4) OS_EXIT_CRITICAL(); Setjmp(PC_JumpBuf); (5) if (PC_ExitFlag = TRUE) OS_ENTER_CRITICAL(); PC_SetTickRate(18); (6) PC_VectSet(VECT_TICK, PC_TickISR); (7) OS_EXIT_CRITICAL(); PC_DispClrScr(DISP_FGND_WHITE + DISP_BGND_BLACK); (8) exit(0); (9) 程序清單 L 1.7設(shè)置返回DOS 。void PC_DOSReturn (void) PC_ExitFlag =

35、 TRUE; (1) longjmp(PC_JumpBuf, 1); (2)現(xiàn)在回到main()這個(gè)函數(shù),在程序清單 L 1.5中,main()調(diào)用PC_VectSet()來(lái)設(shè)置COS-II中的 CPU寄存器切換。任務(wù)級(jí)的CPU寄存器切換由80x86 INT指令來(lái)分配向量地址。筆者使用向量0x80(即128),因?yàn)樗幢籇OS和BIOS使用。這里用了一個(gè)信號(hào)量來(lái)保護(hù)Borland C/C+庫(kù)中的產(chǎn)生隨機(jī)數(shù)的函數(shù)L1.5(5),之所以使用信號(hào)量保護(hù)一下,是因?yàn)楣P者不知道這個(gè)函數(shù)是否具備可重入性,筆者假設(shè)其不具備,初始化將信號(hào)量設(shè)置為1,意思是在某一時(shí)刻只有一個(gè)任務(wù)可以調(diào)用隨機(jī)數(shù)產(chǎn)生函數(shù)。在開(kāi)始多

36、任務(wù)之前,筆者建立了一個(gè)叫做TaskStart()的任務(wù)L1.5(6),在啟動(dòng)多任務(wù)OSStart()之前用戶至少要先建立一個(gè)任務(wù),這一點(diǎn)非常重要L1.5(7)。不這樣做用戶的應(yīng)用程序?qū)?huì)崩潰。實(shí)際上,如果用戶要計(jì)算CPU的利用率時(shí),也需要先建立一個(gè)任務(wù)。COS-II的統(tǒng)計(jì)任務(wù)要求在整個(gè)一秒鐘內(nèi)沒(méi)有任何其它任務(wù)運(yùn)行。如果用戶在啟動(dòng)多任務(wù)之前要建立其它任務(wù),必須保證用戶的任務(wù)代碼監(jiān)控全局變量OSStatRdy和延時(shí)程序 即調(diào)用 OSTimeDly()的執(zhí)行,直到這個(gè)變量變成TRUE。這表明C/OS-II的CPU利用率統(tǒng)計(jì)函數(shù)已經(jīng)采集到了數(shù)據(jù)。1.07.02 TaskStart()例1中的主要工作

37、由TaskStart()來(lái)完成。TaskStart()函數(shù)的示意代碼如程序清單 L 1.8所示。TaskStart()首先在屏幕頂端顯示一個(gè)標(biāo)識(shí),說(shuō)明這是例1 L1.8(1)。然后關(guān)中斷,以改變中斷向量,讓其指向C/OS-II的時(shí)鐘節(jié)拍處理,而后,改變時(shí)鐘節(jié)拍率,從DOS的 18.2Hz 變?yōu)?200Hz L1.8(3)。在處理器改變中斷向量時(shí)以及系統(tǒng)沒(méi)有完全初始化前,當(dāng)然不希望有中斷打入!注意main()這個(gè)函數(shù)(見(jiàn)程序清單 L 1.5)在系統(tǒng)初始化的時(shí)候并沒(méi)有將中斷向量設(shè)置成C/OS-II的時(shí)鐘節(jié)拍處理程序,做嵌入式應(yīng)用時(shí),用戶必須在第一個(gè)任務(wù)中打開(kāi)時(shí)鐘節(jié)拍中斷。程序清單 L 1.8建立其

38、它任務(wù)的任務(wù)。void TaskStart (void *data) Prevent compiler warning by assigning data to itself; Display banner identifying this as EXAMPLE #1; (1) OS_ENTER_CRITICAL(); PC_VectSet(0x08, OSTickISR); (2) PC_SetTickRate(200); (3) OS_EXIT_CRITICAL(); Initialize the statistic task by calling OSStatInit(); (4) Cr

39、eate 10 identical tasks; (5) for (;) Display the number of tasks created; Display the % of CPU used; Display the number of task switches in 1 second; Display uC/OS-IIs version number If (key was pressed) if (key pressed was the ESCAPE key) PC_DOSReturn(); Delay for 1 Second; 在建立其他任務(wù)之前,必須調(diào)用OSStatInit

40、()L1.8(4)來(lái)確定用戶的PC有多快,如程序清單L1.9所示。在一開(kāi)始,OSStatInit()就將自身延時(shí)了兩個(gè)時(shí)鐘節(jié)拍,這樣它就可以與時(shí)鐘節(jié)拍中斷同步L1.9(1)。因此,OSStatInit()必須在時(shí)鐘節(jié)拍啟動(dòng)之后調(diào)用;否則,用戶的應(yīng)用程序就會(huì)崩潰。當(dāng)C/OS-II調(diào)用OSStatInit()時(shí),一個(gè)32位的計(jì)數(shù)器OSIdleCtr被清為0 L1.9(2),并產(chǎn)生另一個(gè)延時(shí),這個(gè)延時(shí)使OSStatInit()掛起。此時(shí),uCOS-II沒(méi)有別的任務(wù)可以執(zhí)行,它只能執(zhí)行空閑任務(wù)(C/OS-II的內(nèi)部任務(wù))??臻e任務(wù)是一個(gè)無(wú)線的循環(huán),它不斷的遞增OSIdleCtrL1.9(3)。1秒以后

41、,uCOS-II重新開(kāi)始OSStatInit(),并且將OSIdleCtr保存在OSIdleMax中L1.9(4)。所以O(shè)SIdleMax是OSIdleCtr所能達(dá)到的最大值。而當(dāng)用戶再增加其他應(yīng)用代碼時(shí),空閑任務(wù)就不會(huì)占用那樣多的CPU時(shí)間。OSIdleCtr不可能達(dá)到那樣多的記數(shù),(如果擁護(hù)程序每秒復(fù)位一次OSIdleCtr)CPU利用率的計(jì)算由C/OS-II 中的OSStatTask()函數(shù)來(lái)完成,這個(gè)任務(wù)每秒執(zhí)行一次。而當(dāng)OSStatRdy置為T(mén)RUEL1.9(5),表示C/OS-II將統(tǒng)計(jì)CPU的利用率。程序清單 L 1.9測(cè)試CPU速度。void OSStatInit (void)

42、 OSTimeDly(2); (1) OS_ENTER_CRITICAL(); OSIdleCtr = 0L; (2) OS_EXIT_CRITICAL(); OSTimeDly(OS_TICKS_PER_SEC); (3) OS_ENTER_CRITICAL(); OSIdleCtrMax = OSIdleCtr; (4) OSStatRdy = TRUE; (5) OS_EXIT_CRITICAL();1.07.03TaskN()OSStatInit()將返回到TaskStart()?,F(xiàn)在,用戶可以建立10個(gè)同樣的任務(wù)(所有任務(wù)共享同一段代碼)。所有任務(wù)都由TaskStart()中建立,由

43、于TaskStart()的優(yōu)先級(jí)為0(最高),新任務(wù)建立后不進(jìn)行任務(wù)調(diào)度。當(dāng)所有任務(wù)都建立完成后,TaskStart()將進(jìn)入無(wú)限循環(huán)之中,在屏幕上顯示統(tǒng)計(jì)信息,并檢測(cè)是否有ESC鍵按下,如果沒(méi)有按鍵輸入,則延時(shí)一秒開(kāi)始下一次循環(huán);如果在這期間用戶按下了ESC鍵,TaskStart()將調(diào)用PC_DOSReturn()返回DOS系統(tǒng)。程序清單L1.10給出了任務(wù)的代碼。任務(wù)一開(kāi)始,調(diào)用OSSemPend()獲取信號(hào)量RandomSem 程序清單L1.10(1)(也就是禁止其他任務(wù)運(yùn)行這段代碼譯者注),然后調(diào)用Borland C/C+的庫(kù)函數(shù)random()來(lái)獲得一個(gè)隨機(jī)數(shù)程序清單L1.10(2

44、),此處設(shè)random()函數(shù)是不可重入的,所以10個(gè)任務(wù)將輪流獲得信號(hào)量,并調(diào)用該函數(shù)。當(dāng)計(jì)算出x和y坐標(biāo)后程序清單L1.10(3),任務(wù)釋放信號(hào)量。隨后任務(wù)在計(jì)算的坐標(biāo)處顯示其任務(wù)號(hào)(0-9,任務(wù)建立時(shí)的標(biāo)識(shí))程序清單L1.10(4)。最后,任務(wù)延時(shí)一個(gè)時(shí)鐘節(jié)拍程序清單L1.10(5),等待進(jìn)入下一次循環(huán)。系統(tǒng)中每個(gè)任務(wù)每秒執(zhí)行200次,10個(gè)任務(wù)每秒鐘將切換2000次。程序清單 L 1.10在屏幕上顯示隨機(jī)位置顯示數(shù)字的任務(wù)。void Task (void *data) UBYTE x; UBYTE y; UBYTE err; for (;) OSSemPend(RandomSem, 0

45、, &err); (1) x = random(80); (2) y = random(16); OSSemPost(RandomSem); (3) PC_DispChar(x, y + 5, *(char *)data, DISP_FGND_LIGHT_GRAY);(4) OSTimeDly(1); (5) 1.08例2例2使用了帶擴(kuò)展功能的任務(wù)建立函數(shù)OSTaskCreateExt()和uCOS-II的堆棧檢查操作(要使用堆棧檢查操作必須用OSTaskCreateExt()建立任務(wù)譯者注)。當(dāng)用戶不知道應(yīng)該給任務(wù)分配多少堆??臻g時(shí),堆棧檢查功能是很有用的。在這個(gè)例子里,先分配足夠的堆??臻g

46、給任務(wù),然后用堆棧檢查操作看看任務(wù)到底需要多少堆??臻g。顯然,任務(wù)要運(yùn)行足夠長(zhǎng)時(shí)間,并要考慮各種情況才能得到正確數(shù)據(jù)。最后決定的堆棧大小還要考慮系統(tǒng)今后的擴(kuò)展,一般多分配10,25或者更多。如果系統(tǒng)對(duì)穩(wěn)定性要求高,則應(yīng)該多一倍以上。uCOS-II的堆棧檢查功能要求任務(wù)建立時(shí)堆棧清零。OSTaskCreateExt()可以執(zhí)行此項(xiàng)操作(設(shè)置選項(xiàng)OS_TASK_OPT_STK_CHK和OS_TASK_OPT_STK_CLR打開(kāi)此項(xiàng)操作)。如果任務(wù)運(yùn)行過(guò)程中要進(jìn)行建立、刪除任務(wù)的操作,應(yīng)該設(shè)置好上述的選項(xiàng),確保任務(wù)建立后堆棧是清空的。同時(shí)要意識(shí)到OSTaskCreateExt()進(jìn)行堆棧清零操作是一

47、項(xiàng)很費(fèi)時(shí)的工作,而且取決于堆棧的大小。執(zhí)行堆棧檢查操作的時(shí)候,uCOS-II從棧底向棧頂搜索非0元素(參看圖F 1.1),同時(shí)用一個(gè)計(jì)數(shù)器記錄0元素的個(gè)數(shù)。例2的磁盤(pán)文件為SOFTWAREuCOS-IIEX2_x86L,它包含9個(gè)任務(wù)。加上uCOS-II本身的兩個(gè)任務(wù):空閑任務(wù)(idle task)和統(tǒng)計(jì)任務(wù)。與例1一樣TaskStart()由main()函數(shù)建立,其功能是建立其他任務(wù)并在屏幕上顯示如下的統(tǒng)計(jì)數(shù)據(jù):l 每秒種任務(wù)切換的次數(shù);l CPU利用率的百分比;l 當(dāng)前日期和時(shí)間;l uCOS_II的版本號(hào);圖F 1.1C/OS-II stack checking.1.08.01 main

48、()例2的main()函數(shù)和例1的看起來(lái)差不多(參看程序清單L1.11),但是有兩處不同。第一,main()函數(shù)調(diào)用PC_ElapsedInit()程序清單L1.11(1)來(lái)初始化定時(shí)器記錄OSTaskStkChk()的執(zhí)行時(shí)間。第二,所有的任務(wù)都使用OSTaskCreateExt()函數(shù)來(lái)建立任務(wù)程序清單L1.11(2)(替代老版本的OSTaskCreate(),這使得每一個(gè)任務(wù)都可進(jìn)行堆棧檢查。程序清單 L 1.11例2中的Main()函數(shù).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, &TaskStartStkTASK_STK_SIZE-1, TASK_START_PRIO, TASK_START_ID, &TaskStartStk0, TASK_STK_SIZE, (v

溫馨提示

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

評(píng)論

0/150

提交評(píng)論