1.Linux把所有的外部终端设备都当做文件进行操作,通常分为块设备、字符设备、网络设备。串口是属于字符设备,是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用。常用的串口是 RS-232-C 接口,传输距离在码元畸变小于 4% 的情况下传输电缆长度应为 50 英尺。通常的操作步骤为"打开串口文件"->"设置串口参数"->"读写串口操作"->"关闭串口文件"。
2.详解:
需要头文件信息:
1
2 #include < stdio_ext.h >
3 #include < stdio.h > /* 标准输入输出定义 */
4 #include < stdlib.h > /* 标准函数库定义 */
5 #include < unistd.h > /* Unix 标准函数定义 */
6 #include < sys / types.h > /* 系统类型定义 */
7 #include < sys / stat.h > /* 系统状态定义 */
8 #include < fcntl.h > /* 文件控制定义 */
9 #include < termios.h > /* PPSIX 终端控制定 */
10 #include < errno.h > /* 错误号定义/
2 #include < stdio_ext.h >
3 #include < stdio.h > /* 标准输入输出定义 */
4 #include < stdlib.h > /* 标准函数库定义 */
5 #include < unistd.h > /* Unix 标准函数定义 */
6 #include < sys / types.h > /* 系统类型定义 */
7 #include < sys / stat.h > /* 系统状态定义 */
8 #include < fcntl.h > /* 文件控制定义 */
9 #include < termios.h > /* PPSIX 终端控制定 */
10 #include < errno.h > /* 错误号定义/
打开串口:
linux下的串口文件通常是位于/dev目录下,串口1为/dev/ttyS0,串口2为/dev/ttyS1,以此类推。其它终端还有usb0,py0等。
1
fd
=
open(
"
/dev/ttyS0
"
,O_RDWR
|
O_NOCTTY
|
O_NDELAY);
2 if ( - 1 == fd)
3 {
4 perror( " can not open serial port " );
5
6 }
2 if ( - 1 == fd)
3 {
4 perror( " can not open serial port " );
5
6 }
设置串口:
最基本的设置串口包括波特率设置,效验位和停止位设置。主要是设置termios结构体的成员函数。
1
struct
termios
2 {
3 tcflag_t c_iflag; /* input mode flags */
4 tcflag_t c_oflag; /* output mode flags */
5 tcflag_t c_cflag; /* control mode flags */
6 tcflag_t c_lflag; /* local mode flags */
7 cc_t c_line; /* line discipline */
8 cc_t c_cc[NCCS]; /* control characters */
9 speed_t c_ispeed; /* input speed */
10 speed_t c_ospeed; /* output speed */
11 #define _HAVE_STRUCT_TERMIOS_C_ISPEED 1
12 #define _HAVE_STRUCT_TERMIOS_C_OSPEED 1
13 };
2 {
3 tcflag_t c_iflag; /* input mode flags */
4 tcflag_t c_oflag; /* output mode flags */
5 tcflag_t c_cflag; /* control mode flags */
6 tcflag_t c_lflag; /* local mode flags */
7 cc_t c_line; /* line discipline */
8 cc_t c_cc[NCCS]; /* control characters */
9 speed_t c_ispeed; /* input speed */
10 speed_t c_ospeed; /* output speed */
11 #define _HAVE_STRUCT_TERMIOS_C_ISPEED 1
12 #define _HAVE_STRUCT_TERMIOS_C_OSPEED 1
13 };
波特率设置
1
struct
termios Opt;
2 tcgetattr(fd, & Opt); /* 获得文件句柄的termios结构 */
3 cfsetispeed( & Opt,B2400); /* 设置为2400Bps,通常串口IO是一致的波特率 */
4 cfsetospeed( & Opt,B2400);
5 tcsetattr(fd,TCANOW, & Opt); /* 设置文件句柄的termios结构,TCANOW为设置立即生效 */
2 tcgetattr(fd, & Opt); /* 获得文件句柄的termios结构 */
3 cfsetispeed( & Opt,B2400); /* 设置为2400Bps,通常串口IO是一致的波特率 */
4 cfsetospeed( & Opt,B2400);
5 tcsetattr(fd,TCANOW, & Opt); /* 设置文件句柄的termios结构,TCANOW为设置立即生效 */
设置数据位
1
options.c_cflag
&=
~
CSIZE;
2 option.c_cflag |= CS8; /* 设置为8位数据位,其它如CS5->CS7 */
2 option.c_cflag |= CS8; /* 设置为8位数据位,其它如CS5->CS7 */
设置校验位
1
option.c_cflag
|=
PARENB;
/*
设置校验位使能
*/
2 option.c_cflag |= PARODD; /* 设置为奇校验 */
3 // option.c_cflag &= ~PARODD; /*设置为偶校验*/
4
5 // 以下设置仅限于linux系统
6 option.c_cflag |= CMSPAR;
7 /* 设置space校验,奇偶校验位恒为0 */
8 // option.c_cflag &= ~PARODD;或者是直接没有设置
9 /* 设置mark校验,奇偶校验位恒为1 */
10 // option.c_cflag |= PARODD;
2 option.c_cflag |= PARODD; /* 设置为奇校验 */
3 // option.c_cflag &= ~PARODD; /*设置为偶校验*/
4
5 // 以下设置仅限于linux系统
6 option.c_cflag |= CMSPAR;
7 /* 设置space校验,奇偶校验位恒为0 */
8 // option.c_cflag &= ~PARODD;或者是直接没有设置
9 /* 设置mark校验,奇偶校验位恒为1 */
10 // option.c_cflag |= PARODD;
设置停止位
1
option.c_cflag
&=
~
CSTOPB;
//
一位停止位
2 // option.c_cflag |= CSTOPB; // 两位停止位
2 // option.c_cflag |= CSTOPB; // 两位停止位
关闭文件
1
close(fd);
//增加关于RAW原始通信(非规范模式)详解
在使用非规范模式的时候,需要关闭c_lflag字段的ICANON标志就会使得终端出于非规范模式,在这个模式下,接受到的数据不是成行的。故这里区别与上面说明,需要使用c_cc数组的两个变量:MIN和TIME,数组元素名下标为VMIN和VTIME。
VTIME定义要求等待的时间(百毫米,通常是unsigned char变量),而VMIN定义了要求等待的最小字节数(相比之下,read函数的第三个参数指定了要求读的最大字节数)。
如果VTIME=0,VMIN=要求等待读取的最小字节数,read必须在读取了VMIN个字节的数据或者收到一个信号才会返回。
如果VTIME=时间量,VMIN=0,不管能否读取到数据,read也要等待VTIME的时间量。
如果VTIME=时间量,VMIN=要求等待读取的最小字节数,那么将从read读取第一个字节的数据时开始计时,并会在读取到VMIN个字节或者VTIME时间后返回。
如果VTIME=0,VMIN=0,不管能否读取到数据,read都会立即返回。
如果VTIME=时间量,VMIN=0,不管能否读取到数据,read也要等待VTIME的时间量。
如果VTIME=时间量,VMIN=要求等待读取的最小字节数,那么将从read读取第一个字节的数据时开始计时,并会在读取到VMIN个字节或者VTIME时间后返回。
如果VTIME=0,VMIN=0,不管能否读取到数据,read都会立即返回。
另外要想以上设置生效,还需要在打开文件的时候,不要指定O_NDELAY或者是O_NONBLOCK参数。
1
#include
<
stdio.h
>
/*
标准输入输出定义
*/
2 #include < stdlib.h > /* 标准函数库定义 */
3 #include < unistd.h > /* Unix 标准函数定义 */
4 #include < sys / types.h > /* 系统类型定义 */
5 #include < sys / stat.h > /* 系统状态定义 */
6 #include < fcntl.h > /* 文件控制定义 */
7 #include < termios.h > /* PPSIX 终端控制定义 */
8 #include < errno.h > /* 错误号定义 */
9
10 int main( void )
11 {
12
13
14 int fd;
15 struct termios option;
16 int status = 0 ;
17 char buff[ 512 ]; // 这样定义buff的内容是随机数
18 int num = 0 ;
19
20 fd = open( " /dev/ttyS0 " , O_RDWR | O_NOCTTY );
21 if ( - 1 == fd)
22 {
23 perror( " can not open serial port " );
24
25 }
26 tcgetattr(fd, & option);
27 option.c_cflag |= CLOCAL; // 保证程序不会成为端的占有者
28 option.c_cflag |= CREAD; // 使端口能读取输入的数据
29 cfsetispeed( & option, B2400);
30 cfsetospeed( & option, B2400);
31
32 option.c_cflag &= ~ CSIZE;
33 option.c_cflag |= CS8;
34 option.c_cflag |= PARENB;
35 // option.c_cflag &= ~PARODD;
36
37 option.c_cflag |= PARODD; // 奇校验
38 option.c_cflag |= CMSPAR; // 标记校验位
39 option.c_cflag &= ~ CSTOPB; // 一位停止位
40 option.c_iflag |= INPCK; /* Disnable parity checking */
41
42 // 一下是添加测试
43 / //
44
45 option.c_lflag &= ~ (ICANON | ECHO | ECHOE | ISIG);
46
47 option.c_oflag &= ~ OPOST;
48 option.c_oflag &= ~ (ONLCR | OCRNL); // 添加的
49
50 option.c_iflag &= ~ (ICRNL | INLCR);
51 option.c_iflag &= ~ (IXON | IXOFF | IXANY); // 添加的
52 ///
53
54 option.c_cc[VTIME] = 0 ; // 设置超时
55 option.c_cc[VMIN] = 1 ; // 设置最小字节数
56 tcflush(fd, TCIFLUSH);
57
58
59 status = tcsetattr(fd, TCSANOW, & option);
60 if ( - 1 == status)
61 {
62 perror( " tcsetattr false " );
63 }
64
65 write(fd, " \x02 " , sizeof ( " \x02 " ));
66 num = read(fd, buff, 512 );
67 printf( " %d\n " , num);
68 printf( " %d\n " , errno);
69 printf( " %x " , buff[ 0 ]); // 注意这里,如果读取不成功,将是随机值。
70 }
71
2 #include < stdlib.h > /* 标准函数库定义 */
3 #include < unistd.h > /* Unix 标准函数定义 */
4 #include < sys / types.h > /* 系统类型定义 */
5 #include < sys / stat.h > /* 系统状态定义 */
6 #include < fcntl.h > /* 文件控制定义 */
7 #include < termios.h > /* PPSIX 终端控制定义 */
8 #include < errno.h > /* 错误号定义 */
9
10 int main( void )
11 {
12
13
14 int fd;
15 struct termios option;
16 int status = 0 ;
17 char buff[ 512 ]; // 这样定义buff的内容是随机数
18 int num = 0 ;
19
20 fd = open( " /dev/ttyS0 " , O_RDWR | O_NOCTTY );
21 if ( - 1 == fd)
22 {
23 perror( " can not open serial port " );
24
25 }
26 tcgetattr(fd, & option);
27 option.c_cflag |= CLOCAL; // 保证程序不会成为端的占有者
28 option.c_cflag |= CREAD; // 使端口能读取输入的数据
29 cfsetispeed( & option, B2400);
30 cfsetospeed( & option, B2400);
31
32 option.c_cflag &= ~ CSIZE;
33 option.c_cflag |= CS8;
34 option.c_cflag |= PARENB;
35 // option.c_cflag &= ~PARODD;
36
37 option.c_cflag |= PARODD; // 奇校验
38 option.c_cflag |= CMSPAR; // 标记校验位
39 option.c_cflag &= ~ CSTOPB; // 一位停止位
40 option.c_iflag |= INPCK; /* Disnable parity checking */
41
42 // 一下是添加测试
43 / //
44
45 option.c_lflag &= ~ (ICANON | ECHO | ECHOE | ISIG);
46
47 option.c_oflag &= ~ OPOST;
48 option.c_oflag &= ~ (ONLCR | OCRNL); // 添加的
49
50 option.c_iflag &= ~ (ICRNL | INLCR);
51 option.c_iflag &= ~ (IXON | IXOFF | IXANY); // 添加的
52 ///
53
54 option.c_cc[VTIME] = 0 ; // 设置超时
55 option.c_cc[VMIN] = 1 ; // 设置最小字节数
56 tcflush(fd, TCIFLUSH);
57
58
59 status = tcsetattr(fd, TCSANOW, & option);
60 if ( - 1 == status)
61 {
62 perror( " tcsetattr false " );
63 }
64
65 write(fd, " \x02 " , sizeof ( " \x02 " ));
66 num = read(fd, buff, 512 );
67 printf( " %d\n " , num);
68 printf( " %d\n " , errno);
69 printf( " %x " , buff[ 0 ]); // 注意这里,如果读取不成功,将是随机值。
70 }
71