摘要:基于嵌入式系統的概念,闡述嵌入式系統的關鍵技術、嵌入式開發以及廣泛的應用。首先,分析嵌入式系統的技術特點,分別從嵌入
式處理器和嵌入式操作系統兩方面介紹,著重說明它不同于其它操作系統的一些處理方法和過程;在此基礎上闡述嵌入式軟件的開發過程,
并結合作者嵌入式軟件開發的實踐,著重闡述嵌入式軟件的一些開發技巧。接著,介紹目前嵌入式系統一些流行的應用,以及南京東大移動
互聯技術有限公司自行研制的基于藍牙技術的嵌入式產品。最后,給出作者的體會,展望嵌入式系統的前景。
關鍵詞:嵌入式系統 嵌入式處理器 微內核 內存管理單元 藍牙系統
引 言
在當前數字信息技術和網絡技術高速發展的后PC(Post-PC)時代,嵌入式系統已經廣泛地滲透到科學研究、工程設計、軍事技術、各
類產業和商業文化藝術以及人們的日常生活等方方面面中。隨著國內外各種嵌入式產品的進一步開發和推廣,嵌入式技術越來越和人們的生活緊密結合。
1970年左右出現了嵌入式系統的概念,此時的嵌入式系統很多都不采用操作系統,它們只是為了實現某個控制功能,使用一個簡單的循
環控制對外界的控制請求進行處理。當應用系統越來越復雜、利用的范圍越來越廣泛的時候,每添加一項新的功能,都可能需要從頭開始設
計。沒有操作系統已成為一個最大的缺點了。
C語言的出現使操作系統開發變得簡單。從上世紀80年代開始,出現了各種各樣的商用嵌入式操作系統百家爭鳴的局面,比較著名的有
VxWorks、pSOS和Windows CE等等,這些操作系統大部分是為專有系統而開發的。另外,源代碼開放的嵌入式Linux,由于其強大的網絡功能
和低成本,近來也得到了越來越多的應用。
1 嵌入式系統的技術特點
嵌入式系統通常包括構成軟件的基本運行環境的硬件和操作系統兩部分。嵌入式系統的運行環境和應用場合決定了嵌入式系統具有區別
于其它操作系統的一些特點。
(1)嵌入式處理器
嵌入式處理器可以分為三類:嵌入式微處理器、嵌入式微控制器、嵌入式DSP(Digital Signal Processor)。嵌入式微處理器就是和通
用計算機的微處理器對應的CPU。在應用中,一般是將微處理器裝配在專門設計的電路板上,在母板上只保留和嵌入式相關的功能即可,這樣
可以滿足嵌入式系統體積小和功耗低的要求。目前的嵌入式處理器主要包括:PowerPC、Motorola 68000、ARM系列等等。
嵌入式微控制器又稱為單片機,它將CPU、存儲器(少量的RAM、ROM或兩者都有)和其它外設封裝在同一片集成電路里。常見的有8051。
嵌入式DSP專門用來對離散時間信號進行極快的處理計算,提高編譯效率和執行速度。在數字濾波、FFT、譜分析、圖像處理的分析等領
域,DSP正在大量進入嵌入式市場。
(2)微內核結構
大多數操作系統至少被劃分為內核層和應用層兩個層次。內核只提供基本的功能,如建立和管理進程、提供文件系統、管理設備等,這些
功能以系統調用方式提供給用戶。一些桌面操作系統,如Windows、Linux等,將許多功能引入內核,操作系統的內核變得越來越大。內核變
大使得占用的資源增多,剪裁起來很麻煩。
大多數嵌入式操作系統采用了微內核結構,內核只提供基本的功能,比如:任務的調度、任務之間的通信與同步、內存管理、時鐘管理
等。其它的應用組件,比如網絡功能、文件系統、GUI系統等均工作在用戶態,以系統進程或函數調用的方式工作。因而系統都是可裁減的,
用戶可以根據自己的需要選用相應的組件。
(3)任務調度
在嵌入式系統中,任務即線程。大多數的嵌入式操作系統支持多任務。多任務運行的實現實際是靠CPU在多個任務之間切換、調度。每個
任務都有其優先級,不同的任務優先級可能相同也可能不同。任務的調度有三種方式:可搶占式調度、不可搶占式調度和時間片輪轉調度。
不可搶占式調度是指,一個任務一旦獲得CPU就獨占CPU運行,除非由于某種原因,它決定放棄CPU的使用權;可搶占式調度是基于任務優先
級的,當前正在運行的任務可以隨時讓位給優先級更高的處于就緒態的其它任務;當兩個或兩個以上任務有同樣的優先級,不同任務輪轉地
使用CPU,直到系統分配的CPU時間片用完,這就是時間片輪轉調度。
目前,大多數嵌入式操作系統對不同優先級的任務采用基于優先級的搶占式調度法,對相同優先級的任務則采用時間片輪轉調度法。
(4)硬實時和軟實時
有些嵌入式系統對時間的要求較高,稱之為實時系統。有兩種類型的實時系統:硬實時系統和軟實時系統。軟實時系統并不要求限定某
一任務必須在一定的時間內完成,只要求各任務運行得越快越好;硬實時系統對系統響應時間有嚴格要求,一旦系統響應時間不能滿足,就
可能會引起系統崩潰或致命的錯誤,一般在工業控制中應用較多。
(5)內存管理
針對有內存管理單元(MMU)的處理器設計的一些桌面操作系統,如Windows、Linux,使用了虛擬存儲器的概念。虛擬內存地址被送到
MMU。在這里,虛擬地址被映射為物理地址,實際存儲器被分割為相同大小的頁面,采用分頁的方式載入進程。一個程序在運行之前,沒有
必要全部裝入內存,而是僅將那些當前要運行的部分頁面裝入內存運行。
大多數嵌入式系統針對沒有MMU的處理器設計,不能使用處理器的虛擬內存管理技術,采用的是實存儲器管理策略。因而對于內存的訪問
是直接的,它對地址的訪問不需要經過MMU,而是直接送到地址線上輸出,所有程序中訪問的地址都是實際的物理地址;而且,大多數嵌入
式操作系統對內存空間沒有保護,各個進程實際上共享一個運行空間。一個進程在執行前,系統必須為它分配足夠的連續地址空間,然后全
部載入主存儲器的連續空間。
由此可見,嵌入式系統的開發人員不得不參與系統的內存管理。從編譯內核開始,開發人員必須告訴系統這塊開發板到底擁有多少內
存;在開發應用程序時,必須考慮內存的分配情況并關注應用程序需要運行空間的大小。另外,由于采用實存儲器管理策略,用戶程序同
內核以及其它用戶程序在一個地址空間,程序開發時要保證不侵犯其它程序的地址空間,以使得程序不至于破壞系統的正常工作,或導致其
它程序的運行異常;因而,嵌入式系統的開發人員對軟件中的一些內存操作要格外小心。
(6)內核加載方式
嵌入式操作系統內核可以在Flash上直接運行,也可以加載到內存中運行。Flash的運行方式,是把內核的可執行映像燒寫到Flash上,
系統啟動時從Flash的某個地址開始執行。這種方法實際上是很多嵌入式系統所采用的方法。內核加載方式是把內核的壓縮文件存放在Flash
上,系統啟動時讀取壓縮文件在內存里解壓,然后開始執行。這種方式相對復雜一些,但是運行速度可能更快,因為RAM的存取速率要比
Flash高。
由于嵌入式系統的內存管理機制,嵌入式操作系統對用戶程序采用靜態鏈接的形式。在嵌入式系統中,應用程序和操作系統內核代碼
編譯、鏈接生成一個二進制影像文件來運行。
2 嵌入式系統開發相關技術
相對于在Windows環境下的開發應用程序,嵌入式系統開發有著很多的不同。不同的硬件平臺和操作系統帶來了許多附加的開發復雜性。
2.1 嵌入式開發過程
在嵌入式開發過程中有宿主機和目標機的角色之分:宿主機是執行編譯、鏈接、定址過程的計算機;目標機指運行嵌入式軟件的硬件
平臺。首先須把應用程序轉換成可以在目標機上運行的二進制代碼。這一過程包含三個步驟:編譯、鏈接、定址。編譯過程由交*編譯器
實現。所謂交*編譯器就是運行在一個計算機平臺上并為另一個平臺產生代碼的編譯器。常用的交*編譯器有GNU C/C++(gcc)。編譯過
程產生的所有目標文件被鏈接成一個目標文件,稱為鏈接過程。定址過程會把物理存儲器地址指定給目標文件的每個相對偏移處。該過程
生成的文件就是可以在嵌入式平臺上執行的二進制文件。
嵌入式開發過程中另一個重要的步驟是調試目標機上的應用程序。嵌入式調試采用交*調試器,一般采用宿主機-目標機的調試方式,
它們之間由串行口線或以太網或BDM線相連。交*調試有任務級、源碼級和匯編級的調試,調試時需將宿主機上的應用程序和操作系統內核
下載到目標機的RAM中或直接燒錄到目標機的ROM中。目標監控器是調試器對目標機上運行的應用程序進行控制的代理(Debugger Agent),
事先被固化在目標機的Flash、ROM中,在目標機上電后自動啟動,并等待宿主機方調試器發來的命令,配合調試器完成應用程序的下載、
運行和基本的調試功能,將調試信息返回給宿主機。
2.2 向嵌入式平臺移植軟件
大部分嵌入式開發人員選用的軟件開發模式是先在PC機上編寫軟件,再進行軟件的移植工作。在PC機上編寫軟件時,要注意軟件的可
移植性,選用具有較高移植性的編程語言(如C語言),盡量少調用操作系統函數,注意屏蔽不同硬件平臺帶來的字節順序、字節對齊等
問題。以下是我們在移植協議棧過程中的一些體會。
2.2.1 字節順序
字節順序是指占內存多于一個字節類型的數據在內存中的存放順序,通常有小端、大端兩種字節順序。小端字節序指低字節數據存放
在內存低地址處,高字節數據存放在內存高地址處;大端字節序是高字節數據存放在低地址處,低字節數據存放在高地址處。基于X86平臺
的PC機是小端字節序的,而有的嵌入式平臺則是大端字節序的。因而對int、uint16、uint32等多于1字節類型的數據,在這些嵌入式平臺
上應該變換其存儲順序。通常我們認為,在空中傳輸的字節的順序即網絡字節序為標準順序,考慮到與協議的一致以及與同類其它平臺產
品的互通,在程序中發數據包時,將主機字節序轉換為網絡字節序,收數據包處將網絡字節序轉換為主機字節序。
2.2.2 字節對齊
有的嵌入式處理器的尋址方式決定了在內存中占2字節的int16、uint16等類型數據只能存放在偶數內存地址處,占4字節的int32 、
uint32 等類型數據只能存放在4的整數倍的內存地址處;占8字節的類型數據只能存放在8的整數倍的內存地址處;而在內存中只占1字節的
類型數據可以存放在任意地址處。由于這些限制,在這些平臺上編程時有很大的不同。首先,結構體成員之間會有空洞,比如這樣一個結
構:
typedef struct test{
char a;
uint16 b;
}TEST
結構TEST在單字節對齊的平臺上占內存三個字節,而在以上所述的嵌入式平臺上有可能占三個或四個字節,視成員a的存儲地址而定。
當a存儲地址為偶數時,該結構占四個字節,在a與b之間存在一個字節的空洞。對于通信雙方都是對結構成員操作的,這種情況不會出錯,
但如果有一方是逐字節讀取內容的(通信協議大都如此),就會錯誤地讀到其它字節的內容。其次,若對內存中數據以強制類型轉換的方
式讀取,字節對齊的不同會引起數據讀取的錯誤。因為假如指針指在基數內存地址處,我們想取得占內存兩個字節的數據存放在uint16型
的變量中,強制類型轉換的結果是取得了該指針所指地址與前一地址處的數據,并沒有按照我們的愿望取該指針所指地址與后一地址處的
數據,這樣就導致了數據讀取的錯誤。
解決字節對齊有許多方法,比如可以在GCC的項目管理文件MakeFile中增加編譯選項--pack-struct;但這種方法只能去除結構中的空
洞,并不能解決強制類型轉換引起的錯誤。為了增強軟件的可移植性以及和同類其它平臺產品的互通性,我們在收數據包處增加了拆包的
函數,發數據包處增加了組包的函數。這兩個函數解決了字節序的問題,也解決了字節對齊的問題。即組包時根據參數中的格式字符串將
內存中的不同數據類型的某段數據放在指定地址處,組成包發給下層;拆包時,根據參數中的格式字符串將收到的內存中的數據存放在不
同類型的變量或結構成員中。在函數中針對不同的數據類型作不同的處理。
2.2.3 位 段
由于位段的空間分配方向因硬件平臺的不同而不同,對X86平臺,位段是從右向左分配的;而一些嵌入式平臺,位段是從左向右分配
的。分配順序的不同導致了數據存取的錯誤。解決這一問題的一種方法是采用條件編譯的方式,針對不同的平臺定義順序不同的位段;
也可以在前面所述的兩個函數中加上對位段的處理。
2.2.4 代碼優化
嵌入式系統對應用軟件的質量要求更高,因而在嵌入式開發中尤其須注意對代碼進行優化,盡可能地提高代碼的效率,減少代碼的大
小。雖然現代C和C++編譯器都提供了一定程度的代碼優化,但大部分由編譯器執行的優化技術僅涉及執行速度和代碼大小的平衡,不可能
使程序既快又小,因而必須在編寫嵌入式軟件時采取必要的措施。
(1)提高代碼的效率
①switch-case 語句。在程序中經常會使用switch-case語句,每一個由機器語言實現的測試和跳轉僅僅是為了決定下一步要做什么,
就浪費了處理器時間。為了提高速度,可以把具體的情況按照它們發生的相對頻率排序。即把最可能發生的情況放在第一,最不可能發生
的情況放在最后,這樣會減少平均的代碼執行時間。
② 全局變量。使用全局變量比向函數傳遞參數更加有效率,這樣做去除了函數調用前參數入棧和函數完成后參數出棧的需要。當然,
使用全局變量會對程序有一些負作用。
(2)減小代碼的大小
嵌入式系統編程應避免使用標準庫例程,因為很多大的庫例程設法處理所有可能的情況,所以占用了龐大的內存空間,因而應盡可能
地減少使用標準庫例程。
(3)避免內存泄漏
用戶內存空間(堆)為RAM中全局數據和任務堆棧空間都分配后的剩余空間,為了使程序能有足夠的內存運行,必須在申請的內存不用
后及時地將其釋放,以確保再次申請時能有空間。如果程序中存在內存泄漏(即申請內存后沒有及時釋放)的情況,程序最終會因為沒有
足夠的內存空間而無法運行。
3 嵌入式系統的廣泛應用
嵌入式系統的應用前景是非常廣泛的,人們將會無時無處不接觸到嵌入式產品,從家里的洗衣機、電冰箱,到作為交通工具的自行車、
小汽車,到辦公室里的遠程會議系統等等。特別是以藍牙為代表的小范圍無線接入協議的出現,使嵌入式無線電的概念悄然興起。當嵌入
式的無線電芯片的價格可被接受時,它的應用可能會無所不在。在家中、辦公室、公共場所,人們可能會使用數十片甚至更多這樣的嵌入
式無線電芯片,將一些電子信息設備甚至電氣設備構成無線網絡;在車上、旅途中,人們利用這樣的嵌入式無線電芯片可以實現遠程辦公、
遠程遙控,真正實現把網絡隨身攜帶。下面介紹幾種具體的應用。
(1)嵌入式移動數據庫
所謂的移動數據庫是支持移動計算的數據庫,有兩層含義:① 用戶在移動的過程中可以聯機訪問數據庫資源。② 用戶可以帶