如果串行接口具有异步读取数据,则 C++ Ubuntu select()
Posted
技术标签:
【中文标题】如果串行接口具有异步读取数据,则 C++ Ubuntu select()【英文标题】:C++ Ubuntu select() if serial interface has data on asynchronous read 【发布时间】:2015-06-17 00:18:30 【问题描述】:我正在使用 C++ 和 termios 为 Ubuntu 编写一个异步串行数据读取器类,我在检查是否有可用数据时遇到了困难。
这是我的代码:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
class MySerialClass
public:
MySerialClass(std::string port);
virtual ~MySerialClass();
void openSerial();
void closeSerial();
void configureSerial();
void writeSerial(std::vector<char> data);
void readSerial(std::vector<char> &data, unsigned int numBytes);
private:
int fd = 0; // The serial file descriptor
fd_set fdset; // The set to check on select
std::string portName = "";
;
MySerialClass::MySerialClass(std::string port) : portName(port)
MySerialClass::~MySerialClass()
void MySerialClass::openSerial()
fd = open(portName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
void MySerialClass::closeSerial()
close(fd);
void MySerialClass::configureSerial()
struct termios config = 0 ;
tcgetattr(fd, &config);
config.c_iflag = IGNPAR | ICRNL;
config.c_oflag = 0;
config.c_lflag = ICANON;
config.c_cc[VINTR] = 0; /* Ctrl-c */
config.c_cc[VQUIT] = 0; /* Ctrl-\ */
config.c_cc[VERASE] = 0; /* del */
config.c_cc[VKILL] = 0; /* @ */
config.c_cc[VEOF] = 4; /* Ctrl-d */
config.c_cc[VTIME] = 0; /* inter-character timer unused */
config.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */
config.c_cc[VSWTC] = 0; /* '\0' */
config.c_cc[VSTART] = 0; /* Ctrl-q */
config.c_cc[VSTOP] = 0; /* Ctrl-s */
config.c_cc[VSUSP] = 0; /* Ctrl-z */
config.c_cc[VEOL] = 0; /* '\0' */
config.c_cc[VREPRINT] = 0; /* Ctrl-r */
config.c_cc[VDISCARD] = 0; /* Ctrl-u */
config.c_cc[VWERASE] = 0; /* Ctrl-w */
config.c_cc[VLNEXT] = 0; /* Ctrl-v */
config.c_cc[VEOL2] = 0; /* '\0' */
speed_t sp = B9600;
config.c_cflag |= CSIZE;
config.c_cflag |= CS8;
cfsetispeed(&config, sp);
cfsetospeed(&config, sp);
tcsetattr(fd, TCSAFLUSH, &config);
void MySerialClass::writeSerial(std::vector<char> data)
char buffer[1024];
if (data.size() > 1024)
return;
int index = 0;
for (char &item : data)
buffer[index++] = item;
unsigned int size = data.size();
write(fd, &buffer[0], size);
void MySerialClass::readSerial(std::vector<char> &data, unsigned int numBytes)
char buffer[1024];
data.clear();
if (numBytes > 1024)
return;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
int ret = select(fd + 1, 0, 0, 0, &tv);
std::cout << "Select returns: " << ret << std::endl;
if (!ret)
return;
read(fd, &buffer[0], numBytes);
for (unsigned int i = 0; i < numBytes; i++)
data.push_back(buffer[i]);
int main()
MySerialClass serial("/dev/ttyS1");
serial.openSerial();
serial.configureSerial();
while(1)
std::vector<char> retData;
serial.readSerial(retData, 100);
std::string retString(retData.begin(), retData.end());
if (retString == "END")
serial.closeSerial();
break;
它编译得很好,但它从不接收数据,因为select()
语句总是返回零。带有阻塞选项且不带select()
的代码工作正常(只需注释select() 行并从open()
中删除O_NODELAY
)。
我很确定这个问题与 select()
的使用方式有关(这是我第一次使用 select()
)。
有人可以帮我解决这个问题吗?代码可在Coliru here获得
顺便说一句:我对select()
的另一个疑问是这个类将用于多线程环境。我需要确保每个类实例只检查其端口繁忙(它自己的fd
),没有其他线程端口繁忙。
【问题讨论】:
【参考方案1】:没有指定要读取的 fd_set。试试这个:
fd_set readfs; /* file descriptor set */
FD_ZERO(&readfs); /* clear the set */
FD_SET(fd, &readfs); /* put the fd in the set */
int ret = select(fd + 1, &readfs, 0, 0, &tv);
编辑:这也应该解决您的其他问题。每个选择只查看您告诉它查看的文件描述符。
呸。糟糕的英语语法,但它看起来更糟。
【讨论】:
谢谢。工作正常。以上是关于如果串行接口具有异步读取数据,则 C++ Ubuntu select()的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Linux 上通过 C++ 中的串行接口与 Arduino 通信?