Serial Programming HOWTO(串口编程HOWTO)

这里给出做好的pdf文件的下载地址:

http://download.csdn.net/source/2770164

个人认为曾元佑对本文译的不好,使用的是台湾的习惯用语.所以我对文进行了翻译,使得语言更为自然流畅;改掉了几个原文中的英文语法和拼写的问题,其他保留原汁原味.

术语的翻译,如有不合适请指教,反馈请发我邮箱,我会更新文档:

scarlettsp@163.com

 

我也很纠结究竟是意译还是直译…定语从句太NB了

Terminals : 终端

Port : 端口

Serial : 串口

Timer:计数器,这里不是计时器

 

Serial Programming HOWTO

Gary Frerking

        gary@frerking.org
      

Peter Baumann

Revision History
Revision 1.012001-08-26Revised by: glf
New maintainer, converted to DocBook
Revision 1.01998-01-22Revised by: phb
Initial document release

 

This document describes how to program communications with devices over a serial port on a Linux box.

 



1. Introduction
 
This is the Linux Serial Programming HOWTO. All about how to program communications with other devices / computers over a serial line under Linux. Different techniques are explained: Canonical I/O (only complete lines are transmitted/received), asyncronous I/O, and waiting for input from multiple sources.

 

这是一个Linux串口编程的HOWTO(之后简称本文档).所有的内容都是在Linux下如何通过串口和别的设备或者电脑进行通信.不同的技巧呈现:规则的IO(仅仅完成收发操作),异步IO,等待不同源的输入.

 

This is the first update to the initial release of the Linux Serial Programming HOWTO. The primary purpose of this update is to change the author information and convert the document to DocBook format. In terms of technical content, very little if anything has changed at this time. Sweeping changes to the technical content aren't going to happen overnight, but I'll work on it as much as time allows.

 

这是本文档最初发布版的第一次更新.这次更新的主要目的是更改作者信息和将格式转化为DocBook格式.就技术内容而言,这次更改的内容很少.在短时间内技术内容不会有太多的改变,但是我会抽出尽可能多的时间在这上面.

 

If you've been waiting in the wings for someone to take over this HOWTO, you've gotten your wish. Please send me any and all feedback you have, it'd be very much appreciated.

 

如果你在旁边等待某人接管这个HOWTO,那么你已经等到了.非常感谢你发送过来的信息和任何反馈

 

All examples were tested using a i386 Linux Kernel 2.0.29.

 

所有的例子都是在2.0.29的内核的i386 Linux 上测试的


1.1. Copyright Information
 

All translations, derivative works, or aggregate works incorporating any Linux HOWTO documents must be covered under this copyright notice. That is, you may not produce a derivative work from a HOWTO and impose additional restrictions on its distribution. Exceptions to these rules may be granted under certain conditions; please contact the Linux HOWTO coordinator at the address given below.

In short, we wish to promote dissemination of this information through as many channels as possible. However, we do wish to retain copyright on the HOWTO documents, and would like to be notified of any plans to redistribute the HOWTOs.

If you have any questions, please contact <linux-howto@metalab.unc.edu>


1.2. Disclaimer
 

All copyrights are held by their by their respective owners, unless specifically noted otherwise. Use of a term in this document should not be regarded as affecting the validity of any trademark or service mark.

Naming of particular products or brands should not be seen as endorsements.

You are strongly recommended to take a backup of your system before major installation and backups at regular intervals.


1.3. New Versions
As previously mentioned, not much is new in terms of technical content yet.

1.4. Credits
 

The original author thanked Mr. Strudthoff, Michael Carter, Peter Waltenberg, Antonino Ianella, Greg Hankins, Dave Pfaltzgraff, Sean Lincolne, Michael Wiedmann, and Adrey Bonar.


1.5. Feedback
 

Feedback is most certainly welcome for this document. Without your submissions and input, this document wouldn't exist. Please send your additions, comments and criticisms to the following email address : <gary@frerking.org>.


2. Getting started
2.1. Debugging
 

 

对代码的最好的debug就是建立另一个Linux box(译者注:不确定是什么,保留原文)之后通过null-modem的方式来连接2个电脑.使用Miniterm(译者注:一个类似串口调试助手的工具) (LDP编程指南(ftp地址可以下载,examples这个目录下))来向你的Linux box传输字符. Miniterm非常容易被编译和通过串口传送所有键盘的原始输入.只有当#define MODEMDEVICE "/dev/ttyS0" 定义被检测的时候, ttyS0 才被认为是 COM1, ttyS1 才被认为是 COM2,等等.测试是非常重要的,所有字符都是通过行来发送的原始数据(没有经过输出处理).为了检测你的连接,在双方电脑启动Miniterm发送任意数据.在一个电脑输入的数据应该在另一个电脑出现这个字符的副本.输入不会在敲击的屏幕上显示

 

To make a null-modem cable you have to cross the TxD (transmit) and RxD (receive) lines. For a description of a cable see sect. 7 of the Serial-HOWTO.

 

为了做一个null-modem的线材要交叉连接TxD(发送)RxD(接收),参见Serial-HOWTO第七章.(译者注:不知道他指的是什么,我这里给出接线方式)

 

It is also possible to perform this testing with only one computer, if you have two unused serial ports. You can then run two miniterms off two virtual consoles. If you free a serial port by disconnecting the mouse, remember to redirect /dev/mouse if it exists. If you use a multiport serial card, be sure to configure it correctly. I had mine configured wrong and everything worked fine as long as I was testing only on my computer. When I connected to another computer, the port started loosing characters. Executing two programs on one computer just isn't fully asynchronous.

 

 

也可以在一个电脑上进行这些测试,如果你有2个没有使用的串口的话.你可以在2个控制台上运行2Miniterm.如果你通过断开鼠标来释放一个串口,如果/dev/mouse存在的话记得对他进行重定位.如果你使用的是一个多口的串口卡,确定你对它配置正确.在我自己的电脑上我就是使用了错误的配置但是却运行良好.当我连接另一个电脑时,串口发送开始丢失字符.在一个电脑上运行2个程序不是完全的异步.

 

 

2.2. Port Settings

 

 

The devices /dev/ttyS* are intended to hook up terminals to your Linux box, and are configured for this use after startup. This has to be kept in mind when programming communication with a raw device. E.g. the ports are configured to echo characters sent from the device back to it, which normally has to be changed for data transmission.

 

在你的Linux box,设备 /dev/ttyS* 会和终端进行挂钩,启动之后就会被配置.当程序和原始设备进行通信的时候,这些都会保留在内存中.如被配置的端口是用来显示从设备发送的字符,端口一般为了数据的传输而相应改变.

 

 

All parameters can be easily configured from within a program. The configuration is stored in a structure struct termios, which is defined in <asm/termbits.h>:

 

在程序中所有的参数都可以进行简单的配置,配置选项存储在struct termios这个结构体中,<asm/termbits.h>中定义如下:

        #define NCCS 19
        struct termios {
                tcflag_t c_iflag;             /* input mode flags */
                tcflag_t c_oflag;             /* output mode flags */
                tcflag_t c_cflag;             /* control mode flags */
                tcflag_t c_lflag;             /* local mode flags */
                cc_t c_line;                  /* line discipline */
                cc_t c_cc[NCCS];              /* control characters */
        };
      

This file also includes all flag definitions. The input mode flags in c_iflag handle all input processing, which means that the characters sent from the device can be processed before they are read with read.

 

这个文件也包含着所有的标志的定义,输入模式标志c_iflag处理所有的输入操作,这就意味着从设备发送的字符可以在被read读取之前已经被处理了.

 

Similarly c_oflag handles the output processing. c_cflag contains the settings for the port, as the baudrate, bits per character, stop bits, etc.. The local mode flags stored in c_lflag determine if characters are echoed, signals are sent to your program, etc.. Finally the array c_cc defines the control characters for end of file, stop, etc.. Default values for the control characters are defined in <asm/termios.h>. The flags are described in the manual page termios(3). The structure termioscontains the c_line (line discipline) element, which is not used in POSIX compliant systems.

类似的 c_oflag处理所有的输出操作.  c_oflag保存着端口的信息,如波特率,每个字节多少位,停止位等等,本地模式位存储在c_lflag中决定的是字符是否被显示,信号是否向你的程序发送等等.最终,数组c_cc决定文件最后的控制字符,停止位等等.默认的控制字符在 <asm/termios.h>中定义,字符的描述信息在termios(3)的手册上(译者注:使用man 3 termios 查看,其中的内容比本文档还多,这仅仅是个HOWTO,深究的话东西不少的). Termios结构体保存着c_line的元素(行控制),POSIX兼容的系统中没有使用


2.3. Input Concepts for Serial Devices
 

Here three different input concepts will be presented. The appropriate concept has to be chosen for the intended application. Whenever possible, do not loop reading single characters to get a complete string. When I did this, I lost characters, whereas a read for the whole string did not show any errors.

这里有3中输入的概念:合适的概念被特定的程序所选择,一旦可能,不要循环读取单个字符来完成一个字符串,当我这样做的时候,我对丢失字符,但是对这个字符串的读却不提示任何错误


2.3.1. Canonical Input Processing
 

This is the normal processing mode for terminals, but can also be useful for communicating with other dl input is processed in units of lines, which means that a read will only return a full line of input. A line is by default terminated by a NL (ASCII LF), an end of file, or an end of line character. A CR (the DOS/Windows default end-of-line) will not terminate a line with the default settings.

这是终端的正常处理模式,在和其他的以行为单元的延时(编者注:dl  :delay line)输入通信的时候也是有用的,这就意味着一个read操作将仅仅返回输入的一整行.行默认以NL结尾(ASCII LF,译者注:值为10 0xA),文件结尾,或者是行的结尾.CR(DOSWin默认的行结束符)根据默认的配置将会结束一行

Canonical input processing can also handle the erase, delete word, and reprint characters, translate CR to NL, etc..

标准的输入处理也可以处理擦除,删除字符,再打印字符,转换CRNL


2.3.2. Non-Canonical Input Processing
 

Non-Canonical Input Processing will handle a fixed amount of characters per read, and allows for a character timer. This mode should be used if your application will always read a fixed number of characters, or if the connected device sends bursts of characters.

非标准的输入操作将处理固定数量的字符的预读,允许字符计数器.这种模式在你的程序一直读固定数量的字符,或者连接设备突然发送的字符时很有用.


2.3.3. Asynchronous Input
 

The two modes described above can be used in synchronous and asynchronous mode. Synchronous is the default, where a read statement will block, until the read is satisfied. In asynchronous mode the read statement will return immediatly and send a signal to the calling program upon completion. This signal can be received by a signal handler.

以上的2中模式可以在同步和异步二种模式中使用,同步是默认的,read状态会被阻塞,直到读取完毕.在异步模式下,读状态会立即返回,当读取完成的时候会对调用它的程序返回一个信号.信号可以被信号的句柄接收到.


2.3.4. Waiting for Input from Multiple Sources
 
This is not a different input mode, but might be useful, if you are handling multiple devices. In my application I was handling input over a TCP/IP socket and input over a serial connection from another computer quasi-simultaneously. The program example given below will wait for input from two different input sources. If input from one source becomes available, it will be processed, and the program will then wait for new input.

这不是一种不同的输入模式,但是当你处理多个设备的时候可能有用.在我的程序中,我处理的是通过TCP/IPsocket和同其他的计算机的串口几乎同时的输入.在线面给出的程序的例子将会等待2种不同的输入源,如果一种输入源有效的时候,它就会处理,之后程序会等待新的输入.

The approach presented below seems rather complex, but it is important to keep in mind that Linux is a multi-processing operating system. The select system call will not load the CPU while waiting for input, whereas looping until input becomes available would slow down other processes executing at the same time.

下面出现的内容看起来可能相当的复杂,但是重要的是要记得Linux是一个多任务的操作系统,select系统调用在等待输入的时候不会被CPU加载,但是一直循环直到输入变为有效会同时降低其他进程的处理速度

 

 3. Program Examples

 

 3.1. Canonical Input Processing

 

 

All examples have been derived from miniterm.c. The type ahead buffer is limited to 255 characters, just like the maximum string length for canonical input processing (<linux/limits.h> or <posix1_lim.h>).

所有的例子都是从miniterm.c衍生而来,buffer前的类型最大为255个字符,就像标准输入处理中的最大字符长度<linux/limits.h> or <posix1_lim.h>

See the comments in the code for explanation of the use of the different input modes. I hope that the code is understandable. The example for canonical input is commented best, the other examples are commented only where they differ from the example for canonical input to emphasize the differences.

例程中的代码解释了不同模式的使用,我希望代码是可以理解的.例程中的标准输入被认为是最好的,其他例子仅仅是强调和标准输入的不同.

The descriptions are not complete, but you are encouraged to experiment with the examples to derive the best solution for your application.

Don't forget to give the appropriate serial ports the right permissions (e. g.: chmod a+rw /dev/ttyS1)!

描述并不完整,但是鼓励你为你的程序做最好的解决方案的实验,不要忘记给对应的串口正确的权限(e. g.: chmod a+rw /dev/ttyS1)!

 

     
        #include <sys/types.h>
        #include <sys/stat.h>
        #include <fcntl.h>
        #include <termios.h>
        #include <stdio.h>
 
        /* baudrate settings are defined in <asm/termbits.h>, which is
included by <termios.h>.波特率定义在 <asm/termbits.h>包含在<termios.h>*/
        #define BAUDRATE B38400            
        /* change this definition for the correct port 
定义正确的端口*/
        #define MODEMDEVICE "/dev/ttyS1"
        #define _POSIX_SOURCE 1 /* POSIX compliant source 
POSIX 兼容*/
        #define FALSE 0
        #define TRUE 1
 
        volatile int STOP=FALSE; 
 
        main()
        {
          int fd,c, res;
          struct termios oldtio,newtio;
          char buf[255];
        /* 
          Open modem device for reading and writing and not as controlling tty, because we don't want to get killed if linenoise sends CTRL-C.
        设备以读和写的方式打开,而不要使用控制位,因为我们并不想让行噪音发送CTRL-C来关闭它*/
         fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY ); 
         if (fd <0) {perror(MODEMDEVICE); exit(-1); }
        
         tcgetattr(fd,&oldtio); 
/* save current serial port settings 
保存当前端口参数*/
         bzero(&newtio, sizeof(newtio)); 
/* clear struct for new port settings 
新端口的参数清零*/
        
        /* 
          BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.设置波特率,你也可以使用cfsetispeedcfsetospeed
          CRTSCTS : output hardware flow control (only used if the cable has all necessary lines. See sect. 7 of Serial-HOWTO.输出硬件流控(只有当线路有所有必要的行的时候才有用,具体见Serial-HOWTO第七部分)
          CS8     : 8n1 (8bit,no parity,1 stopbit)
8bit,无奇偶校验,停止位为1
          CLOCAL  : local connection, no modem contol
                    本地连接,modem控制
          CREAD   : enable receiving characters
                    使能接收字符
        */
         newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
         
        /*
          IGNPAR  : ignore bytes with parity errors
                    忽略校验位的错误
          ICRNL   : map CR to NL (otherwise a CR input on the other computer will not terminate input)otherwise make device raw (no other input processing) CR转化为NL(不然的话另一个电脑将不会中止输入),否则的话使设备作为原始数据(无其他的输入处理)
        */
         newtio.c_iflag = IGNPAR | ICRNL;
         
        /* Raw output. 原始数据模式输出*/
         newtio.c_oflag = 0;
         
        /*
          ICANON  : enable canonical input 使能标准输入
          disable all echo functionality, and don't send signals to calling program禁止所有函数显示,不向调用程序发送信号
        */
         newtio.c_lflag = ICANON;
         
        /* 
          initialize all control characters  初始化所有控制字符
          default values can be found in /usr/include/termios.h, and are given in the comments, but we don't need them here.默认值可以在/usr/include/termios.h找到,但是我们这里不需要它
        */
         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;     /* inter-character timer unused 不使用分割字符的计数器*/
         newtio.c_cc[VMIN]     = 1;     /* blocking read until 1 character arrives 读取一个字符前一直阻塞*/
         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' */
        
        /* 
          now clean the modem line and activate the settings for the port
          现在清空modem,激活端口的配置
        */
         tcflush(fd, TCIFLUSH);
         tcsetattr(fd,TCSANOW,&newtio);
        
        /*
          terminal settings done, now handle input 
终端设置完成后,现在处理输入
          In this example, inputting a 'z' at the beginning of a line will 
          exit the program.
在这个程序中,在行开始的时候输入’z’会退出程序
        */
         while (STOP==FALSE) /* loop until we have a terminating condition  循环直到有一个中止条件*/
{     
         /* read blocks program execution until a line terminating character is input, even if more than 255 chars are input. If the number
of characters read is smaller than the number of chars available, subsequent reads will return the remaining chars. res will be set to the actual number of characters actually read 
程序读取块一直执行直到一个行终结符输入,即使是输入的长度大于255.如果输入的字符的数目小于有效字符的数目,后来的读操作将会返回剩余的字符数.res被置为实际读取的字符数*/
            res = read(fd,buf,255); 
            buf[res]=0;        /* set end of string, so we can printf 
设置字符串的结尾,这样就可以打印*/
            printf(":%s:%d/n", buf, res);
            if (buf[0]=='z') STOP=TRUE;
         }
         /* restore the old port settings 还原就的端口配置*/
         tcsetattr(fd,TCSANOW,&oldtio);
        }


3.2. Non-Canonical Input Processing
 

In non-canonical input processing mode, input is not assembled into lines and input processing (erase, kill, delete, etc.) does not occur. Two parameters control the behavior of this mode: c_cc[VTIME] sets the character timer, and c_cc[VMIN] sets the minimum number of characters to receive before satisfying the read.

在非标准输入处理模式下,输入不是封装为行,而且输出处理(erase,kill,delect)也不会发生.2种变量控制这种模式的行为: c_cc[VTIME]设置字符计数器, c_cc[VMIN]设置满足读条件之前的最小接收字符数.

If MIN > 0 and TIME = 0, MIN sets the number of characters to receive before the read is satisfied. As TIME is zero, the timer is not used.

如果MIN > 0 TIME = 0,那么MIN设置在满足读条件之前的接收字符数.TIEM=0的时候,计数器没有用.

If MIN = 0 and TIME > 0, TIME serves as a timeout value. The read will be satisfied if a single character is read, or TIME is exceeded (t = TIME *0.1 s). If TIME is exceeded, no character will be returned.

如果MIN = 0 TIME > 0,那么TIME作为一个超时值.当信号接收或者是超过了TIME (t = TIME *0.1 s)的时候读条件就满足了. 如果超过TIME,那么没有字符会返回.

If MIN > 0 and TIME > 0, TIME serves as an inter-character timer. The read will be satisfied if MIN characters are received, or the time between two characters exceeds TIME. The timer is restarted every time a character is received and only becomes active after the first character has been received.

如果MIN > 0 TIME > 0,那么TIME作为一个整数字符计数器.如果接收到了MIN个字符的时候read的条件会满足,或者是time同时超过了MINTIME,计数器每次都会复位当接收到一个字符的时候,当接收到第一个字符之后计数器才会变为有效.

If MIN = 0 and TIME = 0, read will be satisfied immediately. The number of characters currently available, or the number of characters requested will be returned. According to Antonino (see contributions), you could issue a fcntl(fd, F_SETFL, FNDELAY); before reading to get the same result.

如果MIN = 0 TIME = 0,那么读条件马上就满足了.当前有效的字符数,或者是需要的字符数将会被返回.根据Antonino(参考文档.译者注:不知道指的是哪个),你可以分配一个fcntl,在你得到相同的结果之前.

By modifying newtio.c_cc[VTIME] and newtio.c_cc[VMIN] all modes described above can be tested.

 
      #include <sys/types.h>
      #include <sys/stat.h>
      #include <fcntl.h>
      #include <termios.h>
      #include <stdio.h>
        
      #define BAUDRATE B38400
      #define MODEMDEVICE "/dev/ttyS1"
      #define _POSIX_SOURCE 1 /* POSIX compliant source */
      #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); /* save current port settings */
        
        bzero(&newtio, sizeof(newtio));
        newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
        newtio.c_iflag = IGNPAR;
        newtio.c_oflag = 0;
        
        /* set input mode (non-canonical, no echo,...) */
        newtio.c_lflag = 0;
         
        newtio.c_cc[VTIME]    = 0;   /* inter-character timer unused */
        newtio.c_cc[VMIN]     = 5;   /* blocking read until 5 chars received */
        
        tcflush(fd, TCIFLUSH);
        tcsetattr(fd,TCSANOW,&newtio);
        
        
        while (STOP==FALSE) {       /* loop for input */
          res = read(fd,buf,255);   /* returns after 5 chars have been input */
          buf[res]=0;               /* so we can printf... */
          printf(":%s:%d/n", buf, res);
          if (buf[0]=='z') STOP=TRUE;
        }
        tcsetattr(fd,TCSANOW,&oldtio);
      }
   


3.3. Asynchronous Input
 

 
      #include <termios.h>
      #include <stdio.h>
      #include <unistd.h>
      #include <fcntl.h>
      #include <sys/signal.h>
      #include <sys/types.h>
        
      #define BAUDRATE B38400
      #define MODEMDEVICE "/dev/ttyS1"
      #define _POSIX_SOURCE 1 /* POSIX compliant source */
      #define FALSE 0
      #define TRUE 1
        
      volatile int STOP=FALSE; 
        
      void signal_handler_IO (int status);   /* definition of signal handler */
      int wait_flag=TRUE;          /* TRUE while no signal received */
        
      main()
      {
        int fd,c, res;
        struct termios oldtio,newtio;
        struct sigaction saio;       /* definition of signal action */
        char buf[255];
        
  /* open the device to be non-blocking (read will return immediatly) 
打开设备为非阻塞模式(读后立即返回)*/
        fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
        if (fd <0) {perror(MODEMDEVICE); exit(-1); }
        
  /* install the signal handler before making the device asynchronous 
在设备设置为异步前,安装信号处理程序*/
        saio.sa_handler = signal_handler_IO;
        saio.sa_mask = 0;
        saio.sa_flags = 0;
        saio.sa_restorer = NULL;
        sigaction(SIGIO,&saio,NULL);
          
        /* allow the process to receive SIGIO 
允许程序接收SIGIO信号*/
        fcntl(fd, F_SETOWN, getpid());
       /* Make the file descriptor asynchronous (the manual page says only 
          O_APPEND and O_NONBLOCK, will work with F_SETFL...) 
使文件描述符fd异步(手册上只有O_APPEND  O_NONBLOCK F_SETFL 一起使用*/
        fcntl(fd, F_SETFL, FASYNC);
        
        tcgetattr(fd,&oldtio); /* save current port settings */
        /* set new port settings for canonical input processing 
为标准输入处理设备端口参数*/
        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);
         
        /* loop while waiting for input. normally we would do something
           useful here 
一直循环等待输入,一般而言我们可以在这里做些有用的事情*/ 
        while (STOP==FALSE) {
          printf("./n");usleep(100000);
          /* after receiving SIGIO, wait_flag = FALSE, input is available
             and can be read 
当接收到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;/* stop loop if only a CR was input */
            wait_flag = TRUE;      /* wait for new input */
          }
        }
        /* restore old port settings */
        tcsetattr(fd,TCSANOW,&oldtio);
      }
        
      /********************************************************************
      * signal handler. sets wait_flag to FALSE, to indicate above loop that characters have been received.
* 信号处理程序:设置wait_flagFALSE,来标识上面的循环已经接收到了字符
     ********************************************************************/
        
      void signal_handler_IO (int status)
      {
        printf("received SIGIO signal./n");
        wait_flag = FALSE;
      }
   


3.4. Waiting for Input from Multiple Sources
 

This section is kept to a minimum. It is just intended to be a hint, and therefore the example code is kept short. This will not only work with serial ports, but with any set of file descriptors.

这一段保持到最短它只能被拿来当成写程序时的提示故例程式也很简短但这个例不只能用在串口上也可以用在任何的文件描述符(fd)

The select call and accompanying macros use a fd_set. This is a bit array, which has a bit entry for every valid file descriptor number. select will accept a fd_set with the bits set for the relevant file descriptors and returns a fd_set, in which the bits for the file descriptors are set where input, output, or an exception occurred. All handling offd_set is done with the provided macros. See also the manual page select(2).

Select调用和与之相关的宏使用 fd_set. fd_set 则是一个数组,其中每一个元素元代表一个有效文件描述符的值(fd). Select调用接收一个在fd_set中有效的fd并返回 fd_set 数组input,output,例外事件发生时,数组的对应位就返回1. fd_set的操作都在给出的宏上完成了也可参考手册 select(2)(译者注:man 2 select). 

      
      #include <sys/time.h>
      #include <sys/types.h>
      #include <unistd.h>
        
      main()
      {
        int    fd1, fd2;  /* input sources 1 and 2 */
        fd_set readfs;    /* file descriptor set */
        int    maxfd;     /* maximum file desciptor used */
        int    loop=1;    /* loop while TRUE */ 
        
        /* open_input_source opens a device, sets the port correctly, and
           returns a file descriptor 
打开一个设备,设置正确的端口属性,返回一个fd*/
        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;  /* maximum bit entry (fd) to test */
        
        /* loop for input */
        while (loop) {
          FD_SET(fd1, &readfs);  /* set testing for source 1 */
          FD_SET(fd2, &readfs);  /* set testing for source 2 */
          /* block until input becomes available 
阻塞直到输入变为有效*/
          select(maxfd, &readfs, NULL, NULL, NULL);
          if (FD_ISSET(fd1))         /* input from source 1 available */
            handle_input_from_source1();
          if (FD_ISSET(fd2))         /* input from source 2 available */
            handle_input_from_source2();
        }
      }   

The given example blocks indefinitely, until input from one of the sources becomes available. If you need to timeout on input, just replace the select call by:

给出的例程会立即阻塞,直到其中的一个源变为有效.如果你需要对输入设置超时,仅仅将select改为如下的形式即可 

        int res;
        struct timeval Timeout;

        /* set timeout value within input loop */
        Timeout.tv_usec = 0;  /* milliseconds */
        Timeout.tv_sec  = 1;  /* seconds */
        res = select(maxfd, &readfs, NULL, NULL, &Timeout);
        if (res==0)
        /* number of file descriptors with input = 0, timeout occurred. */ 
      

This example will timeout after 1 second. If a timeout occurs, select will return 0, but beware that Timeout is decremented by the time actually waited for input by select. If the timeout value is zero, select will return immediatly.

例程在 1 秒钟后超时如果发生超时, select 会返回 0, 但是应该注 Timeout 的时间递减是由 select 所等待输入讯号的时间为基准如果超时的值是 0, select 会马上结束返回.(译者注:这个时候等同非阻塞)


4. Other Sources of Information
Unless otherwise stated, Linux HOWTO documents are copyrighted by their respective authors. Linux HOWTO documents may be reproduced and distributed in whole or in part, in any medium physical or electronic, as long as this copyright notice is retained on all copies. Commercial redistribution is allowed and encouraged; however, the author would like to be notified of any such distributions.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值