標籤:

要認識嵌入式Linux,看這一篇就夠了

要認識嵌入式Linux,看這一篇就夠了

嵌入式Linux跟桌面Linux一樣,是一個操作系統。從單片機走過來的童鞋往往習慣於直接控制寄存器,事必躬親,從零開始實現想要的功能。而在嵌入式Linux的世界裡,我們首先要拋棄這個思想,應把它作為最後沒辦法的辦法。

就像我們想要在windows系統中編寫一個程序,首先想到的不是操作CPU晶元的寄存器,而是學習Windows API一樣。我們在嵌入式linux編程時,首先想到的應該是使用現成的驅動或軟體或Linux API。沒有的話看看能不能修改一下現成的資源為己所用。還是不行的話才考慮自己從頭開始寫。

嵌入式Linux大廈是由很多層組成的,當我們想找一個人時,首先要明確他在那一層樓。同樣的,我們遇到問題時,首先要知道是哪個方面的問題,然後才有可能知道到哪裡尋找答案。下面我們把這座大廈進行一下拆解。

我們平時使用Linux系統的話,最常用的工具就是Shell(或者用windows中常見的說法:命令行),初學者接觸Linux的第一個東西往往也是shell。也許你已經知道,把shell命令組合起來寫成一個文件,亦即shell編程,也是一門大學問,它能做的事很多很強大,但僅限於對Linux系統的操作。

我們一定不會用shell命令去編寫一個顯示屏程序,或者一個GPS導航程序。而且作為嵌入式Linux開發來說,shell不可能作為最終產品工作的平台,因為我們不能要求用戶在屏幕中輸入代碼來實現功能。因此我認為對嵌入式開發來說,shell命令無需深究,掌握基本操作就夠了。

shell基本操作主要包括:獲取命令幫助,到達指定目錄,查看目錄內容,許可權修改,文件的複製粘貼等基本操作,文件搜索,文件內容查看和編輯,系統關機重啟……(這些只是最基本的,後面再慢慢學別的命令,比如學習進程編程時,再學習進程相關的命令;學習C語言編程時,再學各種編譯和調試命令也不遲)

學習嵌入式Linux,我們的最終目的是製作一套嵌入式系統來實現功能。往往需要用C/C++或Python等其他語言來編寫程序,但是編程之前我們要先明確一些基本概念。

最基本的,當我們編寫程序時,首先要明確嵌入式Linux分為用戶空間和內核空間。用戶空間是應用程序運行的空間,內核空間就是操作系統和驅動程序運行的空間。這是從軟體的角度來說的,對應於ARM晶元來說,就是晶元的不同「工作模式」。這兩個空間是通過「地理隔離」實現互相完全獨立的,它們各自的程序使用不同的內存地址區間,各自使用自己的頭文件(有些頭文件在兩個空間內甚至是重名的,要注意區分)、各自調用屬於自己空間的函數(哪怕實現的功能相同,比如printf()和printk()),而且不能互相直接訪問(用指針也不行)。(意味著學習這兩部分的編程時要學習兩套獨立的知識體系)

內核空間相關的東西有:Linux內核源碼、內核編譯和配置、內核移植、文件系統、Busybox、設備驅動程序編寫、中斷編程……

用戶空間相關的東西有:Shell、應用程序編譯和調試、進程、線程、文件IO編程、網路通信相關、Qt圖形界面編程……

如果你僅僅要開發應用程序,那你就可以遠離內核空間那些東西了。對你來說,驅動程序、底層硬體、操作系統的工作方式等都是透明的,你寫的程序在別的晶元上也能跑得很好。

但如果你想要開發驅動程序,或者定製自己的操作系統,或者你想向一片「全裸」晶元中寫入操作系統,並使它正常運行起來,那就得學習內核空間的知識了。

如果你想讓「全裸」晶元運行起來,還會遇到一塊比內核更底層的東西,Bootloader。它是在內核啟動前運行的一段程序,用來初始化硬體、建立內存空間映射等,與晶元的品牌、型號極其相關。我們通常對一些現成的Bootloader進行修改來滿足需求,常見的Bootloader有U-Boot、Vivi等。

再多說一句,如果想從零開始做一個嵌入式設備,還有更底層的問題需要解決和學習:電路設計、PCB布線等。

因此,我們看到的嵌入式Linux書籍就可以粗略分成兩個方向:一類講嵌入式Linux應用程序編程,另一類講如何搭建一個完整的嵌入式Linux平台。分別對應的就是用戶空間和內核空間的事情。

雖然用戶空間和內核空間是獨立的,但就像Windows提供了API,允許我們對系統進行操作一樣,用戶空間的程序也可以通過系統調用來訪問內核(就是一些的C語言函數)。但由於系統調用非常基礎,所以有時使用起來很麻煩。比如說一個簡單的給變數分配內存空間的操作,就需要動用多個系統調用。Linux定義一些庫函數(API)來將系統調用組合成某些常用的功能,以方便我們編程(同樣是C語言函數)。因此,我們在讀別人的程序時,就要區分其中的函數是系統調用,還是庫函數,還是C/C++標準庫中的函數,還是用戶自己定義的函數。如果是前三者,就可以到各個地方搜索相應的資料,這樣學習起來就快很多。

那麼shell程序和我們用C/C++編寫的程序有什麼區別呢?事實上,我們在shell中寫的每一個命令,都對應了一個程序,在程序內部就是通過調用各種API來實現相應功能的。因此用shell能實現的功能,理論上都能用C語言實現。

作為嵌入式Linux開發初學者,簡單熟悉了shell以後,就可以開始進行一些C語言編程的嘗試了。

我們最早接觸編程一般都是在大學的編程課上,而且往往用的是Visual C++ 6.0。竊以為這是讓我對編程原理長期困惑不解的罪魁禍首!啥是環境變數?為啥要設置include路徑,lib路徑?為啥一點編譯按鈕就會出來那麼多後綴名不同的文件?這些很基礎很重要的問題都被VC6.0這個外殼掩蓋了。但哪怕你在Linux中使用gcc編譯一個最簡單程序,一定就會像我一樣馬上明白把一個.c的源文件變成一個可執行文件,中間究竟發生了什麼事情。如果你再用gdb調試一個程序,就會明白得更多一點。

關於C/C++編程的基本工具,我們需要學習的有:vim等代碼編輯器、diff等文件比較的shell命令、gcc等編譯器、gdb等調試工具、交叉編譯等。這裡需要特別提到一個重要工具(網站):github,根據百度的解釋,它是一個「分散式的版本控制系統」,初學者還用不到版本控制,那就可以單純把它當成一個開放的源代碼庫。這個網站里有大量優秀的源代碼供學習和使用。

學習了基本的編程方法,我們就該接觸Linux的API等內容了。畢竟,我們的嵌入式系統要與設備進行交互,只用C/C++標準庫是不夠的。在此之前,需要建立一個Linux的重要概念:一切皆文件。甚至硬體設備對Linux系統來說,也是文件。這樣對設備的操作就等同於對文件進行讀、寫,或讀寫以外的操作。這部分內容在各種書籍資料中通常以「文件IO編程」命名,作為一個章節來寫。我覺得這是應當第一個來學的東西,因為看到自己能隨意操控文件和外設是一件讓人很振奮的事情!成就感是繼續學習的一大動力!

另外一個重要內容是,理解進程和線程。通過學習這個部分,能管中窺豹地大致領略到Linux系統如何進行調度,你的程序是怎麼在Linux中運行的。這是操作系統原理的內容,但作為非軟體專業出身的人,沒辦法,只能自學了。

其他應用程序編程如網路編程、Qt圖形編程等就不一一說明了。

驅動程序可能是我們將來接觸內核空間遇到的第一個內容。不過暫時還沒什麼特別想說的。內核空間距離初學者還是有點遠的……以後再來學這部分內容。

免費試聽C語言、電子、PCB、STM32、Linux、FPGA、JAVA、安卓等。

想學習的你和我聯繫預約就可以免費聽課了。

宋工企鵝號:三五二四六五九零八八 Tel:173--1795--1908


推薦閱讀:

RTOS移植與naked選項的使用-2_實際效果與擴展閱讀
RTOS移植與naked選項的使用-1_必要性與用法
精簡封裝技巧6---- 『:』 關鍵詞的用法
物聯網嵌入式應用已經滲透到我們生活的方方面面

TAG:嵌入式系統 |