導航:首頁 > 源碼編譯 > tcb編譯

tcb編譯

發布時間:2023-03-29 04:31:48

A. 為什麼說操作系統ucos是實時的ucos是多任務的

白話一點解釋一下,希望納大能幫助你:
實時:指OS能夠滿足用戶根據需求所設計的切換時機和切換延時的要求。任意時刻,你希望你的系統里嫌茄模,哪一個事務最應該被優先處理?如果ucOS能滿足你的要求(通過你對任務的合理設計),那麼就可以說他是實時的OS。
使用ucOS構建系統時,你的所有用戶事務(需要做的事情)可以被劃分到多個任務里,ucOS可以根據你的實際設計,按優先順序調度他們(協調該先執行哪一個任務,並立即執行),芹緩這就可以說,ucOS是多任務了。

B. 介紹幾種主流嵌入式操作系統的特點,並分析比較 哥們,我現在糾結這個問題,可以給點指點嗎

如果你是學習階段的話,那linux和UCOS-II是比較合適的
uc/os和uclinux操作系統是兩種性能優良源碼公開且被廣泛應用的的免費嵌入式操作系統,可以作為研究實時操作系統和非實時操作系統的典範。本文通過對 uc/os和uclinux的對比,分析和總結了嵌入式操作系統應用中的若乾重要問題,歸納了嵌入式系統開發中操作系統的選型依據。
兩種開源嵌入式操作系統介紹
uc/os和uclinux操作系統,是當前得到廣泛應用的兩種免費且公開源碼的嵌入式操作系統。uc/os適合小型控制系統,具有執行效率高、佔用空間小、實時性能優良和可擴展性強等特點,最小內核可編譯至2k。uclinux則是繼承標准linux 的優良特性,針對嵌入式處理器的特點設計的一種操作系統,具有內嵌網路協議、支持多種文件系統,開發者可利用標准linux先驗知識等優勢。其編譯後目標文件可控制在幾百k量級。
uc/os是一種免費公開源代碼、結構小巧、具有可剝奪實時內核的實時操作系統。其內核提供任務調度與管理、時間管理、任務間同步與通信、內存管理和中斷服務等功能。
uclinux是一種優秀的嵌入式linux版本。uclinux是micro-conrol-linux的縮寫。同標准linux相比,它集成了標准linux操作系統的穩定性、強大網路功能和出色的文件系統等主要優點。但是由於沒有mmu(內存管理單元),其多任務的實現需要一定技巧。
兩種嵌入式操作系統主要性能比較
嵌入式操作系統是嵌入式系統軟硬體資源的控制中心,它以盡量合理的有效方法組織多個用戶共享嵌入式系統的各種資源。其中用戶指的是系統程序之上的所有軟體。所謂合理有效的方法,指的就是操作系統如何協調並充分利用硬體資源來實現多任務。復雜的操作系統都支持文件系統,方便組織文件並易於對其規范化操作。
嵌入式操作系統還有一個特點就是針對不同的平台,系統不是直接可用的,一般需要經過針對專門平台的移植操作系統才能正常工作。進程調度、文件系統支持和系統移植是在嵌入式操作系統實際應用中最常見的問題,下文就從這幾個角度入手對uc/os和uclinux進行分析比較。
進程調度
任務調度主要是協調任務對計算機系統內資源(如內存、i/o設備、cpu)的爭奪使用。進程調度又稱為cpu調度,其根本任務是按照某種原則為處於就緒狀態的進程分配cpu。由於嵌入式系統中內存和i/o設備一般都和cpu同時歸屬於某進程,所以任務調度和進程調度概念相近,很多場合不加區分,下文中提到的任務其實就是進程的概念。
進程調度可分為"剝奪型調度"和"非剝奪型調度"兩種基本方式。所謂"非剝奪型調度"是指:一旦某個進程被調度執行,則該進程一直執行下去直至該進程結束,或由於某種原因自行放棄cpu進入等待狀態,才將cpu重新分配給其他進程。所謂"剝奪型調度"是指:一旦就緒狀態中出現優先權更高的進程,或者運行的進程已用滿了規定的時間片時,便立即剝奪當前進程的運行(將其放回就緒狀態),把cpu分配給其他進程
作為實時操作系統,uc/os是採用的可剝奪型實時多任務內核。可剝奪型的實時內核在任何時候都運行就緒了的最高優先順序的任務。uc/os中最多可以支持64 個任務,分別對應優先順序0~63,
其中0為最高優先順序。調度工作的內容可以分為兩部分:最高優先順序任務的尋找和任務切換。
其最高優先順序任務的尋找是通過建立就緒任務表來實現的。uc/os中的每一個任務都有獨立的堆棧空間,並有一個稱為任務控制塊tcb(task control block)數據結構,其中第一個成員變數就是保存的任務堆棧指針。任務調度模塊首先用變數 ostcbhighrdy記錄當前最高級就緒任務的tcb地址,然後調用os_task_sw() 函數來進行任務切換。
uclinux的進程調度沿用了linux的傳統,系統每隔一定時間掛起進程,同時系統產生快速和周期性的時鍾計時中斷,並通過調度函數(定時器處理函數)決定進程什麼時候擁有它的時間片。然後進行相關進程切換,這是通過父進程調用fork 函數生成子進程來實現的。
uclinux系統fork調用完成後,要麼子進程代替父進程執行(此時父進程已經 sleep),直到子進程調用exit退出;要麼調用exec執行一個新的進程,這個時候產生可執行文件的載入,即使這個進程只是父進程的拷貝,這個過程也不可避免。當子進程執行exit或exec後,子進程使用wakeup把父進程喚醒,使父進程繼續往下執行。
uclinux由於沒有mmu管理存儲器,其對內存的訪問是直接的,所有程序中訪問的地址都是實際的物理地址。操作系統隊內存空間沒有保護,各個進程實際上共享一個運行空間。這就需要實現多進程時進行數據保護,也導致了用戶程序使用的空間可能佔用到系統內核空間,這些問題在編程時都需要多加註意,否則容易導致系統崩潰。
由上述分析可以得知,uc/os內核是針對實時系統的要求設計實現的,相對簡單,可以滿足較高的實時性要求。而uclinux則在結構上繼承了標准linux的多任務實現方式,僅針對嵌入式處理器特點進行改良。其要實現實時性效果則需要使系統在實時內核的控制下運行,rt-linux就是可以實現這一個功能的一種實時內核。
文件系統
所謂文件系統是指負責存取和管理文件信息的機構,也可以說是負責文件的建立、撤銷、組織、讀寫、修改、復制及對文件管理所需要的資源(如目錄表、存儲介質等)實施管理的軟體部分。
uc/os是面向中小型嵌入式系統的,如果包含全部功能(信號量、消息郵箱、消息隊列及相關函數),編譯後的uc/os內核僅有6~10kb,所以系統本身並沒有對文件系統的支持。但是uc/os具有良好的擴展性能,如果需要的話也可自行加入文件系統的內容。
uclinux則是繼承了linux完善的文件系統性能。其採用的是romfs文件系統,這種文件系統相對於一般的ext2文件系統要求更少的空間。空間的節約來自於兩個方面,首先內核支持romfs文件系統比支持ext2文件系統需要更少的代碼,其次romfs文件系統相對簡單,在建立文件系統超級塊(superblock)需要更少的存儲空間。romfs文件系統不支持動態擦寫保存,對於系統需要動態保存的數據採用虛擬ram盤的方法進行處理(ram盤將採用ext2文件系統)。
uclinux還繼承了linux網路操作系統的優勢,可以很方便的支持網路文件系統且內嵌tcp/ip協議,這為uclinux開發網路接入設備提供了便利。
由兩種操作系統對文件系統的支持可知,在復雜的需要較多文件處理的嵌入式系統中uclinux是一個不錯的選擇。而uc/os則主要適合一些控制系統。
操作系統的移植
嵌入式操作系統移植的目的是指使操作系統能在某個微處理器或微控制器上運行。uc/os和uclinux都是源碼公開的操作系統,且其結構化設計便於把與處理器相關的部分分離出來,所以被移植到新的處理器上是可能的。
以下對兩種系統的移植分別予以說明。
(1)uc/os的移植
要移植uc/os,目標處理器必須滿足以下要求;
·處理器的c編譯器能產生可重入代碼,且用c語言就可以打開和關閉中斷;
·處理器支持中斷,並能產生定時中斷;
·處理器支持足夠的ram(幾k位元組),作為多任務環境下的任務堆棧;
·處理器有將堆棧指針和其他cpu寄存器讀出和存儲到堆棧或內存中的指令。
在理解了處理器和c編譯器的技術細節後,uc/os的移植只需要修改與處理器相關的代碼就可以了。
具體有如下內容:
·os_cpu.h中需要設置一個常量來標識堆棧增長方向;
·os_cpu.h中需要聲明幾個用於開關中斷和任務切換的宏;
·os_cpu.h中需要針對具體處理器的字長重新定義一系列數據類型;
·os_cpu_a.asm需要改寫4個匯編語言的函數;
·os_cpu_c.c需要用c語言編寫6個簡單函數;
·修改主頭文件include.h,將上面的三個文件和其他自己的頭文件加入。
(2)uclinux的移植
由於uclinux其實是linux針對嵌入式系統的一種改良,其結構比較復雜,相對 uc/os,uclinux的移植也復雜得多。一般而言要移植uclinux,目標處理器除了應滿足上述uc/os應滿足的條件外,還需要具有足夠容量(幾百k位元組以上)外部rom和ram。
uclinux的移植大致可以分為3個層次:
·結構層次的移植,如果待移植處理器的結構不同於任何已經支持的處理器結構,則需要修改linux/arch目錄下相關處理器結構的文件。雖然uclinux內核代碼的大部分是獨立於處理器和其體系結構的,但是其最低級的代碼也是特定於各個系統的。這主要表現在它們的中斷處理上下文、內存映射的維護、任務上下文和初始化過程都是獨特的。這些例行程序位於linux/arch/目錄下。由於linux所支持體系結構的種類繁多,所以對一個新型的體系,其低級常式可以模仿與其相似的體系常式編寫。
·平台層次的移植,如果待移植處理器是某種uclinux已支持體系的分支處理器,則需要在相關體系結構目錄下建立相應目錄並編寫相應代碼。如mc68ez328就是基於無mmu的m68k內核的。此時的移植需要創建 linux/arch/m68knommu/platform/ mc68ez328目錄並在其下編寫跟蹤程序(實現用戶程序到內核函數的介面等功能)、中斷控制調度程序和向量初始化程序等。
·板級移植,如果你所用處理器已被uclinux支持的話,就只需要板級移植了。板級移植需要在linux/arch/?platform/中建立一個相應板的目錄,再在其中建立相應的啟動代碼crt0_rom.s或crt0_ram.s和鏈接描述文檔rom.ld或ram.ld就可以了。板級移植還包括驅動程序的編寫和環境變數設置等內容。
結語
通過對uc/os和uclinux的比較,可以看出這兩種操作系統在應用方面各有優劣。 uc/os佔用空間少,執行效率高,實時性能優良,且針對新處理器的移植相對簡單。uclinux則佔用空間相對較大,實時性能一般,針對新處理器的移植相對復雜。但是,uclinux具有對多種文件系統的支持能力、內嵌了tcp/ip協議,可以借鑒linux豐富的資源,對一些復雜的應用,uclinux具有相當優勢。例如cisco 公司的 2500/3000/4000 路由器就是基於uclinux操作系統開發的。總之,操作系統的選擇是由嵌入式系統的需求決定的。簡單的說就是,小型控制系統可充分利用uc/os小巧且實時性強的優勢,如果開發pda和互聯網連接終端等較為復雜的系統則uclinux是不錯的選擇。

還有就是如果從開發的工具方便好用,易用的角度來看,那些收費的系統用起來更爽一些

C. 嵌入式高手進 考試題解答

推薦一:OS_CPU.H
1、定義與編譯器無光的數據類型
只是按照不同的編譯器編寫對應的數據類型的typedef 對應於ARM7的數據類型的編寫如下

typedef unsigned char BOOLEAN;/* 布爾變數*/
typedef unsigned char INT8U; /* 無符號8位整型變數*/
typedef signed char INT8S; /* 有符號8位整型變數*/
typedef unsigned short INT16U; /* 無符號16位整型變數*/
typedef signed short INT16S; /褲返舉* 有符號16位整型變數*/
typedef unsigned int INT32U; /* 無符號32位整型變數*/
typedef signed int INT32S; /* 有符號32位整型變數*/
typedef float FP32; /*單精度浮點數(32Bit)*/
typedef double FP64; /*雙精度浮點數(64Bit)*/
/*在上面定義的數據類型中按照ARM7的堆棧寬度選擇INT32U*/
typedef INT32U OS_STK; /* 堆棧是32位寬度*/

接下來一部分是為了兼容低版本UCOS的數據類型所編寫的代碼,在UCOS-II中暫不考慮
2 與處理器相關的代碼
先定義中斷的實現方式,預先設定的中斷方式有三種,在ARM7中設置為方式 2

#define OS_CRITICAL_METHOD 2/*選擇開,關中斷的方式 */

接下來的一段是我暫時還沒有完全搞懂的一部分,只知道是設定了12個軟體中斷的函數,當調用這
些函數之前都會執行對應中斷號的事情。具體的看到後面應該能完全搞懂軟體中斷的實現方式,
該段代碼在後面的文件中會有具體的解釋,這里暫時不看
定義堆世塌棧的生長方式,ARM7內核支持兩種生長方式,但是ADS的C語言編譯器只支持從上往下的生
長方式,因此:
#define OS_STK_GROWTH 1 /* 堆棧是從上往下長的,0-從下往上的生長方式 */
最後幾行分別定義了用戶模式01和系統模式1f以及IRQ中斷禁止的指令80三個立即數,方便調用.
還有兩個預定義往胡碧後看應該知道作用,暫不考慮,不是很重要.

軟中斷:
中斷不返回形式:
void _swi(swi_num) swi_name(arguments);
返回一個結果到R0中
int _swi(swi_num) swi_name(arguments);
最多可以返回四個結果R0-R3到一個結構struct type{ int a,b,c,d}中
type(返回類型) _value_in_regs(返回多個結果的修飾符) _swi(swi_num) swi_name(arguments);
在ARM中實現軟中斷的方法我在blog裡面搜了很多文章也沒有看到講的通俗一點的,還是自己看
ARM的移植代碼吧首先定義了一堆軟中斷的中斷號,其中0和1的中斷服務子程序是用匯編編寫的,
其他的都是在c語言編寫的中斷服務子程序SWI_Exception中。

__swi(0x00) void OS_TASK_SW(void);
/* 任務級任務切換函數 */
__swi(0x01) void _OSStartHighRdy(void);
/* 運行優先順序最高的任務 */
__swi(0x02) void OS_ENTER_CRITICAL(void);
/* 關中斷 */
__swi(0x03) void OS_EXIT_CRITICAL(void);
/* 開中斷 */
__swi(0x40) void *GetOSAddr(int Index);
/* 獲取系統服務函數入口 */
__swi(0x41) void *GetUsrAddr(int Index);
/* 獲取自定義服務函數入口 */
__swi(0x42) void OSISRBegin(void);
/* 中斷開始處理 */
__swi(0x43) int OSISRNeedSwap(void);
/* 判斷中斷是否需要切換 */
__swi(0x80) void ChangeToSYSMode(void);
/* 任務切換到系統模式 */
__swi(0x81) void ChangeToUSRMode(void);
/* 任務切換到用戶模式 */
__swi(0x82) void TaskIsARM(INT8U prio);
/* 任務代碼是ARM代碼 */
__swi(0x83) void TaskIsTHUMB(INT8U prio);
/* 任務代碼是THUMB */

比如在程序運行到調用OS_TASK_SW(void)函數時,就產生軟體中斷,然後就進入中斷服務子程序,
按照什麼指令走呢?恩,就按照下面這個代碼,這個代碼是將軟體中斷異常處理程序掛接到內核
的作用的,是在啟動代碼中實現的:

LDR PC,SWI_Addr
SWI_Addr DCD SoftwareInterrupt

因此當產生軟中斷之後PC就跳到了SoftwareInterrupt,這時就算真正進入了軟體異常中斷處理部
分了,然後就是執行下面的匯編代碼SoftwareInterrupt

LDR SP, StackSvc
/*重新設置堆棧指針*/
STMFD SP!, {R0-R3, R12, LR}
/*保存 R0,R1,R2,R3,R12,LR(R14),注意為什麼只保存這幾個
寄存器呢,因為R4-R11存儲局部變數,編譯器自動保護他們*/
MOV R1, SP /* R1指向參數存儲位置 */
MRS R3, SPSR /*保存管理模式的狀態寄存器*/
TST R3, #T_bit /* 中斷前是否是Thumb狀態 */
LDRNEH R0, [LR,#-2] /* 若是,取得Thumb狀態SWI號*/
BICNE R0, R0, #0xff00 /*THUMB指令SWI功能號為8位 */
LDREQ R0, [LR,#-4] /* 為零即ARM指令取得SWI號 */
BICEQ R0, R0, #0xFF000000
/*在ARM指令集中SWI功能號為24位所以高8位清零r0=SWI號*/
CMP R0, #1 /*
LDRLO PC, =OSIntCtxSw /* 疑惑ing */
/* 功能號為0到OSIntCtxSw執行中斷任務切換函數 */
LDREQ PC, =__OSStartHighRdy/*SWI為1第一次任務切換*/
BL SWI_Exception /*否則進入c編寫的中斷函數 */
LDMFD SP!, {R0-R3, R12, PC}/*R0-R3,R12,LR出棧 */
StackSvc
DCD (SvcStackSpace + SVC_STACK_LEGTH * 4 - 4)

怎麼進入c編寫的中斷服務子程序SWI_Exception呢?通過下面的申明

IMPORT SWI_Exception ;軟中斷異常處理程序
表示將c程序中的該函數掛接到此段匯編代碼中,同樣的道理
EXPORT __OSStartHighRdy
EXPORT OSIntCtxSw ;中斷退出時的入口
參見startup.s中的IRQ_Handler
EXPORT SoftwareInterrupt ;軟中斷入口上面的申明是將該段匯編代碼掛接到外面,
因此在外部可以直接調用函數名
繼續看OS_CPU_A.S的其他部分代碼,就是兩個軟體異常中斷處理函數OSIntCtxSw和OSStarHighRdyOSIntCtxSw代碼是中斷服務子程序使得更高優先順序的任務進入就緒狀態後,中斷返回後需要切換到該任務時調用的,這是被切換的任務的CPU寄存器的值已經在響應中斷後存入了堆棧中,因此,這里不需要重復保存了直接切換任務即可,具體過程看代碼OSIntCtxSw
;下面為保存任務環境 ;當響應軟體異常中斷後進入了系統模式,在上面的代碼中我們可以看到,進入系統模式時保存的堆棧結構從頂到底依次是:R0,R1,R2,R3,R12,LR,而在用戶模式中任務的堆棧結構應該是:OsEnterSum,CPSR,RO-12,LR,PC,所以在進行軟體中斷任務切換之前先要保存原來任務的堆棧結構。
LDR R2, [SP, #20] ;獲取PC
LDR R12, [SP, #16] ;獲取R12
MRS R0, CPSR MSR CPSR_c, #(NoInt | SYS32Mode)
MOV R1, LR
STMFD SP!, {R1-R2} ;保存LR,PC
STMFD SP!, {R4-R12} ;保存R4-R12 MSR CPSR_c, R0
LDMFD SP!, {R4-R7} ;獲取R0-R3
ADD SP, SP, #8 ;出棧R12,PC
MSR CPSR_c, #(NoInt | SYS32Mode)
STMFD SP!, {R4-R7} ;保存R0-R3
LDR R1, =OsEnterSum ;獲取OsEnterSum
LDR R2, [R1]
STMFD SP!, {R2, R3} ;保存CPSR,OsEnterSum ;保存當前任務堆棧指針到當前任務的TCB
LDR R1, =OSTCBCur
LDR R1, [R1]
STR SP, [R1] BL OSTaskSwHook ;調用鉤子函數
;OSPrioCur <= OSPrioHighRdy
LDR R4, =OSPrioCur
LDR R5, =OSPrioHighRdy
LDRB R6, [R5]
STRB R6, [R4]
;OSTCBCur <= OSTCBHighRdy
LDR R6, =OSTCBHighRdy
LDR R6, [R6]
LDR R4, =OSTCBCur
STR R6, [R4]
OSIntCtxSw_1
;獲取新任務堆棧指針
LDR R4, [R6]
ADD SP, R4, #68 ;17寄存器CPSR,OsEnterSum,R0-R12,LR,SP
LDR LR, [SP, #-8]
MSR CPSR_c, #(NoInt | SVC32Mode) ;進入管理模式
MOV SP, R4 ;設置堆棧指針 LDMFD SP!, {R4, R5} ;CPSR,OsEnterSum
;恢復新任務的OsEnterSum
LDR R3, =OsEnterSum
STR R4, [R3]
MSR SPSR_cxsf, R5 ;恢復CPSR
LDMFD SP!, {R0-R12, LR, PC }^ ;運行新任務

__OSStartHighRdy
MSR CPSR_c, #(NoInt | SYS32Mode) ;調整到管理模式
;告訴uC/OS-II自身已經運行
LDR R4, =OSRunning
MOV R5, #1
STRB R5, [R4] ;標記多任務運行標記為真 BL OSTaskSwHook ;調用鉤子函數,可以運行用戶自定義的函數 LDR R6, =OSTCBHighRdy ;R6存有最高優先順序的就緒任務的控制塊地址
LDR R6, [R6]
B OSIntCtxSw_1 ;轉到前面編寫的中斷返回函數塊的任務跳轉部分的代碼,因為這兩個函數都要用到這部分代碼,進入這段代碼之前高優先順序的就緒任務的任務控制快地址存在R6中。 AREA SWIStacks, DATA, NOINIT,ALIGN=2
SvcStackSpace SPACE SVC_STACK_LEGTH * 4 ;管理模式堆棧空間 OSIntCtxSw_1的代碼:OSIntCtxSw_1
;獲取新任務堆棧指針
LDR R4, [R6] ;任務控制塊的堆棧指針放在R6中,現在放在R4中
ADD SP, R4, #68 ;17寄存器CPSR,OsEnterSum,R0-R12,LR,SP
LDR LR, [SP, #-8]
MSR CPSR_c, #(NoInt | SVC32Mode) ;進入管理模式
MOV SP, R4 ;設置堆棧指針,R4存有沒有改動過的堆棧指針 LDMFD SP!, {R4, R5} ;CPSR,OsEnterSum
;恢復新任務的OsEnterSum
LDR R3, =OsEnterSum
STR R4, [R3]
MSR SPSR_cxsf, R5 ;恢復CPSR
LDMFD SP!, {R0-R12, LR, PC }^ ;運行新任務,恢復現場,異常處理返回;中斷返回指令的寄存器列表其中必須包括PC後的^符號,表示這是一條特殊形式的指令。這條指令在從存儲器中裝載PC的同時,CPSR也得到恢復。這里使用的堆棧指針SP是屬於異常模式的寄存器,每個異常模式有自己的堆棧指針。SoftwareInterrupt
LDR SP, StackSvc ; 重新設置堆棧指針
STMFD SP!, {R0-R3, R12, LR} ;保存寄存器
MOV R1, SP ; R1指向參數存儲位置 MRS R3, SPSR
TST R3, #T_bit ; 中斷前是否是Thumb狀態
LDRNEH R0, [LR,#-2] ; 是: 取得Thumb狀態SWI號
BICNE R0, R0, #0xff00
LDREQ R0, [LR,#-4] ; 否: 取得arm狀態SWI號
BICEQ R0, R0, #0xFF000000
; r0 = SWI號,R1指向參數存儲位置
CMP R0, #1
LDRLO PC, =OSIntCtxSw
LDREQ PC, =__OSStartHighRdy ; SWI 0x01為第一次任務切換 BL SWI_Exception
LDMFD SP!, {R0-R3, R12, PC}^
StackSvc DCD (SvcStackSpace + SVC_STACK_LEGTH * 4 - 4)OSIntCtxSw
;下面為保存任務環境
LDR R2, [SP, #20] ;獲取PC(LR)
LDR R12, [SP, #16] ;獲取R12
MRS R0, CPSR MSR CPSR_c, #(NoInt | SYS32Mode)
MOV R1, LR
STMFD SP!, {R1-R2} ;保存LR,PC
STMFD SP!, {R4-R12} ;保存R4-R12 MSR CPSR_c, R0
LDMFD SP!, {R4-R7} ;獲取R0-R3
ADD SP, SP, #8 ;出棧R12,PC
MSR CPSR_c, #(NoInt | SYS32Mode)
STMFD SP!, {R4-R7} ;保存R0-R3
LDR R1, =OsEnterSum ;獲取OsEnterSum
LDR R2, [R1]
STMFD SP!, {R2, R3} ;保存CPSR,OsEnterSum ;保存當前任務堆棧指針到當前任務的TCB
LDR R1, =OSTCBCur
LDR R1, [R1]
STR SP, [R1] BL OSTaskSwHook ;調用鉤子函數
;OSPrioCur <= OSPrioHighRdy
LDR R4, =OSPrioCur
LDR R5, =OSPrioHighRdy
LDRB R6, [R5]
STRB R6, [R4] ;把OSPrioHighRdy最高優先順序的就緒任務傳給OSPrioCur
;OSTCBCur <= OSTCBHighRdy
LDR R6, =OSTCBHighRdy
LDR R6, [R6]
LDR R4, =OSTCBCur
STR R6, [R4] ;將最高優先順序的任務控制塊指針傳給當前任務控制塊指針

關於中斷和時鍾節拍,UCOS-II對於ARM7通用的中斷服務程序的匯編與c函數介面如下:MACRO和MEND偽指令用於宏定義,MACRO標識宏定義的開始,MEND標識宏定義的結束。定義之後在程序中就可以通過宏指令多次調用該段代碼MACRO
$IRQ_Label HANDLER $IRQ_Exception_ EXPORT $IRQ_Label ; 輸出的標號
IMPORT $IRQ_Exception_ ; 引用的外部標號$IRQ_Label
SUB LR, LR, #4 ; 計算返回地址
STMFD SP!, {R0-R3, R12, LR} ; 保存任務環境
MRS R3, SPSR ; 保存狀態
STMFD SP, {R3, SP, LR}^ ; 保存用戶狀態的R3,SP,LR,注意不能回寫
; 如果回寫的是用戶的SP,所以後面要調整SP
LDR R2, =OSIntNesting ; OSIntNesting++
LDRB R1, [R2]
ADD R1, R1, #1
STRB R1, [R2] SUB SP, SP, #4*3
MSR CPSR_c, #(NoInt | SYS32Mode) ; 切換到系統模式
CMP R1, #1
LDREQ SP, =StackUsr
BL $IRQ_Exception_ ; 調用c語言的中斷處理程序 MSR CPSR_c, #(NoInt | SYS32Mode) ; 切換到系統模式
LDR R2, =OsEnterSum ; OsEnterSum,使OSIntExit退出時中斷關閉
MOV R1, #1
STR R1, [R2] BL OSIntExit LDR R2, =OsEnterSum ; 因為中斷服務程序要退出,所以OsEnterSum=0
MOV R1, #0
STR R1, [R2] MSR CPSR_c, #(NoInt | IRQ32Mode) ; 切換回irq模式
LDMFD SP, {R3, SP, LR}^ ; 恢復用戶狀態的R3,SP,LR,注意不能回寫
; 如果回寫的是用戶的SP,所以後面要調整SP
LDR R0, =OSTCBHighRdy
LDR R0, [R0]
LDR R1, =OSTCBCur
LDR R1, [R1]
CMP R0, R1 ADD SP, SP, #4*3 ;
MSR SPSR_cxsf, R3
LDMEQFD SP!, {R0-R3, R12, PC}^ ; 不進行任務切換
LDR PC, =OSIntCtxSw ; 進行任務切換
MEND二:OS_CPU_C.C 個文件中要求用戶編寫10個簡單的C函數,但是只有1個函數是必要的,其餘的函數必須聲明,但不一定要包含任何代碼,大致看了一下作用好像是用來調試之類的。唯一要編寫的是OSTaskStkInit() OSTaskStkInit()函數的功能是初始化任務的棧結構,任務的堆棧結構與CPU的體系結構、編譯器有密切的關聯。從ARM的結構可以寫出如下的棧結構:程序計數器PC,程序鏈接器LR,R12-R1,R0用於傳遞第一個參數pdata,CPSR/SPSR,關中斷計數器(用於計算關中斷的次數,這樣就實現了中斷的嵌套),返回的地址指針是指向的最後一個存入的數據,而不是一個空地址。軟體中斷異常SWI服務程序C語言部分 void SWI_Exception(int SWI_Num, int *Regs):參數SWI_Num對應前面文件中定義的功能號,其中0、1號的功能在後面的文件中定義,這里只定義了其他10個功能。 2、3分別對應關中斷和開中斷 關中斷:MRS R0, SPSR //在軟體中斷的時候直接對程序狀態保存寄存器SPSR操作也就是對CPSR的操作
ORR R0, R0, #NoInt //在匯編語言中對寄存器的對應位置位用ORR,清零用BIC
MSR SPSR_c, R0 //SPSR_c表示的是只改變SPSR的控制段的8位代碼,其他三段_f,_s,_x中標志位在_f段,其他為保留位 開中斷:MRS R0, SPSR //在開中斷中基本與上面相同,只是ORR改成BIC清零
BIC R0, R0, #NoInt
MSR SPSR_c, R 由於需要實現中斷嵌套,所以只有當關中斷的計數器減為0的時候才能夠開中斷,而且每次關中斷的時候該計數器都應該加1。另外,插入匯編語言時用_asm指令。 80、81、82、83分別對應系統模式、用戶模式、ARM指令集、THUMB指令集 系統模式:MRS R0, SPSR
BIC R0, R0, #0x1f //先將控制模式的低5位清零
ORR R0, R0, #SYS32Mode //設置成系統模式的1F
MSR SPSR_c, R0 用戶模式:MRS R0, SPSR
BIC R0, R0, #0x1f
ORR R0, R0, #USR32Mode //設置成用戶模式的10
MSR SPSR_c, R0 ARM指令集與THUMB指令集的代碼如下: ptcb = OSTCBPrioTbl[Regs[0]];
if (ptcb != NULL)
{
ptcb -> OSTCBStkPtr[1] &= ~(1 << 5);
} ptcb = OSTCBPrioTbl[Regs[0]];
if (ptcb != NULL)
{
ptcb -> OSTCBStkPtr[1] |= (1 << 5);
} 昨天就是看到這里,出現了一個意識到是不能忽悠的地方就是UCOS裡面的任務控制塊OS_TCB的概念,因此今天的任務就是把這部分看看。。。 大概回憶了一下昨天晚上的工作,開始今天的工作吧

一點一點來,什麼不會就學什麼,都不會就都學。。。沒有問題只要你肯努力。。。。。。__OSStartHighRdy
MSR CPSR_c, #(NoInt | SYS32Mode) ;MSR:在ARM中只有MSR能夠直接設置狀態寄存器CPSR或SPSR,可以是立即數或者源寄存器,NoInt是禁止中斷,SYS32Mode是系統模式
;告訴uC/OS-II自身已經運行
LDR R4, =OSRunning ;OSRunning正在運行多任務的標志,=OSRunning是把OSRunning的地址載入到R4,R4里存的是一個地址。。。
MOV R5, #1
STRB R5, [R4] ;將R5存儲到R4存的地址的變數即OSRunning中,也就是將OSRunning置1 BL OSTaskSwHook ;調用鉤子函數,OSTaskSwHook 是用於擴展的,在任務切換的時候執行用戶自己定義的功能。 LDR R6, =OSTCBHighRdy ;OSTCBHighRdy指向最高優先順序任務的控制塊TCB的指針!!!將放指針的地址放到R6中。
LDR R6, [R6] ;將R6地址處的數據讀出即OSTCBHighRdy的地址放到R6中
B OSIntCtxSw_1 ;跳轉到OSIntCtxSw_1 AREA SWIStacks, DATA, NOINIT,ALIGN=2
SvcStackSpace SPACE SVC_STACK_LEGTH * 4 ;管理模式堆棧空間繼續昨天沒有看完的代碼OSIntCtxSw
;下面為保存任務環境
LDR R2, [SP, #20] ;獲取PC,放入R2
LDR R12, [SP, #16] ;獲取R12,//R12存的什麼東西啊???
MRS R0, CPSR MSR CPSR_c, #(NoInt | SYS32Mode) ;進入系統模式並禁止中斷
MOV R1, LR ;R1放LR值
STMFD SP!, {R1-R2} ;保存LR,PC,將R1,R2存入SP
STMFD SP!, {R4-R12} ;保存R4-R12,將R4-12存入SP MSR CPSR_c, R0 ;再回到之前的模式
LDMFD SP!, {R4-R7} ;獲取R0-R3
ADD SP, SP, #8 ;出棧R12,PC
MSR CPSR_c, #(NoInt | SYS32Mode)
STMFD SP!, {R4-R7} ;保存R0-R3
LDR R1, =OsEnterSum ;獲取OsEnterSum
LDR R2, [R1]
STMFD SP!, {R2, R3} ;保存CPSR,OsEnterSum ;保存當前任務堆棧指針到當前任務的TCB
LDR R1, =OSTCBCur
LDR R1, [R1]
STR SP, [R1] BL OSTaskSwHook ;調用鉤子函數
;OSPrioCur <= OSPrioHighRdy
LDR R4, =OSPrioCur
LDR R5, =OSPrioHighRdy
LDRB R6, [R5]
STRB R6, [R4]
;OSTCBCur <= OSTCBHighRdy
LDR R6, =OSTCBHighRdy
LDR R6, [R6]
LDR R4, =OSTCBCur
STR R6, [R4]
OSIntCtxSw_1
;獲取新任務堆棧指針
LDR R4, [R6] ;把OSTCBHighRdy指向最高優先順序任務的控制塊TCB的指針給R4
ADD SP, R4, #68 ;17寄存器:CPSR,OsEnterSum,R0-R12,LR,SP
LDR LR, [SP, #-8] ;取出LR放到LR
MSR CPSR_c, #(NoInt | SVC32Mode) ;進入管理模式並且保持禁止中斷
MOV SP, R4 ;設置堆棧指針 LDMFD SP!, {R4, R5} ;CPSR,OsEnterSum。LDMFD數據出棧,放入R4,R5
;恢復新任務的OsEnterSum
LDR R3, =OsEnterSum ;OsEnterSum的地址存入R3
STR R4, [R3] ;把R4的值賦給OsEnterSum
MSR SPSR_cxsf, R5 ;恢復CPSR;在管理模式里是修改SPSR
LDMFD SP!, {R0-R12, LR, PC }^ ;運行新任務 ,恢復現場,異常處理返回

D. ucosii的用戶程序必須和操作系統一起編譯嗎

是否μC/OS-II,是就看下面的內容,如果不是你想要的答案,本人也無能為力

外行人粗略理解:從這篇文章可以看出μC/OS-II內核和應用程序放在一起編譯成一個文件這種做法是特有的,應該也不能分開。

單片機軟體操作系統的利弊,UCOSII在單片機上的使用

來源:今日電子

摘要:近年來,在單片機系統中嵌入操作系統已經成為人們越來越關心的一個話題。本文通過對一種源碼公開的嵌入式實時操作系統μC/OS-II的分析,以51系列單片機為例,闡述了在單片機中使用該嵌入式操作系統的優缺點,以及在應用中應當注意的一些問題。

關鍵詞:實時操作系統;μC/OS-II;單片機

引言

早在20世紀60年代,就已經有人開始研究和開發嵌入式殲虛操作系統。但直到最近,它才在國內被越來越多的提及,在通信、電子、自動化等需要實時處理的領域所日益顯現的重要性吸引了人們越來越多的注意力。但是,人們所談論的往往是一些著名的商業內核,諸如VxWorks、PSOS等。這些商業內核性能優越,但價格昂貴,主要用於16位和32位處理器中,針對國內大部分用戶使用的51系列8位單片機,可以選擇免費的μC/OS-II。

μC/OS-II的特點

1.μC/OS-II是由Labrosse先生編寫的一個開放式內核,最主要的特點就是源碼公開。這一點對於用戶來說可謂利弊各半,好處在於,一方面它是免費的,另一方面用戶可以根據自己的需要對它進行修改。缺點在於它缺乏必要的支持,沒有功能強大的軟體包,用戶通常需要自己編寫驅動程序,特別是如果用戶使用的是不太常用的單片機,還必須自己編寫移植程序。

2.μC/OS-II是一個佔先式的內核,即已敬改猛經准備就緒的高優先順序任務可以剝奪正在運行的低優先順序任務的CPU使用權。這個特點使得它的實時性比非佔先式的內核要好。通常我們都是在中斷服務程序中使高優先順序任務進入就緒態(例如發信號),這樣退出中斷服務程序後,將進行任務切換,高優先順序任務將被執行。拿51單片機為例,比較一下就可以發現這樣做的好處。假如需要用中斷方式採集一批數據並進行處理,在傳統的編程方法中不能在中斷服務程序中進行復雜的數據處理,因為這會使得關中斷時間過長。所以經常採用的方法是置一標志位,然後退出中斷。由於主程序是循環執行的,所以它總有機會檢測到這一標志並轉到數據處理程序中去。但是因為無法確定發生中斷時程序到底執行到了什麼地方,也就無法判斷要經過多長時間數據處理程序才會執行,中斷響應時間無法確定,系統的實時性不強。如果使用μC/OS-II的話,只要把數據處理程序的優先順序設定得高一些,並在中斷服務程序中使它進入就緒態,中斷結束後數據處理程序就會被立即執行。這樣可以把中斷響亮橋應時間限制在一定的范圍內。對於一些對中斷響應時間有嚴格要求的系統,這是必不可少的。但應該指出的是如果數據處理程序簡單,這樣做就未必合適。因為μC/OS-II要求在中斷服務程序末尾使用OSINTEXIT函數以判斷是否進行任務切換,這需要花費一定的時間。

3.μC/OS-II和大家所熟知的Linux等分時操作系統不同,它不支持時間片輪轉法。μC/OS-II是一個基於優先順序的實時操作系統,每個任務的優先順序必須不同,分析它的源碼會發現,μC/OS-II把任務的優先順序當做任務的標識來使用,如果優先順序相同,任務將無法區分。進入就緒態的優先順序最高的任務首先得到CPU的使用權,只有等它交出CPU的使用權後,其他任務才可以被執行。所以它只能說是多任務,不能說是多進程,至少不是我們所熟悉的那種多進程。顯而易見,如果只考慮實時性,它當然比分時系統好,它可以保證重要任務總是優先佔有CPU。但是在系統中,重要任務畢竟是有限的,這就使得劃分其他任務的優先權變成了一個讓人費神的問題。另外,有些任務交替執行反而對用戶更有利。例如,用單片機控制兩小塊顯示屏時,無論是編程者還是使用者肯定希望它們同時工作,而不是顯示完一塊顯示屏的信息以後再顯示另一塊顯示屏的信息。這時候,要是μC/OS-II即支持優先順序法又支持時間片輪轉法就更合適了。

4.μC/OS-II對共享資源提供了保護機制。正如上文所提到的,μC/OS-II是一個支持多任務的操作系統。一個完整的程序可以劃分成幾個任務,不同的任務執行不同的功能。這樣,一個任務就相當於模塊化設計中的一個子模塊。在任務中添加代碼時,只要不是共享資源就不必擔心互相之間有影響。而對於共享資源(比如串口),μC/OS-II也提供了很好的解決辦法。一般情況下使用的是信號量的方法。簡單地說,先創建一個信號量並對它進行初始化。當一個任務需要使用一個共享資源時,它必須先申請得到這個信號量,而一旦得到了此信號量,那就只有等使用完了該資源,信號量才會被釋放。在這個過程中即使有優先權更高的任務進入了就緒態,因為無法得到此信號量,也不能使用該資源。這個特點的好處顯而易見,例如當顯示屏正在顯示信息的時候,外部產生了一個中斷,而在中斷服務程序中需要顯示屏顯示其他信息。這樣,退出中斷服務程序後,原有的信息就可能被破壞了。而在μC/OS-II中採用信號量的方法時,只有顯示屏把原有信息顯示完畢後才可以顯示新信息,從而可以避免這個現象。不過,採用這種方法是以犧牲系統的實時性為代價的。如果顯示原有信息需要耗費大量時間,系統只好等待。從結果上看,等於延長了中斷響應時間,這對於未顯示信息是報警信息的情況,無疑是致命的。發生這種情況,在μC/OS-II中稱為優先順序反轉,就是高優先順序任務必須等待低優先順序任務的完成。在上述情況下,在兩個任務之間發生優先順序反轉是無法避免的。所以在使用μC/OS-II時,必須對所開發的系統了解清楚,才能決定對於某種共享資源是否使用信號量。

μC/OS-II在單片機使用中的一些特點

1.在單片機系統中嵌入μC/OS-II將增強系統的可靠性,並使得調試程序變得簡單。以往傳統的單片機開發工作中經常遇到程序跑飛或是陷入死循環。可以用看門狗解決程序跑飛問題,而對於後一種情況,尤其是其中牽扯到復雜數學計算的話,只有設置斷點,耗費大量時間來慢慢分析。如果在系統中嵌入μC/OS-II的話,事情就簡單多了。可以把整個程序分成許多任務,每個任務相對獨立,然後在每個任務中設置超時函數,時間用完以後,任務必須交出CPU的使用權。即使一個任務發生問題,也不會影響其他任務的運行。這樣既提高了系統的可靠性,同時也使得調試程序變得容易。

2.在單片機系統中嵌入μC/OS-II將增加系統的開銷。現在所使用的51單片機,一般是指87C51或者89C51,其片內都帶有一定的RAM和ROM。對於一些簡單的程序,如果採用傳統的編程方法,已經不需要外擴存儲器了。如果在其中嵌入μC/OS-II的話,在只需要使用任務調度、任務切換、信號量處理、延時或超時服務的情況下,也不需要外擴ROM了,但是外擴RAM是必須的。由於μC/OS-II是可裁減的操作系統,其所需要的RAM大小就取決於操作系統功能的多少。舉例來說,μC/OS-II允許用戶定義最大任務數。由於每建立一個任務,都要產生一個與之相對應的數據結構TCB,該數據結構要佔用很大一部分內存空間。所以在定義最大任務數時,一定要考慮實際情況的需要。如果定得過大,勢必會造成不必要的浪費。嵌入μC/OS-II以後,總的RAM需求可以由如下表達式得出:

RAM總需求=應用程序的RAM需求+內核數據區的RAM需求+(任務棧需求+最大中斷嵌套棧需求)·任務數

所幸的是,μC/OS-II可以對每個任務分別定義堆棧空間的大小,開發人員可根據任務的實際需求來進行棧空間的分配。但在RAM容量有限的情況下,還是應該注意一下對大型數組、數據結構和函數的使用,別忘了,函數的形參也是要推入堆棧的。

3.μC/OS-II的移植也是一件需要值得注意的工作。如果沒有現成的移植實例的話,就必須自己來編寫移植代碼。雖然只需要改動兩個文件,但仍需要對相應的微處理器比較熟悉才行,最好參照已有的移植實例。另外,即使有移植實例,在編程前最好也要閱讀一下,因為裡面牽扯到堆棧操作。在編寫中斷服務程序時,把寄存器推入堆棧的順序必須與移植代碼中的順序相對應。

4.和其他一些著名的嵌入式操作系統不同,μC/OS-II在單片機系統中的啟動過程比較簡單,不像有些操作系統那樣,需要把內核編譯成一個映像文件寫入ROM中,上電復位後,再從ROM中把文件載入到RAM中去,然後再運行應用程序。μC/OS-II的內核是和應用程序放在一起編譯成一個文件的,使用者只需要把這個文件轉換成HEX格式,寫入ROM中就可以了,上電後,會像普通的單片機程序一樣運行。

結語

由以上介紹可以看出,μC/OS-II具有免費、使用簡單、可靠性高、實時性好等優點,但也有移植困難、缺乏必要的技術支持等缺點,尤其不像商用嵌入式系統那樣得到廣泛使用和持續的研究更新。但開放性又使得開發人員可以自行裁減和添加所需的功能,在許多應用領域發揮著獨特的作用。當然,是否在單片機系統中嵌入μC/OS-II應視所開發的項目而定,對於一些簡單的、低成本的項目來說,就沒必要使用嵌入式操作系統了。

E. AIX是一個什麼樣的系統麻煩給點詳細的資料

AIX 全名為(Advanced Interactive Executive),它是IBM 公司的Unix操作系統,
整個系統的設計從網路、主機硬體系統,到操作系統完全遵守開放系統的原則。
下面對AIX 作以介紹。

RS/6000 採用IBM 的UNIX操作系統-AIX作為其操作系統。這是一
個目前操作系統界最成功,應用領域最廣,最開放的第二代的UNIX系
統。它特別適合於做關鍵數據處理(CRITICAL)。

AIX 包含了許多IBM 大型機傳統受歡迎的特徵,如系統完整性,系統可管理
性和系統可用性。

在 AIX 操作系統上,有許多的資料庫和開發工具,用戶除了選用已有的應用
軟體外,還可以根據各自的需要進行開發。

此外,在AIX 之上,有一組功能強,使用方便的系統管理工具。對於異種平台
互存,互操作有很成熟的解決方案。

由於該 UNIX 的先進的內核技術和最好的開放性,因此,雖然RS/6000
從宣布到今天只有短短的5 年多的時間攜慧陪,它已在各行各業有了廣泛的運用,
並在1993和1994年連續二年在MIDRANGE商用 UNIX 領域處於第一位。

RISC SYSTEM/6000的操作系統是AIX ,它是性能卓越的、開放的
UNIX,匯集了多年來計算機界在UNIX上的研究成果,以IBM 在計算機
體系結構、操作系統方面40多年極其豐富的經驗。最大限度的使用RISC
技術,安裝了象AIX 這樣的具備工業界實力的UNIX操作系統。

它既可連接SAA 體系結構,又能與非IBM 系統的網路相連,因此,可以
和多數專業銀行現有的系統實現互連,這對今後業務系統拓展將帶來極大的
靈活性,並降低投資。

AIX 遵循一系列的國際標准:
* IEEE POSIX1004.1-碧碰1990
* X/OPEN 移植指南ISSUE3的基本級(XPG3)
* AES/OS REVISION A (OSF/1 LEVEL 2 資格)
* FIPS 151-1
* AIX的編譯器: XLC、C++(可選)、FORTRAN(可選)、PASCAL(可選)、COBOL(可選)
* ADA 的編譯器已達到XPG3「成員」級的認可。
* AIX 支持多用戶、多任務。

AIX有一些其它特性包括:

AIX 提供了3 種SHELL :SYSTEM V的KORN、BOURNE SHELL和4.3BSDC
SHELL作為可選擇的UNIX系統界面;

安全設施滿足TCB (Trusted Computing Base)的C2級;

實時處理能力,這對於「面向交易」的應用至關重要(如零售業
和銀行等),它使RS/6000 獲得極高的響應和吞吐量;

虛擬存儲管理,當需要時,可將一些不常用的模塊轉送至外存,
提高內存的可利用性。

先進的文件系統,使得系統管理更加有效,並提高了數據可靠性
以及完整性。

能兼容Dos 應用程序和數據。

InfoExplorer,快速信息超文本索引系統- 不僅包括文字,而且
對包含聲音、圖像的索引辯蠢系統,這是個聯機的文件介面。包括全部的
超文本的索引和查找,以及面向任務和坐標的多重導引和索引系統。
這個文字及圖形索引系統以一個靈活的、基於任務的方式去使用詳細
資料及培訓資料。

高級系統管理工具(SMIT,System Management Interface Tool)。
提供一級菜單驅動程序,諸如完成軟體的安裝與設置、設備的設置及
管理、問題的測定、存貯管理等。可以自動地進行I/O 設備設置,
ASCII 終端也可充當系統控制台。在LAN 上可以進行遠程系統的安裝。

系統工作負載
系統工作負載的完整准確的定義對於預測或理解它的性能是很關鍵的。在衡量系統性能時,工作負載的不同可能會比 CPU 時鍾速度或隨機訪問存儲器(RAM)大小不同帶來更多的變化。工作負載的定義不僅必須包含向系統發送的請求的類型和速率,還要包含將要執行的確切軟體包和內部應用程序。

包括系統將在後台處理的工作也很重要。例如,如果一個系統包含通過 NFS 載入且由其它系統頻繁訪問的文件系統,那麼處理那些訪問很可能是總體工作負載中非常重要的一部分,即使該系統不是正式的伺服器也是如此。

已進行標准化從而允許在不同系統之間進行比較的工作負載稱為基準程序。但是,很少有實際的工作負載能完全符合基準程序的精確演算法和環境。即使是那些最初從實際的應用程序發展而來的行業標准基準程序也已經過簡化和均勻化,從而使它們可移植到大量的硬體平台上。使用行業標准基準程序唯一有效的方法是減小將接受嚴肅評估的候選系統的范圍。因此,在嘗試理解系統的工作負載和性能時不應該只依賴基準測試結果。

可以將工作負載分為以下類別:

多用戶
由多個用戶通過各自的終端提交的工作組成的工作負載。通常,這種工作負載的性能目標有兩種可能,即在保留指定的最壞情況響應時間條件下最大化系統吞吐量,或者對於固定不變的工作負載獲得盡可能快的響應時間。
伺服器
由來源於其它系統的請求組成的工作負載。例如,文件伺服器的工作負載主要是磁碟讀寫請求。它是多用戶工作負載(加上 NFS 或其它 I/O 活動)的磁碟 I/O 部分,所以適用同樣的目標,即在給定的相應時間限制下最大化吞吐量。其它的伺服器工作負載由諸如數學計算密集的程序、資料庫事務、列印機作業之類的項組成。
工作站
由單獨的用戶通過鍵盤提交工作和在該系統的顯示器上接收結果組成的工作負載。通常這種工作負載的最高優先順序性能目標是使用戶請求的響應時間最短。

性能目標
在定義了系統必須處理的工作負載後,可以選擇性能標准並根據這些標准設定性能目標。計算機系統的總體性能標準是響應時間和吞吐量。

響應時間是提交請求和返回該請求的響應之間使用的時間。示例包括:

資料庫查詢花費的時間
將字元回顯到終端上花費的時間
訪問 Web 頁面花費的時間
吞吐量是對單位時間內完成的工作量的量度。示例包括:

每分鍾的資料庫事務
每秒傳送的文件千位元組數
每秒讀或寫的文件千位元組數
每分鍾的 Web 伺服器命中數
這些度量之間的關系很復雜。有時可能以響應時間為代價而得到較高的吞吐量,而有時候又要以吞吐量為代價得到較好的響應時間。在其它情況下,一個單獨的更改可能對兩者都有提高。可接受的性能基於合理的吞吐量與合理的響應時間相結合。

在規劃或調諧任何系統中,當處理特定的工作負載時一定要保證對響應時間和吞吐量都有明確的目標。否則,有可能存在一種風險,那就是您花費了分析時間和物力改善的僅僅是系統性能中一個次要的方面。

程序執行模型
為了清楚地檢查工作負載的性能特徵,需要有一個動態而非靜態的程序執行模型,如下圖所示。

圖 1. 程序執行層次結構. 該圖形以一個三角形為基礎。左邊代表和右邊適當的操作系統實體匹配的硬體實體。程序必須從存儲在磁碟上的最低級別開始,到最高級別的處理器運行程序指令。例如,從底部到頂部,磁碟硬體實體容納可執行程序;實內存容納等待的操作系統線程和中斷處理程序;轉換後備緩沖區容納可分派的結程;高速緩存中包含當前分派的線程和處理器流水線;而寄存器中包含當前的指令。

程序為了運行必須沿著硬體和操作系統層次結構並行向上前進。硬體層次結構中的每個元素都比它下面的元素稀少和昂貴。不僅程序不得不為了每個資源和其它程序競爭,而且從一個級別過渡到下一級別也要花時間。為了理解程序執行動態,需要對層次結構中每一級別有個基本的了解。

硬體層次結構
通常,從一個硬體級別移動到另一級別所需要的時間主要由較低級別的等待時間(從發出請求到接受到第一批數據的時間)組成。

固定磁碟
對於一個在單機系統中運行的程序而言,最慢的操作是從磁碟上取得代碼或數據,這是因為有下列原因:

必須引導磁碟控制器直接訪問指定的塊(排隊延遲)。
磁碟臂必須尋道以找到正確的柱面(尋道等待時間)。
讀/寫磁頭必須等候直到正確的塊旋轉到它們下面(旋轉等待時間)。
數據必須傳送到控制器(傳送時間)然後傳遞到應用程序中(中斷處理時間)。
除了程序中顯式的讀或寫請求以外,還有許多原因導致磁碟操作緩慢。頻繁的系統調諧活動證明是不必要地跟蹤了磁碟 I/O。

實內存
實內存通常稱為隨機存取存儲器或 RAM,它比磁碟速度快,但每個位元組的開銷非常昂貴。操作系統盡量只把當前使用的代碼和數據保存在 RAM 中,而把任何額外的內容存儲在磁碟上,或者決不首先把它們帶入 RAM 中。

然而,RAM 的速度不一定比處理器快。通常在硬體意識到 RAM 訪問需求與處理器可使用數據或指令的時間之間,會出現許多處理器周期的 RAM 等待時間。

如果要訪問存儲到磁碟上(或者尚未調進)的某一虛擬內存頁,則會產生一個缺頁故障,並且程序的執行暫掛直到該頁從磁碟讀取。

轉換後備緩沖區(TLB)
使程序員不會受限於系統的物理局限性的方法是實現虛擬內存。程序員在設計和編寫程序時認為內存非常大,系統將負責將程序中指令和數據的虛擬地址轉換成需要用來從 RAM 取得的指令和數據的實際地址。因為這個地址轉換過程可能很費時,系統將最近訪問過的虛擬內存頁的實際地址保存在一個叫轉換後備緩沖區(TLB)的高速緩存中。

只要運行中的程序繼續訪問程序和數據頁中的一小部分,則完整的從虛擬到實際頁地址的轉換過程就不需要在每次 RAM 訪問的時候都重做一次。當程序試圖訪問的虛擬內存頁沒有 TLB 入口(即 TLB 未命中)時,則需要大量的處理器周期(即 TLB 未命中等待時間)來進行地址轉換。

高速緩存
為了將程序必須經歷的 RAM 等待時間減到最小,系統為指令和數據組織了高速緩存。如果所需的指令和數據已在高速緩存中,則產生高速緩存命中,處理器就可在下一個周期立刻使用該指令或數據。否則產生高速緩存未命中,伴隨有 RAM 等待時間。

在某些系統中,有兩到三級高速緩存,通常稱它們為 L1、L2 和 L3。如果一個特殊的存儲器引用導致 L1 未命中,則檢查 L2。如果 L2 產生未命中,則引用轉至下一個級別,要麼是 L3(如果存在),要麼是 RAM。

高速緩存的大小和結構根據型號的不同而有不同,但是有效使用它們的原理是相同的。

流水線和寄存器
流水線型超標量體系結構使得在某些情況下可以同時處理多個指令。大批的通用寄存器和浮點寄存器使得可以將相當多的程序數據保存在寄存器中,而不需要頻繁存儲和重新裝入。

可以設計優化編譯器最大限度地利用這些能力。當生成產品程序時,無論程序有多小編譯器的優化函數都應該能使用。Optimization and Tuning Guide for XL Fortran, XL C and XL C++ 中描述了如何將程序調諧到最大性能。

軟體層次結構
程序為了運行還必須逐步執行軟體層次結構中的一系列步驟。

可執行程序
當請求運行某個程序時,操作系統執行一些操作以將磁碟上的可執行程序轉換成運行中的程序。首先,必須掃描當前 PATH 環境變數中的目錄以查找程序的正確副本。然後,系統裝入程序(不要和 ld 命令混淆,該命令是個綁定程序)必須解析出從程序到共享庫的任何外部引用。

為了表示用戶的請求,操作系統將創建一個進程或一組資源(例如專用虛擬地址段),任何運行中的程序都需要該進程或資源。

操作系統也會在該進程中自動創建一個單獨的線程。線程是一個單獨程序實例的當前執行狀態。在 AIX 中,對處理器和其它資源的訪問是根據線程來分配而不是根據進程分配的。應用程序可在一個進程中創建多個線程。這些線程共享由運行它們的進程所擁有的資源。

最後,系統轉移到程序的入口點。如果包含入口點的程序頁還不在內存中(可能因為程序最近才編譯、執行和復制),則由它引起的缺頁故障中斷將該頁從它的後備存儲器中讀取出來。

中斷處理程序
通知操作系統發生了外部事件的機制是中斷當前運行線程並將控制轉移到中斷處理程序。在中斷處理程序可以運行之前,必須保存足夠的硬體狀態以保證在中斷處理完成後系統能恢復線程的上下文。新調用的中斷處理程序將經歷在硬體層次結構中上移帶來的所有延遲(除了頁面故障)。如果該中斷處理程序最近沒有運行過(或者中間程序很節約時間),那麼它的任何代碼或數據不太可能保留在 TLB 或高速緩存中。

當再次調度已中斷的線程時,它的執行上下文(如寄存器內容)邏輯上將得到恢復,以便它可以正確運行。然而,TLB 和高速緩存的內容必須根據程序的後繼請求重新構造。因此,作為中斷的結果,中斷處理程序和被中斷的線程都可能遇到大量的高速緩存未命中和 TLB 未命中延遲。

等待線程
無論何時只要執行的程序發出不能立刻滿足的請求,例如同步 I/O 操作(顯式的或缺頁故障的結果),該線程就會處於等待狀態,直到請求完成為止。除了請求本身所需的時間以外,通常這還會導致另外一些 TLB 和高速緩存的延遲時間。

可分派線程
當某個線程可分派但不在運行時,它不能完成任何有用的事情。更糟的是,正運行的其它線程可能導致重新使用該線程的高速緩存線路並將實內存頁收回,從而引起最終分派時出現更多的延遲。

當前已分派的線程
調度程序選擇對使用處理器有強烈要求的線程。在『CPU 調度程序性能概述』中討論了影響該項選擇需要考慮的事項。當分派線程後,處理器的邏輯狀態恢復成線程中斷時有效的狀態。

當前的機器指令
如果未出現 TLB 或高速緩存未命中的情況,絕大多數機器指令都能在單個處理器周期內執行。相比之下,如果程序迅速轉換到該程序的不同區域且訪問大量不同區域中的數據,就會產生較高的 TLB 和高速緩存未命中率,執行每條指令使用的平均處理器周期數(CPI)可能大於 1。這種程序被認為有較差的局域性引用能力。它也許在使用必需的最少指令數來做這個工作,但是要消耗大量不必要的周期數。部分是因為指令數和周期數之間相關性較弱,檢查程序列表來計算路徑長度不會再直接產生一個時間值。由於較短的路徑通常比較長的路徑快,所以速率根據路徑長度率的不同而明顯不同。

編譯器用完善的方法重新安排代碼從而將程序執行所需的周期數降到最小。追求最佳性能的程序員必須首先致力於確保編譯器具有有效優化代碼所需的全部信息,而不是試圖事後批評編譯器的優化技術(請參閱『預處理器和編譯器的有效使用』)。優化有效性的實際衡量標準是可信工作負載的性能。

系統調諧
在有效實現應用程序後,系統總體性能的進一步提高就成了系統調諧考慮的一個問題。系統級調諧包含的主要組件有:

通信 I/O
取決於工作負載的類型與通信鏈路的類型,可能需要調諧以下的一個或多個通信設備驅動程序:TCP/IP 或 NFS。
固定磁碟
邏輯卷管理器(LVM)控制文件系統的位置和磁碟上調頁空間,這可能會極大地影響系統經歷的尋道等待時間。磁碟設備驅動程序控制執行 I/O 請求所遵從的順序。
實內存
虛擬內存管理器(VMM)控制空閑實內存幀的池,並決定何時從何處取用幀來補充該池。
運行線程
調度程序確定接下來由哪個可調度實體接收控制權。在 AIX 中,可調度實體是線程。請參閱『線程支持』。

性能調諧過程介紹
性能調諧主要是資源管理問題和正確的系統參數設置。調諧工作負載和系統以有效利用資源由下列步驟組成:

識別系統中的工作負載
設置目標:
確定如何評測結果
量化目標和區分目標的優先順序
識別限制系統性能的關鍵資源
最小化工作負載的關鍵資源要求:
如果可選擇的話,使用最適當的資源
減少個別程序或系統函數對關鍵資源的要求
結構化資源的並行使用
修改資源的分配以反映優先順序
更改個別程序的優先順序或資源限制
更改系統資源管理參數的設置
重復步驟 3 到步驟 5 直到滿足目標(或者資源飽和)
如果必要的話,使用其它資源
在系統性能管理的每個階段都有相應的工具(參閱附錄 A 『監視和調諧命令和子常式』)。這些工具有些可從 IBM 得到;另一些是第三方產品。下圖說明在一個簡單的 LAN 環境中性能管理的各階段。

圖 2. 性能階段. 該圖用五個加權的圓圈說明對系統性能調諧的各步驟:規劃、安裝、監視、調諧和擴展。每個圓圈代表系統處於不同的性能狀態:空閑、不均衡、均衡和過載。實質上就是擴展一個過載的系統、調諧系統直到它是均衡的、監視不均衡的系統並且在需要擴展時安裝更多的資源。

識別工作負載
系統執行的所有工作都必須能夠識別。特別是在 LAN 連接的系統中,通過系統的用戶之間僅有的非正式協議,可以輕松地開發出一組復雜的交叉安裝的文件系統。這些文件系統必須被識別出來並作為任何調諧活動的一部分進行考慮。

對於多用戶工作負載,分析員必須量化一般情況和高峰期的請求率。確定用戶實際與終端交互時間的實際比例也是很重要的。

該識別階段中的一個要素是決定必須對生產系統進行評估和調諧活動,還是在另一系統上(或「切換」)用實際工作負載的模擬型式來完成評估和調諧活動。分析員必須針對非生產環境的靈活性權衡來自於生產環境結果的較大可靠性,分析員可在非生產環境中進行試驗,當然試驗所冒的風險是性能下降或更糟。

設置目標的重要性
雖然可以根據可測數量設置目標,但實際希望的結果往往帶有主觀性,比如令人滿意的響應時間。進一步講,分析員必須抵擋住調諧可測量的東西而不是對他而言是重要東西的誘惑。如果沒有系統提供的評估能符合所要求的改進,那麼就必須對該評估進行設計。

量化目標最有價值的方面不是選擇達到的數字,而是對(通常)多個目標的相對重要性進行公開判定。如果這些優先順序沒有事先設定且不是每個相關的人都理解的話,分析員在沒有進行頻繁咨詢之前不能作出任何折衷的決定。分析員還容易對用戶的反應或管理性能中一些已經被忽略的方面而感到吃驚。如果系統的支持和使用跨過了組織的邊界,您可能需要供應商和用戶之間的書面服務級協議,可確保對性能目標和優先順序有一個清楚而共同的理解。

識別關鍵資源
通常,給定工作負載的性能可由一兩種關鍵系統資源的可用性和速度決定。分析員必須正確識別出那些資源,否則會冒險陷入無休止的嘗試出錯操作。

系統具有物理資源和邏輯資源。關鍵的物理資源通常比較容易識別,因為較多的系統性能工具可用來評估物理資源的利用率。通常最影響性能的物理資源如下:

CPU 周期
內存
I/O 匯流排
不同的適配器
磁碟臂
磁碟空間
網路訪問
邏輯資源不太容易識別。邏輯資源通常是對物理資源進行分區的編程抽象。進行分區的目的是共享和管理物理資源。

構建於其上的物理資源和邏輯資源的一些示例如下:

CPU
處理器時間片
內存
頁面幀
堆棧
緩沖區
隊列

鎖和信號量
磁碟空間
邏輯卷
文件系統
文件
分區
網路訪問
會話
信息包
通道
了解邏輯資源和物理資源是很重要的。因為缺少邏輯資源線程可能阻塞,就像因為缺少物理資源而阻塞一樣,擴展下層物理資源未必能保證創建附加的邏輯資源。例如,考慮使用 NFS 塊 I/O 守護程序 biod。客戶機上的一個 biod 守護程序要求處理每個暫掛的 NFS 遠程 I/O 請求。因此,biod 守護程序的數量限制了能同時運行的 NFS I/O 操作的數量。當缺少 biod 守護程序時,系統檢測會指示 CPU 和通信鏈路只使用了很少一部分。您可能有系統未充分利用(並且很慢)的假象,事實上這時是因為缺少 biod 守護程序從而限制了其餘的資源。biod 守護程序使用處理器周期和內存,但您不能簡單地通過添加實內存或將它轉移到一個更快的 CPU 上來修正這個問題。解決方案是創建更多的邏輯資源(biod 守護程序)。

在應用程序開發過程中可能不經意間創建邏輯資源和瓶頸。傳遞數據或控制設備的方法可以有效地創建一個邏輯資源。當偶然創建這樣的資源時,通常沒有工具可監視它們的使用,也沒有介面控制它們的分配。它們的存在可能不會引起重視,直到某個特定性能問題出現時就會突出它們的重要性。

最小化關鍵資源要示
下面討論在三個級別上考慮最小化工作負載的關鍵資源要求。

使用適當的資源
決定在一個資源上使用另一個資源時應該理智地考慮並且頭腦中要有明確的目標。在應用程序開發過程中有一個選擇資源的示例,即通過增加內存消耗來減少 CPU 的消耗來達到一個平衡。用於演示資源選擇的公共的系統配置決策為:是將文件放置在單獨的本地工作站上,還是放置在遠程伺服器上。

減少關鍵資源的要求
對於本地開發的應用程序,可用多種方法檢查程序以便其更有效地執行相同的功能或除去不需要的功能。在系統管理級別上,爭用關鍵資源的低優先順序工作負載可以移動到其它系統中、在其它時間運行或由「工作負載管理器」控制。

結構化資源的並行使用
因為工作負載需要運行多個系統資源,從而可以利用這樣的事實,即資源是獨立的且可以並行使用。例如,操作系統預讀演算法檢測到程序在順序訪問文件的事實,因此它調度並行執行的其它順序讀取操作,同時應用程序還處理先前的數據。並行也用於系統管理。例如,如果某個應用程序同時訪問兩個或多個文件且如果同時訪問的這些文件存放在不同的驅動器上,那麼添加一個額外的磁碟驅動器可能會提高磁碟 I/O 的速率。

資源分配優先順序
操作系統提供了一些方法來區分活動的優先順序。有些在系統級別上設置,比如磁碟調步。其它的例如進程優先順序可由單個用戶設置以反映連接到特定任務上的重要性。

重復調諧步驟
性能分析的一個公認的真理是接下來總有瓶頸出現。減少某個資源的使用意味著另一資源限制了吞吐量或響應時間。例如,假設我們的系統中有下列的利用率級別:

CPU:90% 磁碟:70% 內存:60%

這個工作負載是 CPU 受限的。如果成功的調諧工作負載使得 CPU 負載從 90% 降到 45%,則可望在性能上有兩倍的改善。不幸的是現在的工作負載是 I/O 受限的,它有下列的近似利用率:

CPU:45% 磁碟:90% 內存:60%

改善後的 CPU 利用率允許程序立刻提交磁碟請求,但接下來我們會受到由磁碟驅動器的容量施加的限制。性能改善也許是 30% 而不是預期的 100%。

總是存在一個新的關鍵資源。重要的問題是使用手邊的資源是否已經滿足性能目標。

注意: 用 vmtune、schedtune 和其它調諧命令產生的不正當系統調諧可能導致意外的系統行為,例如降低系統或應用程序的性能或系統暫停。更改僅應在性能分析識別出瓶頸時才適用。
注:
對於性能相關的調諧設置,不存在什麼一般建議。
應用額外的資源
在前述所有的方法都用盡後如果系統性能仍不能滿足它的目標,則必須增強或擴展關鍵資源。如果關鍵資源是邏輯資源且下層物理資源足夠,則無需額外代價就可以擴展邏輯資源。如果關鍵資源是物理資源,分析員必須研究一些額外的問題:

必須增強或擴展關鍵資源到什麼程度才可以終止瓶頸?
系統性能會滿足它的目標嗎?或另外的資源會首先飽和嗎?
如果有一串關鍵資源的話,增強或擴展所有這些資源或與另一系統劃分當前工作負載是否更節省成本呢?

性能基準
當試圖比較不同環境中給定軟體的性能時,常會遇到許多可能的錯誤,一些是技術上的,一些是概念上的。本節包含主要的提示信息。本書其它各節討論評測過去和特定處理時間的不同方法。

評測處理系統調用需要花費的時間(掛鍾)時,需要獲取一個由下列內容組成的數字:

執行正運行服務的指令所需要的確切時間
處理器等待內存中的指令或數據時延遲的不同時間(也就是說,高速緩存和 TLB 不命中的代價)
在調用開頭和結束訪問時鍾所需要的時間
由周期性事件如系統定時器中斷所消耗的時間
由或多或少的隨機事件消耗的時間,如 I/O
為了避免報告一個不精確的數字,常常要求多次評測工作負載。因為所有的外部的因素都會增加處理時間,典型的評估集有一個曲線的形式

F. UCOS新手,下面這個可重入函數有什麼作用為什麼要定義OS_TCB *ptcb這個變數

TCB — (Task Control Blank )OS_TCB *ptcb 是任務控制塊結構體指針,用於傳遞任務控制塊地址,在uCOS內所用任務公用一個TCB,每個任務進行操作都會通過地址進行訪問才會生效!該拍逗函數是刪除任務鉤子函數,用於在刪除任務時進行相應用戶操作,比如釋放臨界變數啊,控制其他任務同步等等。
ptcb = ptcb; //預防編譯出錯

因為有些編譯器在預編譯時發現入口參數未使用會出現警告,通過這句埋埋就表示已彎賀螞經使用,相應就不會報錯了!
希望你滿意!

G. UC/OS與Linux操作系統的區別

uc/os比較簡單一點,開始學的uc/os,感覺沒意思了就開始學linux,感覺ucos只是在單片機上跑跑,像arm9的一般是跑linux。其實先學哪個都差不多,因為學習方法大不相同,差別太大了,ucos太簡單,就一些信號量,郵箱什麼的,懂了也就會了,linux有點難,涉及知識太多,光是涉及內核以外的編程就需要大把大把的經典書籍去看。興趣很重要,都靠興趣過來的。

H. 什麼是UCOS操作系統

u C / O S 是一種免費公開源代碼、結構小巧、具有可剝奪實時內核的實時操作系統。x0dx0ax0dx0aμC/OS-II 的前身是μC/OS,最早出自於1992 年美國嵌入式系統專家Jean J.Labrosse 在《嵌入式系統編程》雜志的5 月和6 月刊上刊登的文章連載,並把μC/OS 的源碼發布在該雜志的B B S 上。x0dx0ax0dx0aμC/OS 和μC/OS-II 是專門為計算機的嵌入式應用設計的,絕大部分代碼是用C語言編寫的。CPU 硬體相關部分是用匯編語言編寫的、總量約200行的匯編語言部分被壓縮到最低限度,為的是便於移植到任何一種其它的CPU 上。用戶只要有標準的ANSI 的C交叉編譯器,有匯編器、連接器等軟體工具,就可以將μC/OS-II嵌人到開發的產品中。μC/OS-II 具有執行效率高、佔用空間小、實時性能優良和可擴展性強等特點, 最小內核可編譯至 2KB 。μC/OS-II 已經移植到了幾乎所有知名的CPU 上。x0dx0ax0dx0a嚴格地說uC/OS-II只是一個實時操作系統內核,它僅僅包含了任務調度,任務管理,時間管理,內存管理和任務間的通信和同步等基本功能。沒有提供輸入輸出管理,文件系統,網路等額外的服務。但由於uC/OS-II良好的可擴展性和源碼開放,這些非必須的功能完全可以由用戶自己根據需要分別實現。x0dx0ax0dx0auC/OS-II目標是實現一個基於優先順序調度的搶占式的實時內核,並在這個內核之上提供最基本的系統服務,如信號量,郵箱,消息隊列,內存管理,中斷管理等。x0dx0ax0dx0a任務管理x0dx0ax0dx0auC/OS-II 中最多可以支持64 個任務,分別對應優先順序0~63,其中0 為最高優先順序。63為最低級,系統保留了4個最高優先順序的任務和4個最低優先順序的任務,所有用戶可以培神使用的任務數有56個。x0dx0ax0dx0auC/OS-II提供了任務管理的各種函數調用,包括創建任務,刪除任務,改變任務的優先順序,任務掛起和恢復等。x0dx0ax0dx0a系統初始化時會自動產生兩個任務:一個是空閑任務,它的優先順序最低,改任務僅給一個整形變數做累加運算;另一個是系統任務,它的優先順序為次低,改任務負責統計當前cpu的利用率。x0dx0ax0dx0a時間管理x0dx0ax0dx0auC/OS-II的時間管理是通過定時中斷來實現的,該定蘆薯時中斷一般為10毫秒或100毫秒發生一次,時間頻率取決於用戶對硬體系統的定時器編程來實現。中斷發生的時間間隔是固定不變的,該中斷也成為一個時鍾節拍。x0dx0ax0dx0auC/OS-II要求用戶在定時中斷的服務程序中,調用系統提供的與時鍾節拍相關的系統函數,例如中斷級的任務切換陪中者函數,系統時間函數。x0dx0ax0dx0a內存管理x0dx0ax0dx0a在ANSI C中是使用malloc和free兩個函數來動態分配和釋放內存。但在嵌入式實時系統中,多次這樣的錯作會導致內存碎片,且由於內存管理演算法的原因,malloc和free的執行時間也是不確定。x0dx0ax0dx0auC/OS-II中把連續的大快內存按分區管理。每個分區中包含整數個大小相同的內存塊,但不同分區之間的內存快大小可以不同。用戶需要動態分配內存時,系統選擇一個適當的分區,按塊來分配內存。釋放內存時將該塊放回它以前所屬的分區,這樣能有效解決碎片問題,同時執行時間也是固定的。x0dx0ax0dx0a任務間通信與同步x0dx0ax0dx0a對一個多任務的操作系統來說,任務間的通信和同步是必不可少的。uC/OS-II中提供了4中同步對象,分別是信號量,郵箱,消息隊列和事件。所有這些同步對象都有創建,等待,發送,查詢的介面用於實現進程間的通信和同步。x0dx0ax0dx0a任務調度x0dx0ax0dx0auC/OS-II 採用的是可剝奪型實時多任務內核。可剝奪型的實時內核在任何時候都運行就緒了的最高優先順序的任務。x0dx0ax0dx0auC/os-II的任務調度是完全基於任務優先順序的搶占式調度,也就是最高優先順序的任務一旦處於就緒狀態,則立即搶占正在運行的低優先順序任務的處理器資源。為了簡化系統設計,uC/OS-II規定所有任務的優先順序不同,因為任務的優先順序也同時唯一標志了該任務本身。x0dx0ax0dx0a任務調度將在以下情況下發生:x0dx0ax0dx0a1) 高優先順序的任務因為需要某種臨界資源,主動請求掛起,讓出處理器,此時將調度就緒狀態的低優先順序任務獲得執行,這種調度也稱為任務級的上下文切換。x0dx0ax0dx0a2) 高優先順序的任務因為時鍾節拍到來,在時鍾中斷的處理程序中,內核發現高優先順序任務獲得了執行條件(如休眠的時鍾到時),則在中斷態直接切換到高優先順序任務執行。這種調度也稱為中斷級的上下文切換。x0dx0ax0dx0a這兩種調度方式在uC/OS-II的執行過程中非常普遍,一般來說前者發生在系統服務中,後者發生在時鍾中斷的服務程序中。x0dx0ax0dx0a調度工作的內容可以分為兩部分:最高優先順序任務的尋找和任務切換。其最高優先順序任務的尋找是通過建立就緒任務表來實現的。u C / O S 中的每一個任務都有獨立的堆棧空間,並有一個稱為任務控制塊TCB(Task Control Block)的數據結構,其中第一個成員變數就是保存的任務堆棧指針。任務調度模塊首先用變數OSTCBHighRdy 記錄當前最高級就緒任務的TCB 地址,然後調用OS_TASK_SW()函數來進行任務切換。x0dx0ax0dx0aμC/OS-II的組成部分x0dx0ax0dx0aμC/OS-II可以大致分成核心、任務處理、時間處理、任務同步與通信,CPU的移植等5個部分。x0dx0ax0dx0a1) 核心部分(OSCore.c)x0dx0ax0dx0a是操作系統的處理核心,包括操作系統初始化、操作系統運行、中斷進出的前導、時鍾節拍、任務調度、事件處理等多部分。能夠維持系統基本工作的部分都在這里。x0dx0ax0dx0a2) 任務處理部分(OSTask.c)x0dx0ax0dx0a任務處理部分中的內容都是與任務的操作密切相關的。包括任務的建立、刪除、掛起、恢復等等。因為μC/OS-II是以任務為基本單位調度的,所以這部分內容也相當重要。x0dx0ax0dx0a3) 時鍾部分(OSTime.c)x0dx0ax0dx0aμC/OS-II中的最小時鍾單位是timetick(時鍾節拍)。任務延時等操作是在這里完成的。x0dx0ax0dx0a4) 任務同步和通信部分x0dx0ax0dx0a為事件處理部分,包括信號量、郵箱、郵箱隊列、事件標志等部分;主要用於任務間的互相聯系和對臨界資源的訪問。x0dx0ax0dx0a5) 與CPU的介面部分x0dx0ax0dx0a是指μC/OS-II針對所使用的CPU的移植部分。由於μC/OS-II是一個通用性的操作系統,所以對於關鍵問題上的實現,還是需要根據具體CPU的具體內容和要求作相應的移植。這部分內容由於牽涉到SP等系統指針,所以通常用匯編語言編寫。主要包括中斷級任務切換的底層實現、任務級任務切換的底層實現、時鍾節拍的產生和處理、中斷的相關處理部分等內容。

I. 如何學習 nucleus os

內容:
一、nucleus plus特點:
    1.內核採用微內核的設計,方便移植,資料寫著更reliable,但是我不這么認為,與linux相比,以ARM平台為例,NU只用到了SVC mode,內核與用戶任務都運行在同一個狀態下,消掘也就是說所有的task都擁有訪問任何資源的許可權,這樣很reliable么?
    2.real-time OS,NU是一個軟實時操作系統(VxWorks是硬實時),thread control component支持多任務以及任務的搶占,對於中斷的處理定義了兩種服務方式,LISR和HISR,這個與linux中的上、下半部機制類似,linux中的下半部是通過軟中斷來實現的,NU的HISR只是作為一種優先順序總是高於task的任務出現。
    3.NU是以library的方式應用的,通過寫自己的app task與裁剪後的NU內核及組鍵殲件鏈接起來,NU並沒有CLI

二、組件

1.IN component
    初始化組件由三個部分組成,硬體在reset後首先進入INT_initialize(),進行板級的相關初始化,首先設置SVC mode,關中斷,然後將內核從rom中拷貝至ram中,建立bss段,依次建立sys stack, irq stack和fiq stack,最後初始化timer,建立timer HISR的棧空間,看了一下2410平台的代碼,一個tick大概是15.8ms,完成板級的初始化後就進入了INC_initialize,初始化各個組件,其中包括Application initialize,create task和HISR,最後將控制權交給schele,主要看了一下RAM中地址空間的安排
|timer HISR stack = 1024|
|FIQ stack = 512|
|IRQ stack = 1024|
|SVC stack = 1024|
|.bss|
|.data|
|.text|
其中SVC stack的大小與中斷源的個數相關,nested irq發生時,irq_context保存在SVC stack中,IRQ的stack只是做了臨時棧的作用。

2.thread control component
    TC組件是NU內核的最重要組成部分,主要涵蓋了調度、中斷、任務的相關操作、鎖、時鍾幾個方面,下面分別介紹。

調度(schele)

    NU中的線程類型(在同一個地址空間內)有兩種,HISR和task,HISR可以理解為一種優先順序較高的task,但又不是task,HISR優先順序高於task的實現方式就是schle時,先去查看當前是否有active的HISR,再去查看task。task有suspend、ready、finished和terminated四種狀態,而HISR只有executing和no-active這兩種狀態。

    每一個task都拿亮核有一個線程式控制制的數據結構(TCB thread control block),其中包括了task的優先順序、狀態、時間片、task棧、protect信息、signal操作的標志位和signal_handler等,task在創建時初始化這些信息,將task掛到一個create_list上,初始設定task為pure_suspend,如果設定auto start,調用resume_task()喚醒task,這里有個細節,如果在application initialize中create_task(),則task不會自動運行,因為初始化還未完成,控制權還沒有交給schele,無法調度task。task被喚醒後狀態改變為ready,並掛在一個TCD_Priority_List[256]上,數組的每個元素是一個指向TCB環形雙向鏈表的指針,根據task的tc_priority找到對應優先順序的TCB head pointer。
                           
    每一個HISR都有一個HISR控制的數據結構(HCB HISR control block),其中只有優先順序,HISR棧和HISR entry信息,因此HISR是不可以suspend,同時也沒有time slice以及signal的相關操作,一般情況下當發生了中斷後,HISR被activate,schele就會調度HISR運行,期間如果不發生中斷,HISR的執行是不會被打斷的,HISR的優先順序只有0、1、2,timer的HISR優先順序為2,也就是說由外部中斷激活的HISR很難被搶占的,只有更高優先順序的中斷HISR才可以。與task不同,被激活的HISR使用head_list和tail_list將HCB掛在一個單項的鏈表上,因為相同優先順序的HISR不會搶占對方,因此不需要雙向鏈表,使用兩個指針目的是加快HISR執行的速度。

    一個實時操作系統的核心就是對於任務的調度,NU的調度策略是time slice和round robin的演算法,
調度的部分主要有三個函數control_to_system()用於保存上下文,建立solicited stack,關中斷,關system time slice,並重置task的time slice為預設值,將sp更新為system_stack_pointer,調用schele(),調度的過程是非常簡單的查詢,就是查看兩個全局的變數,TCD_Execute_HISR和TCD_Execute_Task,schele部分的關鍵是打開了中斷,不然如果當前沒有ready的task或是被激活的HISR,則shele死循環下去,查詢到下一個應該執行的線程後跳轉至control_to_thread(),在這里重新開啟system time slice,然後將線程的tc_stack_ptr加入到sp中,切換至線程的棧中,依次pop出來,即完成了任務調度。

    任務的切換主要是上下文的切換,也就是task棧的切換,函數的調用會保存部分regs和返回地址,這些動作都是編譯器來完成的,而OS中的任務切換是運行時(runtime)的一種狀態變化,因此編譯器也無能為力,所以對於上下文的保存需要代碼來實現。

    任務的搶占是非同步的因此必須要通過中斷來實現,一般每次timer的中斷決定當前的task的slice time是否expired,然後設置TCT_Set_Execute_Task為相同優先順序的其他task或更高優先順序的task;高優先順序的task搶占低優先順序的task,一般是外部中斷觸發,在HISR中resume_task()喚醒高優先順序的task,然後schele到高優先順序的task中,因為timer的HISR是在系統初始化就已經注冊的,只是執行timeout和time slice超時後的操作,並沒有執行resume_task的動作。

    NU中的stack有兩種solicited stack和interrupt stack,solicited stack是一種minmum stack,而interrupt stack是對當前所有寄存器全部保存,TCB中的minimum stack size = 申請得到stack size - solicited stack(在arm mode下佔44位元組,thumb mode下佔48位元組),thumb標志用來記錄上下文保存時的ARM的工作模式,c代碼編譯為thumb模式,這樣可以減小code size,提高代碼密度,assembly代碼編譯為arm模式提升代碼的效率,NU中內核的代碼不多,主要是assembly代碼。stack的類型與其中PC指向的shell無關,interrupt stack保存的是task或是HISR在執行的過程中被中斷時的現場,solicited stack建立的地方包括 control_to_system()、schele_protect()和send_signals()發送給佔有protect資源的task的情況,HISR_Shell()執行完後會建立solicited stack,再跳轉至schele。

(Lower Address) Stack Top -> 1 (Interrupt stack type)
CPSR Saved CPSR
r0 Saved r0
r1 Saved r1
r2 Saved r2
r3 Saved r3
r4 Saved r4
r5 Saved r5
r6 Saved r6
r7 Saved r7
r8 Saved r8
r9 Saved r9
r10 Saved r10
r11 Saved r11
r12 Saved r12
sp Saved sp
lr Saved lr
(Higher Address) Stack Bottom-> pc Saved pc

(Lower Address) Stack Top -> 0 (Solicited stack type)
!!FOR THUMB ONLY!! 0/0x20 Saved state mask
r4 Saved r4
r5 Saved r5
r6 Saved r6
r7 Saved r7
r8 Saved r8
r9 Saved r9
r10 Saved r10
r11 Saved r11
r12 Saved r12
(Higher Address) Stack Bottom-> pc Saved pc
一個簡單的例子說明stack的情況,首先是一個task在ready(executing)的狀態下,而且time slice超時了,timer中斷發生後,保存task上下文interrupt_contex_save(),在task的tc_stack_ptr指向的地方建立中斷棧
taskA    |interrupt stack|___tc_stack_ptr 棧頂端是pc=lr-4
ARM對於中斷的判定發生在當前指令完成execute時,同時pipeline的原因pc=pc+8,入棧時就把lr-4首先放在stack的最高端(high)。

timer的LISR完成後激活了HISR,執行TCC_Time_slice()將當前task移到相同優先順序的尾端,並且設置下一個要執行的task,HISR在棧頂端保存的是這個HISR_shell的入口地址,因為task的執行完就finished,HISR是可重入的
HISR     |solicited stack|  棧頂端是HISR_shell_entry

中斷(interrupt)

前面已經提及了中斷的基本操作,這里就寫一些代碼路徑的細節,中斷的執行主要是兩個部分LISR和HISR,分成兩個部分的目的就是將關中斷的時間最小化,並且在LISR中開中斷允許中斷的嵌套,以及建立中斷優先順序,都可以減少中斷的延遲,保證OS的實時性。
NU的中斷模式是可重入的中斷處理方式,也就是基於中斷優先順序和嵌套的模式,中斷的嵌套在處理的過程中應對lr_irq_mode寄存器進行保存,因為高優先順序的中斷發生時會覆蓋掉低優先順序中斷的r14和spsr,因此要利用系統的棧來保存中斷棧。

NU對於中斷上下文的保存具體操作如下:
(1)在中斷發生後執行的入口函數INT_IRQ()中,將r0-r4保存至irq的棧中
(2)查找到對應的interrupt_shell(),clear中斷源,更新全局的中斷計數器,然後進行interrupt_contex_save
(3)首先利用r1,r2,r3保存irq模式下的sp,lr,spsr,這里sp是用來切換至系統棧後拷貝lr和spsr的,這里保存lr和spsr是目的是task被搶占後,當再次schele時可以返回task之前的狀態。
(4)切換至SVC模式,如果是非嵌套的中斷則保存上下文至task stack中,將irq模式下的lr作為頂端PC的返回值入棧,將SVC模式下的r6-r14入棧,將irq模式下的sp保存至r4中入棧,最後將保存在irq_stack中的r0-r4入棧
(5)如果是嵌套中斷,中斷的嵌套發生在LISR中,在執行LISR時已經切換至system stack,因此嵌套中斷要將中斷的上下文保存至system stack中,與task stack中interrupt stack相比只是少了棧頂用來標記嵌套的標志(1 not nested)
(6)有一個分支判斷,就是如果當前線程是空,即TCD_Current_Thread == NULL,表明當前是schele中,因為初始化線程是關中斷的,這樣就不為schele線程建立棧幀,因為schele不需要保存上下文,在restore中斷上下文時直接跳轉至schele。

中斷上下文的恢復
全局的中斷計數器INT_Count是否為0來判定當前出棧的信息,如果是嵌套則返回LISR中,否則切換至system stack執行schele

timer
timer與中斷緊密相關,其實timer也是中斷的一種,只是發生中斷的頻率較高,且作用重大,一個實時操作系統,時間是非常重要的一部分,NU中的timer主要有四個作用:
(1)維護系統時鍾 TMD_system_clock
(2)task的time slice
(3)task的suspend timeout timer
(4)application timer
其中(3)(4)共用一種機制,一個全局的時間軸TMD_timer,timeout timer和app timer都建立在一個TM_TCB的數據結構上,通過tm_remaining_time來表徵當前timer的剩餘時間,例如當前有timer_list上有三個TM_TCB,依次是Ta = 5,Tb = 7, Tc = 20,那麼建立的鏈表上剩餘時間依次是5,2,8,如果現在要加入一個新的timer根據timer值插入至合適的位置,如果插入的timer為13,則安排在Tb後面,剩餘時間為1,後面的8改為7,當發生了timer expired,則觸發timer_HISR,如果是app timer則執行timer callback,如果是task timeout timer,則執行TCC_Task_Timeout喚醒task。

(2)的實現也是依賴於全局的time slice時間軸,每一個task在執行時都會將自己的時間片信息更新至全局的時間軸上,當一個task的time slice執行完在timer HISR中調用TCC_task_Timeout將當前的task放在相同優先順序list的最尾端,並設置下一個最高優先順序的任務。task在執行的過程中只有被中斷後time slice會保存下來,其他讓出處理器的情況都會將time slice更新為預設值。

protect
protect與linux的鎖機制類似,互斥訪問,利用開關中斷來實現,並且擁有protect的task是不可以suspend的,必須要將protect釋放後才可以掛起,當一個優先順序較低的task佔有protect資源,如果被搶占,一個高優先順序的task或HISR在請求protect資源時會執行TCC_schele_protect()讓出處理器給低優先順序的task執行,直到低優先順序的task執行unprotect()為止,此時task或HISR建立的是solicited stack,同時在control_to_thread前開關中斷一次,這樣可以減少一次上下文的切換。NU中常用到的是system_protect,它就是一把大鎖,保護內核中所有全局數據結構的順序訪問,粒度很大。

LISR中不可以請求protect資源,因為LISR是中斷task後執行,如果task佔有protect資源,這時LISR又去請求protect資源,會發生死鎖,因為LISR讓出處理器後,schele沒辦法再次調度到LISR執行,則發生死鎖錯誤,因此在LISR中除了activate_HISR()以外不可以使用system call,例如resume_task等等,這寫系統調用都會請求protect資源。

對於protect的請求按照一定的順序可以防止死鎖,NU的源碼中一般將system_protect資源的請求放在後面,其他如DM_protect先請求。

J. ucos-ii是怎樣移植到Keil C上的

在移植的時候 盡量保證得到的源代碼改動最少
並且調試方便 而且目錄結構分類清晰

網上的各明滾個項目都有如下特點:
1:一來就吭哧吭哧修改頭文件,每個文件都#include "includes.h"
2: ucos和其他文件 或者放在一個文件夾 或者在項目裡面不管3721都加上
跳來跳去頭都是大的 而且調試的時候出些莫名其妙的問題:比如賀扮
設不了斷點 或者調試無法進入c文件等等

我的設想:前提 得到ucos2.84
1: 改動盡量少 即不按常規修改裡面的#include "includes.h"等
ucos說放哪裡我們就放哪裡
2: 項目結構和文件存放結構合理,該有的有 不該有的就沒有
3: 調試時編譯器不會出現怪問題
4: 文檔盡量清楚 每處和每步小小的修改都要說明

建議最開始看完 楊屹 大蝦的文章

[裡面的os_cfg_r.h->改成os_cfg.h] 至此,是ucos裡面的[第一處修改]

1: 建立項目文件 拷貝原始文件 整理文件夾
目錄如下:
FirstVersion: 根目錄 project.uv就放下面
-ucos : 拷貝ucos2.83源代碼和os_cpu_a.a51 等凡是ucos相關的到下面 去掉只讀和存檔屬性 自己加一個app_cfg.h(ucos2.83增

加的) 裡面內容是#include <reg51.h>嘿嘿
-output:

項目設置:
-SourceGroup
->STARTUP.A51 main.c
--ucos
->os_task.c os_core.c

2: 設置
1: Target1 -> options->output和Listing裡面點"Select Folder for Objects" 改為\output
2: Target1->options -> C51和A51裡面的 Include Paths->加入ucos
4: Target1 -> options->Target的MemoryModel和CodeRomSize都用Large

編譯: 有四個警告 'OSIntCtxSw': missing function-prototype
'OSStartHighRdy': missing function-prototype
'OSCtxSw': missing function-prototype
UCOS\OS_CORE.C(1356): warning C275: expression with possibly no effect
第四個警告是由於OS_TaskIdle()裡面
(void)p_arg; /* Prevent compiler warning for not using 'parg' */
沒有起到作用 改成p_arg = p_arg;即可。 至此,是在ucos裡面的[第二處修改]

3:加入 OS_CPU_C.C 不要問這個文件哪裡來的 地球人都知道
在不管它通不通前 還有修改
1: 最前面保持跟其他.c文件一致 加入
#ifndef OS_MASTER_FILE
#include <ucos_ii.h>
#endif

2:加入若干個激拍余函數的函數體 大體都是帶"hook"的, 這些個函數只在ucos_ii.h有個聲明,但由於只有頭文件有定義沒有函數體 ,keil會

把它編譯成LJMP STARTUP1的語句。知道有什麼後果了吧
注意#if的條件頭文件和c文件要一致

在這里感覺ucos是不是搞了點」技術處理「?反正n個函數頭文件和c文件的#if條件不一致
一不小心會造成LJMP STARTUP1! 注意把os_core.c ucos_ii.h和os_cpu_c裡面都要改完
至此,是在ucos裡面的[第三處修改] 要改的地方還不少

//in ucos_ii.h
#if OS_CPU_HOOKS_EN
void OSInitHookBegin (void);
void OSInitHookEnd (void);
void OSTCBInitHook (OS_TCB *ptcb);
void OSTaskCreateHook (OS_TCB *ptcb);
void OSTaskDelHook (OS_TCB *ptcb);
void OSTaskStatHook (void);
void OSTaskIdleHook (void);
#endif

#if OS_TASK_SW_HOOK_EN
void OSTaskSwHook (void);
#endif

#if OS_TIME_TICK_HOOK_EN
void OSTimeTickHook (void);
#endif

4: 現在開始改OS_CPU_C.C裡面的函數
將OSTaskStkInit()改成跟ucos_ii.h裡面一樣。具體就是原來裡面yy大蝦的函數是
void *OSTaskStkInit (void (*task)(void *pd), void *ppdata, void *ptos, INT16U opt)
總之網上各個版本都是ppdata..呵呵 。ucos2.83裡面用的是p_arg.我們把它修改成
OS_STK *OSTaskStkInit (void (*task)(void *p_arg) ,
void *p_arg,
OS_STK *ptos,
INT16U opt)
編譯能通過 先不管運行起來對不對

5: 在ucos組裡面加入os_cpu_a.a51 不要問這個文件哪裡來的 地球人都知道
編譯 會出現錯誤: *** ERROR L102: EXTERNAL ATTRIBUTE MISMATCH
這是因為os_cpu_a.a51裡面
EXTRN IDATA (OSTCBHighRdy)
EXTRN IDATA (OSRunning)
EXTRN IDATA (OSPrioCur)
EXTRN IDATA (OSPrioHighRdy)
對引用的外部變數作了idata的定義,而ucos_ii.h裡面沒有

在這里 os_cpu.h裡面 先增加一個#define DATATYPE_1 idata
在ucos_ii.h找到這四個變數 增加idata定義 至此,是在ucos裡面的[第三處修改]
編譯能通過

6:在ucos_ii.h裡面
#if 0
void OSStartHighRdy (void);
void OSIntCtxSw (void);
void OSCtxSw (void);
#endif

這就是造成上面的其中三個編譯警告的原因 既然ucos2.83裡面有說
* IMPORTANT: These prototypes MUST be placed in OS_CPU.H
那麼我們就把它們placed in OS_CPU.H
不改動原來的代碼 只
void OSStartHighRdy (void);
void OSIntCtxSw (void);
void OSCtxSw (void);
到os_cpu.h裡面 再編譯 現在就只有
*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS的警告了
Program Size: data=84.0 xdata=2348 code=8721 //keil 8.06
至此 整個框架就搭起來了 下面就來慢慢對付OSTaskStkInit()這個函數

gogogo!!!!!!!!!!!!!!!!!!

1: os_cfg.h裡面先 disable掉
OS_DEBUG_EN OS_FLAG_EN OS_MBOX_EN OS_MEM_EN OS_MUTEX_EN OS_Q_EN OS_SEM_EN
等等等等

題外話: 做一個Configuration Wizard的OS_CFG.H 這下方便多了 。這可是個體力活! 嘿嘿
也不違背了不改動原始文件的初衷

開始go了。建立最簡單的一個東西

#include <ucos_ii.h>

void main(void)
{
OSInit();
OSStart();
}

發現走到os_cpu_a.a51裡面的
OSStartHighRdy:
USING 0 ;上電後51自動關中斷,此處不必用CLR EA指令,因為到此處還未開中斷,本程序退出後,開中斷。
LCALL _?OSTaskSwHook --》一call就call復位了 我靠

搗鼓了下建一個os_cpu_a.c 加入工程 且右鍵的options->Generate Assembleer SRC File打勾
內容為
#ifndef OS_MASTER_FILE
#include <ucos_ii.h>
#endif

void OSStartHighRdy(void) {
OSTaskSwHook();
} 看了看 生成的東西是這樣的
?PR?OSStartHighRdy?OS_CPU_A SEGMENT CODE
EXTRN CODE (OSTaskSwHook)
PUBLIC OSStartHighRdy

RSEG ?PR?OSStartHighRdy?OS_CPU_A
OSStartHighRdy:
USING 0

LJMP OSTaskSwHook

END

簡直莫名其妙 於是 將os_cpu_a.a51改成

;EXTRN CODE (_?OSTaskSwHook)
EXTRN CODE (OSTaskSwHook) ;keil8.06 <-----改這里

;子程序
;-------------------------------------------------------------------------
RSEG ?PR?OSStartHighRdy?OS_CPU_A
OSStartHighRdy:
USING 0 ;上電後51自動關中斷,此處不必用CLR EA指令,因為到此處還未開中斷,本程序退出後,開中斷。
;LCALL _?OSTaskSwHook
LCALL OSTaskSwHook <-----改這里

再測試 ok 能進入OSIdleStask 並在裡面循環 看來是c和匯編連接的一些問題 先把它放一邊以後解決 [待解決的問題2]繼續測試

這里又想到個問題 萬一#define OS_TASK_SW_HOOK_EN 0 那麼OSTaskSwHook()就不被編譯。
在匯編裡面調用會不會又復位?keil這點太……[不知道哪裡可以設置 待解決的問題2],
測試了下 果然復位 我靠!作個說明「如果用keil,那麼OS_TASK_SW_HOOK_EN 一定要為1

好了 就算第一步測試搞定 現在來做個」笨活路「 給所有的函數加上reentrant! 內部的static就不用了。

現在開始調試serial 將yy大蝦的serial.c搞過來 加入工程
1: 看到匯編和c混合頭都是大的 把
#pragma asm
push IE
EA = 0;
之類的東東全部改成 _push_(IE); EA = 0;嘿嘿 當然不要忘記在app_cfg.h加#include <intrins.h>

現在有:
#include <ucos_ii.h>

void Task1(void *p_arg) keilReentrant;
void Task2(void *p_arg) keilReentrant;
void Task3(void *p_arg) keilReentrant;

OS_STK Task1Stack[MaxStkSize];//注意:我在ASM文件中設置?STACK空間為40H即64。
OS_STK Task2Stack[MaxStkSize];
OS_STK Task3Stack[MaxStkSize];

void main(void)
{
unsigned char ucReturn;

OSInit();
OSInitTimer0(); //也就是原來的InitTimer0();
InitSerial();
InitSerialBuffer();

ucReturn = OSTaskCreate(Task1, (void *)0, &Task1Stack[0] ,2);
ucReturn = OSTaskCreate(Task2, (void *)0, &Task2Stack[0] ,3);
ucReturn = OSTaskCreate(Task3, (void *)0, &Task3Stack[0] ,4);

OSStart();
}

void Task1(void *p_arg) keilReentrant
{
p_arg = p_arg;

ET0=1;

for(;;){
//PrintStr("Task 1 is active. \n");
OSTimeDly(3*OS_TICKS_PER_SEC);
}
}

void Task2(void *p_arg) keilReentrant
{
p_arg = p_arg;

for(;;){
PrintStr("Task 2 is active. \n");
OSTimeDly(2*OS_TICKS_PER_SEC);
}
}

void Task3(void *p_arg) keilReentrant
{
p_arg = p_arg;

for(;;){
PrintStr("Task 3 is active. \n");
OSTimeDly(3*OS_TICKS_PER_SEC);
}
}

運行 我靠 怎麼就顯示"Task 1 is active" 任務不切換 ?為啥。
原來os_time.c還沒有加到項目裡面去(因為這個項目沒有把
ucos_ii.c加入項目);OSTimeDly()哪裡會工作

加進去,運行->OK

OS_timr 把OS_Timr.c加入 並打開en的開關編譯的時候會出現err。原因是回調函數參數太多的問題
解決方法見 http://www.keil.com/support/docs/2066.htm
在ucos-ii.h裡面
/* add keilReentrant to to solve the Error 212: Indirect call: Parameters do not fit within registers */
typedef void (*OS_TMR_CALLBACK)(void *ptmr, void *parg) reentrant ;

附加一點就是項目裡面直接加如.a文件 不用在include c51L.lib

然後加入一個lcd的驅動 呵呵很簡單1602的。前提就是盡量不修改ucos的變數 函數名稱和調用方式等
詳細見工程。調試通過 不過是在proteus裡面。在這里感謝jjj www.proteus.com.cn
記得因為lcd.c裡面用到了sempost函數 所以如果要用就必須把OS_MAX_EVENTS 算進去,在你原來的設定值加一

到此 新鮮的ucos2.84出爐了。奉獻此身體給大家。想來想去 唯一的賣點就是寫了點細節,二是改了個os_cfg.h...呵呵

打包文件在下 ! 只有文檔的兄台也不用發mail給我 自己網上找去 應該有下

熊偉 於大年初一 深圳 [email protected] jdsu光電

version2:
不知道怎麼回事,一到 LCALL OSTaskSwHook --》一call就call復位了 我靠
又改回來 LCALL _?OSTaskSwHook 又好了
想了想 是不是我又加了.a文件的原因?
因為後來我又加了一個INT0Function.c 和INT0Function_a.a51

void Int0Function() keilReentrant
{ //中斷在匯編中實現,去掉interrupt {//INT0中斷服務子程序

}

#include <include_a.h>

NAME INT0FUNCTION_A ;模塊名

?PR?_?INTOFunction?INT0FUNCTION_A SEGMENT CODE

EXTRN CODE (_?INTOFunction)

;-------------------------------------------------------------------------
CSEG AT 0013H ;INT0中斷
LJMP INT0ISR ;工作於系統態,無任務切換。
RSEG ?PR?_?INTOFunction?INT0FUNCTION_A

INT0ISR:

USING 0
CLR EA ;先關中斷,以防中斷嵌套。
PUSHALL
LCALL _?INTOFunction
POPALL
SETB EA
RETI

;-------------------------------------------------------------------------
END
;-------------------------------------------------------------------------

閱讀全文

與tcb編譯相關的資料

熱點內容
java關鍵字保留字 瀏覽:243
linux系統運維下載 瀏覽:47
同程的簡便演算法 瀏覽:647
linux命令行管理主機 瀏覽:299
騰訊雲20元的伺服器 瀏覽:214
plsql編程入門 瀏覽:11
《fog》txt下載 瀏覽:494
怎樣用氣泡紙解壓 瀏覽:120
香港李時珍的經典電影 瀏覽:319
母親和房子電影 瀏覽:141
收盡天下女明星的超級主播 瀏覽:469
程序員的ios游戲 瀏覽:719
可以在線看 瀏覽:56
十三武士迅雷 瀏覽:809
網站好看,網站不用下載 瀏覽:153
優聊app怎麼上不去了賬號不存在 瀏覽:465
楚天的小說主角 瀏覽:86
重生到民國成為浙江督軍的小說 瀏覽:531
玄幻推母 瀏覽:770
周潤發黃百鳴電影 瀏覽:815