目录
- 示例代码(使用select实现)
- 代码解释
- 总结
在 linux 系统里,我们可以借助 select、poll 或者 epoll 这些 I/O 多路复用机制达成串口数据读取的触发方式。
这些机制能够让程序在特定文件描述符(像串口设备文件描述符)有数据可读时得到通知,进而进行数据读取操作,而不是像轮询方式那样持续调用 read 函数。
示例代码(使用select实现)
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termIOS.h>
#include <unistd.h>
#include <sys/select.h>
// 设置串口波特率
void SetSpeed(int fd, int speed) {
struct termios options;
tcgetattr(fd, &options);
switch (speed) {
case 115200:
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
break;
// 可以添加更多波特率设置
default:
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
break;
}
tcsetattr(fd, TCSANOW, &options);
}
// 设置串口参数
void SetParity(int fd, int databits, int stopbits, char parity) {
struct termios options;
tcgetattr(fd, &options);
// 设置数据位
options.c_cflag &= ~CSIZE;
switch (databits) {
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
options.c_cflag |= CS8;
break;
}
// 设置奇偶校验位
switch (parity) {
case 'n':
case 'N':
options.c_cflag &= ~PARENB;
options.c_cflag &= ~PARODD;
break;
case 'o':
case 'O':
options.c_cflag |= (PARODD | PARENB);
break;
编程客栈 case 'e':
case 'E':
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
break;
default:
options.c_cflag &= ~PARENB;
options.c_cflag &= ~PARODD;
break;
}
// 设置停止位
switch (stopbits) {
case 1:
options.c_cflag &= ~CSTOPB;
break;
case nhVqZVTH2:
options.c_cflag |= CSTOPB;
break;
default:
options.c_cflag &= ~CSTOPB;
break;
}
tcsetattr(fd, TCSANOW, &options);
}
int main(void) {
int fd;
unsigned char buf[300];
unsigned short len;
fd = open("/dev/ttyS1", O_RdwR);
if (fd == -1) {
perror("can't open serial\n");
return -1;
}
SetParity(fd, 8, 1, 'n');
SetSpeed(fd, 115200);
fd_set readfds;
struct timeval timeout;
while (1) {
// 清空文件描述符集
FD_ZERO(&readfds);
// 将串口文件描述符加入读文件描述符集
FD_SET(fd, &readfds);
// 设置超时时间
timeout.tv_sec = 0;
timeout.tv_usec = 20000;
// 调用 select 函数等待事件发生
int activity = select(fd + 1, &readfds, NULL, NULL, &timeout);
if (activityjavascript < 0) {
perror("select error");
break;
www.devze.com} else if (activity > 0) {
// 检查是否是串口文件描述符有数据可读
if (FD_ISSET(fd, &readfds)) {
len = read(fd, buf, 100);
if (len > 0) {
python write(fd, buf, len);
}
}
}
}
close(fd);
return 0;
}
代码解释
SetSpeed 函数:
- 此函数用于设置串口的波特率,
- 它借助
tcsetattr函数来配置串口的输入和输出波特率
SetParity 函数:
- 该函数用于设置串口的数据位、停止位和奇偶校验位
- 同样是通过
tcsetattr函数来完成串口参数的配置
main 函数:
- 打开串口设备文件
/dev/ttyS1,并且设置串口参数。 - 构建一个
fd_set类型的文件描述符集readfds,把串口文件描述符fd添加到该集合中。 - 设定一个超时时间
timeout,防止select函数一直阻塞。 - 调用
select函数等待事件发生,若有数据可读,select函数会返回大于 0 的值。 - 利用
FD_ISSET宏检查是否是串口文件描述符有数据可读,若有则调用read函数读取数据,然后将数据回写到串口。
通过这种方式,程序就无需持续轮询 read 函数,而是在有数据到达时才进行读取操作。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。
加载中,请稍侯......
精彩评论