![](/img/trans.png)
[英]writing and reading to/from a serial port with a timeout in c++ and Linux
[英]Reading from serial port on Ubuntu Linux (11.10) in C++
我想用C / C ++代码从Linux上的串口读取数据。 因为我仍然可以使用GtkTerm从这个串口读取,甚至使用cat /dev/ttyUSB0
,这不是硬件/驱动程序问题。
似乎串口未正确启动,因为在使用gtkterm之类的程序后,读取工作正常。
这是我用来初始化串口的代码(seconde版本):
UbiDriver::UbiDriver(const std::string &ttyPort)
{
// Doc : http://www.easysw.com/~mike/serial/serial.html#2_4
m_serialHandle = open(ttyPort.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); // Open perif
if(m_serialHandle < 0)
{
MY_THROW("Impossible d'ouvrir le port '" << ttyPort << "' !\nerrno = " << errno);
}
// Conf
//if(fcntl(m_serialHandle, F_SETFL, 0) == -1) // lecture en mode bloquant
if(fcntl(m_serialHandle, F_SETFL, O_NONBLOCK) == -1) // lecture en mode non bloquant
{
MY_THROW("fcntl failed !\nerrno = " << errno);
}
struct termios options;
tcgetattr(m_serialHandle, &options); // Init struct avec la conf actuelle
cfsetispeed(&options, B9600); // In speed
cfsetospeed(&options, B9600); // Output speed
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_cflag |= (CLOCAL | CREAD); // Enable the receiver and set local mode...
options.c_cflag &= ~PARENB; // Desactive bit de parité
options.c_cflag &= ~CSTOPB; // Désactive 2 stop bits -> Active 1 stop bits
options.c_cflag &= ~CSIZE; // Désactive le bit "CSIZE"
options.c_cflag |= CS8; // Communication sur 8 bits
options.c_oflag &= ~OPOST; // Raw output is selected by resetting the OPOST option in the c_oflag member:
// Application de la conf
if(tcsetattr(m_serialHandle, TCSAFLUSH, &options) == -1) // Vidage buffer & application immédiate
{
MY_THROW("tcsetattr failed !\nerrno = " << errno);
}
}
并从端口读取数据
std::string UbiDriver::GetAnswer()
{
const int buffSize = 1024;
char buffer[buffSize] = {'\0'};
int count = 0;
std::string wholeAnswer = "";
int noDataTime = 0;
while(noDataTime < 2) // Tant qu'il y a des données à lire
{
count = read(m_serialHandle, buffer, buffSize - 1);
if(count == -1)
{
MY_THROW("Impossible de lire sur le port serie. Verifiez la connexion avec l'imprimante !")
}
if(count > 0)
{
noDataTime = 0;
buffer[count] = '\0';
for(int i = 0; i < count; i++)
{
buffer[i] &= ~128; // Supression du premier 1 du binaire
}
wholeAnswer += std::string(buffer);
std::cout << count << std::endl;
}
else
{
noDataTime++;
usleep(100000);
}
}
cerr << "----------- Answer -----------" << endl;
cerr << "Size = " << wholeAnswer.size() << endl;
cerr << wholeAnswer << endl;
return wholeAnswer;
return std::string("");
}
注意:此代码是根据您的评论完成的第二个版本。
检查你的代码,我没有看到你设置原始输入模式的位置。
您可能需要添加:
options.c_lflag&=〜(ICANON | ECHO | ECHOE | ISIG);
也许在这个版本的Ubuntu上改变的是默认输入模式设置为CANONICAL而不是raw。 您可以查看此文档以获取完整详细信息:
http://www.easysw.com/~mike/serial/serial.html#2_3_2
另请检查其他设备使用的流量控制。 如果它需要硬件流控制,则必须在打开端口时进行设置。 该代码可能在以前的版本中有效,因为默认情况下使用的值与您的程序兼容。 您的程序应设置所需的所有选项:端口速度,奇偶校验,流量控制,输入模式等。
我打开了gtkterm源代码,我终于找到了一个解决方案:事实上,你需要覆盖终端结构(是的,你不应该正常做)。
如果有人找到了更好的解决方案,请随时发布。 与此同时,这是工作代码,英文评论:
要打开串口:
// Doc : http://www.easysw.com/~mike/serial/serial.html#2_4
m_serialHandle = open(ttyPort.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); // Open serial port
if(m_serialHandle < 0)
{
MY_THROW("Impossible d'ouvrir le port '" << ttyPort << "' !\nerrno = " << errno);
}
// Read mode
//if(fcntl(m_serialHandle, F_SETFL, 0) == -1) // Blocking read
if(fcntl(m_serialHandle, F_SETFL, O_NONBLOCK) == -1) // Non-blocking read
{
MY_THROW("fcntl failed !\nerrno = " << errno);
}
// Get current terminos configuration
struct termios options;
tcgetattr(m_serialHandle, &options);
// Force termios values (should not be needed, but is)
options.c_cflag = B9600;
options.c_oflag = 0;
options.c_lflag = 0;
options.c_iflag = IGNPAR | IGNBRK;
options.c_cc[VTIME] = 0;
options.c_cc[VMIN] = 1;
// Set data rate
cfsetispeed(&options, B9600); // In speed
cfsetospeed(&options, B9600); // Output speed
// Set communication flags
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_cflag |= (CLOCAL | CREAD); // Enable the receiver and set local mode...
options.c_cflag &= ~PARENB; // Desactive bit de parité
options.c_cflag &= ~CSTOPB; // Désactive 2 stop bits -> Active 1 stop bits
options.c_cflag &= ~CSIZE; // Désactive le bit "CSIZE"
options.c_cflag |= CS8; // Communication sur 8 bits
options.c_oflag &= ~OPOST; // Raw output is selected by resetting the OPOST option in the c_oflag member:
// Disable flow control
options.c_iflag &= ~(IXON | IXOFF);
// Apply
if(tcsetattr(m_serialHandle, TCSANOW, &options) == -1) // Vidage buffer & application immédiate
{
MY_THROW("tcsetattr failed !\nerrno = " << errno);
}
// Empty buffers
tcflush(m_serialHandle, TCIOFLUSH);
读(非阻塞)
const int buffSize = 1024;
char buffer[buffSize] = {'\0'};
int count = 0;
std::string wholeAnswer = "";
int noDataTime = 0;
while(noDataTime < 3) // while there is data to be read
{
count = read(m_serialHandle, buffer, buffSize - 1);
// May fail in NON-BLOCKING mode if there is nothing to be read
/*if(count == -1)
{
MY_THROW("Impossible de lire sur le port serie. Verifiez la connexion avec l'imprimante !")
}*/
if(count > 0)
{
noDataTime = 0;
buffer[count] = '\0';
/*for(int i = 0; i < count; i++)
{
buffer[i] &= ~128; // Delete first binary bit. Could be useful for 7 bit communication, if the first bit is set to 1
}*/
wholeAnswer += std::string(buffer);
}
else
{
noDataTime++;
usleep(100000);
}
}
if(!wholeAnswer.empty())
{
cerr << "----------- Answer -----------" << endl;
cerr << "Size = " << wholeAnswer.size() << endl;
cerr << wholeAnswer << endl;
}
return wholeAnswer;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.