自從選擇了物聯網這個專業,智能XX的字樣牽動着每一個學習這個專業的孩子。
大家興致勃勃的來到了學校,結果一切想象和自己的設想並不一樣。想象中的各種智能般夢幻的場景變成了真實的高數/電路/模電等等諸如此類!不知道這個世界什么時候變得如此的浮躁,當大家的一段時間的努力看不到結果的時候就往往會不太感興趣,模電大家都沒聽懂,於是大家自我安慰tmd學這玩意到底干什么?本人當初也是這樣,可是到了后來接觸了單片機,接觸了應用電路的設計才知道那些課程那個沒用啊!當初還是too young,too simple呀!
這個學期也將要過去了,明年就開始去實習啦!趁着現在就實現自己的物聯網夢想吧!沒錯,就是比較惡俗的智能家具系統。
考慮到單片機局限比較大,遂向同學借了一塊友善之臂的板子,本人第一次接觸arm,單片機系自學,文中又搞笑的地方大家笑笑就行了,如果能給予指正,那就更好了。先來實現一個比較簡單的功能,即通過web遠程控制燈光的亮滅。要實現這個功能,我們需要在嵌入式linux的平台上寫led的驅動,要學習驅動我們直接寫led的驅動可能難度比較大,而且不易成功,所以我們先用著名的helloworld來熟悉環境。
現在,越來越覺得和計算機打交道,要有兩條准則:1 思路要清晰 2 實現過程要一步一步。因為計算機是機器,0和1的世界,程序過程中稍不注意就會錯誤百出。所以寫程序過程中一定要步步為營,一點一點測試,一點一點推進,這樣看似很慢,卻非常有效也容易成功。好了,不為我寫hellow辯護了。其實我在寫helloworld的時候也是做准備了,那就是在pc端上已經成功的測試過了。
在補充一點,我們寫的驅動程序最終都是要加載進內核的,我們有兩種方法添加到內核中。第一種是直接編進內核里,第二種是動態編進內核里。動態加入內核就是我們把自己的驅動程序看成一個模塊,然后把這個模塊加載到內核內。直接編譯進內核就是這個模塊和內核一起編譯,如果有什么這個驅動有什么問題的話,我們還需要調試編譯整個內核,因此剛開始學習的時候我采用了模塊化的動態加載內核。
下面就開發過程中的一些地方做一些記錄:
1 在pc機上為目標機編寫驅動程序的.c文件應該放在哪里比較好?
這個應該放在目標機內核的目錄。比如我的是友善之臂的板子,因為helloworld是字符設備,因此hello.c就建在了/opt/FriendlyARM/mini2440/linux-2.6.32.2/drivers/char的目錄內。為什么要建在這里,因為這樣我們可以借助與char內的makefile來編譯出模塊,也就是說我們不必自己單獨寫makefile,有點抱大腿的趕腳。
2 最簡單的helloworld模塊是什么樣的?
1 #include <linux/kernel.h> 2 #include <linux/module.h> 3 static int __init mini2440_hello_module_init(void) 4 { 5 printk("Hello, world !\n"); 6 return 0; 7 } 8 static void __exit mini2440_hello_module_cleanup(void) 9 { 10 printk("Good-bye!\n"); 11 } 12 module_init(mini2440_hello_module_init); 13 module_exit(mini2440_hello_module_cleanup); 14 MODULE_LICENSE("GPL");
第一行和第二行就不說了,因為我們用到了內核的相關函數以及模塊的一些東西,因此必須要聲明。
最后一行是內核2.6以上版本建議大家把模塊的lincense帶上。
在我們動態加載和卸載模塊的時候,我們需要init_module和exit_module這兩個函數來加載,而上面的代碼中並沒有。原因在哪里呢?
原來是module_init和module_exit在作怪。以module_init為例,這個函數有兩個功能,一個是驗證傳入的參數是否為正確的模塊格式,另一個是將參數改名字為init_module。這樣模塊就能被成功的加載了。
雖然上面的module是個空架子,但是也可以讓我們對模塊有個感官的認識。
3 編譯這個模塊前需要做那些准備?
第一步,將模塊添加到內核菜單,這樣在我們啟動內核菜單的時候才能對我們新添加的模塊進行配置。
1 config HELLO_MODULE 2 tristate "hello module" 3 depends on MACH_MINI2440 4 default m if MACH_MINI2440 5 help 6 hello module
這個模塊就是比照着周圍的模塊寫的,當然了,用戶手冊上也是詳細步驟的。
簡單看下這段代碼,tristate就是這個模塊在內核菜單中顯示的名字。
depends on 是依靠的平台,下面是說如果依靠這個平台默認的是動態加載到內核。
添加完以上的代碼,回到linux內核目錄下,make menuconfig調出內核編譯菜單。在字符設備的地方可以找到新添加的hello模塊。
第二步,添加完代碼后,還需要將編譯文件Makefile和源碼聯系起來,這樣執行makefile的時候才能找到源碼進行編譯。因為我們是在內核下抱大腿寫的makefile,所以我們不必重新寫makefile,只需要在字符設備的makefile文件中添加這個關系就可以了。
1 obj-$(CONFIG_HELLO_MODULE) += hello.o
這樣一來,make的時候就能找到hello模塊的源文件啦!
4 編譯模塊和檢驗模塊
在2.6以后版本的內核中,我們只需要在內核目錄下執行make modules便可以編譯模塊。
在編譯模塊后一定要做最重要的檢驗工作,可以用modinfo命令查看生成的.ko文件的信息。最重要的是核對.ko文件的vermagic: 所顯示的內核信息和你目標板的內核信息是否一致,這點灰常重要,否則即便你移植到了目標板,也不能加載成功。
5 加載測試
好了,現在我們該檢驗結果啦,雞凍啊!在模塊當前目錄,用insmod來加載我們的hello.ko模塊。
什么居然神馬也木有,心頓時涼了半截。。。。。。
還好不是神馬大問題,上面文章已經說過啦!printk是內核級別的函數,查看需要輸出:dmesg | tail
另外,也可以采用lsmod指令來驗證模塊是否加載成功。
最后刻意驗證了這個模塊的生命周期,退出終端重新進入,查看模塊還在。重新啟動后發現模塊不見鳥。
至此,所有的工作都完成鳥。第一個在嵌入式設備上開發的第一個雞肋驅動就完成了。在整個過程中覺得,只要一步一步來問題都是可以解決的,機器是非常認真的,只要我們按照機器一樣的思維認真的去一步一步解決問題的時候,發現你就可以hold住機器,md,以后會不會變成了一個和機器一樣的人。。。。
發現了為什么大家伙都說嵌入式入門灰常難,其實就是灰常繁,大家可以看上面那么多東西基本上沒有涉及到和智商有關的東西,全部都是步驟程式化的,當自己沒有走完一個流程的時候發現這玩意太難了,當走完一個流程后會覺得,nima,什么玩意。。。。。
問題解決前前后后大概一兩天吧!發現越是糾結的時候長的問題,當結果出來那一刻會更興奮,越是容易的問題,解決后沒有一點興奮的趕腳!
又扯遠啦!馬上進入真槍實彈的驅動-led驅動啦! 加油!md,我是誰,這么帥氣的男淫!
最后覺得linux里面的Makefile和Kconfig真強大,linux內核是一個大工程啦,通過Kconfig一層一層的去建立菜單,通過Makefile文件來批量的去編譯,真是太強大了。這樣以來覺得linux雖然做個什么東西都特別麻煩,但是更能讓我們清楚的去了解系統的工作原理,linux和單片機真不愧是學習操作系統和計算機組成原理的法寶啊!
當然,過程中還會有很多的錯誤,這里沒有一一列出。下面推薦一些這個過程中可能幫助我們的一些網友 的博客:
如果你的內核菜單沒有出現你添加的模塊,請參考
http://blog.csdn.net/hadise/article/details/6222538
inti_module/exit_module的詳細分析,請參考
http://www.embedu.org/Column/Column517.htm
建議第一次接觸的朋友可以現在pc機上的系統去實現一下,這樣過渡一下效果會更好一點,下面是pc機上實現helloworld驅動的鏈接:
http://www.cnblogs.com/heat-man/articles/4174899.html
最后想借此認識一些嵌入式linux的同伙,因為大家一走才能走的更歡樂,才能走的更遠!
如果那個大牛有什么好的建議和方法,那這篇文章就賺大發啦!