You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ubuntu虚拟机C++串口读取报Error11错误求助

串口读取报错Error 11(Resource temporarily unavailable)解决方法

问题背景

在Ubuntu 24.04.2虚拟机中使用C++与串口交互,已将串口设置为Raw模式,可正常写入数据,但每次读取都会触发Error 11(Resource temporarily unavailable)。已简化程序代码、将当前用户加入dialout组,不清楚是否需要停止相关服务及操作方式。

错误原因

Error 11对应EAGAIN错误,根源是打开串口时使用了O_NDELAY标志,将串口设置为非阻塞模式。当串口接收缓冲区没有数据时,read()会直接返回EAGAIN,这并非设备故障,是非阻塞IO的正常行为。

解决方案

方案1:切换为阻塞模式(推荐)

打开串口时移除O_NDELAY标志,让read()阻塞等待数据:

int fd = open(portName, O_RDWR | O_NOCTTY);

修改后,read()会一直等待直到有数据可读,不会再返回EAGAIN错误。

方案2:保留非阻塞模式并处理错误

如果需要维持非阻塞IO,在读取函数中判断errno是否为EAGAIN,将其视为“当前无数据”而非报错:

void readData(int fd) 
{
   char buffer[256];
   ssize_t bytesRead = read(fd, buffer, sizeof(buffer) - 1);

   if (bytesRead < 0) 
   {
      if (errno == EAGAIN) {
          std::cout << "当前无数据可读" << std::endl;
          return;
      }
      printf("Error %i reading from port: %s\n", errno, strerror(errno));
      std::cerr << "Error reading data" << std::endl;
      return;
   }

   buffer[bytesRead] = '\0';
   std::cout << "Bytes read: " << bytesRead << ", data: " << buffer << std::endl;
}

方案3:完善Raw模式配置

串口配置函数缺少c_cc参数设置,Raw模式下需通过VMIN和VTIME控制读取的等待逻辑:

void configurePort(int fd) 
{
   struct termios options;
   tcgetattr(fd, &options);

   cfsetispeed(&options, B115200);
   cfsetospeed(&options, B115200);

   options.c_cflag &= ~PARENB; // 无校验位
   options.c_cflag &= ~CSTOPB; // 1位停止位
   options.c_cflag &= ~CSIZE;  // 重置数据位长度
   options.c_cflag |= CS8;     // 8位数据位

   options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 禁用规范模式、回显等
   options.c_iflag &= ~(IXON | IXOFF | IXANY);        // 禁用软件流控
   options.c_oflag &= ~OPOST;                         // 禁用输出处理(Raw模式必需)

   // 设置读取等待参数
   options.c_cc[VMIN] = 1;    // 至少读取1个字节才返回
   options.c_cc[VTIME] = 10;  // 超时时间1秒(单位:0.1秒)

   tcsetattr(fd, TCSANOW, &options); // 立即应用配置
}
  • VMIN > 0时:VTIME是等待第一个字节的超时时间,超时后即使没到VMIN字节数也返回
  • VMIN = 0时:VTIME是每次读取的超时时间,超时后立即返回

关于停止服务的说明

你遇到的问题不需要停止额外服务。若怀疑串口被其他进程占用,可通过以下命令排查:

lsof /dev/ttyS0

若输出结果中有其他进程,可使用kill <PID>终止,但你的情况大概率是非阻塞模式导致的EAGAIN,无需此操作。

原始代码

#include <iostream>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <cstring>

void configurePort(int fd) 
{
   struct termios options;

   // Get current port parameters
   tcgetattr(fd, &options);

   // Set data rate
   cfsetispeed(&options, B115200);
   cfsetospeed(&options, B115200);

   // Set 8 data bits, no parity, 1 stop bit
   options.c_cflag &= ~PARENB; // No parity
   options.c_cflag &= ~CSTOPB; // 1 stop bit
   options.c_cflag &= ~CSIZE; // Reset data size
   options.c_cflag |= CS8; // 8 bits of data

   // Set non-canonical input mode and disable flow control
   options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
   options.c_iflag &= ~(IXON | IXOFF | IXANY);

   // Apply settings
   tcsetattr(fd, TCSANOW, &options);
}

void sendData(int fd, const char* message) 
{
   ssize_t bytesWritten = write(fd, message, strlen(message));

   if (bytesWritten < 0) 
   {
      std::cerr << "Error sending data" << std::endl;
      return;
   }

   std::cout << "Bytes sent: " << bytesWritten << std::endl;
}

void readData(int fd) 
{
   char buffer[256];

   // Read data from the port
   ssize_t bytesRead = read(fd, buffer, sizeof(buffer) - 1);

   if (bytesRead < 0) 
   {
      printf("Error %i reading from port: %s\n", errno, strerror(errno));
      std::cerr << "Error reading data" << std::endl;
      return;
   }

   buffer[bytesRead] = '\0'; // Terminate the string with a null character
   std::cout << "Bytes read: " << bytesRead << ", data: " << buffer << std::endl;
}

int main() 
{
   const char* portName = "/dev/ttyS0"; // Port name (can be changed to /dev/ttyS1)

   //Open the port in non-blocking mode
   int fd = open(portName, O_RDWR | O_NOCTTY | O_NDELAY);

   if (fd == -1) 
   {
      std::cerr << "Failed to open port " << portName << std::endl;
      return 1;
   }

   // Configure the port
   configurePort(fd);

   const char* message = "123456789!sdas!!\n";

   // Send data
   sendData(fd, message);

   // Read data
   sleep(1); // Delay to wait for a response 

   readData(fd);

   // Close the port
   close(fd);

   return 0;
}

内容的提问来源于stack exchange,提问作者Cmrd_Kirdyk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 15:15:12