www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當前位置:首頁 > 嵌入式 > 嵌入式軟件
[導(dǎo)讀] 這一章介紹如何將μC/OS-Ⅱ移植到不同的處理器上。所謂移植,就是使一個實時內(nèi)核能在某個微處理器或微控制器上運行。為了方便移植,大部分的μC/OS-Ⅱ代碼是用C語言寫

 這一章介紹如何將μC/OS-Ⅱ移植到不同的處理器上。所謂移植,就是使一個實時內(nèi)核能在某個微處理器或微控制器上運行。為了方便移植,大部分的μC/OS-Ⅱ代碼是用C語言寫的;但仍需要用C和匯編語言寫一些與處理器相關(guān)的代碼,這是因為μC/OS-Ⅱ在讀寫處理器寄存器時只能通過匯編語言來實現(xiàn)。由于μC/OS-Ⅱ在設(shè)計時就已經(jīng)充分考慮了可移植性,所以μC/OS-Ⅱ的移植相對來說是比較容易的。如果已經(jīng)有人在您使用的處理器上成功地移植了μC/OS-Ⅱ,您也得到了相關(guān)代碼,就不必看本章了。當然,本章介紹的內(nèi)容將有助于用戶了解μC/OS-Ⅱ中與處理器相關(guān)的代碼。

要使μC/OS-Ⅱ正常運行,處理器必須滿足以下要求:

1.處理器的C編譯器能產(chǎn)生可重入代碼。

2.用C語言就可以打開和關(guān)閉中斷。

3.處理器支持中斷,并且能產(chǎn)生定時中斷(通常在10至100Hz之間)。

4.處理器支持能夠容納一定量數(shù)據(jù)(可能是幾千字節(jié))的硬件堆棧。

5.處理器有將堆棧指針和其它CPU寄存器讀出和存儲到堆?;騼?nèi)存中的指令。

像Motorola6805系列的處理器不能滿足上面的第4條和第5條要求,所以μC/OS-Ⅱ不能在這類處理器上運行。

圖8.1說明了μC/OS-Ⅱ的結(jié)構(gòu)以及它與硬件的關(guān)系。由于μC/OS-Ⅱ為自由軟件,當用戶用到μC/OS-Ⅱ時,有責任公開應(yīng)用軟件和μC/OS-Ⅱ的配置代碼。這本書和磁盤包含了所有與處理器無關(guān)的代碼和Intel80x86實模式下的與處理器相關(guān)的代碼(C編譯器大模式下編譯) 。如果用戶打算在其它處理器上使用μC/OS-Ⅱ,最好能找到一個現(xiàn)成的移植實例,如果沒有只好自己編寫了。用戶可以在正式的μC/OS-Ⅱ網(wǎng)站www. μCOS-Ⅱ.com中查找一些移植實例。

圖 8.1μC/OS-II 硬件和軟件體系結(jié)構(gòu)

如果用戶理解了處理器和C編譯器的技術(shù)細節(jié),移植μC/OS-Ⅱ的工作實際上是非常簡單的。前提是您的處理器和編譯器滿足了μC/OS-Ⅱ的要求,并且已經(jīng)有了必要工具。移植工作包括以下幾個內(nèi)容:

z 用#define設(shè)置一個常量的值(OS_CPU.H)

z 聲明10個數(shù)據(jù)類型(OS_CPU.H)

z 用#define聲明三個宏(OS_CPU.H)

z 用C語言編寫六個簡單的函數(shù)(OS_CPU_C.C)

z 編寫四個匯編語言函數(shù)(OS_CPU_A.ASM)

根據(jù)處理器的不同,一個移植實例可能需要編寫或改寫50至300行的代碼,需要的時間從幾個小時到一星期不等。

一旦代碼移植結(jié)束,下一步工作就是測試。測試一個象μC/OS-Ⅱ一樣的多任務(wù)實時內(nèi)核并不復(fù)雜。 甚至可以在沒有應(yīng)用程序的情況下測試。 換句話說, 就是讓內(nèi)核自己測試自己。這樣做有兩個好處:第一,避免使本來就復(fù)雜的事情更加復(fù)雜;第二,如果出現(xiàn)問題,可以知道問題出在內(nèi)核代碼上而不是應(yīng)用程序。 剛開始的時候可以運行一些簡單的任務(wù)和時鐘節(jié)拍中斷服務(wù)例程。一旦多任務(wù)調(diào)度成功地運行了,再添加應(yīng)用程序的任務(wù)就是非常簡單的工作了。

8.00 開發(fā)工具

如前所述,移植μC/OS-Ⅱ需要一個C編譯器,并且是針對用戶用的CPU的。因為μC/OS-Ⅱ是一個可剝奪型內(nèi)核,用戶只有通過C編譯器來產(chǎn)生可重入代碼;C編譯器還要支持匯編語言程序。 絕大部分的C編譯器都是為嵌入式系統(tǒng)設(shè)計的, 它包括匯編器、 連接器和定位器。

連接器用來將不同的模塊(編譯過和匯編過的文件)連接成目標文件。 定位器則允許用戶將代碼和數(shù)據(jù)放置在目標處理器的指定內(nèi)存映射空間中。 所用的C編譯器還必須提供一個機制來從C中打開和關(guān)閉中斷。一些編譯器允許用戶在C源代碼中插入?yún)R編語言。這就使得插入合適的處理器指令來允許和禁止中斷變得非常容易了。 還有一些編譯器實際上包括了語言擴展功能,可以直接從C中允許和禁止中斷。

8.01 目錄和文件

本書所付的磁盤中提供了μC/OS-Ⅱ的安裝程序,可在硬盤上安裝μC/OS-Ⅱ和移植實例代碼(Intel80x86實模式,大模式編譯)。我設(shè)計了一個連續(xù)的目錄結(jié)構(gòu),使得用戶更容易找到目標處理器的文件。如果想增加一個其它處理器的移植實例,您可以考慮采取同樣的方法(包括目錄的建立和文件的命名等等) 。

所有的移植實例都應(yīng)放在用戶硬盤的SOFTWAREμCOS-Ⅱ目錄下。各個微處理器或微控制器的移植源代碼必須在以下兩個或三個文件中找到:OS_CPU.H,OS_CPU_C.C,OS_CPU_A.ASM。匯編語言文件OS_CPU_A.ASM是可選擇的,因為某些C編譯器允許用戶在C語言中插入?yún)R編語言,所以用戶可以將所需的匯編語言代碼直接放到OS_CPU_C.C中。放置移植實例的目錄決定于用戶所用的處理器, 例如在下面的表中所示的放置不同移植實例的目錄結(jié)構(gòu)。注意,各個目錄雖然針對完全不同的目標處理器,但都包括了相同的文件名。

8.02INCLUDES.H

在第一章中曾提到過,INCLUDES.H是一個頭文件,它在所有.C文件的第一行被包含。

#include"includes.h"

INCLUDES.H使得用戶項目中的每個.C文件不用分別去考慮它實際上需要哪些頭文件。使用INCLUDES.H的唯一缺點是它可能會包含一些實際不相關(guān)的頭文件。這意味著每個文件的編譯時間可能會增加。 但由于它增強了代碼的可移植性, 所以我們還是決定使用這一方法。用戶可以通過編輯INCLUDES.H來增加自己的頭文件,但是用戶的頭文件必須添加在頭文件列表的最后。

8.03OS_CPU.H

OS_CPU.H包括了用#defines定義的與處理器相關(guān)的常量,宏和類型定義。OS_CPU.H的

大體結(jié)構(gòu)如程序清單L8.1所示。

程序清單 L8.1 OS_CPU.H.

#ifdefOS_CPU_GLOBALS

#defineOS_CPU_EXT

#else

#defineOS_CPU_EXTextern

#endif

/*

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

* 數(shù)據(jù)類型

*(與編譯器相關(guān))

[!--empirenews.page--]

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

*/

typedefunsignedcharBOOLEAN;

typedefunsignedcharINT8U;/* 無符號8位整數(shù) */(1)

typedefsignedcharINT8S;/* 有符號8位整數(shù) */

typedefunsignedinTINT16U;/* 無符號16位整數(shù) */

typedefsignedintINT16S;/* 有符號16位整數(shù) */

typedefunsignedlONgINT32U;/* 無符號32位整數(shù) */

typedefsignedlongINT32S;/* 有符號32位整數(shù) */

typedeffloatFP32;/* 單精度浮點數(shù) */(2)

typedefdoubleFP64;/* 雙精度浮點數(shù) */

typedefunsignedintOS_STK;/* 堆棧入口寬度為16位 */

/*

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

* 與處理器相關(guān)的代碼

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

*/

#defineOS_ENTER_CRITICAL()???/* 禁止中斷 */(3)

#defineOS_EXIT_CRITICAL()???/* 允許中斷 */

#defineOS_STK_GROWTH1/* 定義堆棧的增長方向: 1=向下,0=向上 */(4)

#defineOS_TASK_SW()???(5)

8.03.01與編譯器相關(guān)的數(shù)據(jù)類型

因為不同的微處理器有不同的字長,所以μC/OS-Ⅱ的移植包括了一系列的類型定義以確保其可移植性。尤其是,μC/OS-Ⅱ代碼從不使用C的short,int和long等數(shù)據(jù)類型,因為它們是與編譯器相關(guān)的,不可移植。相反的,我定義的整型數(shù)據(jù)結(jié)構(gòu)既是可移植的又是直觀的[L8.1(2)]。為了方便,雖然μC/OS-Ⅱ不使用浮點數(shù)據(jù),但我還是定義了浮點數(shù)據(jù)類型[L8.1(2)]。

例如,INT16U數(shù)據(jù)類型總是代表16位的無符號整數(shù)?,F(xiàn)在,μC/OS-Ⅱ和用戶的應(yīng)用程序就可以估計出聲明為該數(shù)據(jù)類型的變量的數(shù)值范圍是0-65535。 將μC/OS-Ⅱ移植到32位的處理器上也就意味著INT16U實際被聲明為無符號短整型數(shù)據(jù)結(jié)構(gòu)而不是無符號整型數(shù)據(jù)結(jié)構(gòu)。但是,μC/OS-Ⅱ所處理的仍然是INT16U。

用戶必須將任務(wù)堆棧的數(shù)據(jù)類型告訴給μC/OS-Ⅱ。這個過程是通過為OS_STK聲明正確的C數(shù)據(jù)類型來完成的。如果用戶的處理器上的堆棧成員是32位的,并且用戶的編譯文件指定整型為32位數(shù),那么就應(yīng)該將OS_STK聲明位無符號整型數(shù)據(jù)類型。所有的任務(wù)堆棧都必須用OS_STK來聲明數(shù)據(jù)類型。用戶所必須要做的就是查看編譯器手冊,并找到對應(yīng)于μC/OS-Ⅱ的標準C數(shù)據(jù)類型。

8.03.02OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()

與所有的實時內(nèi)核一樣,μC/OS-Ⅱ需要先禁止中斷再訪問代碼的臨界段,并且在訪問完畢后重新允許中斷。這就使得μC/OS-Ⅱ能夠保護臨界段代碼免受多任務(wù)或中斷服務(wù)例程(ISRs)的破壞。中斷禁止時間是商業(yè)實時內(nèi)核公司提供的重要指標之一,因為它將影響到用戶的系統(tǒng)對實時事件的響應(yīng)能力。 雖然μC/OS-Ⅱ盡量使中斷禁止時間達到最短, 但是μC/OS-Ⅱ的中斷禁止時間還主要依賴于處理器結(jié)構(gòu)和編譯器產(chǎn)生的代碼的質(zhì)量。 通常每個處理器都會提供一定的指令來禁止/允許中斷,因此用戶的C編譯器必須要有一定的機制來直接從C中執(zhí)行這些操作。有些編譯器能夠允許用戶在C源代碼中插入?yún)R編語言聲明。這樣就使得插入處理器指令來允許和禁止中斷變得很容易了。其它一些編譯器實際上包括了語言擴展功能,可以直接從C中允許和禁止中斷。為了隱藏編譯器廠商提供的具體實現(xiàn)方法,μC/OS-Ⅱ定義了兩個宏來禁止和允許中斷:

OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()[L8.1(3)]。

{

OS_ENTER_CRITICAL();

/* ? μC/OS-II 臨界代碼段 */

OS_EXIT_CRITICAL();

}

方法1

執(zhí)行這兩個宏的第一個也是最簡單的方法是在OS_ENTER_CRITICAL()中調(diào)用處理器指令來禁止中斷,以及在OS_EXIT_CRITICAL()中調(diào)用允許中斷指令。但是,在這個過程中還存在著小小的問題。如果用戶在禁止中斷的情況下調(diào)用μC/OS-Ⅱ函數(shù),在從μC/OS-Ⅱ返回的時候,中斷可能會變成是允許的了!如果用戶禁止中斷就表明用戶想在從μC/OS-Ⅱ函數(shù)返回的時候中斷還是禁止的。在這種情況下,光靠這種執(zhí)行方法可能是不夠的。

方法2

執(zhí)行OS_ENTER_CRITICAL()的第二個方法是先將中斷禁止狀態(tài)保存到堆棧中,然后禁止中斷。而執(zhí)行OS_EXIT_CRITICAL()的時候只是從堆棧中恢復(fù)中斷狀態(tài)。如果用這個方法的話,不管用戶是在中斷禁止還是允許的情況下調(diào)用μC/OS-Ⅱ服務(wù),在整個調(diào)用過程中都不會改變中斷狀態(tài)。如果用戶在中斷禁止的時候調(diào)用μC/OS-Ⅱ服務(wù),其實用戶是在延長應(yīng)用程序的中斷響應(yīng)時間。用戶的應(yīng)用程序還可以用OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()來保護代碼的臨界段。 但是, 用戶在使用這種方法的時候還得十分小心,因為如果用戶在調(diào)用象OSTimeDly()之類的服務(wù)之前就禁止中斷,很有可能用戶的應(yīng)用程序會崩潰。發(fā)生這種情況的原因是任務(wù)被掛起直到時間期滿,而中斷是禁止的,因而用戶不可能獲得節(jié)拍中斷!很明顯,所有的PEND調(diào)用都會涉及到這個問題,用戶得十分小心。一個通用的辦法是用戶應(yīng)該在中斷允許的情況下調(diào)用μC/OS-Ⅱ的系統(tǒng)服務(wù)!

問題是:哪種方法更好一點?這就得看用戶想犧牲些什么。如果用戶并不關(guān)心在調(diào)用μC/OS-Ⅱ服務(wù)后用戶的應(yīng)用程序中中斷是否是允許的,那么用戶應(yīng)該選擇第一種方法執(zhí)行。

如果用戶想在調(diào)用μC/OS-Ⅱ服務(wù)過程中保持中斷禁止狀態(tài),那么很明顯用戶應(yīng)該選擇第二種方法。

給用戶舉個例子吧,通過執(zhí)行STI命令在Intel80186上禁止中斷,并用CLI命令來允許中斷。用戶可以用下面的方法來執(zhí)行這兩個宏:

#defineOS_ENTER_CRITICAL()asmCLI

#defineOS_EXIT_CRITICAL()asmSTI

CLI和SCI指令都會在兩個時鐘周期內(nèi)被馬上執(zhí)行(總共為四個周期)。為了保持中斷狀態(tài),用戶需要用下面的方法來執(zhí)行宏:

#defineOS_ENTER_CRITICAL()asmPUSHF;CLI

#defineOS_EXIT_CRITICAL()asmPOPF

在這種情況下,OS_ENTER_CRITICAL()需要12個時鐘周期,而OS_EXIT_CRITICAL()需要另外的8個時鐘周期(總共有20個周期)。這樣,保持中斷禁止狀態(tài)要比簡單的禁止/允許中斷多花16個時鐘周期的時間(至少在80186上是這樣的)。當然,如果用戶有一個速度比較快的處理器(如IntelPentiumⅡ),那么這兩種方法的時間差別會很小。[!--empirenews.page--]

8.03.03OS_STK_GROWTH

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

置OS_STK_GROWTH為0表示堆棧從下往上長。

置OS_STK_GROWTH為1表示堆棧從上往下長。

8.03.04OS_TASK_SW()

OS_TASK_SW()[L8.1(5)]是一個宏,它是在μC/OS-Ⅱ從低優(yōu)先級任務(wù)切換到最高優(yōu)先級任務(wù)時被調(diào)用的。OS_TASK_SW()總是在任務(wù)級代碼中被調(diào)用的。另一個函數(shù)OSIntExit()被用來在ISR使得更高優(yōu)先級任務(wù)處于就緒狀態(tài)時,執(zhí)行任務(wù)切換功能。任務(wù)切換只是簡單的將處理器寄存器保存到將被掛起的任務(wù)的堆棧中, 并且將更高優(yōu)先級的任務(wù)從堆棧中恢復(fù)出來。

在μC/OS-Ⅱ中,處于就緒狀態(tài)的任務(wù)的堆棧結(jié)構(gòu)看起來就像剛發(fā)生過中斷并將所有的寄存器保存到堆棧中的情形一樣。換句話說,μC/OS-Ⅱ要運行處于就緒狀態(tài)的任務(wù)必須要做的事就是將所有處理器寄存器從任務(wù)堆棧中恢復(fù)出來,并且執(zhí)行中斷的返回。為了切換任務(wù)可以通過執(zhí)行OS_TASK_SW()來產(chǎn)生中斷。大部分的處理器會提供軟中斷或是陷阱(TRAP)指令來完成這個功能。ISR或是陷阱處理函數(shù)(也叫做異常處理函數(shù))的向量地址必須指向匯編語言函數(shù)OSCtxSw()(參看8.04.02)。

例如,在Intel或者AMD80x86處理器上可以使用INT指令。但是中斷處理向量需要指向OSCtxSw()。Motorola68HC11處理器使用的是SWI指令,同樣,SWI的向量地址仍是OSCtxSw()。還有,Motorola680x0/CPU32可能會使用16個陷阱指令中的一個。當然,選中的陷阱向量地址還是OSCtxSw()。

一些處理器如ZilogZ80并不提供軟中斷機制。在這種情況下,用戶需要盡自己的所能將堆棧結(jié)構(gòu)設(shè)置成與中斷堆棧結(jié)構(gòu)一樣。OS_TASK_SW()只會簡單的調(diào)用OSCtxSw()而不是將某個向量指向OSCtxSw()。μC/OS已經(jīng)被移植到了Z80處理器上,μC/OS-Ⅱ也同樣可以。

8.04OS_CPU_A.ASM

μC/OS-Ⅱ的移植實例要求用戶編寫四個簡單的匯編語言函數(shù):

OSStartHighRdy()

OSCtxSw()

OSIntCtxSw()

OSTickISR()

如果用戶的編譯器支持插入?yún)R編語言代碼的話, 用戶就可以將所有與處理器相關(guān)的代碼放到OS_CPU_C.C文件中,而不必再擁有一些分散的匯編語言文件。

8.04.01OSStartHighRdy()

使就緒狀態(tài)的任務(wù)開始運行的函數(shù)叫做OSStart(),如下所示。在用戶調(diào)用OSStart()之前,用戶必須至少已經(jīng)建立了自己的一個任務(wù)(參看OSTaskCreate()和OSTaskCteateExt())。OSStartHighRdy()假設(shè)OSTCBHighRdy指向的是優(yōu)先級最高的任務(wù)的任務(wù)控制塊。前面曾提到過,在μC/OS-Ⅱ中處于就緒狀態(tài)的任務(wù)的堆棧結(jié)構(gòu)看起來就像剛發(fā)生過中斷并將所有的寄存器保存到堆棧中的情形一樣。要想運行最高優(yōu)先級任務(wù),用戶所要做的是將所有處理器寄存器按順序從任務(wù)堆棧中恢復(fù)出來,并且執(zhí)行中斷的返回。為了簡單一點,堆棧指針總是儲存在任務(wù)控制塊(即它的OS_TCB)的開頭。換句話說,也就是要想恢復(fù)的任務(wù)堆棧指針總是儲存在OS_TCB的0偏址內(nèi)存單元中。

voidOSStartHighRdy(void)

{

CalluserdefinableOSTaskSwHook();

Getthestackpointerofthetasktoresume:

Stackpointer=OSTCBHighRdy->OSTCBStkPtr;

OSRunning=TRUE;

Restoreallprocessorregistersfromthenewtask‘sstack;

Executeareturnfrominterruptinstruction;

}

注意,OSStartHighRdy()必須調(diào)用OSTaskSwHook(),因為用戶正在進行任務(wù)切換的部分工作——用戶在恢復(fù)最高優(yōu)先級任務(wù)的寄存器。而OSTaskSwHook()可以通過檢查OSRunning來知道是OSStartHighRdy()在調(diào)用它(OSRunning為FALSE)還是正常的任務(wù)切換在調(diào)用它(OSRunning為TRUE).

OSStartHighRdy()還必須在最高優(yōu)先級任務(wù)恢復(fù)之前和調(diào)用OSTaskSwHook()之后設(shè)置OSRunning為TRUE。

8.04.02OSCtxSw()

如前面所述, 任務(wù)級的切換問題是通過發(fā)軟中斷命令或依靠處理器執(zhí)行陷阱指令來完成的。中斷服務(wù)例程,陷阱或異常處理例程的向量地址必須指向OSCtxSw()。

如果當前任務(wù)調(diào)用μC/OS-Ⅱ提供的系統(tǒng)服務(wù),并使得更高優(yōu)先級任務(wù)處于就緒狀態(tài),μC/OS-Ⅱ就會借助上面提到的向量地址找到OSCtxSw()。在系統(tǒng)服務(wù)調(diào)用的最后,μC/OS-Ⅱ會調(diào)用OSSched(),并由此來推斷當前任務(wù)不再是要運行的最重要的任務(wù)了。OSSched()先將最高優(yōu)先級任務(wù)的地址裝載到OSTCBHighRdy中,再通過調(diào)用OS_TASK_SW()來執(zhí)行軟中斷或陷阱指令。注意,變量OSTCBCur早就包含了指向當前任務(wù)的任務(wù)控制塊(OS_TCB)的指針。 軟中斷(或陷阱)指令會強制一些處理器寄存器(比如返回地址和處理器狀態(tài)字)到當前任務(wù)的堆棧中,并使處理器執(zhí)行OSCtxSw()。OSCtxSw()的原型如程序清單L8.2所示。這些代碼必須寫在匯編語言中,因為用戶不能直接從C中訪問CPU寄存器。注意在OSCtxSw()和用戶定義的函數(shù)OSTaskSwHook()的執(zhí)行過程中,中斷是禁止的。

程序清單 L8.2 OSCtxSw()的原型

voidOSCtxSw(void)

{

保存處理器寄存器;

將當前任務(wù)的堆棧指針保存到當前任務(wù)的OS_TCB中:

OSTCBCur->OSTCBStkPtr=Stackpointer;

調(diào)用用戶定義的OSTaskSwHook();

OSTCBCur=OSTCBHighRdy;

OSPrioCur=OSPrioHighRdy;

得到需要恢復(fù)的任務(wù)的堆棧指針:

Stackpointer=OSTCBHighRdy->OSTCBStkPtr;

將所有處理器寄存器從新任務(wù)的堆棧中恢復(fù)出來;

執(zhí)行中斷返回指令;

}

8.04.03OSIntCtxSw()

OSIntExit()通過調(diào)用OSIntCtxSw()來從ISR中執(zhí)行切換功能。 因為OSIntCtxSw()是在ISR中被調(diào)用的,所以可以斷定所有的處理器寄存器都被正確地保存到了被中斷的任務(wù)的堆棧之中。實際上除了我們需要的東西外,堆棧結(jié)構(gòu)中還有其它的一些東西。OSIntCtxSw()必須要清理堆棧,這樣被中斷的任務(wù)的堆棧結(jié)構(gòu)內(nèi)容才能滿足我們的需要。

要想了解OSIntCtxSw(),用戶可以看看μC/OS-Ⅱ調(diào)用該函數(shù)的過程。用戶可以參看圖8.2來幫助理解下面的描述。假定中斷不能嵌套(即ISR不會被中斷),中斷是允許的,并且處理器正在執(zhí)行任務(wù)級的代碼。當中斷來臨的時候,處理器會結(jié)束當前的指令,識別中斷并且初始化中斷處理過程, 包括將處理器的狀態(tài)寄存器和返回被中斷的任務(wù)的地址保存到堆棧中[F8.2(1)]。至于究竟哪些寄存器保存到了堆棧上,以及保存的順序是怎樣的,并不重要。[!--empirenews.page--]

圖 8.2 在ISR執(zhí)行過程中的堆棧內(nèi)容.

接著,CPU會調(diào)用正確的ISR。μC/OS-Ⅱ要求用戶的ISR在開始時要保存剩下的處理器寄存器[F8.2(2)]。一旦寄存器保存好了,μC/OS-Ⅱ就要求用戶或者調(diào)用OSIntEnter(),或者將變量OSIntNesting加1。在這個時候,被中斷任務(wù)的堆棧中只包含了被中斷任務(wù)的寄存器內(nèi)容。現(xiàn)在,ISR可以執(zhí)行中斷服務(wù)了。并且如果ISR發(fā)消息給任務(wù)(通過調(diào)用OSMboxPost()或OSQPost()), 恢復(fù)任務(wù)(通過調(diào)用OSTaskResume()), 或者調(diào)用OSTimeTick()或OSTimeDlyResume()的話,有可能使更高優(yōu)先級的任務(wù)處于就緒狀態(tài)。

假設(shè)有一個更高優(yōu)先級的任務(wù)處于就緒狀態(tài)。μC/OS-Ⅱ要求用戶的ISR在完成中斷服務(wù)的時候調(diào)用OSIntExit()。OSIntExit()會告訴μC/OS-Ⅱ到了返回任務(wù)級代碼的時間了。

調(diào)用OSIntExit()會導(dǎo)致調(diào)用者的返回地址被保存到被中斷的任務(wù)的堆棧中[F8.2(3)]。

OSIntExit()剛開始時會禁止中斷,因為它需要執(zhí)行臨界段的代碼。根據(jù)OS_ENTER_CRITICAL()的不同執(zhí)行過程(參看8.03.02),處理器的狀態(tài)寄存器會被保存到被中斷的任務(wù)的堆棧中[F8.2(4)]。OSIntExit()注意到由于有更高優(yōu)先級的任務(wù)處于就緒狀態(tài),被中斷的任務(wù)已經(jīng)不再是要繼續(xù)執(zhí)行的任務(wù)了。在這種情況下,指針OSTCBHighRdy會被指向新任務(wù)的OS_TCB,并且OSIntExit()會調(diào)用OSIntCtxSw()來執(zhí)行任務(wù)切換。調(diào)用OSIntCtxSw()也同樣使返回地址被保存到被中斷的任務(wù)的堆棧中[F8.2(5)]。

在用戶切換任務(wù)的時候,用戶只想將某些項([F8.2(1)]和[F8.2(2)])保留在堆棧中,并忽略其它項(F8.2(3),(4)和(5)) 。這是通過調(diào)整堆棧指針(加一個數(shù)在堆棧指針上)來完成的[F8.2(6)]。加在堆棧指針上的數(shù)必須是明確的,而這個數(shù)主要依賴于移植的目標處理器(地址空間可能是16,32或64位),所用的編譯器,編譯器選項,內(nèi)存模式等等。另外,處理器狀態(tài)字可能是8,16,32甚至64位寬,并且OSIntExit()可能會分配局部變量。有些處理器允許用戶直接增加常量到堆棧指針中,而有些則不允許。在后一種情況下,可以通過簡單的執(zhí)行一定數(shù)量的pop(出棧)指令來實現(xiàn)相同的功能。一旦堆棧指針完成調(diào)整,新的堆棧指針會被保存到被切換出去的任務(wù)的OS_TCB中[F8.2(7)]。

OSIntCtxSw()的原型如程序清單L8.3所示。這些代碼必須寫在匯編語言中,因為用戶不能直接從C語言中訪問CPU寄存器。如果用戶的編譯器支持插入?yún)R編語言代碼的話,用戶就可以將OSIntCtxSw()代碼放到OS_CPU_C.C文件中,而不放到OS_CPU_A.ASM文件中。正如用戶所看到的那樣,除了第一行以外,OSIntCtxSw()的代碼與OSCtxSw()是一樣的。這樣在移植實例中,用戶可以通過“跳轉(zhuǎn)”到OSCtxSw()中來減少 OSIntCtxSw()代碼量。

程序清單 L8.3 OSIntCtxSw()的原型

voidOSIntCtxSw(void)

{

調(diào)整堆棧指針來去掉在調(diào)用:

OSIntExit(),

OSIntCtxSw()過程中壓入堆棧的多余內(nèi)容;

將當前任務(wù)堆棧指針保存到當前任務(wù)的OS_TCB中:

OSTCBCur->OSTCBStkPtr= 堆棧指針;

調(diào)用用戶定義的OSTaskSwHook();

OSTCBCur=OSTCBHighRdy;

OSPrioCur=OSPrioHighRdy;

得到需要恢復(fù)的任務(wù)的堆棧指針:

堆棧指針 =OSTCBHighRdy->OSTCBStkPtr;

將所有處理器寄存器從新任務(wù)的堆棧中恢復(fù)出來;

執(zhí)行中斷返回指令;

}

OSIntCtxSw()是μC/OS-Ⅱ(和μC/OS)中唯一的與編譯器相關(guān)的函數(shù);在我收到的e-mail中,關(guān)于該函數(shù)的e-mail明顯多于關(guān)于μC/OS其它方面的。如果在多次任務(wù)切換后用戶的系統(tǒng)崩潰了,用戶應(yīng)該懷疑堆棧指針在OSIntCtxSw()中是否被正確地調(diào)整了。

8.04.04OSTickISR()

μC/OS-Ⅱ要求用戶提供一個時鐘資源來實現(xiàn)時間的延時和期滿功能。時鐘節(jié)拍應(yīng)該每秒鐘發(fā)生10-100次。 為了完成該任務(wù), 可以使用硬件時鐘, 也可以從交流電中獲得50/60Hz的時鐘頻率。

用戶必須在開始多任務(wù)調(diào)度后(即調(diào)用OSStart()后)允許時鐘節(jié)拍中斷。換句話說,就是用戶應(yīng)該在OSStart()運行后,μC/OS-Ⅱ啟動運行的第一個任務(wù)中初始化節(jié)拍中斷。通常所犯的錯誤是在調(diào)用OSInit()和OSStart()之間允許時鐘節(jié)拍中斷(如程序清單L8.4所示)。

程序清單 L8.4 在不正確的位置啟動時鐘節(jié)拍中斷

voidmain(void)

{

.

.

OSInit();/* 初始化 ? μC/OS-II*/

.

.

/* 應(yīng)用程序初始化代碼 ...*/

/*... 調(diào)用OSTaskCreate()建立至少一個任務(wù) */

.

.

允許時鐘節(jié)拍中斷;/* 千萬不要在這里允許!!! */

.

.

OSStart();/* 開始多任務(wù)調(diào)度 */

}

有可能在μC/OS-Ⅱ開始執(zhí)行第一個任務(wù)前時鐘節(jié)拍中斷就發(fā)生了。在這種情況下,μC/OS-Ⅱ的運行狀態(tài)不確定,用戶的應(yīng)用程序也可能會崩潰。

時鐘節(jié)拍ISR的原型如程序清單L8.5所示。這些代碼必須寫在匯編語言中,因為用戶不能直接從C語言中訪問CPU寄存器。如果用戶的處理器可以通過單條指令來增加OSIntNesting,那么用戶就沒必要調(diào)用 OSIntEnter()了。增加OSIntNesting要比通過函數(shù)調(diào)用和返回快得多。OSIntEnter()只增加OSIntNesting,并且作為臨界段代碼中受到保護。

程序清單 L8.5 時鐘節(jié)拍ISR的原型

voidOSTickISR(void)

{

保存處理器寄存器;

調(diào)用OSIntEnter()或者直接將 OSIntNesting加1;

調(diào)用OSTimeTick();

調(diào)用OSIntExit();

恢復(fù)處理器寄存器;

執(zhí)行中斷返回指令;

}

8.05OS_CPU_C.C

μC/OS-Ⅱ的移植實例要求用戶編寫六個簡單的C函數(shù):

OSTaskStkInit()

OSTaskCreateHook()

OSTaskDelHook()

OSTaskSwHook()

OSTaskStatHook()

OSTimeTickHook()

唯一必要的函數(shù)是OSTaskStkInit(),其它五個函數(shù)必須得聲明但沒必要包含代碼。[!--empirenews.page--]

8.05.01OSTaskStkInt()

OSTaskCreate()和OSTaskCreateExt()通過調(diào)用OSTaskStkInt()來初始化任務(wù)的堆棧結(jié)構(gòu),因此,堆??雌饋砭拖駝偘l(fā)生過中斷并將所有的寄存器保存到堆棧中的情形一樣。圖8.3顯示了OSTaskStkInt()放到正被建立的任務(wù)堆棧中的東西。注意,在這里我假定了堆棧是從上往下長的。下面的討論同樣適用于從下往上長的堆棧。

在用戶建立任務(wù)的時候,用戶會傳遞任務(wù)的地址,pdata指針,任務(wù)的堆棧棧頂和任務(wù)的優(yōu)先級給OSTaskCreate()和OSTaskCreateExt()。雖然OSTaskCreateExt()還要求有其它的參數(shù),但這些參數(shù)在討論OSTaskStkInt()的時候是無關(guān)緊要的。為了正確初始化堆棧結(jié)構(gòu),OSTaskStkInt()只要求剛才提到的前三個參數(shù)和一個附加的選項,這個選項只能在OSTaskCreateExt()中得到。

圖 8.3 堆棧初始化(pdata通過堆棧傳遞)

回顧一下,在μC/OS-Ⅱ中,無限循環(huán)的任務(wù)看起來就像其它的C函數(shù)一樣。當任務(wù)開始被μC/OS-Ⅱ執(zhí)行時,任務(wù)就會收到一個參數(shù),好像它被其它的任務(wù)調(diào)用一樣。

voidMyTask(void*pdata)

{

/* 對‘pdata‘做某些操作 */

for(;;){

/* 任務(wù)代碼 */

}

}

如果我想從其它的函數(shù)中調(diào)用MyTask(),C編譯器就會先將調(diào)用MyTask()的函數(shù)的返回地址保存到堆棧中,再將參數(shù)保存到堆棧中。實際上有些編譯器會將pdata參數(shù)傳至一個或多個寄存器中。在后面我會討論這類情況。假定pdata會被編譯器保存到堆棧中,OSTaskStkInit()就會簡單的模仿編譯器的這種動作,將pdata保存到堆棧中[F8.3(1)]。但是結(jié)果表明,與C函數(shù)調(diào)用不一樣,調(diào)用者的返回地址是未知的。用戶所擁有的是任務(wù)的開始地址,而不是調(diào)用該函數(shù)(任務(wù))的函數(shù)的返回地址!事實上用戶不必太在意這點,因為任務(wù)并不希望返回到其它函數(shù)中。

這時,用戶需要將寄存器保存到堆棧中,當處理器發(fā)現(xiàn)并開始執(zhí)行中斷的時候,它會自動地完成該過程的。一些處理器會將所有的寄存器存入堆棧,而其它一些處理器只將部分寄存器存入堆棧。一般而言,處理器至少得將程序計數(shù)器的值(中斷返回地址)和處理器的狀態(tài)字存入堆棧[F8.3(2)]。很明顯,處理器是按一定的順序?qū)⒓拇嫫鞔嫒攵褩5?,而用戶在將寄存器存入堆棧的時候也就必須依照這一順序。

接著,用戶需要將剩下的處理器寄存器保存到堆棧中[F8.3(3)]。保存的命令依賴于用戶的處理器是否允許用戶保存它們。 有些處理器用一個或多個指令就可以馬上將許多寄存器都保存起來。用戶必須用特定的指令來完成這一過程。例如,Intel80x86使用PUSHA指令將8個寄存器保存到堆棧中。對Motorola68HC11處理器而言,在中斷響應(yīng)期間,所有的寄存器都會按一定順序自動的保存到堆棧中,所以在用戶將寄存器存入堆棧的時候,也必須依照這一順序。

現(xiàn)在是時候討論這個問題了: 如果用戶的C編譯器將pdata參數(shù)傳遞到寄存器中而不是堆棧中該作些什么?用戶需要從編譯器的文檔中找到pdata儲存在哪個寄存器中。pdata的內(nèi)容就會隨著這個寄存器的儲存被放置在堆棧中。

圖 8.4 堆棧初始化(pdata通過寄存器傳遞)

一旦用戶初始化了堆棧,OSTaskStkInit()就需要返回堆棧指針所指的地址[F8.3(4)]。

OSTaskCreate()和OSTaskCreateExt()會獲得該地址并將它保存到任務(wù)控制塊(OS_TCB)中。

處理器文檔會告訴用戶堆棧指針會指向下一個堆??臻e位置, 還是會指向最后存入數(shù)據(jù)的堆棧單元位置。例如,對Intel80x86處理器而言,堆棧指針會指向最后存入數(shù)據(jù)的堆棧單元位置,而對Motorola68HC11處理器而言,堆棧指針會指向下一個空閑的位置。

8.05.02OSTaskCreateHook()

當用OSTaskCreate()或OSTaskCreateExt()建立任務(wù)的時候就會調(diào)用OSTaskCreateHook()。該函數(shù)允許用戶或使用用戶的移植實例的用戶擴展μC/OS-Ⅱ的功能。

當μC/OS-Ⅱ設(shè)置完了自己的內(nèi)部結(jié)構(gòu)后,會在調(diào)用任務(wù)調(diào)度程序之前調(diào)用OSTaskCreateHook()。該函數(shù)被調(diào)用的時候中斷是禁止的。因此用戶應(yīng)盡量減少該函數(shù)中的代碼以縮短中斷的響應(yīng)時間。

當OSTaskCreateHook()被調(diào)用的時候,它會收到指向已建立任務(wù)的OS_TCB的指針,這樣它就可以訪問所有的結(jié)構(gòu)成員了。當使用OSTaskCreate()建立任務(wù)時,OSTaskCreateHook()的功能是有限的。但當用戶使用OSTaskCreateExt()建立任務(wù)時,用戶會得到OS_TCB中的擴展指針OSTCBExtPtr),該指針可用來訪問任務(wù)的附加數(shù)據(jù),如浮點寄存器,MMU寄存器,任務(wù)計數(shù)器的內(nèi)容,以及調(diào)試信息。

只用當OS_CFG.H中的OS_CPU_HOOKS_EN被置為1時才會產(chǎn)生OSTaskCreateHook()的代碼。這樣,使用用戶的移植實例的用戶可以在其它的文件中重新定義hook函數(shù)。

8.05.03OSTaskDelHook()

當任務(wù)被刪除的時候就會調(diào)用OSTaskDelHook()。 該函數(shù)在把任務(wù)從μC/OS-Ⅱ的內(nèi)部任務(wù)鏈表中解開之前被調(diào)用。當OSTaskDelHook()被調(diào)用的時候,它會收到指向正被刪除任務(wù)的OS_TCB的指針, 這樣它就可以訪問所有的結(jié)構(gòu)成員了。 OSTaskDelHook()可以用來檢驗TCB擴展是否被建立了(一個非空指針)并進行一些清除操作。OSTaskDelHook()不返回任何值。

只用當OS_CFG.H中的OS_CPU_HOOKS_EN被置為1時才會產(chǎn)生OSTaskDelHook()的代碼。

8.05.04OSTaskSwHook()

當發(fā)生任務(wù)切換的時候調(diào)用OSTaskSwHook()。不管任務(wù)切換是通過OSCtxSw()還是OSIntCtxSw()來執(zhí)行的都會調(diào)用該函數(shù)。OSTaskSwHook()可以直接訪問OSTCBCur和OSTCBHighRdy,因為它們是全局變量。OSTCBCur指向被切換出去的任務(wù)的OS_TCB,而OSTCBHighRdy指向新任務(wù)的OS_TCB。 注意在調(diào)用OSTaskSwHook()期間中斷一直是被禁止的。

因為代碼的多少會影響到中斷的響應(yīng)時間,所以用戶應(yīng)盡量使代碼簡化。OSTaskSwHook()沒有任何參數(shù),也不返回任何值。

[!--empirenews.page--]

只用當OS_CFG.H中的OS_CPU_HOOKS_EN被置為1時才會產(chǎn)生 OSTaskSwHook()的代碼。

8.05.05OSTaskStatHook()

OSTaskStatHook()每秒鐘都會被OSTaskStat()調(diào)用一次。用戶可以用OSTaskStatHook()來擴展統(tǒng)計功能。例如,用戶可以保持并顯示每個任務(wù)的執(zhí)行時間,每個任務(wù)所用的CPU份額,以及每個任務(wù)執(zhí)行的頻率等等。OSTaskStatHook()沒有任何參數(shù),也不返回任何值。

只用當OS_CFG.H中的OS_CPU_HOOKS_EN被置為1時才會產(chǎn)生OSTaskStatHook()的代碼。

8.05.06OSTimeTickHook()

OSTaskTimeHook()在每個時鐘節(jié)拍都會被OSTaskTick()調(diào)用。實際上,OSTaskTimeHook()是在節(jié)拍被μC/OS-Ⅱ真正處理,并通知用戶的移植實例或應(yīng)用程序之前被調(diào)用的。OSTaskTimeHook()沒有任何參數(shù),也不返回任何值。

只用當OS_CFG.H中的OS_CPU_HOOKS_EN被置為1時才會產(chǎn)生OSTaskTimeHook()的代碼。

無論何時建立任務(wù),在分配好和初始化TCB后就會調(diào)用該函數(shù),當然任務(wù)的堆棧結(jié)構(gòu)也已經(jīng)初始化好了。OSTaskCreateHook()允許用戶用自己的方式來擴展任務(wù)建立函數(shù)的功能。例如用戶可以初始化和存儲與任務(wù)相關(guān)的浮點寄存器,MMU寄存器以及其它寄存器的內(nèi)容。通常,用戶可以存儲用戶的應(yīng)用程序所分配的附加的內(nèi)存信息。用戶還可以通過使用OSTaskCreateHook()來觸發(fā)示波器或邏輯分析儀,以及設(shè)置斷點。

參數(shù)

ptcb是指向所創(chuàng)建任務(wù)的任務(wù)控制塊的指針。

返回值

注意事項

該函數(shù)在被調(diào)用的時候中斷是禁止的。 因此用戶應(yīng)盡量減少該函數(shù)中的代碼以縮短中斷

的響應(yīng)時間。

范例

該例子假定了用戶是用OSTaskCreateExt()建立任務(wù)的,因為它希望在任務(wù)OS_TCB中

有.OSTCBExtPtr域,該域包含了指向浮點寄存器的指針。

VoidOSTaskCreateHook(OS_TCB*ptcb)

{

if(ptcb->OSTCBExtPtr!=(void*)0){

/* 儲存浮點寄存器的內(nèi)容到..*/

/*..TCB擴展域中 */

}

}

當用戶通過調(diào)用OSTaskDel()來刪除任務(wù)時都會調(diào)用該函數(shù)。這樣用戶就可以處理OSTaskCreateHook()所分配的內(nèi)存。 OSTaskDelHook()就在TCB從TCB鏈中被移除前被調(diào)用。

用戶還可以通過使用OSTaskDelHook()來觸發(fā)示波器或邏輯分析儀,以及設(shè)置斷點。

參數(shù)

ptcb是指向所創(chuàng)建任務(wù)的任務(wù)控制塊的指針。

返回值

注意事項

該函數(shù)在被調(diào)用的時候中斷是禁止的。 因此用戶應(yīng)盡量減少該函數(shù)中的代碼以縮短中斷

的響應(yīng)時間。

范例

voidOSTaskDelHook(OS_TCB*ptcb)

{

/* 輸出信號觸發(fā)示波器 */

}

當執(zhí)行任務(wù)切換時都會調(diào)用該函數(shù)。全局變量OSTCBHighRdy指向得到CPU的任務(wù)的TCB,而OSTCBCur指向被切換出去的任務(wù)的TCB。OSTaskSwHook()在保存好了任務(wù)的寄存器和保存好了指向當前任務(wù)TCB的堆棧指針后馬上被調(diào)用。 用戶可以用該函數(shù)來保存或恢復(fù)浮點寄存器或MMU寄存器的內(nèi)容,來得到任務(wù)執(zhí)行時間的軌跡以及任務(wù)被切換進來的次數(shù)等等。

參數(shù)

返回值

注意事項

該函數(shù)在被調(diào)用的時候中斷是禁止的。 因此用戶應(yīng)盡量減少該函數(shù)中的代碼以縮短中斷的響應(yīng)時間。

范例

voidOSTaskSwHook(void)

{

/* 將浮點寄存器的內(nèi)容儲存在當前任務(wù)的TCB擴展域中。 */

/* 用新任務(wù)的TCB擴展域中的值更新浮點寄存器的內(nèi)容。 */

}

該函數(shù)每秒鐘都會被μC/OS-Ⅱ的統(tǒng)計任務(wù)調(diào)用。OSTaskStatHook()允許用戶加入自己的統(tǒng)計功能。

參數(shù)

返回值

注意事項

統(tǒng)計任務(wù)大概在調(diào)用OSStart()后再過5秒開始執(zhí)行。注意,當OS_TASK_STAT_EN或者

OS_TASK_CREATE_EXT_EN被置為0時,該函數(shù)不會被調(diào)用。

范例

voidOSTaskStatHook(void)

{

/* 計算所有任務(wù)執(zhí)行的總時間 */

/* 計算每個任務(wù)的執(zhí)行時間在總時間內(nèi)所占的百分比 */

}

只要發(fā)生時鐘節(jié)拍,該函數(shù)就會被OSTimeTick()調(diào)用。一旦進入OSTimeTick()就會馬上調(diào)用OSTimeTickHook()以允許執(zhí)行用戶的應(yīng)用程序中的與時間密切相關(guān)的代碼。用戶還可以通過使用該函數(shù)觸發(fā)示波器或邏輯分析儀來調(diào)試,或者為仿真器設(shè)置斷點。

參數(shù)

返回值

注意事項

OSTimeTick()通常是被ISR調(diào)用的, 所以時鐘節(jié)拍ISR的執(zhí)行時間會因為用戶在該函數(shù)

中提供的代碼而增加。當OSTimeTick()被調(diào)用的時候,中斷可以是禁止的也可以是允許的,

這主要取決于該處理器上的移植是怎樣進行的。如果中斷是禁止的,該函數(shù)將會影響到中斷

響應(yīng)時間。

范例

voidOSTimeTickHook(void)

{

/* 觸發(fā)示波器 */

}

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉