嵌入式开发中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
相关产品推荐
相关产品推荐

