Linux序列槽程式設計(中斷方式和select方式)
分類: 嵌入式
Linux下的序列槽程式設計,在嵌入式開發中占據着重要的地位,因為很多的嵌入式裝置都是通過序列槽交換資料的。在沒有作業系統的我們可以使用UART的中斷來出來資料的接受和發送,而在Linux作業系統下,我們也可以使用軟中斷的方式來處理資料的接受和發送,這裡主要使用的是信号SIGIO,也就是異步I/O。這裡也可以使用select實作異步形式的通知。 這裡可以參考《UNIX 環境進階程式設計》中的第14章 進階I/O和第18章的I/O終端,這兩章描述了序列槽的程式設計和異步I/O方面的内容。還有一本書《linux serial programming how-to》, 《Serial Programming Guide for POSIX Operating Systems》 。這都是序列槽程式設計的必讀和經典書籍。
序列槽參數的設定一般包括波特率、起始位數量、資料位、停止位和流控協定。在接收端和發送端要配置成一樣的參數設定。在Linux中,所有的裝置檔案一般都位于“/dev”下,其中序列槽一、序列槽二對應的裝置名依次為“/dev/ttyS0”、"/dev/ttyS1"。這可以通過檢視"/dev"下的檔案加以确認。我的序列槽通信是開發闆ARM9--mini2440發送資料,PC機通過序列槽接受資料。我的序列槽的參數設定為 115200,8,‘N’,1。也就是波特率是115200,8位資料位,無奇偶校驗位,1位停止位。因為是用的開發闆發送資料,是以要用到在minicom中運作發送的程式,不過在發送程式運作後,要立即關閉minicom,否則,接受程式不能接受到資料。這個是我使用中斷時出現的問題,當我使用select是沒有此問題,現在還不知道具體的原因是什麼。
序列槽程式設計中有一個最重要的結構體:
|
這個結構中最重要的是c_cflag。通過對它的指派,使用者可以設定波特率、字元大小、資料位、停止位、奇偶校驗位和硬體流控等。其中的參數在網上和很多的書籍上都介紹的很詳細了,這裡主要介紹一下我在其中遇到的問題和解決的辦法,以供學習。其中的c_line,在POSIX中的Linux中沒有用到。
在c_lflag中有這麼一個參數ICANON,如若設定,則按規範模式工作,這使下列字元起作用:EOF、EOL EOL2、 ERASE、 KILL、 REPRINT 、STATUS、WERASE。輸入字元被裝配成行。如果不以規範模式工作,則讀請求直接從輸入隊列取字元。在至少接收到MIN個位元組或已超過TIME值之前,read将不傳回。
在規範模式很容易:系統每次傳回一行。但在非規範模式下,系統怎樣才能知道在什麼時候将資料傳回給我們呢?如果它一次傳回一個位元組,那麼系統開銷就很大。解決方法是:當已讀了指定量的資料後,或者已經過了給定的時間後,即通知系統傳回。這種技術使用了termios結構中c_cc數組的兩個變量:MIN和TIME。C_cc資料中的這兩個元素的下标名為VMIN和VTIME。MIN說明一個read傳回前的最小位元組數。TIME說明等待資料到達的分秒數。
|
其中的“Set_Uart.c”是我設定序列槽的模式和打開序列槽的檔案。模式的設定就是按上面說的進行設定。
下面是發送資料,寫序列槽的程式,
|
把該檔案進行交叉編譯後下載下傳到開發闆,進行運作./Write_Uart。
下面是中斷讀取資料的main函數。Read_Uart_IRQ.c 當使用中斷方式的讀取資料時,要先運作開發闆上的Write_Uart.c檔案,然後,立即關閉,再在PC上運作讀取資料的Read_Uart_IRQ.c檔案。是以,在Write_Uart.c中,在使用write()函數向UART寫資料之間加入一小段的延時。這樣便于關閉minicom,如果在兩台PC上進行測試的話,應該不存在此問題。
|
下面是select方式的讀取資料的main函數。Read_Uart.c
|
下面是運作的結果,PC機收到的開發闆發送過來的資料。
|
其中序列槽中的一些重要的裝置如下;
newtio.c_cc[VTIME] = 1;
newtio.c_cc[VMIN] = 0;
newtio.c_lflag &= ~( ECHO | ECHOE | ISIG);
newtio.c_lflag |=ICANON; //關閉ICANON标志就使終端處于非規範模式 現在處于打開 處于規範模式下
newtio.c_oflag &= ~OPOST; //執行輸出處理 現在就關閉狀态
newtio.c_iflag |= (IGNPAR | ICRNL); //忽略奇偶校驗錯誤 将CR 映射成NL