Computer serial port data reading is often used when using sensors. Next, I introduce the method of reading Linux serial port data in a project. I hope it will be helpful to you.
Data Format
A set of data transmitted by the sensor through serial port is 13 bytes. The data format is as follows:
Initialize Serial Port
We need to initialize the serial port before reading the serial port data. The initialization of the serial port needs three steps:opening the serial port, setting the parameters of the serial port (including baud rate, data bit, stop bit, check bit).
Opening the Port
The procedure of opening serial port is as follow, function returns a handle:1
2
3
4
5
6
7
8
9
10
11int openPort()
{
int fd;
fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY |O_NDELAY);
if(fd == -1)
{
perror("open serial failed!\n");
exit(1);
}
return fd;
}
SERIAL_PORT is a serial address;
O_RDWR means to open in a readable and writable manner;
O_NOCTTY indicates that if the open file is a terminal device, the terminal will not be regarded as a process control terminal;
O_NDELAY denotes opening a file in an uninterruptible manner.
Setting the Parameters
Here is the program for setting baud rate and data bits1
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
119int setSpeed(int fd, int speed, struct termios Opt)
{
int i;
if(tcgetattr(STDIN_FILENO, &Opt) != 0)
{
perror("tcgetattr fd\n");
return 1;
}
//识别波特率,设置输入输出波特率
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]);
//设置数据接收方式
if(tcsetattr(fd, TCSANOW, &Opt) != 0)
{
perror("tcsetattr fd");
return 1;
}
tcflush(fd, TCIOFLUSH);
}
}
return 0;
}
int setParity(int fd, int databits, int stopbits, int parity, struct termios Opt)
{
if(tcgetattr(fd, &Opt) != 0)
{
perror("tcgetattr fd");
return 1;
}
Opt.c_cflag |= (CLOCAL | CREAD); //CLOCAL:忽略 modem 控制线。
//CREAD: 打开接受者。
switch(databits) //设置数据位数
{
case 7:
Opt.c_cflag &= ~CSIZE; //屏蔽字符大小位
Opt.c_cflag |= CS7; //选择7位数据位
break;
case 8:
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= CS8;
break;
default:
fprintf(stderr, "Unsupported data size.\n");
return 1;
}
switch(parity) //设置校验位
{
case 'n':
Opt.c_cflag &= ~PARENB; //清除校验位
Opt.c_iflag &= ~INPCK; //启用输入奇偶检测。
break;
case 'o':
Opt.c_cflag |= PARENB; //使能校验位
Opt.c_cflag |= PARODD; //奇校验
Opt.c_iflag |= INPCK; //启用输入奇偶检测。
break;
case 'e':
Opt.c_cflag |= PARENB; //使能校验位
Opt.c_cflag &= ~PARODD; //偶校验
Opt.c_iflag |= INPCK; //启用输入奇偶检测。
break;
case 's':
Opt.c_cflag &= ~PARENB; //清除校验位
Opt.c_cflag &= ~CSTOPB; //设置一个停止位
Opt.c_iflag |= INPCK; //启用输入奇偶检测。
break;
default:
fprintf(stderr, "Unsupported parity.\n");
return 1;
}
switch(stopbits) //设置停止位
{
case 1:
Opt.c_cflag &= ~CSTOPB;
break;
case 2:
Opt.c_cflag |= CSTOPB;
break;
default:
fprintf(stderr, "Unsupported stopbits.\n");
return 1;
}
Opt.c_cflag |= (CLOCAL | CREAD);
Opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
Opt.c_oflag &= ~OPOST; //OPOST :启用具体实现自行定义的输出处理。
Opt.c_oflag &= ~(ONLCR | OCRNL); //OCRNL :将输出中的回车映射为新行符
//ONLCR :(XSI) 将输出中的新行符映射为回车-换行。
Opt.c_iflag &= ~(ICRNL | INLCR); //ICRNL :将输入中的回车翻译为新行 (除非设置了 IGNCR)(否则当输入信号有 CR 时不会终止输入)。
//INLCR :将输入中的 NL 翻译为 CR。(将收到的换行符号转换为Return)
Opt.c_iflag &= ~(IXON | IXOFF | IXANY); //IXON :启用输出的 XON/XOFF 流控制。
//IXOFF :启用输入的 XON/XOFF 流控制。
//IXANY :(不属于 POSIX.1;XSI) 允许任何字符来重新开始输出。
tcflush(fd, TCIFLUSH); //清空输入缓存
//MIN = 0 , TIME =0; 有READ立即回传否则传回 0,不读取任何字元
Opt.c_cc[VTIME] = 0;
Opt.c_cc[VMIN] = 0;
if(tcsetattr(fd, TCSANOW, &Opt) != 0) //设置数据接收方式
{
perror("tcsetattr fd");
return 1;
}
return 0;
}
Initialize Port
Use the following program to initialize the serial port, the function returns a handle.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
28int init(void)
{
int fd;
struct termios opt;
//打开串口
fd = openPort();
//设置波特率
if(setSpeed(fd, PORT_SPEED, opt) == 1)
{
printf("setSpeed failed!\n");
exit(1);
}
//设置数据位、停止位和校验位
if(setParity(fd, DATABITS, STOPBITS, PARITY, opt) == 1)
{
printf("setParity failed!\n");
exit(1);
}
if(tcsetattr(fd, TCSANOW, &opt) != 0) //TCSANOW:不等数据传输完毕就立即改变属性。
{ //TCSADRAIN:等待所有数据传输结束才改变属性。
perror("serial error");
return -1;
}
return fd;
}
Data Reading and Analysis
A set of data has 13 characters, each time we read a character, we can judge whether it is the starting bit at each reading, and separate each group of data. The judgement method is as follows: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
43void readPort(int fd)
{
time_t t;
int signal=0,pm1_0,pm1_1,pm2_0,pm2_1,pm10_0,pm10_1,pm1,pm2,pm10,temporary;
int i,len,n,parameter1,parameter2,Initiator;
char read_buf[24],sql_insert[200];
while(1)
{
bzero(read_buf, sizeof(read_buf));
while((n = read(fd, read_buf, sizeof(read_buf))) > 0)
{
//printf("\nlen= %d \n",n);
for(i=0;i<n;i++){
int tst=(int)read_buf[i];
// 判断起始符号
parameter2=parameter1;
parameter1=tst;
Initiator=parameter1+parameter1;
// 累加标志
signal++;
// 判断起始位位置
if(parameter2==66 && parameter1==77) signal=2;
if(signal==11) pm1_0=tst;
if(signal==12) pm1_1=tst;
if(signal==13) pm2_0=tst;
if(signal==14) pm2_1=tst;
if(signal==15) pm10_0=tst;
if(signal==16) pm10_1=tst;
pm1=pm1_0*256+pm1_1;
pm2=pm2_0*256+pm2_1;
pm10=pm10_0*256+pm10_1;
if(signal==49) signal=1;
printf("\n pm1.0=%d pm2.5=%d pm10=%d \n" ,pm1,pm2,pm10);
temporary=24;
t=time(0);
sprintf(sql_insert,"insert into dust_data(`date`,`pm1.0`,`pm2.5`,`pm10`,`temporary`,`host_ip`) values ('%ld','%d','%d','%d','%d','127.0.0.1')",t,pm1,pm2,pm10,temporary);
executesql("delete from dust_data limit 1");
executesql(sql_insert);
}
}
}
}
Database Operation
I built MySQL database locally and wrote the readed datas directly into the database.
Initialize Connection
First, initialize the database using the following method:1
2
3
4
5
6
7
8
9int init_mysql() {
// init the database connection
g_conn = mysql_init(NULL);
/* connect the database */
if(!mysql_real_connect(g_conn, g_host_name, g_user_name, g_password, g_db_name, g_db_port, NULL, 0))
return -1;
return 0;
}
g_host_name is the database address;
g_user_name is the database user name;
g_password is the database password;
g_db_name is the name of the database;
g_db_port is the database port;
Database Operation
1 | int executesql(const char * sql) { |

...
...
If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !