歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux資訊 >> 更多Linux >> Linux Serial Programming HOWTO (2)

Linux Serial Programming HOWTO (2)

日期:2017/2/27 9:46:41   编辑:更多Linux
  藉由修改 newtio.c_cc[VTIME] 及 newtio.c_cc[VMIN] 上述的模式就可以測試了. [code] #include #include #include #include #include #define BAUDRATE B38400 #define MODEMDEVICE "/dev/ttyS1" #define _POSIX_SOURCE 1 /* POSIX 系統相容 */ #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); /* 儲存目前的序列埠設定 */ bzero(&newtio, sizeof(newtio)); newtio.c_cflag = BAUDRATE CRTSCTS CS8 CLOCAL CREAD; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; /* 設定輸入模式 (非標准型, 不回應,...) */ newtio.c_lflag = 0; newtio.c_cc[VTIME] = 0; /* 不使用分割字元組計時器 */ newtio.c_cc[VMIN] = 5; /* 在讀取到 5 個字元前先停止 */ tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); while (STOP==FALSE) { /* 輸入回圈 */ res = read(fd,buf,255); /* 在輸入 5 個字元後即返回 */ buf[res]=0; /* 所以我們能用 printf... */ printf(":%s:%d\n", buf, res); if (buf[0]=='z') STOP=TRUE; } tcsetattr(fd,TCSANOW,&oldtio); } [/code] 3.3 非同步式輸入 [code] #include #include #include #include #include #include #define BAUDRATE B38400 #define MODEMDEVICE "/dev/ttyS1" #define _POSIX_SOURCE 1 /* POSIX 系統相容 */ #define FALSE 0 #define TRUE 1 volatile int STOP=FALSE; void signal_handler_IO (int status); /* 定義訊號處理程序 */ int wait_flag=TRUE; /* 沒收到訊號的話就會是 TRUE */ main() { int fd,c, res; struct termios oldtio,newtio; struct sigaction saio; /* definition of signal action */ char buf[255]; /* 開啟裝置為 non-blocking (讀取功能會馬上結束返回) */ fd = open(MODEMDEVICE, O_RDWR O_NOCTTY O_NONBLOCK); if (fd <0) {perror(MODEMDEVICE); exit(-1); } /* 在使裝置非同步化前, 安裝訊號處理程序 */ saio.sa_handler = signal_handler_IO; saio.sa_mask = 0; saio.sa_flags = 0; saio.sa_restorer = NULL; sigaction(SIGIO,&saio,NULL); /* 允許行程去接收 SIGIO 訊號*/ fcntl(fd, F_SETOWN, getpid());


/* 使檔案ake the file descriptor 非同步 (使用手冊上說只有 O_APPEND 及 O_NONBLOCK, 而 F_SETFL 也可以用...) */ fcntl(fd, F_SETFL, FASYNC); tcgetattr(fd,&oldtio); /* 儲存目前的序列埠設定值 */ /* 設定新的序列埠為標准輸入程序 */ 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); /* 等待輸入訊號的回圈. 很多有用的事我們將在這做 */ while (STOP==FALSE) { printf(".\n");usleep(100000); /* 在收到 SIGIO 後, wait_flag = FALSE, 輸入訊號存在則可以被讀取 */ 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; /* 等待新的輸入訊號 */ } } /* 回存舊的序列埠設定值 */ tcsetattr(fd,TCSANOW,&oldtio); } /*************************************************************************** * 訊號處理程序. 設定 wait_flag 為 FALSE, 以使上述的回圈能接收字元 * ***************************************************************************/ void signal_handler_IO (int status) { printf("received SIGIO signal.\n"); wait_flag = FALSE; } [/code] 3.4 等待來自多個訊號來源的輸入 這一段很短. 它只能被拿來當成寫程式時的提示, 故□例程式也很簡短. 但這個□例不只能用在序列埠上, 還可以用在被當成檔案來使用的裝置上. select 呼叫及伴隨它所引發的巨集共用 fd_set. fd_set 則是一個位元陣列, 而其中每一個位元代表一個有效的檔案敘述結構. select 呼叫接受一個有效的檔案敘述結構並傳回 fd_set 位元陣列, 而該位元陣列中若有某一個位元為 1, 就表示相對映的檔案敘述結構的檔案發生了輸入, 輸出或有例外事件. 而這些巨集提供了所有處理 fd_set 的功能. 亦可參考手冊 select(2). [code] #include #include #include main() { int fd1, fd2; /* 輸入源 1 及 2 */ fd_set readfs; /* 檔案敘述結構設定 */ int maxfd; /* 最大可用的檔案敘述結構 */ int loop=1; /* 回圈在 TRUE 時成立 */ /* open_input_source 開啟一個裝置, 正確的設定好序列埠, 並回傳回此檔案敘述結構體 */ 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; /* 測試最大位元輸入 (fd) */ /* 輸入回圈 */ while (loop) { FD_SET(fd1, &readfs); /* 測試輸入源 1 */ FD_SET(fd2, &readfs); /* 測試輸入源 2 */ /* block until input becomes available */ select(maxfd, &readfs, NULL, NULL, NULL); if (FD_ISSET(fd1)) /* 如果輸入源 1 有訊號 */ handle_input_from_source1(); if (FD_ISSET(fd2)) /* 如果輸入源 2 有訊號 */ handle_input_from_source2(); } } [/code] 這個□例程式在等待輸入訊號出現前, 不能確定它會停頓下來. 如果你需要在輸入時加入逾時功能, 只需把 select 呼叫換成:

int res; struct timeval Timeout; /* 設定輸入回圈的逾時值 */ Timeout.tv_usec = 0; /* 毫秒 */ Timeout.tv_sec = 1; /* 秒 */ res = select(maxfd, &readfs, NULL, NULL, &Timeout); if (res==0) /* 檔案敘述結構數在 input = 0 時, 會發生輸入逾時. */ 這個程式會在 1 秒鐘後逾時. 如果超過時間, select 會傳回 0, 但是應該留意 Timeout 的時間遞減是由 select 所等待輸入訊號的時間為基准. 如果逾時的值是 0, select 會馬上結束返回. -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- 4. 其它資源 Linux Serial-HOWTO 敘述如何設定序列埠及所有相關的硬體資訊. 由 Michael Sweet 所寫的 Serial Programming Guide for POSIX Compliant Operating Systems. 這個連結已經荒廢了但我找不到它的新位址. 有人知道能在哪找到它嗎? 它是很棒的文件! termios(3) 的使用手冊. 敘述所有有關 termios 結構體的旗標. -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- 5. 貢獻 就跟簡介所說的一樣, 我並非在這領域有所專精, 但我自己遇到問題, 並透過他人的幫助找到答案. 感謝來自 European Transonic Windtunnel 的 Strudthoff 先生, Cologne, Michael Carter ([email protected]), 及 Peter Waltenberg ([email protected]) 與我同時准備這份文件的 Antonino Ianella ([email protected] 所篆寫的 Serial-Port-Programming Mini HOWTO. Greg Hankins 要求我把 Antonino's Mini-HOWTO 一並放入這份文件. 這份文件的結構及 SGML 的格式是源自 Greg Hankins 的 Serial-HOWTO. 感謝 Dave Pfaltzgraff ([email protected]), Sean Lincolne ([email protected]



這份文件的結構及 SGML 的格式是源自 Greg Hankins 的 Serial-HOWTO. 感謝 Dave Pfaltzgraff ([email protected]), Sean Lincolne ([email protected]



Copyright © Linux教程網 All Rights Reserved