详解linux下的串口通讯开发
串行口是計(jì)算機(jī)一種常用的接口,具有連接線少,通訊簡(jiǎn)單,得到廣泛的使用。常用的串口是RS-232-C接口(又稱EIA RS-232-C)它是在1970年由美國(guó)電子工業(yè)協(xié)會(huì)(EIA)聯(lián)合貝爾系統(tǒng)、調(diào)制解調(diào)器廠家及計(jì)算機(jī)終端生產(chǎn)廠家共同制定的用于串行通訊的標(biāo)準(zhǔn)。串口通訊指的是計(jì)算機(jī)依次以位(bit)為單位來傳送數(shù)據(jù),串行通訊使用的范圍很廣,在嵌入式系統(tǒng)開發(fā)過程中串口通訊也經(jīng)常用到通訊方式之一。
Linux對(duì)所有設(shè)備的訪問是通過設(shè)備文件來進(jìn)行的,串口也是這樣,為了訪問串口,只需打開其設(shè)備文件即可操作串口設(shè)備。在linux系統(tǒng)下面,每一個(gè)串口設(shè)備都有設(shè)備文件與其關(guān)聯(lián),設(shè)備文件位于系統(tǒng)的/dev目錄下面。如linux下的/ttyS0,/ttyS1分別表示的是串口1和串口2。下面來詳細(xì)介紹linux下是如何使用串口的:
1. 串口操作需要用到的頭文件
#include /*標(biāo)準(zhǔn)輸入輸出定義*/
#include /*標(biāo)準(zhǔn)函數(shù)庫(kù)定義*/
#include /*Unix 標(biāo)準(zhǔn)函數(shù)定義*/
#include
#include
#include /*文件控制定義*/
#include /*POSIX 終端控制定義*/
#include /*錯(cuò)誤號(hào)定義*/
#include /*字符串功能函數(shù)*/
2. 串口通訊波特率設(shè)置
波特率的設(shè)置定義在,其包含在頭文件里。
常用的波特率常數(shù)如下:
B0-------à0 B1800-------à1800
B50-----à50 B2400------à2400
B75-----à75 B4800------à4800
B110----à110 B9600------à9600
B134----à134.5 B19200-----à19200
B200----à200 B38400------à38400
B300----à300 B57600------à57600
B600----à600 B76800------à76800
B1200---à1200 B115200-----à115200
假定程序中想要設(shè)置通訊的波特率,使用cfsetispeed( )和cfsetospeed( )函數(shù)來操作,獲取波特率信息是通過cfgetispeed()和cfgetospeed()函數(shù)來完成的。比如可以這樣來指定串口通訊的波特率:
#include //頭文件定義
........
........
.......
struct termios opt; /*定義指向termios 結(jié)構(gòu)類型的指針opt*/
/***************以下設(shè)置通訊波特率****************/
cfsetispeed(&opt,B9600 ); /*指定輸入波特率,9600bps*/
cfsetospeed(&opt,B9600);/*指定輸出波特率,9600bps*/
/************************************************/
.........
..........
一般來說,輸入、輸出的波特率應(yīng)該是一致的。
3. 串口屬性配置
在程序中,很容易配置串口的屬性,這些屬性定義在結(jié)構(gòu)體struct termios中。為在程序中使用該結(jié)構(gòu)體,需要包含文件,該頭文件定義了結(jié)構(gòu)體struct termios。該結(jié)構(gòu)體定義如下:
#define NCCS 19
struct termios {
tcflag_t c_iflag; /* 輸入?yún)?shù) */
tcflag_t c_oflag; /* 輸出參數(shù) */
tcflag_t c_cflag; /* 控制參數(shù)*/
tcflag_t c_ispeed; /* 輸入波特率 */
tcflag_t c_ospeed; /* 輸出波特率 */
cc_t c_line; /* 線控制 */
cc_t c_cc[NCCS]; /* 控制字符*/
};
其中成員c_line在POSIX(Portable Operating System Interface for UNIX)系統(tǒng)中不使用。對(duì)于支持POSIX終端接口的系統(tǒng)中,對(duì)于端口屬性的設(shè)置和獲取要用到兩個(gè)重要的函數(shù)是:
(1).int tcsetattr(int fd,int opt_DE,*ptr)
該函數(shù)用來設(shè)置終端控制屬性,其參數(shù)說明如下:
l fd:待操作的文件描述符
l opt_DE:選項(xiàng)值,有三個(gè)選項(xiàng)以供選擇:
TCSANOW: 不等數(shù)據(jù)傳輸完畢就立即改變屬性
TCSADRAIN:等待所有數(shù)據(jù)傳輸結(jié)束才改變屬性
TCSAFLUSH:清空輸入輸出緩沖區(qū)才改變屬性
l *ptr:指向termios結(jié)構(gòu)的指針
函數(shù)返回值:成功返回0,失敗返回-1。
(2).int tcgetattr(int fd,*ptr)
該函數(shù)用來獲取終端控制屬性,它把串口的默認(rèn)設(shè)置賦給了termios數(shù)據(jù)數(shù)據(jù)結(jié)構(gòu),其參數(shù)說明如下:
l fd:待操作的文件描述符
l *ptr:指向termios結(jié)構(gòu)的指針
函數(shù)返回值:成功返回0,失敗返回-1。
4. 打開串口
在前面已經(jīng)提到linux下的串口訪問是以設(shè)備文件形式進(jìn)行的,所以打開串口也即是打開文件的操作。函數(shù)原型可以如下所示:
int open(“DE_name”,int open_Status)
參數(shù)說明:
(1).DE_name:要打開的設(shè)備文件名
比如要打開串口1,即為/dev/ttyS0。
(2).open_Status:文件打開方式,可采用下面的文件打開模式:
l O_RDONLY:以只讀方式打開文件
l O_WRONLY:以只寫方式打開文件
l O_RDWR:以讀寫方式打開文件
l O_APPEND:寫入數(shù)據(jù)時(shí)添加到文件末尾
l O_CREATE:如果文件不存在則產(chǎn)生該文件,使用該標(biāo)志需要設(shè)置訪問權(quán)限位mode_t
l O_EXCL:指定該標(biāo)志,并且指定了O_CREATE標(biāo)志,如果打開的文件存在則會(huì)產(chǎn)生一個(gè)錯(cuò)誤
l O_TRUNC:如果文件存在并且成功以寫或者只寫方式打開,則清除文件所有內(nèi)容,使得文件長(zhǎng)度變?yōu)?
l O_NOCTTY:如果打開的是一個(gè)終端設(shè)備,這個(gè)程序不會(huì)成為對(duì)應(yīng)這個(gè)端口的控制終端,如果沒有該標(biāo)志,任何一個(gè)輸入,例如鍵盤中止信號(hào)等,都將影響進(jìn)程。
l O_NONBLOCK:該標(biāo)志與早期使用的O_NDELAY標(biāo)志作用差不多。程序不關(guān)心DCD信號(hào)線的狀態(tài),如果指定該標(biāo)志,進(jìn)程將一直在休眠狀態(tài),直到DCD信號(hào)線為0。
函數(shù)返回值:
成功返回文件描述符,如果失敗返回-1
例如假定以可讀寫方式打開/dev/ttyS0設(shè)備,就可以這樣操作:
#include //頭文件包含
......
......
int fd; /* 文件描述符 */
fd = open("/dev/ttyS0", O_RDWR | 0_NOCTTY); /*以讀寫方式打開設(shè)備*/
if(fd == -1)
perror("Can not open Serial_Port 1/n!");/*打開失敗時(shí)的錯(cuò)誤提示*/
........
........
5. 串口讀操作(接收端)
用open函數(shù)打開設(shè)備文件,函數(shù)返回一個(gè)文件描述符(file descriptors,fd),通過文件描述符來訪問文件。讀串口操作是通過read函數(shù)來完成的。函數(shù)原型如下:
int read(int fd, *buffer,length);
參數(shù)說明:
(1).int fd:文件描述符
(2).*buffer:數(shù)據(jù)緩沖區(qū)
(3).length:要讀取的字節(jié)數(shù)
函數(shù)返回值:
讀操作成功讀取返回讀取的字節(jié)數(shù),失敗則返回-1。
6. 串口寫操作(發(fā)送端)
寫串口操作是通過write函數(shù)來完成的。函數(shù)原型如下:
write(int fd, *buffer,length);
參數(shù)說明:
(1).fd:文件描述符
(2).*buffer:存儲(chǔ)寫入數(shù)據(jù)的數(shù)據(jù)緩沖區(qū)
(3).length:寫入緩沖去的數(shù)據(jù)字節(jié)數(shù)
函數(shù)返回值:
成功返回寫入數(shù)據(jù)的字節(jié)數(shù),該值通常等于length,如果寫入失敗返回-1。
例如:向終端設(shè)備發(fā)送初始化命令
#include //頭文件包含
......
......
int n
sbuf[]={Hello,this is a Serial_Port test!/n };//待發(fā)送數(shù)據(jù)
int len_send="sizeof"(sbuf);//發(fā)送緩沖區(qū)字節(jié)數(shù)定義
n = write(fd,sbuf,len_send); //寫緩沖區(qū)
if(n == -1)
{
printf("Wirte sbuf error./n");
}
......
......
7. 關(guān)閉串口
對(duì)設(shè)備文件的操作與對(duì)普通文件的操作一樣,打開操作之后還需要關(guān)閉,關(guān)閉串口用函數(shù)close( )來操作,函數(shù)原型為:
int close(int fd);
參數(shù)說明:
fd:文件描述符
函數(shù)返回值:
成功返回0,失敗返回-1。
NAME
termios, tcgetattr, tcsetattr, tcsendbreak, tcdrain, tcflush, tcflow, cfmakeraw, cfgetospeed, cfgetispeed, cfsetispeed, cfsetospeed - 獲取和設(shè)置終端屬性,行控制,獲取和設(shè)置波特率
SYNOPSIS 總覽
#include <termios.h>
#include <unistd.h>
int tcgetattr(intfd, struct termios *termios_p);
int tcsetattr(intfd, intoptional_actions, struct termios *termios_p);
int tcsendbreak(intfd, intduration);
int tcdrain(intfd);
int tcflush(intfd, intqueue_selector);
int tcflow(intfd, intaction);
int cfmakeraw(struct termios *termios_p);
speed_t cfgetispeed(struct termios *termios_p);
speed_t cfgetospeed(struct termios *termios_p);
int cfsetispeed(struct termios *termios_p, speed_tspeed);
int cfsetospeed(struct termios *termios_p, speed_tspeed);
DESCRIPTION 描述
termios 函數(shù)族提供了一個(gè)常規(guī)的終端接口,用于控制非同步通信端口。
這里描述的大部分屬性有一個(gè)termios_p類型的參數(shù),它是指向一個(gè)termios結(jié)構(gòu)的指針。這個(gè)結(jié)構(gòu)包含了至少下列成員:
tcflag_t c_iflag; /* 輸入模式 */
tcflag_t c_oflag; /* 輸出模式 */
tcflag_t c_cflag; /* 控制模式 */
tcflag_t c_lflag; /* 本地模式 */
cc_t c_cc[NCCS]; /* 控制字符 */
c_iflag標(biāo)志常量:
IGNBRK忽略輸入中的 BREAK 狀態(tài)。BRKINT如果設(shè)置了IGNBRK,將忽略 BREAK。如果沒有設(shè)置,但是設(shè)置了BRKINT,那么 BREAK 將使得輸入和輸出隊(duì)列被刷新,如果終端是一個(gè)前臺(tái)進(jìn)程組的控制終端,這個(gè)進(jìn)程組中所有進(jìn)程將收到SIGINT信號(hào)。如果既未設(shè)置IGNBRK也未設(shè)置BRKINT,BREAK 將視為與 NUL 字符同義,除非設(shè)置了PARMRK,這種情況下它被視為序列 /377 /0 /0。IGNPAR忽略楨錯(cuò)誤和奇偶校驗(yàn)錯(cuò)。PARMRK如果沒有設(shè)置IGNPAR,在有奇偶校驗(yàn)錯(cuò)或楨錯(cuò)誤的字符前插入 /377 /0。如果既沒有設(shè)置IGNPAR也沒有設(shè)置PARMRK,將有奇偶校驗(yàn)錯(cuò)或楨錯(cuò)誤的字符視為 /0。INPCK啟用輸入奇偶檢測(cè)。ISTRIP去掉第八位。INLCR將輸入中的 NL 翻譯為 CR。IGNCR忽略輸入中的回車。ICRNL將輸入中的回車翻譯為新行 (除非設(shè)置了IGNCR)。IUCLC(不屬于 POSIX) 將輸入中的大寫字母映射為小寫字母。IXON啟用輸出的 XON/XOFF 流控制。IXANY(不屬于 POSIX.1;XSI) 允許任何字符來重新開始輸出。(?)IXOFF啟用輸入的 XON/XOFF 流控制。IMAXBEL(不屬于 POSIX) 當(dāng)輸入隊(duì)列滿時(shí)響零。Linux 沒有實(shí)現(xiàn)這一位,總是將它視為已設(shè)置。
POSIX.1 中定義的c_oflag標(biāo)志常量:
OPOST啟用具體實(shí)現(xiàn)自行定義的輸出處理。
其余c_oflag標(biāo)志常量定義在 POSIX 1003.1-2001 中,除非另外說明。
OLCUC(不屬于 POSIX) 將輸出中的小寫字母映射為大寫字母。ONLCR(XSI) 將輸出中的新行符映射為回車-換行。OCRNL將輸出中的回車映射為新行符ONOCR不在第 0 列輸出回車。ONLRET不輸出回車。OFILL發(fā)送填充字符作為延時(shí),而不是使用定時(shí)來延時(shí)。OFDEL(不屬于 POSIX) 填充字符是 ASCII DEL (0177)。如果不設(shè)置,填充字符則是 ASCII NUL。NLDLY新行延時(shí)掩碼。取值為NL0和NL1。CRDLY回車延時(shí)掩碼。取值為CR0,CR1,CR2, 或CR3。TABDLY水平跳格延時(shí)掩碼。取值為TAB0,TAB1,TAB2,TAB3(或XTABS)。取值為 TAB3,即 XTABS,將擴(kuò)展跳格為空格 (每個(gè)跳格符填充 8 個(gè)空格)。(?)BSDLY回退延時(shí)掩碼。取值為BS0或BS1。(從來沒有被實(shí)現(xiàn)過)VTDLY豎直跳格延時(shí)掩碼。取值為VT0或VT1。FFDLY進(jìn)表延時(shí)掩碼。取值為FF0或FF1。
c_cflag標(biāo)志常量:
CBAUD(不屬于 POSIX) 波特率掩碼 (4+1 位)。CBAUDEX(不屬于 POSIX) 擴(kuò)展的波特率掩碼 (1 位),包含在 CBAUD 中。
(POSIX 規(guī)定波特率存儲(chǔ)在 termios 結(jié)構(gòu)中,并未精確指定它的位置,而是提供了函數(shù)cfgetispeed()和cfsetispeed()來存取它。一些系統(tǒng)使用c_cflag中 CBAUD 選擇的位,其他系統(tǒng)使用單獨(dú)的變量,例如sg_ispeed和sg_ospeed。)
CSIZE字符長(zhǎng)度掩碼。取值為CS5,CS6,CS7, 或CS8。CSTOPB設(shè)置兩個(gè)停止位,而不是一個(gè)。CREAD打開接受者。PARENB允許輸出產(chǎn)生奇偶信息以及輸入的奇偶校驗(yàn)。PARODD輸入和輸出是奇校驗(yàn)。HUPCL在最后一個(gè)進(jìn)程關(guān)閉設(shè)備后,降低 modem 控制線 (掛斷)。(?)CLOCAL忽略 modem 控制線。LOBLK(不屬于 POSIX) 從非當(dāng)前 shell 層阻塞輸出(用于shl)。(?)CIBAUD(不屬于 POSIX) 輸入速度的掩碼。CIBAUD 各位的值與 CBAUD 各位相同,左移了 IBSHIFT 位。CRTSCTS(不屬于 POSIX) 啟用 RTS/CTS (硬件) 流控制。
c_lflag標(biāo)志常量:
ISIG當(dāng)接受到字符 INTR, QUIT, SUSP, 或 DSUSP 時(shí),產(chǎn)生相應(yīng)的信號(hào)。ICANON啟用標(biāo)準(zhǔn)模式 (canonical mode)。允許使用特殊字符 EOF, EOL, EOL2, ERASE, KILL, LNEXT, REPRINT, STATUS, 和 WERASE,以及按行的緩沖。XCASE(不屬于 POSIX; Linux 下不被支持) 如果同時(shí)設(shè)置了ICANON,終端只有大寫。輸入被轉(zhuǎn)換為小寫,除了以 / 前綴的字符。輸出時(shí),大寫字符被前綴 /,小寫字符被轉(zhuǎn)換成大寫。ECHO回顯輸入字符。ECHOE如果同時(shí)設(shè)置了ICANON,字符 ERASE 擦除前一個(gè)輸入字符,WERASE 擦除前一個(gè)詞。ECHOK如果同時(shí)設(shè)置了ICANON,字符 KILL 刪除當(dāng)前行。ECHONL如果同時(shí)設(shè)置了ICANON,回顯字符 NL,即使沒有設(shè)置 ECHO。ECHOCTL(不屬于 POSIX) 如果同時(shí)設(shè)置了ECHO,除了 TAB, NL, START, 和 STOP 之外的 ASCII 控制信號(hào)被回顯為 ^X, 這里 X 是比控制信號(hào)大 0x40 的 ASCII 碼。例如,字符 0x08 (BS) 被回顯為 ^H。ECHOPRT(不屬于 POSIX) 如果同時(shí)設(shè)置了ICANON和IECHO,字符在刪除的同時(shí)被打印。ECHOKE(不屬于 POSIX) 如果同時(shí)設(shè)置了ICANON,回顯 KILL 時(shí)將刪除一行中的每個(gè)字符,如同指定了ECHOE和ECHOPRT一樣。DEFECHO(不屬于 POSIX) 只在一個(gè)進(jìn)程讀的時(shí)候回顯。FLUSHO(不屬于 POSIX; Linux 下不被支持) 輸出被刷新。這個(gè)標(biāo)志可以通過鍵入字符 DISCARD 來開關(guān)。NOFLSH禁止在產(chǎn)生 SIGINT, SIGQUIT 和 SIGSUSP 信號(hào)時(shí)刷新輸入和輸出隊(duì)列。TOSTOP向試圖寫控制終端的后臺(tái)進(jìn)程組發(fā)送 SIGTTOU 信號(hào)。PENDIN(不屬于 POSIX; Linux 下不被支持) 在讀入下一個(gè)字符時(shí),輸入隊(duì)列中所有字符被重新輸出。(bash用它來處理 typeahead)IEXTEN啟用實(shí)現(xiàn)自定義的輸入處理。這個(gè)標(biāo)志必須與ICANON同時(shí)使用,才能解釋特殊字符 EOL2,LNEXT,REPRINT 和 WERASE,IUCLC標(biāo)志才有效。
c_cc數(shù)組定義了特殊的控制字符。符號(hào)下標(biāo) (初始值) 和意義為:
VINTR(003, ETX, Ctrl-C, or also 0177, DEL, rubout) 中斷字符。發(fā)出 SIGINT 信號(hào)。當(dāng)設(shè)置 ISIG 時(shí)可被識(shí)別,不再作為輸入傳遞。VQUIT(034, FS, Ctrl-/) 退出字符。發(fā)出 SIGQUIT 信號(hào)。當(dāng)設(shè)置 ISIG 時(shí)可被識(shí)別,不再作為輸入傳遞。VERASE(0177, DEL, rubout, or 010, BS, Ctrl-H, or also #) 刪除字符。刪除上一個(gè)還沒有刪掉的字符,但不刪除上一個(gè) EOF 或行首。當(dāng)設(shè)置 ICANON 時(shí)可被識(shí)別,不再作為輸入傳遞。VKILL(025, NAK, Ctrl-U, or Ctrl-X, or also @) 終止字符。刪除自上一個(gè) EOF 或行首以來的輸入。當(dāng)設(shè)置 ICANON 時(shí)可被識(shí)別,不再作為輸入傳遞。VEOF(004, EOT, Ctrl-D) 文件尾字符。更精確地說,這個(gè)字符使得 tty 緩沖中的內(nèi)容被送到等待輸入的用戶程序中,而不必等到 EOL。如果它是一行的第一個(gè)字符,那么用戶程序的read()將返回 0,指示讀到了 EOF。當(dāng)設(shè)置 ICANON 時(shí)可被識(shí)別,不再作為輸入傳遞。VMIN非 canonical 模式讀的最小字符數(shù)。VEOL(0, NUL) 附加的行尾字符。當(dāng)設(shè)置 ICANON 時(shí)可被識(shí)別。VTIME非 canonical 模式讀時(shí)的延時(shí),以十分之一秒為單位。VEOL2(not in POSIX; 0, NUL) 另一個(gè)行尾字符。當(dāng)設(shè)置 ICANON 時(shí)可被識(shí)別。VSWTCH(not in POSIX; not supported under Linux; 0, NUL) 開關(guān)字符。(只為shl所用。)VSTART(021, DC1, Ctrl-Q) 開始字符。重新開始被 Stop 字符中止的輸出。當(dāng)設(shè)置 IXON 時(shí)可被識(shí)別,不再作為輸入傳遞。VSTOP(023, DC3, Ctrl-S) 停止字符。停止輸出,直到鍵入 Start 字符。當(dāng)設(shè)置 IXON 時(shí)可被識(shí)別,不再作為輸入傳遞。VSUSP(032, SUB, Ctrl-Z) 掛起字符。發(fā)送 SIGTSTP 信號(hào)。當(dāng)設(shè)置 ISIG 時(shí)可被識(shí)別,不再作為輸入傳遞。VDSUSP(not in POSIX; not supported under Linux; 031, EM, Ctrl-Y) 延時(shí)掛起信號(hào)。當(dāng)用戶程序讀到這個(gè)字符時(shí),發(fā)送 SIGTSTP 信號(hào)。當(dāng)設(shè)置 IEXTEN 和 ISIG,并且系統(tǒng)支持作業(yè)管理時(shí)可被識(shí)別,不再作為輸入傳遞。VLNEXT(not in POSIX; 026, SYN, Ctrl-V) 字面上的下一個(gè)。引用下一個(gè)輸入字符,取消它的任何特殊含義。當(dāng)設(shè)置 IEXTEN 時(shí)可被識(shí)別,不再作為輸入傳遞。VWERASE(not in POSIX; 027, ETB, Ctrl-W) 刪除詞。當(dāng)設(shè)置 ICANON 和 IEXTEN 時(shí)可被識(shí)別,不再作為輸入傳遞。VREPRINT(not in POSIX; 022, DC2, Ctrl-R) 重新輸出未讀的字符。當(dāng)設(shè)置 ICANON 和 IEXTEN 時(shí)可被識(shí)別,不再作為輸入傳遞。VDISCARD(not in POSIX; not supported under Linux; 017, SI, Ctrl-O) 開關(guān):開始/結(jié)束丟棄未完成的輸出。當(dāng)設(shè)置 IEXTEN 時(shí)可被識(shí)別,不再作為輸入傳遞。VSTATUS(not in POSIX; not supported under Linux; status request: 024, DC4, Ctrl-T).
這些符號(hào)下標(biāo)值是互不相同的,除了 VTIME,VMIN 的值可能分別與 VEOL,VEOF 相同。 (在 non-canonical 模式下,特殊字符的含義更改為延時(shí)含義。MIN 表示應(yīng)當(dāng)被讀入的最小字符數(shù)。TIME 是以十分之一秒為單位的計(jì)時(shí)器。如果同時(shí)設(shè)置了它們,read 將等待直到至少讀入一個(gè)字符,一旦讀入 MIN 個(gè)字符或者從上次讀入字符開始經(jīng)過了 TIME 時(shí)間就立即返回。如果只設(shè)置了 MIN,read 在讀入 MIN 個(gè)字符之前不會(huì)返回。如果只設(shè)置了 TIME,read 將在至少讀入一個(gè)字符,或者計(jì)時(shí)器超時(shí)的時(shí)候立即返回。如果都沒有設(shè)置,read 將立即返回,只給出當(dāng)前準(zhǔn)備好的字符。) (?)
tcgetattr()得到與fd指向的對(duì)象相關(guān)的參數(shù),將它們保存于termios_p引用的termios結(jié)構(gòu)中。函數(shù)可以從后臺(tái)進(jìn)程中調(diào)用;但是,終端屬性可能被后來的前臺(tái)進(jìn)程所改變。
tcsetattr()設(shè)置與終端相關(guān)的參數(shù) (除非需要底層支持卻無(wú)法滿足),使用termios_p引用的termios結(jié)構(gòu)。optional_actions指定了什么時(shí)候改變會(huì)起作用:
TCSANOW改變立即發(fā)生TCSADRAIN改變?cè)谒袑懭?em>fd的輸出都被傳輸后生效。這個(gè)函數(shù)應(yīng)當(dāng)用于修改影響輸出的參數(shù)時(shí)使用。TCSAFLUSH改變?cè)谒袑懭?em>fd引用的對(duì)象的輸出都被傳輸后生效,所有已接受但未讀入的輸入都在改變發(fā)生前丟棄。
tcsendbreak()傳送連續(xù)的 0 值比特流,持續(xù)一段時(shí)間,如果終端使用異步串行數(shù)據(jù)傳輸?shù)脑挕H绻?em>duration是 0,它至少傳輸 0.25 秒,不會(huì)超過 0.5 秒。如果duration非零,它發(fā)送的時(shí)間長(zhǎng)度由實(shí)現(xiàn)定義。
如果終端并非使用異步串行數(shù)據(jù)傳輸,tcsendbreak()什么都不做。
tcdrain()等待直到所有寫入fd引用的對(duì)象的輸出都被傳輸。
tcflush()丟棄要寫入 引用的對(duì)象,但是尚未傳輸?shù)臄?shù)據(jù),或者收到但是尚未讀取的數(shù)據(jù),取決于queue_selector的值:
TCIFLUSH刷新收到的數(shù)據(jù)但是不讀TCOFLUSH刷新寫入的數(shù)據(jù)但是不傳送TCIOFLUSH同時(shí)刷新收到的數(shù)據(jù)但是不讀,并且刷新寫入的數(shù)據(jù)但是不傳送
tcflow()掛起fd引用的對(duì)象上的數(shù)據(jù)傳輸或接收,取決于action的值:
TCOOFF掛起輸出TCOON重新開始被掛起的輸出TCIOFF發(fā)送一個(gè) STOP 字符,停止終端設(shè)備向系統(tǒng)傳送數(shù)據(jù)TCION發(fā)送一個(gè) START 字符,使終端設(shè)備向系統(tǒng)傳輸數(shù)據(jù)
打開一個(gè)終端設(shè)備時(shí)的默認(rèn)設(shè)置是輸入和輸出都沒有掛起。
波特率函數(shù)被用來獲取和設(shè)置termios結(jié)構(gòu)中,輸入和輸出波特率的值。新值不會(huì)馬上生效,直到成功調(diào)用了tcsetattr()函數(shù)。
設(shè)置速度為B0使得 modem "掛機(jī)"。與B38400相應(yīng)的實(shí)際比特率可以用setserial(8) 調(diào)整。
輸入和輸出波特率被保存于termios結(jié)構(gòu)中。
cfmakeraw設(shè)置終端屬性如下:
termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
|INLCR|IGNCR|ICRNL|IXON);
termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
termios_p->c_cflag &= ~(CSIZE|PARENB);
termios_p->c_cflag |= CS8;
cfgetospeed()返回termios_p指向的termios結(jié)構(gòu)中存儲(chǔ)的輸出波特率
cfsetospeed()設(shè)置termios_p指向的termios結(jié)構(gòu)中存儲(chǔ)的輸出波特率為speed。取值必須是以下常量之一:
B0
B50
B75
B110
B134
B150
B200
B300
B600
B1200
B1800
B2400
B4800
B9600
B19200
B38400
B57600
B115200
B230400
零值B0用來中斷連接。如果指定了 B0,不應(yīng)當(dāng)再假定存在連接。通常,這樣將斷開連接。CBAUDEX是一個(gè)掩碼,指示高于 POSIX.1 定義的速度的那一些 (57600 及以上)。因此,B57600&CBAUDEX為非零。
cfgetispeed()返回termios結(jié)構(gòu)中存儲(chǔ)的輸入波特率。
cfsetispeed()設(shè)置termios結(jié)構(gòu)中存儲(chǔ)的輸入波特率為speed。如果輸入波特率被設(shè)為0,實(shí)際輸入波特率將等于輸出波特率。
RETURN VALUE 返回值
cfgetispeed()返回termios結(jié)構(gòu)中存儲(chǔ)的輸入波特率。
cfgetospeed()返回termios結(jié)構(gòu)中存儲(chǔ)的輸出波特率。
其他函數(shù)返回:
0成功-1失敗,并且為errno置值來指示錯(cuò)誤。
注意tcsetattr()返回成功,如果任何所要求的修改可以實(shí)現(xiàn)的話。因此,當(dāng)進(jìn)行多重修改時(shí),應(yīng)當(dāng)在這個(gè)函數(shù)之后再次調(diào)用tcgetattr()來檢測(cè)是否所有修改都成功實(shí)現(xiàn)。
NOTES 注意
Unix V7 以及很多后來的系統(tǒng)有一個(gè)波特率的列表,在十四個(gè)值 B0, ..., B9600 之后可以看到兩個(gè)常數(shù) EXTA, EXTB ("External A" and "External B")。很多系統(tǒng)將這個(gè)列表擴(kuò)展為更高的波特率。
tcsendbreak中非零的duration有不同的效果。SunOS 指定中斷duration*N秒,其中N至少為 0.25,不高于 0.5 。Linux, AIX, DU, Tru64 發(fā)送duration微秒的 break 。FreeBSD, NetBSD, HP-UX 以及 MacOS 忽略duration的值。在 Solaris 和 Unixware 中,tcsendbreak搭配非零的duration效果類似于tcdrain。
所有的范例來源自miniterm.c. The type ahead 暫存器被限制在 255 個(gè)字元, 就跟標(biāo)準(zhǔn)輸入程序的最大字串長(zhǎng)度相同 (或).
參考程序碼中的注解它會(huì)解釋不同輸入模式的使用. 我希望這些程序碼都能被了解. 標(biāo)準(zhǔn)輸入程序的程序范例的注解寫得最好, 其它的范例都只在不同于其它范例的地方做注解.
敘述不是很完整, 但可以激勵(lì)你對(duì)這范例做實(shí)驗(yàn), 以延生出合于你所需應(yīng)用程序的最佳解.
別忘記要把序列埠的權(quán)限設(shè)定正確 (也就是:chmod a+rw /dev/ttyS1)!
3.1 標(biāo)準(zhǔn)輸入程序
#include
#include
#include
#include
#include
/* 鮑率設(shè)定被定義在 , 這在 被引入 */
#define BAUDRATE B38400
/* 定義正確的序列埠 */
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* POSIX 系統(tǒng)兼容 */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
main()
{
int fd,c, res;
struct termios oldtio,newtio;
char buf[255];
/*
開啟數(shù)據(jù)機(jī)裝置以讀取并寫入而不以控制 tty 的模式
因?yàn)槲覀儾幌氤绦蛟谒统?CTRL-C 后就被殺掉.
*/
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); exit(-1); }
tcgetattr(fd,&oldtio); /* 儲(chǔ)存目前的序列埠設(shè)定 */
bzero(&newtio, sizeof(newtio)); /* 清除結(jié)構(gòu)體以放入新的序列埠設(shè)定值 */
/*
BAUDRATE: 設(shè)定 bps 的速度. 你也可以用 cfsetispeed 及 cfsetospeed 來設(shè)定.
CRTSCTS : 輸出資料的硬件流量控制 (只能在具完整線路的纜線下工作
參考 Serial-HOWTO 第七節(jié))
CS8 : 8n1 (8 位元, 不做同位元檢查,1 個(gè)終止位元)
CLOCAL : 本地連線, 不具數(shù)據(jù)機(jī)控制功能
CREAD : 致能接收字元
*/
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
/*
IGNPAR : 忽略經(jīng)同位元檢查后, 錯(cuò)誤的位元組
ICRNL : 比 CR 對(duì)應(yīng)成 NL (否則當(dāng)輸入信號(hào)有 CR 時(shí)不會(huì)終止輸入)
在不然把裝置設(shè)定成 raw 模式(沒有其它的輸入處理)
*/
newtio.c_iflag = IGNPAR | ICRNL;
/*
Raw 模式輸出.
*/
newtio.c_oflag = 0;
/*
ICANON : 致能標(biāo)準(zhǔn)輸入, 使所有回應(yīng)機(jī)能停用, 并不送出信號(hào)以叫用程序
*/
newtio.c_lflag = ICANON;
/*
初始化所有的控制特性
預(yù)設(shè)值可以在 /usr/include/termios.h 找到, 在注解中也有,
但我們?cè)谶@不需要看它們
*/
newtio.c_cc[VINTR] = 0; /* Ctrl-c */
newtio.c_cc[VQUIT] = 0; /* Ctrl-/ */
newtio.c_cc[VERASE] = 0; /* del */
newtio.c_cc[VKILL] = 0; /* @ */
newtio.c_cc[VEOF] = 4; /* Ctrl-d */
newtio.c_cc[VTIME] = 0; /* 不使用分割字元組的計(jì)時(shí)器 */
newtio.c_cc[VMIN] = 1; /* 在讀取到 1 個(gè)字元前先停止 */
newtio.c_cc[VSWTC] = 0; /* '/0' */
newtio.c_cc[VSTART] = 0; /* Ctrl-q */
newtio.c_cc[VSTOP] = 0; /* Ctrl-s */
newtio.c_cc[VSUSP] = 0; /* Ctrl-z */
newtio.c_cc[VEOL] = 0; /* '/0' */
newtio.c_cc[VREPRINT] = 0; /* Ctrl-r */
newtio.c_cc[VDISCARD] = 0; /* Ctrl-u */
newtio.c_cc[VWERASE] = 0; /* Ctrl-w */
newtio.c_cc[VLNEXT] = 0; /* Ctrl-v */
newtio.c_cc[VEOL2] = 0; /* '/0' */
/*
現(xiàn)在清除數(shù)據(jù)機(jī)線并啟動(dòng)序列埠的設(shè)定
*/
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
/*
終端機(jī)設(shè)定完成, 現(xiàn)在處理輸入信號(hào)
在這個(gè)范例, 在一行的開始處輸入 'z' 會(huì)退出此程序.
*/
while (STOP==FALSE) { /* 回圈會(huì)在我們發(fā)出終止的信號(hào)后跳出 */
/* 即使輸入超過 255 個(gè)字元, 讀取的程序段還是會(huì)一直等到行終結(jié)符出現(xiàn)才停止.
如果讀到的字元組低于正確存在的字元組, 則所剩的字元會(huì)在下一次讀取時(shí)取得.
res 用來存放真正讀到的字元組個(gè)數(shù) */
res = read(fd,buf,255);
buf[res]=0; /* 設(shè)定字串終止字元, 所以我們能用 printf */
printf(":%s:%d/n", buf, res);
if (buf[0]=='z') STOP=TRUE;
}
/* 回存舊的序列埠設(shè)定值 */
tcsetattr(fd,TCSANOW,&oldtio);
}
3.2 非標(biāo)準(zhǔn)輸入程序
在非標(biāo)準(zhǔn)的輸入程序模式下, 輸入的資料不會(huì)被組合成一行而輸入后的處理功能 (清除, 殺掉, 刪除, 等等.) 都不能使用. 這個(gè)模式有兩個(gè)功能控制參數(shù):c_cc[VTIME]設(shè)定字元輸入時(shí)間計(jì)時(shí)器, 及c_cc[VMIN]設(shè)定滿足讀取功能的最低字元接收個(gè)數(shù).
如果 MIN > 0 且 TIME = 0, MIN 設(shè)定為滿足讀取功能的最低字元接收個(gè)數(shù). 由于 TIME 是 零, 所以計(jì)時(shí)器將不被使用.
如果 MIN = 0 且 TIME > 0, TIME 將被當(dāng)做逾時(shí)設(shè)定值. 滿足讀取功能的情況為讀取到單一字元, 或者超過 TIME 所定義的時(shí)間 (t = TIME *0.1 s). 如果超過 TIME 所定義的時(shí)間, 則不會(huì)傳回任何字元.
如果 MIN > 0 且 TIME > 0, TIME 將被當(dāng)做一個(gè)分割字元組的計(jì)時(shí)器. 滿足讀取功能的條件為接收到 MIN 個(gè)數(shù)的字元, 或兩個(gè)字元的間隔時(shí)間超過 TIME 所定義的值. 計(jì)時(shí)器會(huì)在每讀到一個(gè)字元后重新計(jì)時(shí), 且只會(huì)在第一個(gè)字元收到后才會(huì)啟動(dòng).
如果 MIN = 0 且 TIME = 0, 讀取功能就馬上被滿足. 目前所存在的字元組個(gè)數(shù), 或者 將回傳的字元組個(gè)數(shù). 根據(jù) Antonino (參考 貢獻(xiàn)) 所說, 你可以用fcntl(fd, F_SETFL, FNDELAY);在讀取前得到相同的結(jié)果.
藉由修改newtio.c_cc[VTIME]及newtio.c_cc[VMIN]上述的模式就可以測(cè)試了.
#include
#include
#include
#include
#include
#define BAUDRATE B38400
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* POSIX 系統(tǒng)兼容 */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
main()
{
int fd,c, res;
struct termios oldtio,newtio;
char buf[255];
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); exit(-1); }
tcgetattr(fd,&oldtio); /* 儲(chǔ)存目前的序列埠設(shè)定 */
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
/* 設(shè)定輸入模式 (非標(biāo)準(zhǔn)型, 不回應(yīng),...) */
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0; /* 不使用分割字元組計(jì)時(shí)器 */
newtio.c_cc[VMIN] = 5; /* 在讀取到 5 個(gè)字元前先停止 */
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
while (STOP==FALSE) { /* 輸入回圈 */
res = read(fd,buf,255); /* 在輸入 5 個(gè)字元后即返回 */
buf[res]=0; /* 所以我們能用 printf... */
printf(":%s:%d/n", buf, res);
if (buf[0]=='z') STOP=TRUE;
}
tcsetattr(fd,TCSANOW,&oldtio);
}
3.3 非同步式輸入
#include
#include
#include
#include
#include
#include
#define BAUDRATE B38400
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* POSIX 系統(tǒng)兼容 */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
void signal_handler_IO (int status); /* 定義信號(hào)處理程序 */
int wait_flag=TRUE; /* 沒收到信號(hào)的話就會(huì)是 TRUE */
main()
{
int fd,c, res;
struct termios oldtio,newtio;
struct sigaction saio; /* definition of signal action */
char buf[255];
/* 開啟裝置為 non-blocking (讀取功能會(huì)馬上結(jié)束返回) */
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd <0) {perror(MODEMDEVICE); exit(-1); }
/* 在使裝置非同步化前, 安裝信號(hào)處理程序 */
saio.sa_handler = signal_handler_IO;
saio.sa_mask = 0;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
/* 允許行程去接收 SIGIO 信號(hào)*/
fcntl(fd, F_SETOWN, getpid());
/* 使文檔ake the file descriptor 非同步 (使用手冊(cè)上說只有 O_APPEND 及
O_NONBLOCK, 而 F_SETFL 也可以用...) */
fcntl(fd, F_SETFL, FASYNC);
tcgetattr(fd,&oldtio); /* 儲(chǔ)存目前的序列埠設(shè)定值 */
/* 設(shè)定新的序列埠為標(biāo)準(zhǔn)輸入程序 */
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
/* 等待輸入信號(hào)的回圈. 很多有用的事我們將在這做 */
while (STOP==FALSE) {
printf("./n");usleep(100000);
/* 在收到 SIGIO 后, wait_flag = FALSE, 輸入信號(hào)存在則可以被讀取 */
if (wait_flag==FALSE) {
res = read(fd,buf,255);
buf[res]=0;
printf(":%s:%d/n", buf, res);
if (res==1) STOP=TRUE; /* 如果只輸入 CR 則停止回圈 */
wait_flag = TRUE; /* 等待新的輸入信號(hào) */
}
}
/* 回存舊的序列埠設(shè)定值 */
tcsetattr(fd,TCSANOW,&oldtio);
}
/***************************************************************************
* 信號(hào)處理程序. 設(shè)定 wait_flag 為 FALSE, 以使上述的回圈能接收字元 *
***************************************************************************/
void signal_handler_IO (int status)
{
printf("received SIGIO signal./n");
wait_flag = FALSE;
}
3.4 等待來自多個(gè)信號(hào)來源的輸入
這一段很短. 它只能被拿來當(dāng)成寫程序時(shí)的提示, 故范例程序也很簡(jiǎn)短. 但這個(gè)范例不只能用在序列埠上, 還可以用在被當(dāng)成文檔來使用的裝置上.
select 呼叫及伴隨它所引發(fā)的巨集共用fd_set.fd_set則是一個(gè)位元陣列, 而其中每一個(gè)位元代表一個(gè)有效的文檔敘述結(jié)構(gòu).select呼叫接受一個(gè)有效的文檔敘述結(jié)構(gòu)并傳回fd_set位元陣列, 而該位元陣列中若有某一個(gè)位元為 1, 就表示相對(duì)映的文檔敘述結(jié)構(gòu)的文檔發(fā)生了輸入, 輸出或有例外事件. 而這些巨集提供了所有處理fd_set的功能. 亦可參考手冊(cè) select(2).
#include
#include
#include
main()
{
int fd1, fd2; /* 輸入源 1 及 2 */
fd_set readfs; /* 文檔敘述結(jié)構(gòu)設(shè)定 */
int maxfd; /* 最大可用的文檔敘述結(jié)構(gòu) */
int loop=1; /* 回圈在 TRUE 時(shí)成立 */
/* open_input_source 開啟一個(gè)裝置, 正確的設(shè)定好序列埠,
并回傳回此文檔敘述結(jié)構(gòu)體 */
fd1 = open_input_source("/dev/ttyS1"); /* COM2 */
if (fd1<0) exit(0);
fd2 = open_input_source("/dev/ttyS2"); /* COM3 */
if (fd2<0) exit(0);
maxfd = MAX (fd1, fd2)+1; /* 測(cè)試最大位元輸入 (fd) */
/* 輸入回圈 */
while (loop) {
FD_SET(fd1, &readfs); /* 測(cè)試輸入源 1 */
FD_SET(fd2, &readfs); /* 測(cè)試輸入源 2 */
/* block until input becomes available */
select(maxfd, &readfs, NULL, NULL, NULL);
if (FD_ISSET(fd1)) /* 如果輸入源 1 有信號(hào) */
handle_input_from_source1();
if (FD_ISSET(fd2)) /* 如果輸入源 2 有信號(hào) */
handle_input_from_source2();
}
}
這個(gè)范例程序在等待輸入信號(hào)出現(xiàn)前, 不能確定它會(huì)停頓下來. 如果你需要在輸入時(shí)加入逾時(shí)功能, 只需把 select 呼叫換成:
int res;
struct timeval Timeout;
/* 設(shè)定輸入回圈的逾時(shí)值 */
Timeout.tv_usec = 0; /* 毫秒 */
Timeout.tv_sec = 1; /* 秒 */
res = select(maxfd, &readfs, NULL, NULL, &Timeout);
if (res==0)
/* 文檔敘述結(jié)構(gòu)數(shù)在 input = 0 時(shí), 會(huì)發(fā)生輸入逾時(shí). */
這個(gè)程序會(huì)在 1 秒鐘后逾時(shí). 如果超過時(shí)間, select 會(huì)傳回 0, 但是應(yīng)該留意Timeout的時(shí)間遞減是由select所等待輸入信號(hào)的時(shí)間為基準(zhǔn). 如果逾時(shí)的值是 0, select 會(huì)馬上結(jié)束返回.
Linux 環(huán)境下使用RS-232接口
RS是英文 "推薦標(biāo)準(zhǔn)"的縮寫
232為標(biāo)識(shí)號(hào)
RS-485
串口通信表示計(jì)算機(jī)一次傳送一個(gè)位的數(shù)據(jù),
當(dāng)使用串行通信時(shí),每個(gè)字的數(shù)據(jù)是一個(gè)位一個(gè)位的傳輸或接收的,
每個(gè)位不是高電平,就是低電平.
串行通信的速率通常是使用"位/每秒"的方式來表示的,即波特率。
全雙工--計(jì)算機(jī)可以同時(shí)收發(fā)數(shù)據(jù),
它有兩個(gè)獨(dú)立的數(shù)據(jù)通道,一個(gè)輸入,一個(gè)輸出,
半雙工意味著計(jì)算機(jī)不能同時(shí)收發(fā)信息,
只能有一人通道進(jìn)行通信.
流控:
通常,當(dāng)數(shù)據(jù)在兩個(gè)串行接口之間進(jìn)行傳輸時(shí)需要對(duì)其進(jìn)行控制.
這通常依賴于串行通信連接的各種規(guī)定,
對(duì)異步數(shù)據(jù)傳輸?shù)目刂朴袃煞N方法.
一種叫:“軟件”流控 。
一種叫: “硬件"流控 。
串口設(shè)備:
打開一個(gè)串行口
#include
#include
#include
#include // 文件控制定義
#include
#include //POSIX終端控制定義
/*
* open_port() --打開串行口
*
* 成功的話,返回文件描述符,錯(cuò)誤則返回 -1.
*/
int open_port(void)
{
int fd;
fd=open("/dev/ttyS0",O_RDWR|O_NOCTTY|O_NDELAY);
if (fd == -1)
{
/*無(wú)法打開串口*/
perror("open_port : Unable to open /dev/ttyS0");
}
else
fcntl(fd,F_SETFL,0);
return (fd);
}
//O_NOCTTY 標(biāo)志 ,該程序不想成為此端口的“控制終端"。
如果沒有強(qiáng)調(diào)這一點(diǎn),
//O_NDELAY標(biāo)志 , 標(biāo)志告訴Linux ,該程序并不關(guān)注DCD信叼線所處的狀態(tài),
即不管另外一端的設(shè)備是在運(yùn)行還是被掛起。如果沒有指定該標(biāo)志,那么程序就會(huì)被設(shè)置睡
眠狀態(tài),
(2)向端口寫數(shù)據(jù)
向端口寫數(shù)據(jù)是很容易的,只要使用write()系統(tǒng)調(diào)用就可以了。
例如:
n=write(fd,"ATZ/r",4);
if (n<0)
fputs("write() of 4 bytes failed!/n",stderr);
write函數(shù)返回發(fā)送數(shù)據(jù)的個(gè)數(shù),如果出現(xiàn)錯(cuò)誤,則返回 -1。
(3) 讀端口數(shù)據(jù)
從端口讀數(shù)據(jù)則需要些技巧。如果在原始數(shù)據(jù)的模式下對(duì)端口進(jìn)行操作,
read()系統(tǒng)調(diào)用將返回串行口輸入緩沖區(qū)中所有的字符數(shù)據(jù),不管有多少,
如果沒有數(shù)據(jù),那么該調(diào)用將被阻塞.處于等待狀態(tài),直到有字符輸入,
或者到了規(guī)定的時(shí)限和出現(xiàn)錯(cuò)誤為止,
通過以下方法,能使read函數(shù)立即返回。
fcntl(fd,F_SETFL,FNDELAY);
FNDELAY 函數(shù)使read函數(shù)在端口沒月字符存在的情況下,立刻返回0,
如果要恢復(fù)正常(阻塞)狀態(tài),可以調(diào)用fcntl()函數(shù),不要FNDELAY參數(shù),
如下所示:
fcntl(Fd,F_SETFL,0);
在使用O_NDELAY參數(shù)打開串行口后,同樣與使用了該函數(shù)調(diào)用。
fcntl(fd,F_SETFL,0);
POSIX終端接口
串口,波特率,字符大小等,
POSIX函數(shù)是 tcgetattr()和tcsetattr()
獲取和設(shè)置終端的屬性,
可以提供 structrure termios的指針
總結(jié)
以上是生活随笔為你收集整理的详解linux下的串口通讯开发的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: uniapp中引入阿里巴巴图标iconf
- 下一篇: 微信支付中分账功能 填坑指南V1