Linux串列埠應用程式設計

2021-08-07 14:11:28 字數 4691 閱讀 8963

常見的資料通訊的基本方式可分為並行通訊與序列通訊兩種。

1.並行通訊是指利用多條資料傳輸線將乙個字資料的各位元位同時傳送。它的特點是傳輸速度快,適用於傳輸距離短且傳輸速度較高的通訊。

2.序列通訊是指利用一條傳輸線將資料以位元位為單位順序傳送。特點是通訊 線路簡單,利用簡單的線纜就可實現通訊,降低成本,適用於傳輸距離長且 傳輸速度較慢的通訊。

串列埠的設定主要是設定 struct termios 結構體的各成員值

#include.h> 

struct termios

;

termios 是在 posix 規範中定義的標準介面,表示終端裝置(包括虛擬終端、串 口等)。口是一種終端裝置,一般通過終端程式設計介面對其進行配置和控制。在具體講 解串列埠相關程式設計之前,先了解一下終端相關知識。

終端 有 3 種 工 作 模 式 ,分 別為 規 範模 式 ( canonical mode )、 非規 範模 式

(non-canonical mode)和原始模式(raw mode)。

在 非規 範模 式 下, 對 參 數 min ( c_cc[vmin] )和 time(c_cc[vtime])的設定決定 read()函式的呼叫方式。設定可以有 4 種不同的情況。

min = 0 和 time = 0:read()函式立即返回。若有可讀資料,則讀取資料並 返回被讀取的位元組數,否則讀取失敗並返回 0。

min > 0 和 time = 0:read()函式會被阻塞直到 min 個位元組資料可被讀取。

min = 0 和 time > 0:只要有資料可讀或者經過 time 個十分之一秒的時間, read()函式則立即返回,返回值為被讀取的位元組數。如果超時並且未讀到數 據,則 read()函式返回 0。

min > 0 和 time > 0:當有 min 個位元組可讀或者兩個輸入字元之間的時間 間隔超過 time 個十分之一秒時,read()函式才返回。因為在輸入第乙個字元 之後系統才會啟動定時器,所以在這種情況下,read()函式至少讀取乙個字 節之後才返回。

按照嚴格意義來講,原始模式是一種特殊的非規範模式。在原始模式下,所有的 輸入資料以位元組為單位被處理。在這個模式下,終端是不可回顯的,而且所有特定的 終端輸入/輸出控制處理不可用。通過呼叫 cfmakeraw()函式可以將終端設定為原始模 式。

設定串列埠中最基本的包括波特率設定,校驗位和 停止位設定。在這個結構中最為重要的是 c_cflag,通過對它的賦值,使用者可以設定波 特率、字元大小、資料位、停止位、奇偶校驗位和硬軟流控等。在這裡,不能直接對 c_cflag 成員初始化,而要將其通過「與」、「或」操作使用 其中的某些選項。

首先,為了安全起見和以後除錯程式方便,可以先儲存原先串列埠的配置,在這裡 可以使用函式 tcgetattr(fd, &old_cfg)。該函式得到 fd 指向的終端的配置引數,並將它 們儲存於 termios 結構變數 old_cfg 中。該函式還可以測試配置是否正確、該串列埠是否 可用等。若呼叫成功,函式返回值為 0,若呼叫失敗,函式返回值為-1,其使用如下 所示:

if(tcgetattr(fd, &old_cfg) != 0)

clocal 和 cread 分別用於本地連線和接受使能,因此,首先要通過位掩碼的

方式啟用這兩個選項。

newtio.c_cflag  |=clocal | cread;
呼叫 cfmakeraw()函式可以將終端設定為原始模式,在後面的例項中,採用原始

模式進行串列埠資料通訊。其原型cfmakeraw(&new_cfg);

設定波特率有專門的函式,使用者不能直接通過位掩碼來操作。設定波特率的主要

函式有:cfsetispeed()和 cfsetospeed()。這兩個函式的使用很簡單,如下所示:

cfsetispeed(&new_cfg, b115200); 

cfsetospeed(&new_cfg, b115200);

一般地,使用者需將終端的輸入和輸出波特率設定成一樣的。這幾個函式在成功時

返回 0,失敗時返回-1。

與設定波特率不同,設定字元大小並沒有現成可用的函式,需要用位掩碼。一般 首先去除資料位中的位掩碼,再重新按要求設定。如下所示:

new_cfg.c_cflag &= ~csize; /* 用資料位掩碼清空資料位設定 */

new_cfg.c_cflag |= cs8;

設定奇偶校驗位需要用到 termios 中的兩個成員:c_cflag 和 c_iflag。首先要啟用 c_cflag 中的校驗位使能標誌 parenb 和是否要進行偶校驗,同時還要啟用 c_iflag 中 的對於輸入資料的奇偶校驗使能(inpck)。無校驗位,**如下:

new_cfg.c_cflag &=~parenb;
如使能奇校驗時,**如下所示:

new_cfg.c_cflag |= (parodd | parenb);

new_cfg.c_iflag |= inpck;

而使能偶校驗時,**如下所示:

new_cfg.c_cflag |= parenb;

new_cfg.c_cflag &= ~parodd; /* 清除偶校驗標誌,則配置為奇校驗*/

new_cfg.c_iflag |= inpck;

設定停止位是通過啟用 c_cflag 中的 cstopb 而實現的。若停止位為乙個,則清除

cstopb,若停止位為兩個,則啟用 cstopb。以下分別是停止位為乙個和兩個位元時

的**:

new_cfg.c_cflag &= ~cstopb; /* 將停止位設定為乙個位元 */

new_cfg.c_cflag |= cstopb; /* 將停止位設定為兩個位元 */

在一般的情況下,可以設定設定為阻塞等待,直read到資料才返回

termios_new.c_cc[vtime] = 0;

termios_new.c_cc[vmin] = 4;

由於串列埠在重新設定之後,需要對當前的串列埠裝置進行適當的處理,這時就可呼叫在中宣告的tcdrain()、tcflow()、tcflush()等函式來處理目前串列埠緩衝中的資料,它們的格式如下所示。

int tcdrain(int fd); /* 使程式阻塞,直到輸出緩衝區的資料全部傳送完畢*/

int tcflow(int fd, int action) ; /* 用於暫停或重新開始輸出 */

int tcflush(int fd, int queue_selector); /* 用於清空輸入/輸出緩衝區*/

本例項中使用 tcflush()函式,對於在緩衝區中的尚未傳輸的資料,或者收到的

但是尚未讀取的資料,其處理方法取決於 queue_selector 的值,它可能的取值有以下幾種。

tciflush:對接收到而未被讀取的資料進行清空處理。

tcoflush:對尚未傳送成功的輸出資料進行清空處理。

tcioflush:包括前兩種功能,即對尚未處理的輸入輸出資料進行清空處理。

在完成全部串列埠配置之後,要啟用剛才的配置並使配置生效。這裡用到的函式是tcsetattr(),

它的函式原型是:

tcsetattr(int fd, int optional_actions, const struct termios*termios_p);
其中引數 termios_p 是 termios 型別的新配置變數。

引數 optional_actions 可能的取值有以下 3 種:

tcsanow:配置的修改立即生效。

tcsadrain:配置的修改在所有寫入 fd 的輸出都傳輸完畢之後生效。

tcsaflush:所有已接受但未讀入的輸入都將在修改生效之前被丟棄。

該函式若呼叫成功則返回 0,若失敗則返回-1,**如下所示:

if ((tcsetattr(fd, tcsanow, &new_cfg)) != 0)

在配置完串列埠的相關屬性後,就可以對串列埠進行開啟和讀寫操作了。它所使用的函式和普通檔案的讀寫函式一樣,都是 open()、write()和 read()。它們之間的區別的只是串列埠是乙個終端裝置,因此在選擇函式的具體引數時會有一些區別。另外,這裡會用到一些附加的函式,用於測試終端裝置的連線情況等。下面將對其進行具體講解。

開啟串列埠和開啟普通檔案一樣,都是使用 open()函式,如下所示:

fd = open( "/dev/ttys0", o_rdwr|o_noctty);
可以看到,這裡除了普通的讀寫引數外,還有引數 o_noctty 。o_noctty 標誌用於通知 linux 系統,該引數不會使開啟的檔案成為這個程序的控制終端。如果沒有指定這個標誌,那麼任何乙個輸入(諸如鍵盤中止訊號等)都將會影響使用者的程序

讀寫串列埠操作和讀寫普通檔案一樣,使用 read()和 write()函式即可,如下所示:

write(fd, buff, strlen(buff));

read(fd, buff, buffer_size)

串列埠應用程式設計

include include 標準輸入輸出定義 include 標準函式庫定義 include unix 標準函式定義 include include include 檔案控制定義 include ppsix 終端控制定義 include 錯誤號定義 include include include...

Linux應用程式設計 mmap

二話不說,上來就問下那個man name mmap,munmap map or unmap files or devices into memory synopsis include void mmap void addr,size t length,int prot,int flags,int f...

嵌入式Linux串列埠應用程式設計之串列埠讀寫

2013 08 27 在配置完串列埠的相關屬性後,就可以對串列埠進行開啟和讀寫操作了。它所使用的函式和普通檔案的讀寫函式一樣,都是open write 和read 它們之間區別的只是串列埠是乙個終端裝置,因此在選擇函式的具體引數時會有一些區別。另外,這裡會用到一些附加的函式,用於測試終端裝置的連線情...