Linux串口操作

1、所需的头文件

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>     //unix标准函数
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>      //文件控制
#include <termios.h>    //POSIX中断控制
#include <errno.h>

2、打开串口

fd = open("/dev/ttyUSB0", O_RDWR);

3、设置波特率
最基本的串口设置包括波特率、校验位和停止位设置,主要使用termios.h头文件中定义的termios结构,如下:

struct termios
{
    tcflag_t c_iflag;   //输入模式标志
    tcflag_t c_oflag;   //输出模式标志
    tcflag_t c_cflag;   //控制模式标志
    tcflag_t c_lflag;   //本地模式标志
    cc_t c_line;
    cc_t c_cc[NCC];
}

4、设置数据位、停止位和校验位

8位数据位、无校验位:
Opt.c_cflag &= ~PARENB;
Opt.c_cflag &= ~CSTOPB;
Opt.c_cflag &= ~CSIZE;
Opt.c_iflag |= CS8
7位数据位、奇校验
Opt.c_cflag |= PARENB;
Opt.c_cflag |= PARODD;
Opt.c_cflag &= ~CSTOPB;
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= CS7;
7位数据位、偶校验
Opt.c_cflag |= PARENB;
Opt.c_cflag &= ~PARODD;
Opt.c_cflag &= ~CSTOPB;
Opt.c_cflag &= CSIZE;
Opt.c_cflag |= CS7;
7位数据位、Space校验
Opt.c_cflag &= ~PARENB;
Opt.c_cflag &= ~CSTOPB;
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= CS7;

5、读写串口
读使用read函数;写使用write函数。

6、关闭串口

close(fd);

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> //unix标准函数
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //文件控制
#include <termios.h> //POSIX中断控制
#include <errno.h>

#define TRUE 1
#define FALSE 0
#define SERIAL "/dev/ttyUSB0"

int speed_arr[] = {B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B600, B300, };
int name_arr[] = {115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 600, 300, };

//设置波特率
void SetSpeed(int fd, int speed)
{
int i;
struct termios Opt; //定义termios结构

if (tcgetattr(fd, &Opt) != 0)
{
perror("tcgetattr fd");
return;
}
for (i=0; i<sizeof(speed_arr)/sizeof(int); i++)
{
if (speed == name_arr[i])
{
tcflush(fd, TCIOFLUSH);
cfsetispeed(&Opt, speed_arr[i]);
cfsetospeed(&Opt, speed_arr[i]);
//tcsetattr函数标志:
//TCSANOW:立即执行而不等待数据发送或者接受完成
//TCSADRAIN:等待所有数据传递完成后执行
//TCSAFLUSH:Flush input and output buffers and make the change
if (tcsetattr(fd, TCSANOW, &Opt) != 0)
{
perror("tcsetattr fd");
return;
}
tcflush(fd, TCIOFLUSH);
}
}
}

//设置数据位、停止位和校验位
int SetParity(int fd, int databits, int stopbits, int parity)
{
struct termios Opt;
if (tcgetattr(fd, &Opt) != 0)
{
perror("tcgetattr fd");
return FALSE;
}
Opt.c_cflag |= (CLOCAL | CREAD); //一般必设置的标志
switch (databits) //设置数据位
{
case 7:
{
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= CS7;
break;
}
case 8:
{
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= CS8;
break;
}
default:
{
fprintf(stderr, "Unsupport data size.\n");
return FALSE;
}
}
switch (parity) //设置校验位
{
case 'n':
case 'N':
{
Opt.c_cflag &= ~PARENB; //清除校验位
Opt.c_iflag &= ~INPCK; //enable parity checking
break;
}
case 'o':
case 'O':
{
Opt.c_cflag |= PARENB; //enable parity
Opt.c_cflag |= PARODD; //奇校验
Opt.c_iflag |= INPCK; //disable parity checking
break;
}
case 'e':
case 'E':
{
Opt.c_cflag |= PARENB; //enable parity
Opt.c_cflag &= ~PARODD; //偶校验
Opt.c_iflag |= INPCK; //disable parity checking
break;
}
case 's':
case 'S':
{
Opt.c_cflag &= ~PARENB; //清除校验位
Opt.c_cflag &= ~CSTOPB; //?????
Opt.c_iflag |= INPCK; //disable parity checking
break;
}
default:
{
fprintf(stderr,"Unsupoort parity.\n");
return FALSE;
}
}
switch (stopbits) //设置停止位
{
case 1:
{
Opt.c_cflag &= ~CSTOPB;
break;
}
case 2:
{
Opt.c_cflag |= CSTOPB;
break;
}
default:
{
fprintf(stderr, "Unsupport stopbits.\n");
return FALSE;
}
}

Opt.c_cflag |= (CLOCAL | CREAD);
Opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

Opt.c_oflag &= ~OPOST;
Opt.c_oflag &= ~(ONLCR | OCRNL); //添加的

Opt.c_iflag &= ~(ICRNL | INLCR);
Opt.c_iflag &= ~(IXON | IXOFF | IXANY); //添加的

tcflush(fd, TCIFLUSH);
Opt.c_cc[VTIME] = 0; //设置超时为15sec
Opt.c_cc[VMIN] = 0; //Update the Opt and do it now
if (tcsetattr(fd, TCSANOW, &Opt) != 0)
{
perror("tcsetattr fd");
return FALSE;
}
return TRUE;
}

int main()
{
int fd;
int i, len, n=0;
char read_buf[256];
char write_buf[256];
char c;
struct termios opt;

fd = open(SERIAL, O_RDWR|O_NOCTTY);
if (fd == -1)
{
perror("open serial\n");
exit(-1);
}
SetSpeed(fd, 115200);
SetParity(fd, 8, 1, 'n');
while (1)
{
n = 0;
len = 0;
memset(read_buf, 0, sizeof(read_buf));
memset(write_buf, 0, sizeof(write_buf));

while ((n=read(fd, read_buf, sizeof(read_buf))) > 0)
{
read_buf[n] = '\0';
printf("%s", read_buf);
}
scanf("%c", &c);
write(fd, &c, 1);
while ((n=read(fd, read_buf, sizeof(read_buf))) > 0)
{
read_buf[n] = '\0';
printf("%s\n", read_buf);
}
}
}