当前位置:Linux教程 - Linux资讯 - Linux Serial Programming HOWTO (2)

Linux Serial Programming HOWTO (2)

  藉由修改 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());
[1] [2] [3] 下一页 

/* 使档案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 呼叫换成:
上一页 [1] [2] [3] 下一页 

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]

(出处:http://www.sheup.com)


上一页 [1] [2] [3] 

这份文件的结构及 SGML 的格式是源自 Greg Hankins 的 Serial-HOWTO. 感谢 Dave Pfaltzgraff ([email protected]), Sean Lincolne ([email protected]

(出处:http://www.sheup.com)


上一页 [1] [2] [3] [4]