免费色播,亚洲国产欧美国产第一区二区三区,毛片看,日本精品在线观看视频,国产成人精品一区二区免费视频,日本黄色免费网站,一级毛片免费

ucos ii嵌入式操作系統(tǒng)的分析和移植

來(lái)源:網(wǎng)絡(luò)

點(diǎn)擊:2024

A+ A-

所屬頻道:新聞中心

關(guān)鍵詞: ucos ii,移植

      ucos ii的特點(diǎn)

      1.ucos ii是由Labrosse先生編寫(xiě)的一個(gè)開(kāi)放式內(nèi)核,最主要的特點(diǎn)就是源碼公開(kāi)。這一點(diǎn)對(duì)于用戶(hù)來(lái)說(shuō)可謂利弊各半,好處在于,一方面它是免費(fèi)的,另一方面用戶(hù)可以根據(jù)自己的需要對(duì)它進(jìn)行修改。缺點(diǎn)在于它缺乏必要的支持,沒(méi)有功能強(qiáng)大的軟件包,用戶(hù)通常需要自己編寫(xiě)驅(qū)動(dòng)程序,特別是如果用戶(hù)使用的是不太常用的單片機(jī),還必須自己編寫(xiě)移植程序。

      2.ucos ii是一個(gè)占先式的內(nèi)核,即已經(jīng)準(zhǔn)備就緒的高優(yōu)先級(jí)任務(wù)可以剝奪正在運(yùn)行的低優(yōu)先級(jí)任務(wù)的CPU使用權(quán)。這個(gè)特點(diǎn)使得它的實(shí)時(shí)性比非占先式的內(nèi)核要好。通常我們都是在中斷服務(wù)程序中使高優(yōu)先級(jí)任務(wù)進(jìn)入就緒態(tài)(例如發(fā)信號(hào)),這樣退出中斷服務(wù)程序后,將進(jìn)行任務(wù)切換,高優(yōu)先級(jí)任務(wù)將被執(zhí)行。拿51單片機(jī)為例,比較一下就可以發(fā)現(xiàn)這樣做的好處。假如需要用中斷方式采集一批數(shù)據(jù)并進(jìn)行處理,在傳統(tǒng)的編程方法中不能在中斷服務(wù)程序中進(jìn)行復(fù)雜的數(shù)據(jù)處理,因?yàn)檫@會(huì)使得關(guān)中斷時(shí)間過(guò)長(zhǎng)。所以經(jīng)常采用的方法是置一標(biāo)志位,然后退出中斷。由于主程序是循環(huán)執(zhí)行的,所以它總有機(jī)會(huì)檢測(cè)到這一標(biāo)志并轉(zhuǎn)到數(shù)據(jù)處理程序中去。但是因?yàn)闊o(wú)法確定發(fā)生中斷時(shí)程序到底執(zhí)行到了什么地方,也就無(wú)法判斷要經(jīng)過(guò)多長(zhǎng)時(shí)間數(shù)據(jù)處理程序才會(huì)執(zhí)行,中斷響應(yīng)時(shí)間無(wú)法確定,系統(tǒng)的實(shí)時(shí)性不強(qiáng)。如果使用μC/OS-II的話(huà),只要把數(shù)據(jù)處理程序的優(yōu)先級(jí)設(shè)定得高一些,并在中斷服務(wù)程序中使它進(jìn)入就緒態(tài),中斷結(jié)束后數(shù)據(jù)處理程序就會(huì)被立即執(zhí)行。這樣可以把中斷響應(yīng)時(shí)間限制在一定的范圍內(nèi)。對(duì)于一些對(duì)中斷響應(yīng)時(shí)間有嚴(yán)格要求的系統(tǒng),這是必不可少的。但應(yīng)該指出的是如果數(shù)據(jù)處理程序簡(jiǎn)單,這樣做就未必合適。因?yàn)閡cos ii要求在中斷服務(wù)程序末尾使用OSINTEXIT函數(shù)以判斷是否進(jìn)行任務(wù)切換,這需要花費(fèi)一定的時(shí)間。

      3.ucos ii和大家所熟知的Linux等分時(shí)操作系統(tǒng)不同,它不支持時(shí)間片輪轉(zhuǎn)法。ucos ii是一個(gè)基于優(yōu)先級(jí)的實(shí)時(shí)操作系統(tǒng),每個(gè)任務(wù)的優(yōu)先級(jí)必須不同,分析它的源碼會(huì)發(fā)現(xiàn),ucos ii把任務(wù)的優(yōu)先級(jí)當(dāng)做任務(wù)的標(biāo)識(shí)來(lái)使用,如果優(yōu)先級(jí)相同,任務(wù)將無(wú)法區(qū)分。進(jìn)入就緒態(tài)的優(yōu)先級(jí)最高的任務(wù)首先得到CPU的使用權(quán),只有等它交出CPU的使用權(quán)后,其他任務(wù)才可以被執(zhí)行。所以它只能說(shuō)是多任務(wù),不能說(shuō)是多進(jìn)程,至少不是我們所熟悉的那種多進(jìn)程。顯而易見(jiàn),如果只考慮實(shí)時(shí)性,它當(dāng)然比分時(shí)系統(tǒng)好,它可以保證重要任務(wù)總是優(yōu)先占有CPU。但是在系統(tǒng)中,重要任務(wù)畢竟是有限的,這就使得劃分其他任務(wù)的優(yōu)先權(quán)變成了一個(gè)讓人費(fèi)神的問(wèn)題。另外,有些任務(wù)交替執(zhí)行反而對(duì)用戶(hù)更有利。例如,用單片機(jī)控制兩小塊顯示屏?xí)r,無(wú)論是編程者還是使用者肯定希望它們同時(shí)工作,而不是顯示完一塊顯示屏的信息以后再顯示另一塊顯示屏的信息。這時(shí)候,要是ucos ii即支持優(yōu)先級(jí)法又支持時(shí)間片輪轉(zhuǎn)法就更合適了。

      4.ucos ii對(duì)共享資源提供了保護(hù)機(jī)制。正如上文所提到的,ucos ii是一個(gè)支持多任務(wù)的操作系統(tǒng)。一個(gè)完整的程序可以劃分成幾個(gè)任務(wù),不同的任務(wù)執(zhí)行不同的功能。這樣,一個(gè)任務(wù)就相當(dāng)于模塊化設(shè)計(jì)中的一個(gè)子模塊。在任務(wù)中添加代碼時(shí),只要不是共享資源就不必?fù)?dān)心互相之間有影響。而對(duì)于共享資源(比如串口),ucos ii也提供了很好的解決辦法。一般情況下使用的是信號(hào)量的方法。簡(jiǎn)單地說(shuō),先創(chuàng)建一個(gè)信號(hào)量并對(duì)它進(jìn)行初始化。當(dāng)一個(gè)任務(wù)需要使用一個(gè)共享資源時(shí),它必須先申請(qǐng)得到這個(gè)信號(hào)量,而一旦得到了此信號(hào)量,那就只有等使用完了該資源,信號(hào)量才會(huì)被釋放。在這個(gè)過(guò)程中即使有優(yōu)先權(quán)更高的任務(wù)進(jìn)入了就緒態(tài),因?yàn)闊o(wú)法得到此信號(hào)量,也不能使用該資源。這個(gè)特點(diǎn)的好處顯而易見(jiàn),例如當(dāng)顯示屏正在顯示信息的時(shí)候,外部產(chǎn)生了一個(gè)中斷,而在中斷服務(wù)程序中需要顯示屏顯示其他信息。這樣,退出中斷服務(wù)程序后,原有的信息就可能被破壞了。而在μC/OS-II中采用信號(hào)量的方法時(shí),只有顯示屏把原有信息顯示完畢后才可以顯示新信息,從而可以避免這個(gè)現(xiàn)象。不過(guò),采用這種方法是以犧牲系統(tǒng)的實(shí)時(shí)性為代價(jià)的。如果顯示原有信息需要耗費(fèi)大量時(shí)間,系統(tǒng)只好等待。從結(jié)果上看,等于延長(zhǎng)了中斷響應(yīng)時(shí)間,這對(duì)于未顯示信息是報(bào)警信息的情況,無(wú)疑是致命的。發(fā)生這種情況,在μC/OS-II中稱(chēng)為優(yōu)先級(jí)反轉(zhuǎn),就是高優(yōu)先級(jí)任務(wù)必須等待低優(yōu)先級(jí)任務(wù)的完成。在上述情況下,在兩個(gè)任務(wù)之間發(fā)生優(yōu)先級(jí)反轉(zhuǎn)是無(wú)法避免的。所以在使用ucos ii時(shí),必須對(duì)所開(kāi)發(fā)的系統(tǒng)了解清楚,才能決定對(duì)于某種共享資源是否使用信號(hào)量。

      ucos ii在單片機(jī)使用中的一些特點(diǎn)

      1.在單片機(jī)系統(tǒng)中嵌入ucos ii將增強(qiáng)系統(tǒng)的可靠性,并使得調(diào)試程序變得簡(jiǎn)單。以往傳統(tǒng)的單片機(jī)開(kāi)發(fā)工作中經(jīng)常遇到程序跑飛或是陷入死循環(huán)。可以用看門(mén)狗解決程序跑飛問(wèn)題,而對(duì)于后一種情況,尤其是其中牽扯到復(fù)雜數(shù)學(xué)計(jì)算的話(huà),只有設(shè)置斷點(diǎn),耗費(fèi)大量時(shí)間來(lái)慢慢分析。如果在系統(tǒng)中嵌入 ucos ii的話(huà),事情就簡(jiǎn)單多了。可以把整個(gè)程序分成許多任務(wù),每個(gè)任務(wù)相對(duì)獨(dú)立,然后在每個(gè)任務(wù)中設(shè)置超時(shí)函數(shù),時(shí)間用完以后,任務(wù)必須交出 CPU的使用權(quán)。即使一個(gè)任務(wù)發(fā)生問(wèn)題,也不會(huì)影響其他任務(wù)的運(yùn)行。這樣既提高了系統(tǒng)的可靠性,同時(shí)也使得調(diào)試程序變得容易。

      2.在單片機(jī)系統(tǒng)中嵌入ucos ii將增加系統(tǒng)的開(kāi)銷(xiāo)?,F(xiàn)在所使用的51單片機(jī),一般是指87C51或者89C51,其片內(nèi)都帶有一定的RAM和 ROM。對(duì)于一些簡(jiǎn)單的程序,如果采用傳統(tǒng)的編程方法,已經(jīng)不需要外擴(kuò)存儲(chǔ)器了。如果在其中嵌入ucos ii的話(huà),在只需要使用任務(wù)調(diào)度、任務(wù)切換、信號(hào)量處理、延時(shí)或超時(shí)服務(wù)的情況下,也不需要外擴(kuò)ROM了,但是外擴(kuò)RAM是必須的。由于ucos ii是可裁減的操作系統(tǒng),其所需要的RAM大小就取決于操作系統(tǒng)功能的多少。舉例來(lái)說(shuō),μC/OS-II允許用戶(hù)定義最大任務(wù)數(shù)。由于每建立一個(gè)任務(wù),都要產(chǎn)生一個(gè)與之相對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)TCB,該數(shù)據(jù)結(jié)構(gòu)要占用很大一部分內(nèi)存空間。所以在定義最大任務(wù)數(shù)時(shí),一定要考慮實(shí)際情況的需要。如果定得過(guò)大,勢(shì)必會(huì)造成不必要的浪費(fèi)。嵌入ucos ii以后,總的RAM需求可以由如下表達(dá)式得出:

      RAM總需求=應(yīng)用程序的RAM需求+內(nèi)核數(shù)據(jù)區(qū)的RAM需求+(任務(wù)棧需求+最大中斷嵌套棧需求)·任務(wù)數(shù)

      所幸的是,μC/OS-II可以對(duì)每個(gè)任務(wù)分別定義堆棧空間的大小,開(kāi)發(fā)人員可根據(jù)任務(wù)的實(shí)際需求來(lái)進(jìn)行??臻g的分配。但在RAM容量有限的情況下,還是應(yīng)該注意一下對(duì)大型數(shù)組、數(shù)據(jù)結(jié)構(gòu)和函數(shù)的使用,別忘了,函數(shù)的形參也是要推入堆棧的。

      3.ucos ii的移植也是一件需要值得注意的工作。如果沒(méi)有現(xiàn)成的移植實(shí)例的話(huà),就必須自己來(lái)編寫(xiě)移植代碼。雖然只需要改動(dòng)兩個(gè)文件,但仍需要對(duì)相應(yīng)的微處理器比較熟悉才行,最好參照已有的移植實(shí)例。另外,即使有移植實(shí)例,在編程前最好也要閱讀一下,因?yàn)槔锩鏍砍兜蕉褩2僮?。在編?xiě)中斷服務(wù)程序時(shí),把寄存器推入堆棧的順序必須與移植代碼中的順序相對(duì)應(yīng)。

      4.和其他一些著名的嵌入式操作系統(tǒng)不同,ucos ii在單片機(jī)系統(tǒng)中的啟動(dòng)過(guò)程比較簡(jiǎn)單,不像有些操作系統(tǒng)那樣,需要把內(nèi)核編譯成一個(gè)映像文件寫(xiě)入ROM中,上電復(fù)位后,再?gòu)腞OM中把文件加載到RAM中去,然后再運(yùn)行應(yīng)用程序。ucos ii的內(nèi)核是和應(yīng)用程序放在一起編譯成一個(gè)文件的,使用者只需要把這個(gè)文件轉(zhuǎn)換成HEX格式,寫(xiě)入ROM中就可以了,上電后,會(huì)像普通的單片機(jī)程序一樣運(yùn)行。

      結(jié)語(yǔ)

      由以上介紹可以看出,ucos ii具有免費(fèi)、使用簡(jiǎn)單、可靠性高、實(shí)時(shí)性好等優(yōu)點(diǎn),但也有移植困難、缺乏必要的技術(shù)支持等缺點(diǎn),尤其不像商用嵌入式系統(tǒng)那樣得到廣泛使用和持續(xù)的研究更新。但開(kāi)放性又使得開(kāi)發(fā)人員可以自行裁減和添加所需的功能,在許多應(yīng)用領(lǐng)域發(fā)揮著獨(dú)特的作用。當(dāng)然,是否在單片機(jī)系統(tǒng)中嵌入ucos ii應(yīng)視所開(kāi)發(fā)的項(xiàng)目而定,對(duì)于一些簡(jiǎn)單的、低成本的項(xiàng)目來(lái)說(shuō),就沒(méi)必要使用嵌入式操作系統(tǒng)了。

      --摘自INTERNET

      44B0下ucos-ii的移植

      要保證ucos Ⅱ移植到微處理器后能正確運(yùn)行;處理器需具備如下特性:

      1) 處理器的c編譯器支持可重入函數(shù)

      可重入的代碼指的是一段代碼(如一個(gè)函數(shù))可以被多個(gè)任務(wù)同時(shí)調(diào)用,而不必?fù)?dān)心會(huì)破壞數(shù)據(jù)。也就是說(shuō),可重入型函數(shù)在任何時(shí)候都可以被中斷執(zhí)行,過(guò)一段時(shí)間以后又可以繼續(xù)運(yùn)行,而不會(huì)因?yàn)樵诤瘮?shù)中斷的時(shí)候被其他的任務(wù)重新調(diào)用,影響函數(shù)中的數(shù)據(jù)。下面的兩個(gè)例子可以比較可重入型函數(shù)和非可重入型函數(shù):

      程序1:可重入型函數(shù)

      void swap(int *x, int *y)

      int temp;

      temp=*x;

      *x=*y;

      *y=temp;

      程序2:非可重入型函數(shù)

      int temp;

      void swap(int *x, int *y)

      temp=*x;

      *x=*y;

      *y=temp;

      程序1 中使用的是局部變量temp 作為變量。通常的C 編譯器,把局部變量分配在棧中。

      所以,多次調(diào)用同一個(gè)函數(shù),可以保證每次的temp 互不受影響。而程序2 中temp 定義的是全局變量,多次調(diào)用函數(shù)的時(shí)候,必然受到影響。代碼的可重入性是保證完成多任務(wù)的基礎(chǔ),除了在C 程序中使用局部變量以外,還需要C 編譯器的支持。筆者使用的是ARM SDT 以及ADS 的集成開(kāi)發(fā)環(huán)境,均可以生成可重入的代碼。

      2)在程序中可以打開(kāi)和關(guān)閉中斷

      在ucos Ⅱ中,可以通過(guò)OS_ENTER_CRITICAL()或者OS_EXIT_CRITICAL()宏來(lái)控制

      系統(tǒng)關(guān)閉或者打開(kāi)中斷。這需要處理器的支持,在ARM7TDMI 的處理器上,可以設(shè)置相應(yīng)的寄存器來(lái)關(guān)閉或者打開(kāi)系統(tǒng)的所有中斷。

      3)處理器支持中斷,并且能產(chǎn)生定時(shí)器中斷(ucos Ⅱ是通過(guò)定時(shí)器中斷來(lái)實(shí)現(xiàn)多任務(wù)的調(diào)度,即時(shí)間片的產(chǎn)生 )ucos Ⅱ 是通過(guò)處理器產(chǎn)生的定時(shí)器的中斷來(lái)實(shí)現(xiàn)多任務(wù)之間的調(diào)度的。在ARM7TDMI 的處理器上可以產(chǎn)生定時(shí)器中斷。

      4)處理器要具有一定的硬件堆棧數(shù)量

      5)處理器要有將堆棧指針和其他cpu寄存器存儲(chǔ)和讀出堆棧(或者內(nèi)存)的指令(如51的pop,push指令)。

      ucos Ⅱ進(jìn)行任務(wù)調(diào)度的時(shí)候,會(huì)把當(dāng)前任務(wù)的CPU 寄存器存放到此任務(wù)的堆棧中,然后,再?gòu)牧硪粋€(gè)任務(wù)的堆棧中恢復(fù)原來(lái)的工作寄存器,繼續(xù)運(yùn)行另一個(gè)任務(wù)。所以,寄存器的入棧和出棧是ucos Ⅱ多任務(wù)調(diào)度的基礎(chǔ)。

      ARM7TDMI 處理器完全滿(mǎn)足上述要求。

     

      接下來(lái)將介紹如何把ucos Ⅱ移植到Samsung公司的一款A(yù)RM7TDMI 的嵌入式處理器——S3C44B0X 上。

      ucos Ⅱ中與處理器有關(guān)的代碼:os_cpu.h os_cpu_a.asm os_cpu_c.c

      ucos Ⅱ的設(shè)置 : os_cfg.h inludes.h

      ucos Ⅱ在44b0上的移植

      1)設(shè)置inludes.h中與處理器及編譯器有關(guān)的代碼

      FORADS

      #include “os_cpu.h”

      #include “os_cfg.h”

      #include “ucos_ii.h”

      這里未做處理 取默認(rèn)的數(shù)據(jù)類(lèi)型。

      FOR SDT

      #include 》stdio.h《

      #include 》stdlib.h《

      #include 》string.h《

      #include “os_cpu.h”

      #include “os_cfg.h”

      #include “ucos_ii.h”

      #ifdef EX3_GLOBALS

      #define EX3_EXT

      #else

      #define EX3_EXT extern

      #endif

      typedef struct {

      char TaskName[30];

      INT16U TaskCtr;

      INT16U TaskExecTime;

      INT32U TaskTotExecTime;

      } TASK_USER_DATA;

      EX3_EXT TASK_USER_DATA TaskUserData[10];

      void DispTaskStat(INT8U id);

      ********************************************************************************

      其他人的應(yīng)用修改事例:

      #define INT8U unsigned char

      #define INT16U unsigned short

      #define INT32U unsigned long

      #define OS_STK unsigned long

      #define BOOLEAN int

      #define OS_CPU_SR unsigned long

      #define INT8S char

      extern int INTS_OFF(void);

      extern void INTS_ON(void);

      #define OS_ENTER_CRITICAL() { cpu_sr = INTS_OFF(); }

      #define OS_EXIT_CRITICAL() { if(cpu_sr == 0) INTS_ON(); }

      #define OS_STK_GROWTH 1

      #define STACKSIZE 256

      因?yàn)椴煌奈⑻幚砥饔胁煌淖珠L(zhǎng),所以u(píng)cos Ⅱ的移植包括了一系列的類(lèi)型定義以確

      保其可移植性。尤其是ucos Ⅱ代碼從不使用C 的short,int 和long 等數(shù)據(jù)類(lèi)型,因?yàn)樗鼈兪桥c編譯器相關(guān)的,不可移植。相反的,我們定義的整形數(shù)據(jù)結(jié)構(gòu)既是可移植的又是直觀的。為了方便,雖然ucos Ⅱ不是用浮點(diǎn)數(shù)據(jù),但我們還是定義了浮點(diǎn)數(shù)據(jù)類(lèi)型。

      例如,INT16U 數(shù)據(jù)類(lèi)型總是代表16 位的無(wú)符號(hào)整數(shù)?,F(xiàn)在,ucos Ⅱ和用戶(hù)的應(yīng)用程序就可以估計(jì)出聲明為該數(shù)據(jù)類(lèi)型的變量的取值范圍是0~65535。將ucos Ⅱ移植到32 位的處理器上也就意味著INT16U 實(shí)際被聲明為無(wú)符號(hào)短整形數(shù)據(jù)結(jié)構(gòu)而不是無(wú)符號(hào)整數(shù)數(shù)據(jù)結(jié)構(gòu)。但是,μC/OS-Ⅱ所處理的仍然是INT16U。用戶(hù)必須將任務(wù)堆棧的數(shù)據(jù)類(lèi)型告訴給μC/OS-Ⅱ。這個(gè)過(guò)程是通過(guò)為OS_STK 聲明正確的C 數(shù)據(jù)類(lèi)型來(lái)完成的。我們的處理器上的堆棧成員是16 位的,所以將OS_TSK 聲明為無(wú)符號(hào)整形數(shù)據(jù)類(lèi)型。所有的任務(wù)堆棧都必須用OS_TSK 聲明數(shù)據(jù)類(lèi)型。

      2)OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()

      與所有的實(shí)時(shí)內(nèi)核一樣,μC/OS-Ⅱ需要先禁止中斷再訪(fǎng)問(wèn)代碼的臨界區(qū),并且在訪(fǎng)問(wèn)完

      畢后重新允許中斷。這就使得μC/OS-Ⅱ能夠保護(hù)臨界區(qū)代碼免受多任務(wù)或中斷服務(wù)例程

     ?。↖SR)的破壞。在S3C44B0X 上是通過(guò)兩個(gè)函數(shù)(OS_CPU_A.S)實(shí)現(xiàn)開(kāi)關(guān)中斷的。

      INTS_OFF

      mrs r0, cpsr ; 當(dāng)前CSR

      mov r1, r0 ; 復(fù)制屏蔽

      orr r1, r1, #0xC0 ; 屏蔽中斷位

      msr CPSR, r1 ; 關(guān)中斷(IRQ and FIQ)

      and r0, r0, #0x80 ; 從初始CSR 返回FIQ 位

      mov pc,lr ; 返回

      INTS_ON

      mrs r0, cpsr ; 當(dāng)前CSR

      bic r0, r0, #0xC0 ; 屏蔽中斷

      msr CPSR, r0 ; 開(kāi)中斷(IRQ and FIQ)

      mov pc,lr ; 返回

      3)OS_STK_GROWTH

      絕大多數(shù)的微處理器和微控制器的堆棧是從上往下長(zhǎng)的。但是某些處理器是用另外一種方式工作的。μC/OS-Ⅱ被設(shè)計(jì)成兩種情況都可以處理,只要在結(jié)構(gòu)常量OS_STK_GROWTH中指定堆棧的生長(zhǎng)方式就可以了。

      置OS_STK_GROWTH 為0 表示堆棧從下往上長(zhǎng)。

      置OS_STK_GROWTH 為1 表示堆棧從上往下長(zhǎng)。

      用c語(yǔ)言編寫(xiě)6個(gè)與操作系統(tǒng)相關(guān)的函數(shù)(OS_CPU_C.C)

      1. OsTaskStKInit()

      OSTaskCreate()和OSTaskCreateExt()通過(guò)調(diào)用OSTaskStkInit()來(lái)初始化任務(wù)的堆

      棧結(jié)構(gòu)。因此,堆棧看起來(lái)就像剛發(fā)生過(guò)中斷并將所有的寄存器保存到堆棧中的情形一樣。

      圖12-2 顯示了OSTaskStkInt()放到正被建立的任務(wù)堆棧中的東西。這里我們定義了堆棧是

      從上往下長(zhǎng)的。

      在用戶(hù)建立任務(wù)的時(shí)候,用戶(hù)傳遞任務(wù)的地址,pdata 指針,任務(wù)的堆棧棧頂和任務(wù)的

      優(yōu)先級(jí)給OSTaskCreate()和OSTaskCreateExt()。一旦用戶(hù)初始化了堆棧,OSTaskStkInit

     ?。ǎ┚托枰祷囟褩V羔?biāo)傅牡刂贰STaskCreate()和OSTaskCreateExt()會(huì)獲得該地

      址并將它保存到任務(wù)控制塊(OS_TCB)中。

      OS_STK * OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)

      {

      unsigned int * stk;

      stk = (unsigned int *)ptos;

      opt++;

      *--stk = (unsigned int) task;

      *--stk = (unsigned int) task;

      *--stk = 12;

      *--stk = 11;

      *--stk = 10;

      *--stk = 9;

      *--stk = 8;

      *--stk = 7;

      *--stk = 6;

      *--stk = 5;

      *--stk = 4;

      *--stk = 3;

      *--stk = 2;

      *--stk = 1;

      *--stk = (unsigned int) pdata;

      *--stk = (SUPMODE);

      *--stk = (SUPMODE);

      return ((OS_STK *)stk);

      }

      2).OSTaskCreateHook

      當(dāng)用OSTaskCreate()和OSTaskCreateExt ()建立任務(wù)的時(shí)候就會(huì)調(diào)用OSTaskCreateHook

     ?。ǎ?。該函數(shù)允許用戶(hù)或使用移植實(shí)例的用戶(hù)擴(kuò)展μC/OS-Ⅱ功能。當(dāng)μC/OS-Ⅱ設(shè)置完了自己的內(nèi)部結(jié)構(gòu)后,會(huì)在調(diào)用任務(wù)調(diào)度程序之前調(diào)用OSTaskCreateHook()。該函數(shù)被調(diào)用的時(shí)候中斷是禁止的。因此用戶(hù)應(yīng)盡量減少該函數(shù)中的代碼以縮短中斷的響應(yīng)時(shí)間。當(dāng)OSTaskCreateHook()被調(diào)用的時(shí)候,它會(huì)收到指向已建立任務(wù)的OS_TCB 的指針,這樣它就可以訪(fǎng)問(wèn)所有的結(jié)構(gòu)成員了。

      函數(shù)原型:

      void OSTaskCreateHook (OS_TCB *ptcb)

      3).OsTaskDelHook()

      當(dāng)任務(wù)被刪除的時(shí)候就會(huì)調(diào)用OSTaskDelHook()。該函數(shù)在把任務(wù)從μC/OS-Ⅱ的內(nèi)部

      任務(wù)鏈表中解開(kāi)之前被調(diào)用。當(dāng)OSTaskDelHook()被調(diào)用的時(shí)候,它會(huì)收到指向正被刪除任務(wù)的OS_TCB 的指針,這樣它就可以訪(fǎng)問(wèn)所有的結(jié)構(gòu)成員了。OSTaskDelHook()可以來(lái)檢驗(yàn)TCB 擴(kuò)展是否被建立(一個(gè)非空指針)并進(jìn)行一些清除操作。

      函數(shù)原型:

      void OSTaskDelHook (OS_TCB *ptcb)

      4.OsTaskSwHook()

      當(dāng)發(fā)生任務(wù)切換的時(shí)候就會(huì)調(diào)用OSTaskSwHook()。OSTaskSwHook()可以直接訪(fǎng)問(wèn)

      OSTCBCur 和OSTCBHighRdy,因?yàn)樗鼈兪侨肿兞?。OSTCBCur 指向被切換出去的任務(wù)OS_TCB,而OSTCBHighRdy 指向新任務(wù)OS_TCB。注意在調(diào)用OSTaskSwHook()期間中斷一直是被禁止的。因此用戶(hù)應(yīng)盡量減少該函數(shù)中的代碼以縮短中斷的響應(yīng)時(shí)間。

      函數(shù)原型:

      void OSTaskSwHook (void)

      5.OsTaskStatHook()

      OSTaskStatHook()每秒鐘都會(huì)被OSTaskStat()調(diào)用一次。用戶(hù)可以用OSTaskStatHook

     ?。ǎ﹣?lái)擴(kuò)展統(tǒng)計(jì)功能。例如,用戶(hù)可以保持并顯示每個(gè)任務(wù)的執(zhí)行時(shí)間,每個(gè)任務(wù)所用的CPU 份額,以及每個(gè)任務(wù)執(zhí)行的頻率等。

      函數(shù)原型:

      void OSTaskStatHook (void)

      6.OsTimeTickHook()

      OSTimeTickHook()在每個(gè)時(shí)鐘節(jié)拍都會(huì)被OSTaskTick()調(diào)用。實(shí)際上,OSTimeTickHook

     ?。ǎ┦窃诠?jié)拍被μC/OS-Ⅱ真正處理,并通知用戶(hù)的移植實(shí)例或應(yīng)用程序之前被調(diào)用的。

     

      函數(shù)原型:

      void OSTimeTickHook (void)

      后5 個(gè)函數(shù)為鉤子函數(shù),可以不加代碼。只有當(dāng)OS_CFG.H 中的OS_CPU_HOOKS_EN

      被置為1 時(shí)才會(huì)產(chǎn)生這些函數(shù)的代碼。

      用匯編語(yǔ)言編寫(xiě)4個(gè)與處理器相關(guān)的函數(shù)(OS_CPU_a.asm)

     ?。?)OsStartHighRdy();運(yùn)行優(yōu)先級(jí)最高的就緒任務(wù)

      OSStartHighRdy

      LDR r4, addr_OSTCBCur ; 得到當(dāng)前任務(wù)TCB 地址

      LDR r5, addr_OSTCBHighRdy ; 得到最高優(yōu)先級(jí)任務(wù)TCB 地址

      LDR r5, [r5] ; 獲得堆棧指針

      LDR sp, [r5] ; 轉(zhuǎn)移到新的堆棧中

      STR r5, [r4] ; 設(shè)置新的當(dāng)前任務(wù)TCB 地址

      LDMFD sp!, {r4} ;

      MSR SPSR, r4

      LDMFD sp!, {r4} ; 從棧頂獲得新的狀態(tài)

      MSR CPSR, r4 ; CPSR 處于SVC32Mode 摸式

      LDMFD sp!, {r0-r12, lr, pc } ; 運(yùn)行新的任務(wù)

      (2)OS_TaSK_SW();任務(wù)級(jí)的任務(wù)切換函數(shù)

      OS_TASK_SW

      STMFD sp!, {lr} ; 保存pc

      STMFD sp!, {lr} ; 保存lr

      STMFD sp!, {r0-r12} ; 保存寄存器和返回地址

      MRS r4, CPSR

      STMFD sp!, {r4} ; 保存當(dāng)前的PSR

      MRS r4, SPSR

      STMFD sp!, {r4} ; 保存SPSR

      ; OSPrioCur = OSPrioHighRdy

      LDR r4, addr_OSPrioCur

      LDR r5, addr_OSPrioHighRdy

      LDRB r6, [r5]

      STRB r6, [r4]

      ; 得到當(dāng)前任務(wù)TCB 地址

      LDR r4, addr_OSTCBCur

      LDR r5, [r4]

      STR sp, [r5] ; 保存sp 在被占先的任務(wù)的TCB

      ; 得到最高優(yōu)先級(jí)任務(wù)TCB 地址

      LDR r6, addr_OSTCBHighRdy

      LDR r6, [r6]

      LDR sp, [r6] ; 得到新任務(wù)堆棧指針

      ; OSTCBCur = OSTCBHighRdy

      STR r6, [r4] ; 設(shè)置新的當(dāng)前任務(wù)的TCB 地址

      ;保存任務(wù)方式寄存器

      LDMFD sp!, {r4}

      MSR SPSR, r4

      LDMFD sp!, {r4}

      MSR CPSR, r4

      ; 返回到新任務(wù)的上下文

      LDMFD sp!, {r0-r12, lr, pc}

     ?。?)OSINTCTXSW();中斷級(jí)的任務(wù)切換函數(shù)

      OSIntCtxSw

      add r7, sp, #16 ; 保存寄存器指針

      LDR sp, =IRQStack ;FIQ_STACK

      mrs r1, SPSR ; 得到暫停的PSR

      orr r1, r1, #0xC0 ; 關(guān)閉IRQ, FIQ.

      msr CPSR_cxsf, r1 ; 轉(zhuǎn)換模式(應(yīng)該是SVC_MODE)

      ldr r0, [r7, #52] ; 從IRQ 堆棧中得到IRQ‘s LR (任務(wù)PC)

      sub r0, r0, #4 ; 當(dāng)前PC 地址是(saved_LR - 4)

      STMFD sp!, {r0} ; 保存任務(wù)PC

      STMFD sp!, {lr} ; 保存LR

      mov lr, r7 ; 保存FIQ 堆棧ptr in LR (轉(zhuǎn)到nuke r7)

      ldmfd lr!, {r0-r12} ; 從FIQ 堆棧中得到保存的寄存器

      STMFD sp!, {r0-r12} ;在任務(wù)堆棧中保存寄存器

      ;在任務(wù)堆棧上保存PSR 和任務(wù)PSR

      MRS r4, CPSR

      bic r4, r4, #0xC0 ; 使中斷位處于使能態(tài)

      STMFD sp!, {r4} ; 保存任務(wù)當(dāng)前PSR

      MRS r4, SPSR

      STMFD sp!, {r4} ; SPSR

      ; OSPrioCur = OSPrioHighRdy // 改變當(dāng)前程序

      LDR r4, addr_OSPrioCur

      LDR r5, addr_OSPrioHighRdy

      LDRB r6, [r5]

      STRB r6, [r4]

      ; 得到被占先的任務(wù)TCB

      LDR r4, addr_OSTCBCur

      LDR r5, [r4]

      STR sp, [r5] ; 保存sp 在被占先的任務(wù)的TCB

      ; 得到新任務(wù)TCB 地址

      LDR r6, addr_OSTCBHighRdy

      LDR r6, [r6]

      LDR sp, [r6] ; 得到新任務(wù)堆棧指針

      ; OSTCBCur = OSTCBHighRdy

      STR r6, [r4] ; 設(shè)置新的當(dāng)前任務(wù)的TCB 地址

      LDMFD sp!, {r4}

      MSR SPSR, r4

      LDMFD sp!, {r4}

      BIC r4, r4, #0xC0 ; 必須退出新任務(wù)通過(guò)允許中斷

      MSR CPSR, r4

      LDMFD sp!, {r0-r12, lr, pc}

      完成了上述工作以后,μC/OS-Ⅱ就可以正常運(yùn)行在ARM 處理器上了。

      我們的板子上已經(jīng)有移植成功的簡(jiǎn)單應(yīng)用,移植部分不須多大改動(dòng)就可以直接復(fù)制到您的應(yīng)用中去。

      文件系統(tǒng)的建立:

      文件系統(tǒng)相關(guān)的API函數(shù)功能解釋?zhuān)?/p>

      void initosfile();

      功能:初始化文件管理,為文件結(jié)構(gòu)分配空間,在系統(tǒng)初始化時(shí)調(diào)用

      FILE* OPENOSFILE(char filename[],u32 open mode);

      功能:以讀取方式或?qū)懭敕绞街付ù蜷_(kāi)的文件,并創(chuàng)建FILE結(jié)構(gòu),為文件讀取分配緩沖區(qū),返回當(dāng)前指向文件結(jié)構(gòu)的指針。

      參數(shù)說(shuō)明:

      filename 打開(kāi)的文件名

      openmode 打開(kāi)文件的方式:FILEMODE_READ 1

      FILEMODE_WRITE 2

      U32 Readosfile(FILE* pfile,u8* readbuffer,u32 nreadbyte);

      功能: 讀取已經(jīng)打開(kāi)的文件到制定的緩沖區(qū),成功則返回讀取的字節(jié)數(shù)

      參數(shù)說(shuō)明:

      pfile : 指向打開(kāi)文件的指針

      readbuffer :讀文件的目的緩沖區(qū)。

      Nreadbyte: 讀文件的字節(jié)數(shù)

      U32 linereadosfile(FILE* pfile,char str[]);

      功能:讀取之定文件的一行,返回讀取文件的字節(jié)數(shù)。

      參數(shù)說(shuō)明:

      Pfile: 指向打開(kāi)文件的指針

      Str: 讀取的字符竄數(shù)組

      U8 writeosfile(FILE* pfile,u8* writebuffer,u32 nreadbyte);

      功能:把緩沖區(qū)寫(xiě)入指定的文件,如果成功就返回true 否則false.

      參數(shù)說(shuō)明:

      pfile: 指向打開(kāi)文件的指針

      writebuffer :寫(xiě)入文件的目的緩沖區(qū)。

      Nreadbyte: 寫(xiě)入文件的字節(jié)數(shù)

      Void closeosfile()

      功能:關(guān)閉打開(kāi)的文件,釋放文件緩沖區(qū)

      參數(shù)說(shuō)明:

      pfile: 指向打開(kāi)文件的指針

      u8 getnextfilename(u32 *filepos,char filename[]);

      功能:得到文件目錄分配表中的指定位置的文件名(包括擴(kuò)展名),文件位置自動(dòng)下移。

      若文件有效則返回true ,否則flase

      filepos: 文件的位置,范圍從0~511;

      filename: 返回的文件名

      u8 listnextfilename(u32 *filepos,char fileexname[],char filename[]);

      功能:列出當(dāng)前位置開(kāi)始第一個(gè)制定擴(kuò)展名的文件,如果沒(méi)有,返回flase

      參數(shù)說(shuō)明:

      filepos: 文件的位置,范圍從0~511;

      fileexname:指定的文件擴(kuò)展名

      filename:返回的文件名

      外設(shè)計(jì)驅(qū)動(dòng)程序

      1) 串口接口函數(shù)

      void Uart_Init(int uartnum,int mclk,int baud);

      功能:初始化串口,設(shè)置通訊的波特率

      參數(shù)說(shuō)明:

      uartnum :所設(shè)定的串行口號(hào)

      mclk: 系統(tǒng)的主時(shí)鐘頻率,如果為0則為默認(rèn)值 60

      baud:所設(shè)定的串口通訊波特率

      void uart_printf(char *fmt,…)

      功能:輸出字符到串口0

      參數(shù)說(shuō)明:

      fmt:輸出到串口的字符串

      char uart_getch(char *revdatq,int uartnum,int timeout);

      功能:接收指定的串口的數(shù)據(jù),收到數(shù)據(jù)是返回true 否則flase

      參數(shù)說(shuō)明:

      revdatq: 輸入緩沖區(qū)

      uartnum:所設(shè)定得串口號(hào)

      timeout: 等待超時(shí)時(shí)間

      void uart_sendbyte(int uartnum,u8 data);

      功能:向指定串口發(fā)送數(shù)據(jù)

      參數(shù)說(shuō)明:

      uart_num : 所設(shè)定得串口號(hào)

      data: 發(fā)送的數(shù)據(jù)

      例子:

      當(dāng)操作系統(tǒng)啟動(dòng)時(shí),將自動(dòng)初始化各串行口,所以應(yīng)用程序調(diào)用串行口資源將變得非常

      容易。值的注意的是,應(yīng)用程序往往是多任務(wù)系統(tǒng),為了實(shí)時(shí)監(jiān)測(cè)串行口信息,在本操作環(huán)

      境中必須單開(kāi)一個(gè)串行口掃描任務(wù),保證信息不丟失。

     ?、?打開(kāi)一個(gè)已有的工程文件,在其中的主函數(shù)MAIN 中添加串行口的寄存器初始化

      代碼,并添加串行口和鍵盤(pán)掃描任務(wù),串行口掃描任務(wù)的代碼如下:

      void Uart_Scan_Task1(void *Id)

      {

      char c1;

      POSMSG pmsg1;

      for (;;){

      if(Uart_Getch(&c1,0,1))

      {

      pmsg1=OSCreateMessage(NULL,OSM_SERIAL,0,c1);

      if(pmsg1)

      SendMessage(pmsg1);

      }

      }

      }//Uart_Scan_Task

     

     ?。?)當(dāng)系統(tǒng)收到串行口信息時(shí),將會(huì)自動(dòng)向主任務(wù)發(fā)送一個(gè)串行口消息。主任務(wù)接收

      到該消息,將會(huì)調(diào)用響應(yīng)函數(shù),響應(yīng)該消息。添加消息響應(yīng)函數(shù)的代碼如下:

      void onSerial(int portn, char c)

      {

      Uart_SendByte(0,c);

      ⑶ 添加主任務(wù)

      void Main_Task(void *Id) //Main_Test_Task

      {

      POSMSG pMsg=0;

      ClearScreen();

      //消息循環(huán)

      for(;;){

      pMsg=WaitMessage(0); //等待消息

      switch(pMsg-{

      case OSM_SERIAL:

      onSerial(pMsg-break;

      }

      DeleteMessage(pMsg);//刪除消息,釋放資源

      }

      }

      2) 鍵盤(pán)掃描驅(qū)動(dòng)4*4

      u32 GetKey();

      功能:1 有效。此函數(shù)位死鎖函數(shù),調(diào)用以后,除非有鍵按下 否則不返回

      void setfunctionkey();

      功能:設(shè)定功能鍵掃描碼,1 有效。類(lèi)似計(jì)算機(jī)的ctrl/alt ,可以提供復(fù)合鍵

      u32 getnotaskkey();

      功能:1 有效。此函數(shù)位死鎖函數(shù),調(diào)用以后,除非有鍵按下 否則不返回, 與u32 GetKey()的區(qū)別詩(shī)詞函數(shù)不會(huì)釋放此任務(wù)的控制權(quán),除非有更高級(jí)的任務(wù)運(yùn)行

      例子

      1)在主函數(shù)中定義鍵盤(pán)映射表,定義鍵盤(pán)掃描函數(shù),定義鍵盤(pán)驅(qū)動(dòng)函數(shù)。

     ?。?)定義鍵盤(pán)響應(yīng)函數(shù),將得到的鍵值在液晶屏上顯示。

      void onKey(int nkey, int fnkey)//鍵盤(pán)響應(yīng)函數(shù)

      {

      char temp[3];//轉(zhuǎn)換成ASC-II 的鍵值數(shù)組

      if(nkey《9)

      {

      temp[0]=0x31;

      temp[1]=(nkey-10)|0x30;

      temp[2]=0;

      }

      else

      {

      temp[0]=nkey+0x30;

      temp[1]=0;

      }

      LCD_printf(temp);//在液晶平上顯示鍵值

      LCD_printf(“\n”);

      }

     ?。?)定義鍵盤(pán)掃描任務(wù)。

      OS_STK My_Key_Scan_Stack[STACKSIZE]={0, }; //定義鍵盤(pán)掃描任務(wù)的堆棧大小

      void My_Key_Scan_Task(void *Id); //定義鍵盤(pán)掃描任務(wù)

      #define MyKey_Scan_Task_Prio 58 //定義鍵盤(pán)掃描任務(wù)的優(yōu)先級(jí)

      OSTaskCreate(My_Key_Scan_Task,(void*)0,(OS_STK*)&My_Key_Scan_Stack[STACKSIZE-1],

      MyKey_Scan_Task_Prio );//在主函數(shù)中創(chuàng)建鍵盤(pán)掃描任務(wù)

      void My_Key_Scan_Task(void *Id)//鍵盤(pán)掃描任務(wù)

      {

      U32 key;

      u32 tempkey=0;

      POSMSG pmsg;//創(chuàng)建消息

      Uart_Printf(“begin key task \n”);

      for (;;)

      {

      key=MyGetKey();

      key&=0x000f;

      if(key《9)

      {

      Uart_SendByte(0,0x31);

      32

      tempkey=key-10;

      Uart_SendByte(0,tempkey|=0x0030);

      }

      else

      Uart_SendByte(0,key|0x0030);

      Uart_Printf(“,”);

      pmsg=OSCreateMessage(NULL, OSM_KEY,key,key);//創(chuàng)建鍵盤(pán)消息

      if(pmsg)

      SendMessage(pmsg);//發(fā)送鍵盤(pán)消息

      }

      }

     ?。?)定義主任務(wù)。

      OS_STK Main_Stack[STACKSIZE*8]={0, };//定義主任務(wù)的堆棧大小

      void Main_Task(void *Id); //定義主任務(wù)

      #define Main_Task_Prio 12 //定義主任務(wù)的優(yōu)先級(jí)

      OSTaskCreate(Main_Task,(void*)0,(OS_STK*)&Main_Stack[STACKSIZE*8-1],

      Main_Task_Prio);//在主函數(shù)重創(chuàng)建主任務(wù)

      void Main_Task(void *Id) //主任務(wù)

      {

      POSMSG pMsg=0;//創(chuàng)建消息

      LCD_ChangeMode(DspTxtMode);//將液晶屏設(shè)為文本顯示摸式

      LCD_Cls();//清屏

      for(;;)

      {

      pMsg=WaitMessage(0); //等待消息

      switch(pMsg-{

      case OSM_KEY:

      onKey(pMsg-break;

      Delay(200);

      }

      DeleteMessage(pMsg);//刪除消息,釋放資源

      } }

      注意:以上API接口函數(shù)只是原型 ;例子只作為參考

    (審核編輯: 智匯小新)