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

Linux嵌入式UART可发送无法接收、select返回0问题求助

select返回0不代表串口繁忙,仅表示在你设定的5秒超时窗口内,串口没有产生可读事件,不是硬件被占用的问题。你遇到的接收失败是代码实现存在多个错误导致的,具体问题如下:

1. 流控配置逻辑完全写反

你实现的buildFlowControl函数三个分支的配置全部匹配错误:

  • 无流控(NO_FLOW_CTRL)场景下你反而开启了硬件流控CRTSCTS,如果你的RS232接线没有接RTS/CTS引脚,串口内核驱动会一直等待硬件流控信号就绪,直接导致无法接收数据
  • FC_RTSCTS(硬件流控)场景你反而关了CRTSCTS开了软件流控,FC_XONXOFF(软件流控)场景你反而关了软件流控,逻辑完全颠倒

修正后的流控配置参考:

static int buildFlowControl(Enum_FlowCtrl fc, struct termios* term)
{
    if (NO_FLOW_CTRL == fc)
    {
        term->c_cflag &= ~CRTSCTS; // 无流控关闭硬件流控
        term->c_iflag &= ~(IXON | IXOFF | IXANY); // 关闭软件流控
    }
    else if (FC_RTSCTS == fc)
    {
        term->c_cflag |= CRTSCTS; // 硬件流控开启CRTSCTS
        term->c_iflag &= ~(IXON | IXOFF | IXANY);
    }
    else if (FC_XONXOFF == fc)
    {
        term->c_cflag &= ~CRTSCTS;
        term->c_iflag |= (IXON | IXOFF | IXANY); // 软件流控开启相关标志位
    }else{
        return -1;
    }
    return 0;
}

2. 串口配置顺序错误,前面的配置全部被覆盖

你在UART_Open里先初始化了term结构体、调用cfmakeraw、设置CREAD之后才调用tcgetattr读当前串口配置,这会导致你前面所有对term的修改全部被tcgetattr读出的默认值覆盖,完全不生效。

修正后的配置顺序参考:

fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY); // 建议加O_NOCTTY防止串口控制进程,O_NDELAY设置非阻塞
if (fd < 0) { 
    // 必须补充open失败的错误处理
}
tcgetattr(fd, &term); // 先读取现有配置,再基于该配置修改参数
cfmakeraw(&term);
term->c_cflag |= CREAD | CLOCAL; // 建议加CLOCAL忽略调制解调器状态线,避免被外部信号影响
// 后续再调用各个buildxxx函数修改参数

3. select的fd_set未在每次循环前重新初始化

select调用结束后会修改传入的fd_set,仅保留有事件触发的文件描述符。你当前只在循环外初始化了一次fd_set,第一次超时后fd_set里的串口描述符就被清空了,后续所有循环调用select的时候传入的都是空的fd_set,必然永远返回0超时。

修正方式是把FD_ZERO和FD_SET操作放到while循环内部,每次调用select前重新设置fd_set:

while(true)
{
    FD_ZERO(&fdset); 
    FD_SET(socketFileDescriptor, &fdset); 
    ret = select(socketFileDescriptor + 1, &fdset, NULL, NULL, &timeout);
    timeout.tv_sec = 5;
    // 后续逻辑不变
}

4. 接收逻辑存在死循环缺陷

你在可读事件触发后进入了do{}while(true)的死循环,第一次读到数据后就永远卡在这个循环里,而且完全没有判断read的返回值,即使读失败也不会退出,同时加了sleep(3)会导致大量数据丢包。建议去掉该死循环,单次read后回到外层select循环等待下一次事件,同时处理read的返回值:

if (FD_ISSET(socketFileDescriptor, &fdset)) 
{
    memset(buffer, 0x0, sizeof(buffer));
    ret = read(socketFileDescriptor, buffer, 100);
    if (ret > 0) {
        // 处理收到的ret个字节
    } else if (ret == 0) {
        // 串口断开相关处理
    } else {
        // 读错误处理
    }
}

补充验证建议

你可以先不用自己的程序,直接在设备侧执行cat /dev/ttyHSL0命令,然后在minicom侧发送数据,看能不能收到数据:如果能收到就确认是代码问题,否则检查硬件接线、串口驱动权限和设备树配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 22:42:03