我想用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 ya 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,而不是原始的。 你可以查看这个文件的全部细节:
http://www.easysw.com/~mike/serial/serial.html#2_3_2
同时检查您的其他设备使用的流量控制。 如果需要硬件流量控制,则必须在打开端口时进行设置。 代码可能在以前的版本中工作,因为默认使用的值与您的程序兼容。 您的程序应该设置所有需要的选项:端口速度,奇偶校验,流量控制,输入模式等
我打开了gtkterm源代码,终于找到了一个解决方案:事实上,你需要重写terminos结构(是的,你不应该这样做)。
如果有人找到更好的解决方案,随时发布。 与此同时,这里是工作代码,英文评论:
打开串口:
// 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;