在 linux 驅動中字符設備驅動是必須掌握的,本章主要介紹字符設備應用的程序,無論是學習了后面的知識自己寫的字符驅動,還是已有的字符驅動,都需要能夠寫一些簡單的應用程序。即使從事 Linux 驅動方面的工作,Linux 驅動寫出來之后,也需要由驅動程序員編寫簡單的應用程序來進行測試的。 另外,關于驅動部分,迅為電子有專門的驅動實驗教程提供給大家學習,大家有了這些基礎之后再去學習底層的知識就會很容易了。 在本手冊的 10.22 章節,大家可以看到這些 C 程序也是可以在 Android 下面運行的,只不過沒有圖形界面。 本章配套視頻為: “視頻 06_01 字符設備控制之 main 函數傳參數” “視頻 06_02 字符設備控制之 led 燈” “視頻 06_03 字符設備控制之 buzzer 蜂鳴器” “視頻 06_04 字符設備控制之 ADC 模數轉換” 17.1 入口 main 函數的參數 在和用戶交流的過程中,雖然所有人都學習過 C 語言,但是對 C 語言中的 main 函數的用法并不是很清楚。由于后面的實驗需要用到這部分知識,這里就占用一個小節,先簡單介紹一下 main 函數。 main 函數簡介 main 函數作為應用程序的入口,在頭文件“#include int main(int argc,char **argv) 參數 argc,表示參數的個數 參數**argv,存儲輸入字符的數組,argv[0]表示程序名稱,argv[1]——argv[n]輸入的參數 不傳參數的時候定義為 int main(void) 函數 main 的返回值為類型為 int,用于判斷程序執行成功還是失敗 main 函數例程 編寫簡單的 argvc.c 文件測試 main 函數。 ![]() 如上圖所示,將輸入的參數第一個和第二個轉換成 int 類型,賦值給 i 和 j,最后輸出打印。 其中 argv[0]為程序名稱,這里就是后面要編譯的目標文件“argvc”。 編譯運行測試 在 Ubuntu 系統下,如下圖所示,進入前面實驗創建的目錄“/home/linuxsystemcode/”,使用命令“mkdircharcontrol”新建 charcontrol 文件夾,將源碼 argvc.c 拷貝進去,進入新建的文件夾 charcontrol,如下圖所示。 ![]() 使用命令“arm-none-linux-gnueabi-gcc -o argvc argvc.c -static”編譯 argvc 文件, 如下圖所示,使用命令“ls”可以看到生成了 argvc 可執行文件。 ![]() 這里介紹 U 盤拷貝代碼的方法,也可以編譯進文件系統,具體方法參考 10.3.5 小節。 將編譯成的可執行文件 argvc,拷貝到 U 盤,啟動開發板,插入 U 盤,加載 U 盤,運行程序如下。 ![]() 如上圖所示,程序成功運行,打印: the Program name is ./mnt/udisk/argvc。 因為運行的程序就是“./mnt/udisk/argvc”,這是第一個參數 The command line has 2 argument: 10,11。 輸入的參數是 10 和 11,對應 argv[2]和 argv[2]。 17.2 字符類 led 燈 在前面介紹 open 函數的時候,已經提到過如何打開字符類設備,獲得句柄的方法和一般文件都是一樣。 Led 燈的設備節點在/dev 目錄下,如下圖所示,在超級終端可以使用 ls 命令查找。 ![]() 由于涉及到硬件知識,這里簡單介紹一下硬件原理,如下圖所示,led 小燈的硬件原理很簡單。 ![]() 如上圖所示,給 KP_COL0 和 VDD50_EN 網絡高電平,三極管 L9014 就會導通,電源 VSYS 就會將電壓加到電阻 R 和 led 小燈上,小燈就會亮。 給 KP_COL0 和 VDD50_EN 網絡低電平,三極管 L9014 就會截止,形成斷路,小燈滅。 在前面介紹過,如果要給文件進行寫操作,那么使用的是 write 函數。對于 led 小燈的操作,使用寫函數,理論上也是可以的。但是對于 IO 口(這里的 IO 口指的是硬件上的 IO 口, 不是指 IO 文件)的 操作,Linux 專門設計了一個高效的函數 ioctl。 這個函數在頭文件#include int ioctl( int fd, int request, int cmd); 參數 fd,函數 open 返回的句柄。 參數 request 和參數 cmd,由內核驅動決定具體操作,例如 request 可以代表那個 IO 口,cmd 代表對 IO 進行什么樣的操作,也可以反過來。具體的含義由驅動工程師在驅動中 switch 決定。 返回值:返回 0 成功;返回-1,出錯。 小燈測試例程 編寫簡單的 leds.c 文件測試小燈。首先添加頭文件,如下圖所示。 通過 main 參數傳過來的參數是 char 字符格式的,如果要傳遞給 ioctl 函數,需要用到數值轉化函數atoi,添加了頭文件#include 接著由于小燈的數量和命令都是 2,所以對小燈數量和操作數進行宏定義 #define LED_NUM 2 #define LED_C 2。 ![]() 然后 main 函數如下圖所示。 ![]() 如上圖所示。 第 33 行,調用了 ioctl 函數,將 main 函數的第一個和第二個參數傳入驅動。 第 19 行,解釋那個參數具體代表什么含義,"argv1 is cmd;argv2 is io”,參數 1 對應命令,參數 2 對應具體那個 led 燈。 第 36 行,將打開的設備節點"/dev/leds"關閉。 編譯運行測試 在 Ubuntu 系統下,如下圖所示,進入前面實驗創建的目錄“/home/linuxsystemcode/charcontrol”,將源碼 leds.c 拷貝進去,如下圖所示。 ![]() 使用命令“arm-none-linux-gnueabi-gcc -o leds leds.c -static”編譯 leds 文件,如下圖所示,使用命令“ls”可以看到生成了 leds 可執行文件。 ![]() 這里介紹 U 盤拷貝代碼的方法,也可以編譯進文件系統,具體方法參考實驗 02 將編譯成的可執行文件 open,拷貝到 U 盤,啟動開發板,插入 U 盤,加載 U 盤,運行程序如下。 如下圖所示,如果不加參數會有提示,然后報錯。 ![]() 如下圖所示,使用命令“./mnt/udisk/leds 0 0”運行,可以看到靠近蜂鳴器的小燈滅了。 ![]() 所有參數對小燈的控制如下: 0 0 靠近蜂鳴器的小燈滅; 0 1 靠近按鍵的小燈滅; 1 0 靠近蜂鳴器的小燈亮; 1 1 靠近按鍵的小燈亮。用戶可以自行測試一下。 ![]() |