分享

linux 串口通讯

 techres 2011-11-27

linux 串口通讯  

2010-03-11 20:18:03|  分类: 转载 |  标签:termios  串口  属性  c_oflag  c_iflag  linux   |字号 订阅

配置串口

POSIX终端接口

POSIX

POSIX是Portable Operating System Interface(可移植操作系统界面)的缩写,而X则表明其对Unix API的传承。WindowsNT和现代UNIX都支持POSIX接口。

很多系统都支持POSIX终端(串口)接口。程序可以利用这个接口来改变终端的参数,比如,波特率,字符大小等等。要使用这个端口的话,你必须将<termios.h>头文件包含到你的程序中。这个头文件中定义了终端控制结构体和POSIX控制函数。

与串口操作相关的最重要的两个POSIX函数可能就是tcgetattr(3)和tcsetattr(3)。顾名思义,这两个函数分别用来取得设设置终端的属性。调用这两个函数的时候,你需要提供一个包含着所有串口选项的termios结构体:

termios结构体成员

成员 描述
c_cflag 控制选项
c_lflag 行选项
c_iflag 输入选项
c_oflag 输出选项
c_cc 控制字符
c_ispeed 输入波特率(NEW)
c_ospeed 输出波特率(NEW)

控制选项

通过termios结构体的c_cflag成员可以控制波特率,数据的比特数,parity,停止位和硬件流控制。下面这张表列出了所有可以使用的常数。

c_cflag常数

常量 描述
CBAUD Bit mask for baud rate
B0 0 baud (drop DTR)
B50 50 baud
B75 75 baud
B110 110 baud
B134 134.5 baud
B150 150 baud
B200 200 baud
B300 300 baud
B600 600 baud
B1200 1200 baud
B1800 1800 baud
B2400 2400 baud
B4800 4800 baud
B9600 9600 baud
B19200 19200 baud
B38400 38400 baud
B57600 57,600 baud
B76800 76,800 baud
B115200 115,200 baud
EXTA External rate clock
EXTB External rate clock
CSIZE Bit mask for data bits
CS5 5 data bits
CS6 6 data bits
CS7 7 data bits
CS8 8 data bits
CSTOPB 2 stop bits (1 otherwise)
CREAD Enable receiver
PARENB Enable parity bit
PARODD Use odd parity instead of even
HUPCL Hangup (drop DTR) on last close
CLOCAL Local line - do not change "owner" of port
LOBLK Block job control output
CNEW_RTSCTS/CRTSCTS Enable hardware flow control (not supported on all platforms)

在传统的POSIX编程中,当连接一个本地的(不通过调制解调器)或者远程的终端(通过调制解调器)时,这里有两个选项应当一直打开,一个是CLOCAL,另一个是CREAD。这两个选项可以保证你的程序不会变成端口的所有者,而端口所有者必须去处理发散性作业控制和挂断信号,同时还保证了串行接口驱动会读取过来的数据字节。

发散性作业控制和信号

这个名词非常难以理解。但现在大多数的串口编程都已经脱离了终端本身,一般不会发生这里提到的情况,详细的说明请参看这里

波特率常数(CBAUD,B9600等等)通常指用到那些不支持c_ispeed和c_ospeed成员的旧的接口上。后面文章将会提到如何使用其他POSIX函数来设置波特率。

千万不要直接用使用数字来初始化c_cflag(当然还有其他标志),最好的方法是使用位运算的与或非组合来设置或者清除这个标志。不同的操作系统版本会使用不同的位模式,使用常数定义和位运算组合来避免重复工作从而提高程序的可移植性。

设置波特率

不同的操作系统会将波特率存储在不同的位置。旧的编程接口将波特率存储在上表所示的c_cflag成员中,而新的接口实装则提供了c_ispeed和c_ospeed成员来保存实际波特率的值。

程序中可是使用cfsetospeed(3)和cfsetispeed(3)函数在termios结构体中设置波特率而不用去管底层操作系统接口。下面的代码是个非常典型的设置波特率的例子。

struct termios options;/* * Get the current options for the port... */tcgetattr(fd, &options);/* * Set the baud rates to 19200... */cfsetispeed(&options, B19200);cfsetospeed(&options, B19200);/* * Enable the receiver and set local mode... */options.c_cflag |= (CLOCAL | CREAD);/* * Set the new options for the port... */tcsetattr(fd, TCSANOW, &options);

函数tcgetattr(3)会将当前串口配置回填到termio结构体option中。然后,程序设置了输入输出的波特率并且将本地模式(CLOCAL)和串行数据接收(CREAD)设置为有效,接着将新的配置作为参数传递给函数tcsetattr(3)。常量TCSANOW标志所有改变必须立刻生效而不用等到数据传输结束。其他另一些常数可以保证等待数据结束或者刷新输入输出之后再生效。

tcsetattr常量

常量 描述
TCSANOW Make changes now without waiting for data to complete
TCSADRAIN Wait until everything has been transmitted
TCSAFLUSH Flush input and output buffers and make the change

不同的系统上可能支持不同的输入输出速度,所以,通过串口连接两台机器或者设备的时候,应该将波特率设置成两者中较小的那个,即MIN(speed1, speed2)。

设置字符大小

设置字符大小的时候,这里却没有像设置波特率那么方便的函数。所以,程序中需要一些位掩码运算来把事情搞定。字符大小以比特为单位指定:

options.c_flag &= ~CSIZE; /* Mask the character size bits */options.c_flag |= CS8; /* Select 8 data bits */

设置奇偶校验

与设置字符大小的方式差不多,这里仍然需要组合一些位掩码来将奇偶校验设为有效和奇偶校验的类型。UNIX串口驱动可以生成even,odd和no parity位码。设置space奇偶校验需要耍点小手段。

  • No parity (8N1)

options.c_cflag &= ~PARENBoptions.c_cflag &= ~CSTOPBoptions.c_cflag &= ~CSIZE;options.c_cflag |= CS8;

  • Even parity (7E1)

options.c_cflag |= PARENBoptions.c_cflag &= ~PARODDoptions.c_cflag &= ~CSTOPBoptions.c_cflag &= ~CSIZE;options.c_cflag |= CS7;

  • Odd parity (7O1)

options.c_cflag |= PARENBoptions.c_cflag |= PARODDoptions.c_cflag &= ~CSTOPBoptions.c_cflag &= ~CSIZE;options.c_cflag |= CS7;

  • Space parity is setup the same as no parity (7S1)

options.c_cflag &= ~PARENBoptions.c_cflag &= ~CSTOPBoptions.c_cflag &= ~CSIZE;options.c_cflag |= CS8;

设置硬件流控制

某些版本的UNIX系统支持通过CTS(Clear To Send)和RTS(Request To Send)信号线来设置硬件流控制。如果系统上定义了CNEW_RTSCTS和CRTSCTS常量,那么很可能它会支持硬件流控制。使用下面的方法将硬件流控制设置成有效:

options.c_cflag |= CNEW_RTSCTS; /* Also called CRTSCTS

将它设置成为无效的方法与此类似:

options.c_cflag &= ~CNEW_RTSCTS;

本地设置

经典输入

经典输入是终端中最常用的输入方式。但它同样适用于其他以行为单位的通讯方式,也就是说这种方式中另一端的“读取”只会返回一整行的输入。默认情况下,一行总是以NL(ASCII LF),EOF(End of File)或者EOL(End Of Line)结尾。默认设置中,CR(DOS/Windows默认的EOL)字符不能用来结束一行。经典输入处理过程一般情况也可以处理擦写,删除字和重新打印字符,将CR翻译成NL等任务。

本地模式成员变量c_lflag可以控制串口驱动怎样控制输入字符。通常,你可能需要通过c_lflag成员来设置经典输入和原始输入模式。

成员变量c_lflag可以使用的常量

ISIG Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals
ICANON Enable canonical input (else raw)
XCASE Map uppercase \lowercase (obsolete)
ECHO Enable echoing of input characters
ECHOE Echo erase character as BS-SP-BS
ECHOK Echo NL after kill character
ECHONL Echo NL
NOFLSH Disable flushing of input buffers after interrupt or quit characters
IEXTEN Enable extended functions
ECHOCTL Echo control characters as ^char and delete as ~?
ECHOPRT Echo erased character as character erased
ECHOKE BS-SP-BS entire line on line kill
FLUSHO Output being flushed
PENDIN Retype pending input at next read or input char
TOSTOP Send SIGTTOU for background output

选择经典输入

不要使用ECHO

当通过串口给一个调制解调器或者计算机发送命令的时候,永远不要使用回声选项(ECHO,ECHOE),这样的话程序会产生发送方和接收方相互反馈循环!

经典输入是以面向行设计的。在经典输入模式中输入字符会被放入一个缓冲之中,这样可以以与用户交互的方式编辑缓冲的内容,直到收到CR(carriage return)或者LF(line feed)字符。

选择使用经典输入模式的时候,你通常需要选择ICANON,ECHO和ECHOE选项:

options.c_lflag |= (ICANON | ECHO | ECHOE);

选择原始输入

原始输入根本不会被处理。输入字符只是被原封不动的接收。一般情况中,如果要使用原始输入模式,程序中需要去掉ICANON,ECHO,ECHOE和ISIG选项:

options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

输入选项

可以通过输入模式成员c_iflag来控制从端口上收到的字符的输入过程。与c_cflag一样,c_iflag的最终值是想要使用的所有状态的位运算OR的组合。

c_iflag成员可以使用的常量

常量 描述
INPCK Enable parity check
IGNPAR Ignore parity errors
PARMRK Mark parity errors
ISTRIP Strip parity bits
IXON Enable software flow control (outgoing)
IXOFF Enable software flow control (incoming)
IXANY Allow any character to start flow again
IGNBRK Ignore break condition
BRKINT Send a SIGINT when a break condition is detected
INLCR Map NL to CR
IGNCR Ignore CR
ICRNL Map CR to NL
IUCLC Map uppercase to lowercase
IMAXBEL Echo BEL on input line too long

设置输入奇偶校验选项

当程序在c_cflag中设置了奇偶校验成员(PARENB)的时候,程序就需要将输入奇偶校验设置成为有效。与奇偶校验相关的常量有INPCK,IGNPAR,PARMRK和ISTRIP。一般情况下,你可能需要选择INPCK和ISTRIP将奇偶校验设置为有效同时从接收字串中脱去奇偶校验位:

options.c_iflag |= (INPCK | ISTRIP);

IGNPAR是一个比较危险选项,即便有错误发生时,它也会告诉串口驱动直接忽略奇偶校验错误给数据放行。这个选项在测试链接的通讯质量时比较有用而通常不会被用在实际程序中。

PARMRK会导致奇偶校验错误被标志成特殊字符加入到输入流之中。如果IGNPAR选项也是有效的,那么一个NUL(八进制000)字符会被加入到发生奇偶校验错误的字符前面。否则,DEL(八进制177)和NUL字符会和出错的字符一起送出。

设置软件流控制

软件流控制可以通过IXON,IXOFF和IXANY常量设置成有效:

options.c_iflag |= (IXON | IXOFF | IXANY);

将其设置为无效的时候,很简单,只需要对这些位取反:

options.c_iflag &= ~(IXON | IXOFF | IXANY);

XON(start data)和XOFF(stop data)字符却是在c_cc数组中定义的,下面会详细描述这个数组。

输出选项

成员变量c_oflag之中包括了输出过滤选项。和输入模式相似,程序可以选择使用经过加工的或者原始的数据输出。

c_oflag成员的常量

常量 描述
OPOST Postprocess output (not set = raw output)
OLCUC Map lowercase to uppercase
ONLCR Map NL to CR-NL
OCRNL Map CR to NL
NOCR No CR output at column 0
ONLRET NL performs CR function
OFILL Use fill characters for delay
OFDEL Fill character is DEL
NLDLY Mask for delay time needed between lines
NL0 No delay for NLs
NL1 Delay further output after newline for 100 milliseconds
CRDLY Mask for delay time needed to return carriage to left column
CR0 No delay for CRs
CR1 Delay after CRs depending on current column position
CR2 Delay 100 milliseconds after sending CRs
CR3 Delay 150 milliseconds after sending CRs
TABDLY Mask for delay time needed after TABs
TAB0 No delay for TABs
TAB1 Delay after TABs depending on current column position
TAB2 Delay 100 milliseconds after sending TABs
TAB3 Expand TAB characters to spaces
BSDLY Mask for delay time needed after BSs
BS0 No delay for BSs
BS1 Delay 50 milliseconds after sending BSs
VTDLY Mask for delay time needed after VTs
VT0 No delay for VTs
VT1 Delay 2 seconds after sending VTs
FFDLY Mask for delay time needed after FFs
FF0 No delay for FFs
FF1 Delay 2 seconds after sending FFs

选择加工过的输出

通过在c_oflag成员变量中设置OPOST选项的方法程序可以选择加工过的输入。

options.c_oflag |= OPOST;

在所有选项当中,你可能只需要使用ONLCR选项来将行分隔符映射到CR-LF组合对上。其他选项主要是历史遗留,仅仅与行打印机和终端跟不上串行数据的年代有关。

选择原始输出

原始输出方式可以通过在c_oflag中重置OPOST选项来选择:

options.c_oflag &= ~OPOST;

如果OPOST选项被设置成无效的话,其他c_oflag中的选项都会失效。

控制字符

字符数组c_cc里面包括了控制字符的定义和超时参数。这个数组的每个元素都是以常量定义的。

成员变量c_cc中的控制字符

常量 描述
VINTR Interrupt CTRL-C
VQUIT Quit CTRL-Z
VERASE Erase Backspace (BS)
VKILL Kill-line CTRL-U
VEOF End-of-file CTRL-D
VEOL End-of-line Carriage return (CR)
VEOL2 Second end-of-line Line feed (LF)
VMIN Minimum number of characters to read -
VSTART Start flow CTRL-Q (XON)
VSTOP Stop flow CTRL-S (XOFF)
VTIME Time to wait for data (tenths of seconds) -

设置软件流控制字符

用来做软件流控制的字符包含在数组c_cc的VSTART和VSTOP元素里面。通常情况下,它们应该被设置成DC1(八进制021)和DC3(八进制023),它们在ASCII标准中代表着XON和XOFF字符。

设置读取超

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多