串口属性通过结构体struct termios来设置。通过tcgetattr()函数可以获取串口当前属性,通过tcsetattr函数把新的属性设置到串口上。
struct termios包含以下成员:
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用于设置控制参数,除波特率外还包含以下内容:
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)
其中CLOCAL和CREAD通常总是应该被使能的。
下面是c_cflag的一些典型配置方式:
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;
c_lfalg用于设置本地模式,它决定串口驱动如何处理输入的字符。其设置包含以下内容:
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
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_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_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)
-
其中,控制符 VTIME 和 VMIN 之间有着复杂的关系。 VTIME 定义要求等待的零到几百毫秒的值(通常是一个8位的unsigned char变量)。VMIN 定义了要求等待的最小字节数(不是要求读的字节数,read()的第三个参数才是指定要求读的最大字节数),这个字节数可能是0。
> 如果 VTIME 取 0 , VMIN 定义了要求等待读取的最小字节数。函数read() 只有在读取了 VMIN 个字节的数据或者收到一个信号的时候才返回。
> 如果 VMIN 取 0 , VTIME 定义了即使没有数据可以读取, read() 函数返回前也要等待几百毫秒的时间量。这时, read() 函数不需要像其通常情况那样要遇到一个文件结束标志才返回 0 。
> 如果 VTIME 和 VMIN 等不取 0 , VTIME 定义的时当接收到底一个自己的数据后开始计算等待的时间量。如果当调用 read 函数时可以得到数据,计时器马上开始计时。如果但调用 read 函数时还没有任何数据可读,则等接收到底一个字节的数据后,计时器开始计时。函数 read 可能会在读取到 VMIN 个字节的数据后返回,也可能在计时完毕后返回,这主要取决于哪个条件首先实现。不过函数至少会读取到一个字节的数据,因为计时器是在读取到第一个数据时开始计时的。
> 如果 VTIME 和 VMIN 都取 0 ,即使读取不到任何数据,函数read也会立即返回。同时,返回值 0 表示 read 函数不需要等待文件结束标志就返回了。
串口属性一般不应该直接赋值,而用按位或和按位与非来设置。设置好的属性使用tcsetattr函数来让它在串口上生效。此函数的第一个参数是串口设备描述符,第三个是指向设置属性的termios结构体的指针,第二个参数有以下选择:
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
串口通信源程序(此程序接收14个字节数据再把它发回去):
#include
#include
#include
#include
#include
#include
#include
#include
main()
{
int fd;
int i;
int len;
int n=0;
char read_buf[256];
char write_buf[256];
struct termios opt;
fd = open("/dev/tts/0", O_RDWR | O_NOCTTY); //默认为阻塞读方式
if(fd == -1)
perror("open serial 0\n");
tcgetattr(fd, &opt);
cfsetispeed(&opt, B9600);
cfsetospeed(&opt, B9600);
if(tcsetattr(fd, TCSANOW, &opt) != 0 )
{ perror("tcsetattr error");
return -1;
}
opt.c_cflag &=~CSIZE;
opt.c_cflag |= CS8;
opt.c_cflag &=~CSTOPB;
opt.c_cflag &=~PARENB;
opt.c_cflag &=~INPCK;
opt.c_cflag |= (CLOCAL | CREAD);
opt.c_lflag &=~(ICANON | ECHO | ECHOE | ISIG);
opt.c_oflag &=~OPOST;
opt.c_iflag &=~ICRNL;
opt.c_iflag &=~INLCR;
opt.c_cc[VTIME] = 150;
opt.c_cc[VMIN] = 1;
tcflush(fd, TCIOFLUSH);
printf("configure complete\n");
if(tcsetattr(fd, TCSANOW, &opt) != 0)
{
perror("serial error");
return -1;
}
printf("start send and receive data\n");
while(1)
{
n = 0;
len = 0;
bzero(read_buf,sizeof read_buf);
bzero(write_buf,sizeof write_buf);
while( (n = read(fd, read_buf, 14)) > 0 )
{
for(i=len; i
{
write_buf[i] = read_buf[i-len];
}
len += n;
if(len == 14) //读完全部14个数据就结束
break;
}
for(i=0; i
printf("%d ",write_buf[i]);
n = write(fd, write_buf, len);
printf("write %d chars\n",n);
}
}