ARM嵌入式系統(tǒng)C語言編程_第1頁
ARM嵌入式系統(tǒng)C語言編程_第2頁
ARM嵌入式系統(tǒng)C語言編程_第3頁
ARM嵌入式系統(tǒng)C語言編程_第4頁
ARM嵌入式系統(tǒng)C語言編程_第5頁
全文預覽已結束

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、ARM 嵌入式系統(tǒng)C 語言編程 · 字體大小: 小 中 大 作者:姜換新     來源:     日期:2007-03-28     點擊:1443 摘要本文詳細介紹了嵌入式平臺上用C 語言編寫系統(tǒng)軟件和應用軟件的方法。雖然是針對ARM平臺介紹的,但基本經驗和算法也適合于其他嵌入式平臺的軟件設計。1 引言        無操作系統(tǒng)支持的嵌入式軟件包括系統(tǒng)引導(BOOT) 、外圍驅動程序、存儲管理、系統(tǒng)IPO、通信、應用程序等方

2、面,需要結合采用匯編語言(約占10 %) 和C 語言(約占90 %) 。本文結合作者實踐,詳細介紹ARM嵌入式平臺的C 編程方法??紤]到通信軟件涉及范圍較大,本文不進行討論。2 系統(tǒng)引導與main 函數(shù)        通常C 語言是從main 函數(shù)開始的。main 函數(shù)的原型是:int main(int argc ,char 3 3 argv)        其中argc 是參數(shù)的個數(shù), argv 是指向各參數(shù)的指針的數(shù)組。  

3、0;     main 函數(shù)由操作系統(tǒng)內核啟動,操作系統(tǒng)內核完成函數(shù)所需的變量初始化工作,并在調用結束后檢查main 函數(shù)的返回值,若返回值為0 ,表明程序運行正常,否則表明程序運行出錯。在嵌入式系統(tǒng)中,由于沒有操作系統(tǒng)內核存在,對main 函數(shù)的初始化工作只能由系統(tǒng)引導(BOOT) 模塊完成。       系統(tǒng)引導(BOOT) 部分完成系統(tǒng)初始化工作,用匯編語言實現(xiàn)。它的工作包括硬件初始化、棧寄存器的設置、全局變量的初始化或清0、RAM中運行的模塊的加載、堆參數(shù)的初始化等。完成這些工作后,再把

4、控制權交給C 的main 函數(shù)。顯然,對嵌入式系統(tǒng)的main 而言,argc 和argv 這兩個參數(shù)及返回值都是沒有意義的(如果返回,表明系統(tǒng)出現(xiàn)嚴重錯誤) 。另外,為了避免產生混淆,我們還必須給main 函數(shù)另外取一個名字,比如Main。否則,編譯器將會給main 函數(shù)生成一大堆初始化代碼,導致C 程序的主入口與系統(tǒng)引導模塊的接口錯誤。       系統(tǒng)引導模塊完成各種初始化工作后,用一條跳轉指令進入C 的主入口Main ,控制權從此移交給了C 應用程序。3 存儲管理     

5、60;  存儲管理是一個復雜的課題。從廣義的角度來說,磁盤文件系統(tǒng)、內存、片內高速Cache 等都屬于這個范疇。嵌入式系統(tǒng)中,較有意義的是內存的動態(tài)分配與釋放及Flash 存儲器管理兩方面。本文要介紹的是我們在嵌入式系統(tǒng)中實現(xiàn)的動態(tài)內存管理。        C 語言中動態(tài)內存分配與釋放主要由malloc 和free 兩個標準庫函數(shù)實現(xiàn)。malloc 從系統(tǒng)空閑內存中分配合適的內存塊,free 函數(shù)完成內存塊的回收。這兩個函數(shù)一般需要操作系統(tǒng)內核的支持,在ARM 裸平臺上,不能直接調用。為此,我們編寫了m_alloc

6、 和m_free 兩個函數(shù),實現(xiàn)動態(tài)存儲管理的功能。       典型應用程序內存映象分成代碼區(qū)、數(shù)據(jù)區(qū)和棧區(qū),三個區(qū)從低地址到高地址依次分布。代碼區(qū)從最低地址開始,棧區(qū)則占據(jù)最高地址。代碼區(qū)和數(shù)據(jù)區(qū)可以相連,也可以分開。嵌入式系統(tǒng)里,代碼區(qū)位于只讀存儲器(如Flash) 中,數(shù)據(jù)區(qū)和棧區(qū)則位于RAM中,因此代碼區(qū)和數(shù)據(jù)區(qū)一般并不相連1) 。數(shù)據(jù)區(qū)和棧區(qū)是分開的,它們之間的空隙稱作堆。       堆作為一個連續(xù)的可利用空間,是系統(tǒng)的初始可分配塊。  &#

7、160;   每次應用程序申請內存,m_alloc 便從堆中分割出一塊(從低地址開始) 給它。隨著申請次數(shù)的增加,原來一個完整的內存塊便被分割為多個獨立的塊分配給應用程序。由于內存釋放的先后順序是隨機的,因此一定時間后,系統(tǒng)中將存在多個互不相連的內存塊。這就使得整個內存區(qū)呈現(xiàn)出占用塊和空閑塊犬牙交錯的狀態(tài),如圖1 所示。圖中灰色部分表示內存被占用,白色部分表示未被占用。        為了進行內存動態(tài)管理,需要維護兩張全局表,一張是可利用空間表(avail list) ,管理空閑內存塊的信息,另

8、一張是已分配空間表(used_list) ,管理占用內存塊。這兩張表都用雙向循環(huán)鏈表實現(xiàn)。隨著系統(tǒng)的運行,可利用空間表中往往會有多個空閑塊存在,究竟分配哪一塊呢? 文 1 介紹了三種不同的分配策略,即首次擬合法、最佳擬合法和最差擬合法,各有優(yōu)缺點。筆者實現(xiàn)的是首次擬合法。       可利用空間表和已分配空間表采用相同的“表元”數(shù)據(jù)結構,定義如下:struct mblockstruct mblock *next ;    struct mblock * prev ; 

9、0;  size_t size ;    char *space ; ;       在系統(tǒng)初始化時,整個可分配內存塊是一個連續(xù)的存儲區(qū),可利用空間表的元素只有一個。m_alloc 函數(shù)每次分配內存時,先檢查size (m_alloc 的參數(shù)) 是否合法(如是否超出堆的范圍) ,若合法,再將其與32 - bit 字對齊,然后從avail_list 中搜索合適的內存塊,并將其分配給應用程序。如果內存塊的大小比size 大得較多,則對內存塊進行分裂,低地址的一塊分配給應用程序,高地址的一塊

10、仍然放入avail_list 中。如果搜索不到合適的空閑塊,m_alloc 返回(void 3 ) 0。       m_free 函數(shù)釋放內存時,根據(jù)參數(shù)addr 給定的地址,在used_list 中搜索相應的表元,找到后,將它標識的內存塊釋放,并插入到avail_list 中去。然后,在avail_list 中檢查是否有相鄰的空閑塊,并進行空閑塊的合并。有三種不同的情況要分別處理:1. 左相鄰:相鄰塊在當前釋放塊的低地址端。 2. 右相鄰:相鄰塊在當前釋放塊的高地址端。 3. 左右相鄰:當前釋放塊的低地址端和高地址端都有相鄰塊。

11、   在具體的分配算法上,文1 介紹了邊界標識法和伙伴系統(tǒng)。前者直接將鏈表管理信息插入到內存塊的前端和后端,回收算法效率較高,但如果應用程序改寫了超出它所申請范圍的內存區(qū),則會破壞整個數(shù)據(jù)結構,魯棒性差一些。后者是筆者采用的算法之一,但使用下來發(fā)現(xiàn)它沒有本文所描述的算法的效率高,且容易形成很多內存碎片。4 LCD 終端( 系統(tǒng)I/O)        LCD 終端軟件是系統(tǒng)I/ O 范疇的重要內容,主要包括LCD字符顯示(英文8 ×16 點陣,漢字16 ×16 點陣) ,LCD 繪圖(點

12、、線、圓、面、位圖、圖形旋轉等) 。320 ×240 象素的LCD 顯示器,能顯示15 行×40 列英文字符,或15 行×20 列漢字字符,并基本實現(xiàn)有較好分辨率的圖形/ 圖像的顯示。         LCD 顯示的最基本程序是畫點程序,其原型如下:void LCDPixel (int x , int y ,char color)        其中,x 和y 是點的坐標,坐標原點在左上角,color 是點的灰度。&

13、#160;       字符和位圖的顯示利用了點陣方式。線、圓和面則利用相應的算法實現(xiàn)。圖形旋轉需要使用坐標變換函數(shù)。        這里要詳細介紹的是把LCD 作為(英文) 字符型終端時的相應軟件設計。把LCD 作為字符型終端時,一個關鍵點是定義好光標:static unsigned CurrentLine ,CurrentColumn        這里CurrentLine 和Cu

14、rrentColumn 分別定義了光標的橫坐標和縱坐標(坐標原點在左上角) ,取值范圍分別是(039) 和(014) ,對應于橫行40 個字符和縱列15 個字符。       定義好光標后,每次向屏幕輸出字符時,總是從光標處開始,這樣就保證了輸出的有序性和連貫性。向屏幕輸出字符串的基本函數(shù)是Printf ,其原型如下:void Printf (const char * fmt ,  )       這是一個可變參數(shù)函數(shù),功能上與printf 標準

15、庫函數(shù)完全相似。為了實現(xiàn)可變參數(shù)的處理,要使用stdarg. h 中定義一些宏。      Printf 分析每個格式字符,并對各轉義字符(如 n , t , b , r , v 等) 進行相應處理。在屏幕的合適位置打印格式化后的字符串。Printf 還調用一個滾屏函數(shù)ScreenScroll ,當光標位于末行時讓屏幕向上滾動若干行。      Printf 函數(shù)不僅為LCD 作為字符型終端提供了一個好的手段,同時也為程序的調試提供了便利。我們可以在程序可能出錯的地方用Printf 函數(shù)打印一些

16、信息,這為我們對程序的跟蹤提供了相當大的方便。Printf 函數(shù)在嵌入式系統(tǒng)編程中使用是十分明顯的。5 驅動程序設計      驅動程序包括最底層的中斷處理程序設計和建立在其上的驅動程序設計兩個部分,其實現(xiàn)與具體的外圍設備有關,復雜性較大。這里只介紹用C 語言設計驅動程序時需要注意的一些方面。      外圍硬件設備一般通過中斷與CPU 進行通信。中斷是一種外部異步事件。在處理與中斷相關的變量時,需要小心。通常,編譯器的優(yōu)化選項打開后,對變量的操作,將盡量安排在寄存器中。中斷服務程序常常通過改變

17、一些全局變量來通知應用程序某個外部事件已經發(fā)生,這些全局變量是不應該被優(yōu)化的。解決的辦法是在聲明變量時加上volatile修飾符,以通知編譯器這是一個可能被異步事件改變的量。這個問題看似簡單,但如果不注意,實際運行時,程序將出現(xiàn)錯誤,且調試時很難定位故障。       運行效率是設計驅動程序的另外一個問題。中斷比較頻繁的外設,其中斷處理程序的速度對整個系統(tǒng)的性能影響是很大的。這些模塊應該直接用匯編語言編寫,并盡可能優(yōu)化算法。      C 語言的編寫風格也要為效率考慮。例如對

18、數(shù)組元素的操作“Array id/4 = 1 ;”就不如改為“Array idx > > 2 = 1 ;”這里?!?>> ”是移位運算,有相應的機器指令,而“/ ”是除法運算,算法要復雜得多。當然,先進的編譯器一般能優(yōu)化這類的語句,但不能保證所有編譯器都有此功能。6 應用程序設計      嵌入式裸平臺上的應用程序設計也有與PC 機上的應用程序設計不同的地方,需要格外注意。      首先,凡是由需操作系統(tǒng)支持的標準庫函數(shù)均不能使用,除非自己編寫(如m_alloc 和m_

19、free) 。      其次,由于內存資源有限,棧容量有限且不能自動擴展,使用時要格外小心。常常能見到這樣的局部變量的應用:int buf 2048       其目的是要申請一個2048word(8192Byte) 的緩沖區(qū),對于嵌入式系統(tǒng)來說,開銷過于龐大。同時,??臻g中用于嵌套調用的開銷是不可見的,在嵌套層數(shù)較多時尤其如此。一下子申請這么大的??臻g,對系統(tǒng)是一個大的挑戰(zhàn),搞不好系統(tǒng)會崩潰。我們可以采用類似于下面的替代方式:int * buf ;if ( (buf = m_alloc (2048 * sizeof (int) ) ) = = NULL)return ERROR;/* other processing */m_free (buf) ;.      堆的操作比棧更靈活,也更好控制。如果m_alloc 調用成功,它將返回分配的內存塊的地址,否則返回0。如果返回0 ,表明系統(tǒng)內存已經所剩不多,這時程序員可以采取別的措施來解決

溫馨提示

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

評論

0/150

提交評論