这一章介绍怎样使用C语言的POSIX终端接口配置串口。
多数系统支持使用POSIX终端接口改变波特率、字符数等参数。首先要包含头文件<termios.h>;这样就定义了终端控制结构和POSIX控制函数。
两个最重要的POSIX函数是tcgetattr(3)和tcsetattr(3),用了获取和设置终端属性。你可以设置一个指向termios结构的指针,这个结构包含了所有可用的串口选项:
Table 3 - Termios Structure Members
Member |
Description |
c_cflag |
Control options |
c_lflag |
Line options |
c_iflag |
Input options |
c_oflag |
Output options |
c_cc |
Control characters |
c_ispeed |
Input baud (new interface) |
c_ospeed |
Output baud (new interface) |
c_cflag用来控制波特率、数据位、奇偶位、停止位和硬件流控制。下面是所有支持的配置的常量:
Table 4 - Constants for the c_cflag Member
Constant |
Description |
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) |
c_cflag有两个选项需要一直使能,CLOCAL:忽略所有调制解调器的状态信号;CREAD:启用字符接收器。
波特率常数(CBAUD,B9600,etc.)用于缺少c_ispeed和c_ospeed 成员的旧接口。下一节介绍用于设置波特率的POSIX函数。
注:决不能直接初始化c_cflag(或其他flag)。应该使用AND,OR或NOT等位操作符来置1或清0成员中的位。不同的操作系统版本的位操作可能不同,使用位操作符可以避免错误操作一个新串行设备所需要的标志位。
1)设置波特率
不同的操作系统中,波特率储存的位置也不同。旧的接口将波特率按照Table4中的常量保存c_cflag中。新的实现方法提供了c_ispeed 和c_ospeed 来保存实际的波特率值。
cfsetospeed(3)和cfsetispeed(3)函数用来设置termios结构中的波特率,从而屏蔽了底层的操作系统。你可以使用下面的代码设置波特率:
Listing 2 - Setting the baud rate.
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)函数使用你提供的串口配置参数填充termios结构。设置了波特率、使能本地模式和串行数据接收后,使用tcsetattr(3)使新的配置生效。常量TCSANOW指定了新的设置立即生效,不需要等待数据接收或发生结束。还有其他常量,可以等待输入或输出数据结束,或清空缓冲区。
多数操作系统不支持不同的输入和输出速率,为了最好的可移植性,请确保相同的输入和输出速率。
Table 5 - Constants for tcsetattr
Constant |
Description |
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 |
2)设置字符大小
与波特率设置不同,没有方便的函数用来设置字符大小,所有必须用位掩码。字符大小用位数指定。
options.c_cflag &= ~CSIZE; /* Mask the character size bits */
options.c_cflag |= CS8; /* Select 8 data bits */
3)设置奇偶校验
类似设置字符大小,你必须手动设置使能奇偶校验和奇偶校验位数。UNIX的串口设备支持奇、偶和无校验。
No parity (8N1):
options.c_cflag &= ~PARENB
options.c_cflag &= ~CSTOPB
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
Even parity (7E1):
options.c_cflag |= PARENB
options.c_cflag &= ~PARODD
options.c_cflag &= ~CSTOPB
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
Odd parity (7O1):
options.c_cflag |= PARENB
options.c_cflag |= PARODD
options.c_cflag &= ~CSTOPB
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
Space parity is setup the same as no parity (7S1):
options.c_cflag &= ~PARENB
options.c_cflag &= ~CSTOPB
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
4)硬件流控制
有些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;
本地选项
本地模式成员c_lflag用于控制串行设备如何管理输入字符。通常可以将c_lflag配置为canonical或raw 。
Table 6 - Constants for the c_lflag Member
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 |
Canonical Input是以行进行操作的。输入的字符被放在一个可以由用户进行交互编辑的缓冲区,知道收到回车(CR)或换行(LF)字符。选择这个模式的话,你需要选择ICANON,ECHO和ECHOE选项:
options.c_lflag |= (ICANON | ECHO | ECHOE);
Raw input 是不做任何处理的。输入字符被收到后就直接传送。你需要取消ICANON、ECHO、ECHOE和ISIG选项来选择Raw Input模式:
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
决不能在发生命令给一个MODOM或电脑时使能输入回显,那样的话会在两个串口之间形成一个回环。
输入模式成员变量c_iflag用于控制串口接收端的字符的处理过程。与c_cflag一样,c_iflag的值也是将需要的选项通过OR运算得到的。
Table 7 - Constants for the c_iflag Member
Constant |
Description |
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中使能了奇偶校验,那你可以使能输入奇偶校验。与输入奇偶校验相关的常量是INPCK, IGNPAR, PARMRK和ISTRIP。通常你需要选择INPCK和ISTRIP来使能输入奇偶校验并去掉数据中的校验位:
options.c_iflag |= (INPCK | ISTRIP);
IGNPAR是一个危险的选项,它告诉串口忽略校验错误并让数据通过,就想没用发生错误一样。这在测试通信连接的质量时有用,通常没有实用价值。
PARMRK会使校验错误被标记为“marked",并使用特殊的字符放入输入流中。如果使能IGNPAR,一个空字符(000 octal)会被加入到校验错误的前面。否则,DEL(177 octal)和NUL字符会和错误字符一起发生。
使用IXON、IXOFf和IXANY常量来使能软件流控制:
options.c_iflag |= (IXON | IXOFF | IXANY);
取消软件流控制只需掩掉这些位:
options.c_iflag &= (IXON | IXOFF | IXANY);
XON(开始数据)和XOFF(停止数据)字符定义在下面描述的c_cc数组中。
C_oflag成员包含了输出过滤选项。像输入模式一样,你可以选择processed或raw数据输出。
Table 8 - Constants for the c_oflag Member
Constant |
Description |
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选项来选择Processed输出:
options.c_oflag |= OPOST;
在所有的选项中,你大概只需要用ONLCR选项将换行符映射到CR-LF上。
在c_oflag中重新设置OPOST选项就选择了Raw输出:
Options.c_oflag &= ~OPOST;
取消OPOST选项时,c_oflag中的其他选项都将被忽略。
c_cc字符数组包含控制字符的定义和超时参数。数组的元素都定义了常量。
Table 9 - Control Characters in the c_cc Member
Constant |
Description |
Key |
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 |
|
VTIME |
Time to wait for data (tenths of seconds) |