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

嵌入式开发中C语言串口读取如何无需等待换行符(0x0a)?

解决C语言串口固定字节读取不等待换行的问题

你的问题本质是串口被配置成了规范模式(Canonical Mode),这种模式下read()会一直等待换行符(\n/0x0A)或回车符才返回数据。要实现不依赖换行符的固定字节读取,必须切换到非规范模式(Non-Canonical Mode),同时调整串口参数配置。

一、修正termios串口配置

打开串口后,修改termios结构体的关键参数(替换你现有配置中的对应部分):

struct termios tty;
tcgetattr(port, &tty);

// 1. 禁用规范模式,关闭换行触发的读取逻辑
tty.c_lflag &= ~ICANON;
// 2. 禁用回显、信号等无关功能(推荐)
tty.c_lflag &= ~ECHO;
tty.c_lflag &= ~ECHOE;
tty.c_lflag &= ~ISIG;
// 3. 禁用CR转NL转换,避免0x0D被自动转成0x0A
tty.c_iflag &= ~ICRNL;
// 4. 设置读取规则:
//    - VMIN=0:不强制等待固定字节
//    - VTIME=10:超时时间1秒(单位0.1秒)
//    若要阻塞到凑够N字节,可设VMIN=N、VTIME=0
tty.c_cc[VMIN] = 0;
tty.c_cc[VTIME] = 10;

// 立即应用配置
tcsetattr(port, TCSANOW, &tty);

二、改进读取逻辑

原来用ioctl(FIONREAD)的方式不可靠——串口是流式传输,FIONREAD只能获取当前已到达缓冲区的字节数,后续数据可能还在传输中。结合你能从第一个字节获取预期长度的需求,推荐以下读取流程:

void recv(int port){
    printf("Opened connection on port:%d \n",port);
    while(1){
        if(stop){
            break;
        }

        // 先读取第一个字节,解析预期总长度
        uint8_t first_byte;
        int n = read(port, &first_byte, 1);
        if(n <= 0){
            continue; // 读取失败或超时,跳过
        }

        // 从第一个字节解析预期接收的总字节数(根据你的协议调整)
        int expected_len = /* 你的解析逻辑,比如取first_byte低6位 */;
        if(expected_len > BUF_LEN || expected_len <= 0){
            printf("Invalid length: %d\n", expected_len);
            continue;
        }

        // 初始化缓冲区,存入第一个字节
        uint8_t buf[BUF_LEN] = {0};
        buf[0] = first_byte;
        int received = 1;

        // 循环读取剩余字节,直到凑够预期长度
        while(received < expected_len){
            n = read(port, buf + received, expected_len - received);
            if(n > 0){
                received += n;
            } else if(n == -1){
                perror("Read error");
                received = 0;
                break;
            }
            // n=0表示超时,可按需决定是否继续等待
        }

        if(received == expected_len){
            // 处理完整数据包
            req = buf[0];
            printf("Bytes received: %d, req= 0x%x\n", received, req);
            switch (((req&0b11000000)>>6)){
                // 你的命令处理逻辑
            }
        }
    }
}

关键说明

  • 规范模式是终端设备默认模式,专为交互式输入设计,串口通信必须关闭它。
  • VMIN和VTIME的组合决定read()行为:
    • VMIN=N, VTIME=0:阻塞直到读取N字节才返回
    • VMIN=0, VTIME=T:最多等待T*0.1秒,有多少字节返回多少
    • VMIN=N, VTIME=T:先等N字节,超时未凑够则返回已收字节
  • 不要依赖FIONREAD决定读取长度,需根据协议定义的长度循环读取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 23:24:46