劉彥文等《Linux環(huán)境嵌入式系統(tǒng)開發(fā)基礎》第10章_第1頁
劉彥文等《Linux環(huán)境嵌入式系統(tǒng)開發(fā)基礎》第10章_第2頁
劉彥文等《Linux環(huán)境嵌入式系統(tǒng)開發(fā)基礎》第10章_第3頁
劉彥文等《Linux環(huán)境嵌入式系統(tǒng)開發(fā)基礎》第10章_第4頁
劉彥文等《Linux環(huán)境嵌入式系統(tǒng)開發(fā)基礎》第10章_第5頁
已閱讀5頁,還剩189頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、第10章 應用程序編程舉例 及驅動程序分析(一) 本章重點:本章重點: 讀取、轉換時間函數編程舉例; 多線程編程舉例; 串行端口及標準輸入/輸出/錯誤編程舉例; ADC應用程序編程舉例(S3C2410A)。10.1 讀取、轉換時間函數編程舉例 Linux系統(tǒng)中,涉及到時間較為常用的三個名詞術語是:n GMT(Greenwich Mean Time),格林尼治標準時間。n UTC(Coordinated Universal Time),世界標準時間,是由原子鐘提供的時間,比格林尼治標準時間更為準確。n CST(China Standard Time),中國標準時間,或稱北京時間。 我們現在所說的

2、標準時間,通常是指UTC時間。 北京時間CST=UTC+8小時。 另外,本節(jié)中所說的時間,除了我們通常所說的時間外,還包含日期。10.1.1Linux查看、設置時間的命令 查看時間 使用date命令可以查看時間,通常顯示的是當地時區(qū)的時間,例如北京時間: rootvm-dev # date 六 3月 31 09:14:41 CST 2012 上述內容分別表示:年、月、日、星期、時、分、秒以及CST,是主機Linux的輸出。 有的目標板,配置為顯示UTC時間,例如: /mnt/yaffsdate Sat Mar 31 09:27:06 UTC 2012 設置時間 主機Linux設置時間后,會保留

3、;目標板設置時間后,加電或RESET后不保留。以下是主機顯示、設置時間舉例。 使用參數u表示UTC時間 設置時間可以使用命令及參數: date u MMDDhhmmYYYY.ss 其中u表示UTC,從MM開始的參數分別表示月、日、時、分、年和秒。 例如: rootvm-dev # date -u 033110162012.30 六 3月 31 10:16:30 UTC 2012 系統(tǒng)會將設置的UTC時間,自動轉換成CST時間顯示,例如輸入date命令后,會顯示: rootvm-dev # date 六 3月 31 18:16:42 CST 2012 不使用參數u表示按當地時間設置 以下設置沒有

4、設置秒,缺省值為0: rootvm-dev # date 033110162012 六 3月 31 10:16:00 CST 2012 rootvm-dev # date 六 3月 31 10:16:03 CST 201210.1.2 常用的讀取、轉換時間的函數 所有的Linux系統(tǒng),把GMT時間的1970年1月1日0時0分0秒,作為時間的起點,所有時間都是從那時起,以經過的秒數來計算。 時間通過一個預定義的類型time_t來處理,這是一個以秒計算的時間的整數類型,是一個長整型,與處理時間的函數一起定義在頭文件time.h中。 time()函數 例如代碼: #include time_t th

5、e_time;/*定義類型*/ (void)time(&the_time);/*得到時間值,單位為秒*/ printf(“Raw time is %ldn”,the_time);/*輸出時間值*/ 上述代碼能夠輸出從Linux時間起點,到time函數讀取那一刻所經過的時間的秒數。 關于time()函數進一步的用法,見例10.1。 gmtime()函數 gmtime()函數能夠把以秒表示的時間值,轉換成用戶易讀格式的值。 gmtime()函數把底層時間值分解為一個結構,該結構包含一些常用的成員: #include struct tm *gmtime(const time_t timeva

6、l); tm結構被定義為至少包含表10-1所示的成員。 tm成員成員含義含義tm成員成員含義含義int tm_sec秒,秒,061int tm_year從從1900年算起的年算起的年數年數int tm_min分,分,059int tm_wday星期幾,星期幾,06,0表示周日表示周日int tm_hour時,時,023int tm_yday年 份 中 的 日 ,年 份 中 的 日 ,0365int tm_mday月 份 中 的 日 ,月 份 中 的 日 ,131int tm_isdst是否夏令時是否夏令時int tm_mon月,月,011,0表示表示1月月注:注:tm_sec的范圍允許臨時閏的

7、范圍允許臨時閏1秒或秒或2秒。秒。表表10-1 tm結構至少包含的成員結構至少包含的成員 函數gmtime()按GMT返回時間。 如果要看當地時區(qū)的時間,可以使用localtime()函數,使用方法是在程序中,用localtime()函數代替gmtime()函數。 有些小規(guī)模的目標板,生產商把當地時區(qū)的時間直接設置為GMT時間,使用者要引起注意。 ctime()函數 函數ctime()返回一個長度為26個字符、有固定格式、表示當地時間的字符串,函數格式為: char *ctime(const time_t *timeval); 函數ctime()輸出字符串格式見例10.1。 函數ctime()

8、將底層的時間值,即秒值,轉換成用戶易讀格式的值。 10.1.3 讀取、轉換時間的函數編程舉例(S3C2410A) 編程舉例 【例10.1】以下為讀取、轉換并輸出時間的程序,程序名為time.c,源程序保存在主機Linux,路徑為源程序所在路徑為/arm2410cl/exp/basic/01_time/。 程序中time()函數讀取時間的秒值;gmtime()函數將這個秒值轉換成一個結構,保存在tm_ptr中;ctime()函數把秒值轉換成一個字符串;printf()函數將秒值、結構、字符串輸出。sleep(3)函數表示休眠3秒,然后重復讀取秒值、轉換成結構和字符串輸出。 程序代碼為:#incl

9、ude #include /*#include */int main() struct tm *tm_ptr; time_t the_time; (void)time(&the_time); tm_ptr=gmtime(&the_time); printf(Raw time is %ldn,the_time); printf(date:%2d/%2d/%2dn, tm_ptr-tm_year, tm_ptr-tm_mon+1,tm_ptr-tm_mday); printf(time: %2d/%2d/%2dn, tm_ptr-tm_hour,tm_ptr-tm_min,tm_p

10、tr-tm_sec); printf(The date is:%sn,ctime(&the_time); sleep(3); (void)time(&the_time); tm_ptr=gmtime(&the_time); printf(Raw time is %ldn,the_time); printf(date:%2d/%2d/%2dn, tm_ptr-tm_year,tm_ptr-tm_mon+1, tm_ptr-tm_mday); printf(time: %2d/%2d/%2dn, tm_ptr-tm_hour,tm_ptr-tm_min, tm_ptr-tm

11、_sec); printf(The date is: %sn,ctime(&the_time); return 0; 程序運行結果解釋 例10.1的源代碼經過交叉編譯,產生的可執(zhí)行文件為time,能夠在目標板運行。 運行可執(zhí)行文件前,為了與程序輸出的時間對比,可以先用date命令查看目標板的時間: /host/exp/basic/01_timedate Fri Mar 30 10:06:00 UTC 2012在目標板運行可執(zhí)行文件time,輸出內容為:/host/exp/basic/01_time./timeRaw time is 1333101971date: 112/ 3/30ti

12、me: 10/ 6/11The date is:Fri Mar 30 10:06:11 2012 Raw time is 1333101974 date: 112/ 3/30 time: 10/ 6/14 The date is: Fri Mar 30 10:06:14 2012 上述內容中,Raw time對應的是秒數;date對應的是112/3/30,表示從1900年算起經過112年(2012年)的3月30日,time對應的是時/分/秒;然后是ctime()函數產生的字符串。10.1.4 例10.1對應的Makefile文件(S3C2410A) 對例10.1代碼進行編譯的Makefile文

13、件內容如下: rootvm-dev 01_time# vi Makefile TOPDIR=./ include $(TOPDIR)Rules.mak EXEC = $(INSTALL_DIR)/time ./time OBJS = time.o all: $(EXEC) $(EXEC): $(OBJS)$(CC) $(LDFLAGS) -o $ $(OBJS) install:$(EXP_INSTALL) $(EXEC) $(INSTALL_DIR) clean:-rm -f $(EXEC) *.elf *.gdb *.o 上述TOPDIR=./中的./表示父目錄,即上一層目錄,在該目錄中含

14、有Rules.mak文件。另外編譯器產生的可執(zhí)行文件名為time,目標文件名為time.o。 在文件Rules.mak中,指出了交叉編譯器的前綴是armv4l-unknown-linux: rootvm-dev basic# vi Rules.mak TOPDIR= . CROSS = armv4l-unknown-linux- CC= $CROSSgcc #CC=gcc #CFLAGS += -g #LDFLAGS += -static EXTRA_LIBS += EXP_INSTALL = install -m 755 INSTALL_DIR = ./bin10.1.5 讀取、轉換時間的函

15、數編程舉例 (OMAP3530)1. 編程舉例 【例10.2】以下為讀取、轉換并輸出時間的程序,程序名為time.c,源程序保存在主機Linux,路徑為/home/nfs1/01_time,Makefile文件也保存在這個目錄。 程序中time()函數讀取時間的秒值;gmtime()函數將這個秒值轉換成一個結構,保存在tm_ptr中;ctime()函數把秒值轉換成一個字符串;printf()函數將秒值、結構、字符串輸出。sleep(3)函數表示休眠3秒,然后重復讀取秒值、轉換成結構和字符串輸出。 程序代碼為:#include #include /*#include */int main() s

16、truct tm *tm_ptr; time_t the_time; (void)time(&the_time); tm_ptr=gmtime(&the_time); printf(Raw time is %ldn,the_time); printf(date:%2d/%2d/%2dn, tm_ptr-tm_year, tm_ptr-tm_mon+1,tm_ptr-tm_mday); printf(time: %2d/%2d/%2dn, tm_ptr-tm_hour,tm_ptr-tm_min,tm_ptr-tm_sec); printf(The date is:%sn,cti

17、me(&the_time); sleep(3); (void)time(&the_time); tm_ptr=gmtime(&the_time); printf(Raw time is %ldn,the_time); printf(date:%2d/%2d/%2dn, tm_ptr-tm_year,tm_ptr-tm_mon+1, tm_ptr-tm_mday); printf(time: %2d/%2d/%2dn, tm_ptr-tm_hour,tm_ptr-tm_min, tm_ptr-tm_sec); printf(The date is: %sn,ctime(&

18、amp;the_time); return 0; 程序運行結果解釋 例10.2的源代碼經過交叉編譯,產生的可執(zhí)行文件為time,能夠在目標板運行。 運行可執(zhí)行文件前,為了與程序輸出的時間對比,可以先用date命令查看目標板的時間: rootTechv_OMAP35xx:/# date Fri Jan 11 10:45:00 UTC 2013在目標板運行可執(zhí)行文件time,輸出內容為:rootTechv_OMAP35xx:/# cd /tmp/01_timerootTechv_OMAP35xx:/var/volatile/tmp/01_time# ./timeRaw time is 135790

19、1145date: 113/ 1/11time: 10/45/45The date is:Fri Jan 11 10:45:45 2013 Raw time is 1357901148 date: 113/ 1/11 time: 10/45/48 The date is: Fri Jan 11 10:45:48 2013 上述內容中,Raw time對應的是秒數;date對應的是113/1/1,表示從1900年算起經過113年(2013年)的1月1日,time對應的是時/分/秒;然后是ctime()函數產生的字符串。10.1.6 例10.2對應的Makefile文件(OMAP3530) 對例1

20、0.2代碼進行編譯的Makefile文件內容如下: rootlocalhost 01_time# vi Makefile CC = /usr/local/arm/arm-2007q3/bin/arm-none-linux-gnueabi-gcc all: $(CC) -o time time.c clean: -rm -f *.o time 10.1.7 執(zhí)行例10.2程序前的操作過程舉例 (OMAP3530) 進入例10.2程序所在目錄并顯示程序名 rootlocalhost nfs1# cd /home/nfs1/01_time rootlocalhost 01_time# ls -l 總

21、計 20 -rwxr-xr-x 1 root root 116 11-19 17:09 Makefile -rwxr-xr-x 1 root root 5813 11-19 17:09 time -rwxr-xr-x 1 root root 959 2012-04-16 time.c -rwxr-xr-x 1 root root 1456 2012-04-16 time.o 檢查或設置主機、目標板IP地址 在主機終端窗口設置主機Linux IP地址 rootlocalhost 01_time# ifconfig eth0 192.168.1.5 在目標板終端窗口設置目標板Linux IP地址

22、Techv_OMAP35xx login: root rootTechv_OMAP35xx:# ifconfig eth0 192.168.1.9 eth0: link down rootTechv_OMAP35xx:# eth0: link up, 100Mbps, full-duplex1 在目標板終端窗口測試與主機網絡連接狀況 rootTechv_OMAP35xx:# ping 192.168.1.5 在目標板終端窗口掛接NFS # mount -o soft,nolock,rsize=1024 -v 192.168.1.5:/home/nfs1 /tmp 在主機終端窗口編譯源程序 ro

23、otlocalhost 01_time# make 在目標板進入相應目錄、顯示文件名、執(zhí)行文件 rootTechv_OMAP35xx:/# cd tmp/01_time rootTechv_OMAP35xx:/var/volatile/tmp/01_time# ls Makefile time time.c time.o rootTechv_OMAP35xx:/var/volatile/tmp/01_time# ./time 10.2 多線程編程舉例10.2.1Linux線程概述 通常把一個程序中的多個執(zhí)行路線,稱為線程(thread)。 Linux系統(tǒng)在1996年第一次獲得了線程的支持,當時

24、使用的函數庫稱為LinuxThread。 本地POSIX線程庫(Native POSIX Thread Library,NPTL)項目,是通過修改Linux內核來實現支持新的線程函數庫的。通過該項目的實施,極大地提高了Linux線程的性能。NPTL將成為Linux線程的新標準,第一個NPTL的主流版本出現在Red Hat 9.0版上。 絕大部分線程函數是以pthread_開頭的,并且要求在應用程序中包含頭文件pthread.h,pthread.h文件提供了代碼中使用的定義和函數原型。 對應用程序進行編譯時,需要使用選項-lpthread來鏈接線程庫,例如可以在Makefile文件中增加語句:

25、EXTRA_LIBS += -lpthread 來實現鏈接線程庫。 10.2.2 線程、互斥量、條件變量函數 線程函數 創(chuàng)建線程函數 創(chuàng)建線程函數的作用是創(chuàng)建一個新的線程,定義如下: int pthread_create(pthread_t *thread,pthread_attr_t *attr,void *(*start_routine)(void *),void *arg); 函數中第1個參數是指向pthread_t類型數據的指針,線程被創(chuàng)建時,這個指針指向的變量中將被寫入一個標識符,之后用這個標識符來引用新線程。 函數中第2個參數用于設置線程的屬性,通常設置為NULL。 函數中第3、4

26、個參數,分別告訴線程將要啟動執(zhí)行的函數地址和傳遞給該函數的參數。 創(chuàng)建線程函數調用成功時,返回值為0。 創(chuàng)建線程函數代碼舉例如下:(p351) 上述代碼中,創(chuàng)建線程函數的第1個參數th_a中將被寫入一個標識符,以后用th_a中的標識符來引用新線程;函數中第2個參數屬性為NULL;第3個參數傳遞了一個函數地址,即producer函數入口地址,新線程將在這個新的地址開始執(zhí)行;第4個參數傳遞的值為0。 等待線程結束函數 等待線程結束函數,將阻塞調用它的線程(在前述創(chuàng)建線程函數代碼舉例中,main()也是一個線程,等待線程結束函數將阻塞main()線程),直到該函數指定的線程結束為止。 int pth

27、read_join(pthread_t th,void *thread_return); 函數中第1個參數指定了正在等待結束的線程,即創(chuàng)建線程時指定的標識符,如創(chuàng)建線程函數代碼舉例中th_a中的標識符。 函數中第2個參數是一個指針,它指向另一個指針,而后者指向線程的返回值。 等待線程結束函數調用成功時,返回值為0。 互斥量函數 多線程程序中,可以通過互斥量加鎖、解鎖機制,控制各個線程對共享數據區(qū)訪問的同步操作。 通常將多個線程用到的共享數據區(qū),設計成通過函數進行訪問;并且對訪問的函數,使用同一個互斥量進行保護;進入這個函數后對互斥量加鎖,完成訪問操作后對互斥量解鎖。這樣可以保證在一個互斥量的保

28、護下,訪問函數的運行不會被其他線程所打斷,從而保證了每次只有一個線程訪問共享數據區(qū)。 常用的互斥量函數有初始化互斥量、互斥量加鎖、互斥量解鎖和釋放互斥量4個函數。 初始化互斥量函數定義: int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *mutexattr); 互斥量加鎖函數定義: int pthread_mutex_lock(pthread_mutex_t *mutex); 互斥量解鎖函數定義: int pthread_mutex_unlock(pthread_mutex_t *mutex); 釋

29、放互斥量函數定義: int pthread_mutex_destroy(pthread_mutex_t *mutex); 這4個函數的參數,都是一個事先聲明過的對象的指針,類型為pthread_mutex_t。 使用互斥量前,要先對互斥量進行初始化。 互斥量加鎖函數,首先檢查互斥量是否已經處于加鎖狀態(tài),如果沒有處在加鎖狀態(tài),則對其加鎖,并運行后續(xù)程序;如果已經處于加鎖狀態(tài),則使當前運行的程序進入阻塞狀態(tài),一直等到其他程序使互斥量解鎖,才能退出阻塞狀態(tài),運行后續(xù)程序。 互斥量解鎖函數,使已加鎖的互斥量變?yōu)榻怄i狀態(tài)。加鎖和解鎖函數,必須在同一段代碼中配對使用。如果有多個線程等待互斥量解鎖,排在等待

30、隊列中的第1個線程首先從阻塞中退出并運行。 使用完互斥量,應該釋放互斥量,釋放占用的資源。釋放前,互斥量應處于未加鎖狀態(tài)。 上述4個函數成功執(zhí)行后,返回值均為0。 互斥量函數的使用,見例10.3。 條件變量函數 條件變量通常與互斥量相互配合使用,使用條件變量之前要先進行初始化,使用完應該釋放條件變量。 常用的條件變量函數有初始化條件變量、等待條件變量、設置條件變量和釋放條件變量4個函數。 初始化條件變量函數定義: int pthread_cond_init (pthread_cond_t * cond, _const pthread_condattr_t * cond_attr); 等待條件變

31、量函數定義: int pthread_cond_wait (pthread_cond_t *_restrict_cond, pthread_mutex_t *_restrict _mutex); 設置條件變量函數定義: int pthread_cond_signal (pthread_cond_t *_cond); 釋放條件變量函數定義: int pthread_cond_destroy (pthread_cond_t *_cond); 條件變量只有未被使用時才能初始化。 等待條件變量函數,使線程(或函數)阻塞在指定的條件變量上;并且對指定的互斥量解鎖,使其他線程可運行;阻塞一直持續(xù)到條件變量

32、被其他線程喚醒為止,并且在函數返回前系統(tǒng)自動對互斥量加鎖。 設置條件變量函數,是用來喚醒被阻塞在條件變量上的一個線程(或函數),如果有多個線程阻塞在這一個條件變量上,由線程的調度策略來決定喚醒哪一個。如果沒有一個關于條件變量的線程被阻塞,則該函數無效。 釋放條件變量函數,只有在沒有線程被阻塞在該條件變量上時,才能釋放這個條件變量。 上述4個函數成功執(zhí)行后,返回值均為0。 條件變量的使用,見例10.3。 10.2.3 生產者、消費者編程舉例(S3C2410A) 生產者、消費者程序編程考慮 假定有一個數據緩沖區(qū),大小為8個單元,整數類型。生產者(程序)要往緩沖區(qū)填充數據,比如填充數據0199,并且

33、每填充一個數據同時將該數據送終端顯示。而消費者(程序)要從緩沖區(qū)讀出數據,同時送終端顯示。為了填充數據,設置一個寫指針;為了讀出數據,設置一個讀指針。每寫入緩沖區(qū)一次數據,修改寫指針;從緩沖區(qū)每讀出一次數據,修改讀指針。 數據緩沖區(qū)設置為環(huán)狀,即指針從0開始,最大到7,7以后再回到0。生產者將緩沖區(qū)填滿后,要等消費者從緩沖區(qū)讀出數據后,使緩沖區(qū)處于非滿(not full)狀態(tài),生產者才能填充下一個數據;同樣,消費者如果將緩沖區(qū)全部數據讀出后,要等生產者往緩沖區(qū)填充數據后,使緩沖區(qū)處于非空(not empty)狀態(tài),消費者才能讀取下一個數據。生產者和消費者線程通過使用互斥量和條件變量,交替進行。

34、 生產者producer對應的標識符在th_a中,消費者consumer對應的標識符在th_b中。 互斥量為b-lock,非滿條件變量為b-notfull,非空條件變量為b-notempty。 生產者調用填充函數put()填充數據,消費者調用get()函數讀出數據。 生產者、消費者程序代碼及執(zhí)行結果 以下程序代碼,讀者閱讀時從主程序main()處開始。 【例10.3】生產者、消費者程序代碼。(p354)n上述代碼編譯后,執(zhí)行結果(部分)如下: /host/exp/basic/02_pthread./pthread put-0 put-1 put-2 put-3 put-4 put-5 put-

35、6 wait for not full 0-get put-7 1-get put-8 2-get . put-198 192-get put-199 193-get producer stopped! 194-get 195-get 196-get 197-get 198-get 199-get consumer stopped! /host/exp/basic/02_pthread 生產者、消費者程序代碼和程序執(zhí)行結果討論 本程序中,生產者、消費者線程分別調用put()、get()函數,實現填充和讀出數據功能,由于兩個函數共用一個緩沖區(qū),所以每個函數中都要對互斥量加鎖、解鎖。 生產者、消費

36、者程序代碼中printf()函數,使用了串行口,將輸出內容送到主機Linux下的minicom對應的窗口。在嚴格意義上講,兩個線程共用一個串行口設備,也應該對其使用互斥量加鎖和解鎖。 上述生產者、消費者程序代碼,已經在兩種開發(fā)環(huán)境下測試通過,一種是PC機只運行Linux;另一種是PC機運行Windows XP,然后啟動虛擬機,在虛擬機中運行Linux。雖然程序是在目標板上執(zhí)行的,但開發(fā)環(huán)境不一樣,輸出結果也不一樣。例如,當程序中的填充數據從0199改為0999時,在Windows、虛擬機Linux環(huán)境下,minicom窗口的顯示內容會發(fā)生錯誤;而只運行Linux的環(huán)境不會發(fā)生錯誤。經過測試、分

37、析認為,目標板執(zhí)行的程序在兩種環(huán)境下是相同的、沒有錯誤的。錯誤可能產生在目標板-Windows-虛擬機-Linux的傳輸過程中。因此建議在產品開發(fā)階段,開發(fā)環(huán)境中主機應該單獨運行Linux。10.3 串行端口及 標準輸入/輸出/錯誤編程舉例10.3.1Linux標準輸入/輸出/錯誤系統(tǒng)調用編程舉例 系統(tǒng)調用、庫函數和設備驅動程序 Linux中系統(tǒng)調用、庫函數和設備驅動程序之間的關系,如圖10.1所示。圖10.1 系統(tǒng)調用、庫函數和設備驅動程序之間的關系 由圖10.1可見,用戶程序可以直接使用系統(tǒng)調用;也可以通過庫函數(如標準I/O庫函數對應的頭文件是stdio.h),由庫函數去調用系統(tǒng)調用。由

38、系統(tǒng)調用去調用設備驅動程序,驅動硬件設備工作。 系統(tǒng)調用也是一些函數,它們由Linux直接提供,是通向操作系統(tǒng)本身的接口。 Linux系統(tǒng)把不同的設備,抽象成不同的文件;對設備的操作,抽象成對文件的open、read、write、close和ioctl等操作。 Linux標準輸入/輸出/錯誤系統(tǒng)調用 Linux標準輸入/輸出/錯誤這一術語的含義,是指標準輸入設備/標準輸出設備/標準錯誤輸出設備。在一個用戶程序運行時,系統(tǒng)已經打開了這3個設備,并且返回了相應的文件描述符。 Linux環(huán)境中,每個運行的程序被稱為進程(process),每個進程有一些與之相關聯的文件描述符。文件描述符是一些小數值的

39、整數,通常由用戶打開(open)一個文件或設備時產生的返回值得到。 當一個用戶程序開始運行時,它一般可以使用3個已經打開設備返回的文件描述符,這3個描述符不是由用戶程序中打開(open)操作返回的,而是由系統(tǒng)產生的。這3個文件描述符是: 0表示標準輸入,例如read(0,&c,1);表示從標準輸入讀入一個字符保存在c中; 1表示標準輸出,例如write(1,&c,1);表示輸出c中的一個字符到標準輸出; 2表示標準錯誤,例如write(2,&c,1);表示輸出c中的一個字符到標準錯誤。 當一個程序運行結束時,也不用通過這3個文件描述符去關閉(close)對應的文件或設備

40、。 標準輸入/輸出/錯誤與串行端口及仿真終端 嵌入式開發(fā)系統(tǒng)目標板上運行的程序,通常把標準輸入/輸出/錯誤對應的文件,與目標板上第一個串行端口,即/dev/tts/0設備關聯起來。對標準輸入/輸出/錯誤的操作,就是對該串行端口的讀、寫操作。 由于目標板第一個串行端口通過電纜與主機串行端口連接,主機Linux系統(tǒng)啟動minicom仿真終端程序后,目標板運行的程序中的標準輸入系統(tǒng)調用,讀入的是主機鍵盤輸入內容,而標準輸出和標準錯誤系統(tǒng)調用將輸出的信息,通過串口送到主機仿真終端窗口。 使用標準輸入/輸出/錯誤系統(tǒng)調用時,不需要對串行端口重新設置波特率、幀格式、有無調制解調器等參數,默認使用目標板Li

41、nux內核已經設定的值。 10.3.2 Linux標準輸入/輸出/錯誤系統(tǒng)調用 編程舉例(S3C2410A) 【例10.4】以下程序是使用標準輸入/輸出/錯誤系統(tǒng)調用的一個示例。 在目標板運行這個程序后,用戶在主機minicom終端輸入一個小寫字母并回車,程序會自動輸出全部小寫字母,然后輸出回車;繼續(xù)輸出全部小寫字母,輸出回車;直到用戶按下Ctrl+c,程序終止;如果用戶最初輸入的不是小寫字母,則程序直接退出。 程序代碼如下:#include /*#include */#define FALSE 0#define TRUE 1/*-*/int main()char c;int STOP=FAL

42、SE;write(2,test std err output is ok.n,27);/*標準錯誤系統(tǒng)調用*/write(1,start std input test.n,22); /*標準輸出系統(tǒng)調用*/write(1,input 1 char from a-z,out a-z string,and reapet.n,49);write (1,if input first char is other char,end.n,39);while (1) read(0,&c,1); /*標準輸入系統(tǒng)調用*/ if (c z ) STOP=TRUE; break; write(1,the c

43、har is from read() function,std input:n ,44); write(1,&c,1); write(1,n std output,send data to terminal:n,36); c=a; while (STOP=FALSE) write(1,&c,1); c+; usleep(100000); if (c=z+1) c=n;write(1,&c,1);c=a; write(1,exit from program.n,19);exit(0); n目標板程序執(zhí)行過程中,在主機仿真終端輸出如下信息: test std err out

44、put is ok. start std input test. input 1 char from a-z out a-z string,and reapet. if input first char is other char,end. a std output,send data to terminal: abcdefghijklmnopqrstuvwxyz abc 10.3.3 Linux標準輸入/輸出/錯誤系統(tǒng)調用 編程舉例(OMAP3530) 【例10.5】 以下程序是使用標準輸入/輸出/錯誤系統(tǒng)調用的一個示例。 在目標板運行這個程序后,用戶在主機minicom終端輸入一個小寫字母

45、并回車,程序會自動輸出全部小寫字母,然后輸出回車;繼續(xù)輸出全部小寫字母,輸出回車;直到用戶按下Ctrl+c鍵,程序終止;如果用戶最初輸入的不是小寫字母,則程序直接退出。 程序代碼與例10.4完全相同,此處不再列出。 目標板程序執(zhí)行過程中,在主機仿真終端輸出信息與例10.4完全相同,此處不再列出。 說明:第5行a是從主機minicom終端鍵盤輸入的字符,后面要跟回車。這個字符的顯示,是由主機仿真終端程序minicom輸出的,不是用戶程序輸出的。 程序中止用Ctrl+c鍵。 目標板每次加電或RESET后,都要輸入mount命令和參數,重新掛接NFS目錄。 Makefile文件代碼如下: CC =

46、/usr/local/arm/arm-2007q3/bin/arm-none-linux-gnueabi-gcc all: $(CC) -o term term.c clean: -rm -f *.o term 假定上述程序代碼、Makefile文件已經輸入,保存在主機Linux的/home/nfs1/03_tty0目錄,源程序名為term.c。rootlocalhost nfs1# cd /home/nfs1/03_tty0rootlocalhost 03_tty0# ls -l總計 20-rwxr-xr-x 1 root root 118 11-20 08:56 Makefiledrwxr

47、-xr-x 2 root root 4096 10-18 16:01 old-rwxr-xr-x 1 root root 5838 11-20 09:06 term-rwxr-xr-x 1 root root 1082 11-20 09:04 term.c10.3.4串行端口設備與文件關聯及系統(tǒng)調用串行端口設備與文件關聯及系統(tǒng)調用 Linux環(huán)境中,文件具有非常重要的意義,文件為操作系統(tǒng)服務,對設備的操作提供了一個簡單而一致的接口。 在Linux中,一切都是文件。 用戶程序完全可以像使用文件那樣使用盤文件、目錄、串行端口、打印機及其他設備。例10.6中,用戶程序將一個串行端口映射為一個文件,然

48、后使用系統(tǒng)調用,對這個文件進行操作,內核通過調用對應的設備驅動程序,對串行端口硬件進行操作。 用于訪問設備驅動程序的系統(tǒng)調用有: open:打開文件或設備 read:對打開的文件或設備執(zhí)行讀操作 write:對打開的文件或設備執(zhí)行寫操作 close:關閉文件或設備 ioctl:把控制信息傳遞給設備驅動程序 open系統(tǒng)調用,創(chuàng)建了一條到達文件或設備的訪問路徑,如果調用成功,返回一個系統(tǒng)文件描述符,其他幾個系統(tǒng)調用,能夠使用這個描述符對指定的文件或設備進行操作。 open系統(tǒng)調用中常用參數的含義如下所示: O_RDONLY,規(guī)定以讀方式打開; O_WRONLY,規(guī)定以寫方式打開; O_RDWR,

49、規(guī)定以讀、寫方式打開。 read系統(tǒng)調用,從文件描述符相關聯的文件里,讀入指定字節(jié)個數的數據,存入指定的數據區(qū)。調用成功,返回實際讀入的字節(jié)個數,允許實際讀入字節(jié)個數小于指定字節(jié)個數。如果返回為0,表示未讀入數據,已到了文件尾;如果返回-1,表示出錯。從目標板串口連接的終端鍵盤讀入數據時,輸入數據后按下回車鍵,數據才能由終端程序送到用戶程序的read函數。 write系統(tǒng)調用,是把寫緩沖區(qū)的指定字節(jié)個數的數據,寫入與文件描述符關聯的文件中。它的返回值是實際寫入的字節(jié)數。如果返回0,表示未寫入任何數據;如果返回-1,表示調用中出現了錯誤。 close系統(tǒng)調用,用于終止文件描述符與對應文件或設備之

50、間的關聯。close調用成功時返回0,錯誤時返回-1。 10.3.5 串行端口設備與文件關聯及 系統(tǒng)調用舉例(S3C2410A) 在例10.6代碼中,前半部分是將串行端口/dev/ttyS0與文件關聯,使用系統(tǒng)調用對文件進行讀寫操作。這些操作實際上是通過目標板指定的串口,對串口連接的主機Linux下minicom仿真終端,進行讀寫操作。例10.6代碼中后半部分,是Linux標準輸入/輸出/錯誤系統(tǒng)調用,其讀寫操作同樣是對目標板連接的主機Linux下minicom仿真終端進行讀寫操作。 【例10.6】 以下程序中,fp是系統(tǒng)文件描述符;nread是實際讀寫字節(jié)個數;buffer是讀寫緩沖區(qū)。程序

51、先打開/dev/ttyS0文件(串行端口),然后對其讀、寫,最后關閉。后半部分程序中函數的含義同例10.4。 程序代碼如下:#include #include #include #include #include #define COM1 /dev/ttyS2/*-*/int main()char buffer80;int nread;int fp;fp=open(COM1,O_RDWR);if (fp=-1) write(2,/dev/ttyS2 open err,exit.n,26); exit (0); write(1,n plese input char string,from /de

52、v/ttyS2:n,43);nread=read(fp,buffer,80);if (nread=-1) write(2,/dev/ttyS2 read err,exit.n,26); exit (0); write(1,n- from /dev/ttyS2 read string, out to /dev/tty2:-n,63);if (write(fp,buffer,nread)!=nread) write(2,/dev/ttyS2 write err,exit.n,27); exit(0); else write(fp,from /dev/ttyS2 read char string,h

53、as output.ok.n,48);close(fp);write(1,n please input char string from std in:n,40);nread=read(0,buffer,80);if (nread=-1) write(2,std in read err,exit.n,22); exit(0); write(1,n- from std in read string, out to std out:-n,56);if (write(1,buffer,nread)!=nread) write(2,std out write err,exitn,23);exit (0

54、); else write(1,from std in read char string,has output.nn,42);exit(0); 如果程序不能正確執(zhí)行,并顯示以下信息: /dev/ttyS0:No such file or directory 表示找不到/dev/ttyS0設備,需要建立以下軟鏈接,然后再執(zhí)行程序。 /mnt/yaffs cd /dev /dev ln sf /dev/tts/0 ttyS0 如果對目標板文件已經進行了軟鏈接操作,那么在目標板RESET后,要重新鏈接,因為軟鏈接產生的信息沒有被長期保存。 程序執(zhí)行結果舉例如下: please input char

55、string,from /dev/ttyS0: abcd(回車) - from /dev/ttyS0 read string,out to /dev/ttyS0: - abcd from /dev/ttyS0 read char string,has output.ok. please input char string from std in: efgh(回車) - from std in read string,out to std out: - efgh from std in read char string,has output. 10.3.6 串行端口設備與文件關聯及 系統(tǒng)調用舉例

56、(OMAP3530) 在例10.7代碼中,前半部分是將串行端口/dev/ttyS2與文件關聯,使用系統(tǒng)調用對文件進行讀寫操作。這些操作實際上是通過目標板指定的串口,對串口連接的主機Linux下minicom仿真終端,進行讀寫操作。 例10.7代碼中后半部分,是Linux標準輸入/輸出/錯誤系統(tǒng)調用,其讀寫操作同樣是對目標板連接的主機Linux下minicom仿真終端進行讀寫操作。 例10.7代碼串行端口參數沒有重新設置,仍使用系統(tǒng)默認的波特率、幀格式,不使用調制解調器。 【例10.7】以下程序中,fp是系統(tǒng)文件描述符;nread是實際讀寫字節(jié)個數;buffer是讀寫緩沖區(qū)。程序先打開/dev/

57、ttyS0文件(串行端口),然后對其讀、寫,最后關閉。后半部分程序中函數的含義同例10.4。 程序代碼如下:#include #include #include #include #include #define COM1 /dev/ttyS2/*-*/int main()char buffer80;int nread;int fp;fp=open(COM1,O_RDWR);if (fp=-1) write(2,/dev/ttyS2 open err,exit.n,26); exit (0); write(1,n plese input char string,from /dev/ttyS2:

58、n,43);nread=read(fp,buffer,80);if (nread=-1) write(2,/dev/ttyS2 read err,exit.n,26); exit (0); write(1,n- from /dev/ttyS2 read string, out to /dev/tty2:-n,63);if (write(fp,buffer,nread)!=nread) write(2,/dev/ttyS2 write err,exit.n,27); exit(0); else write(fp,from /dev/ttyS2 read char string,has outpu

59、t.ok.n,48);close(fp);write(1,n please input char string from std in:n,40);nread=read(0,buffer,80);if (nread=-1) write(2,std in read err,exit.n,22); exit(0); write(1,n- from std in read string, out to std out:-n,56);if (write(1,buffer,nread)!=nread) write(2,std out write err,exitn,23);exit (0); else

60、write(1,from std in read char string,has output.nn,42);exit(0);執(zhí)行程序及輸出結果舉例如下:rootTechv_OMAP35xx:/var/volatile/tmp/03_tty1# ./term plese input char string,from /dev/ttyS2:abcd- from /dev/ttyS2 read string, out to /dev/tty2:-abcdfrom /dev/ttyS2 read char string,has output.ok. please input char string from std in:qwer- from std in read string, out to std out:-qwerfrom std

溫馨提示

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

評論

0/150

提交評論