Linux UART多次十六进制写后如何按帧顺序读取数据 C语言问题
UART串口命令收发与帧拆分问题修复
原有代码故障原因
- 循环起始逻辑错误:变量i从0开始遍历,i=0时无任何串口写操作,配置的
VMIN=1会让read函数永久阻塞等待数据,导致没有任何输出 - 字符串操作逻辑错误:
sprintf(data3,"\n")直接覆盖了之前拼接的所有十六进制内容,就算读到数据也无法正常显示 - 无帧拆分逻辑:单次读操作会取出串口缓冲区中所有累计数据,没有按照返回帧的固定特征(帧头
0xA5、固定长度13字节)做拆分,导致多帧数据粘连 - 缓冲区操作错误:未判断实际读取字节数就遍历整个40字节缓冲区,会打印大量无效的0值,且未初始化的
data数组直接复制到data3会引入垃圾值 - 内存泄漏:每次循环
malloc申请的data3没有释放,长时间运行会占用过多内存
修正后的可运行代码
#include <termios.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> int main(void) { int fd; fd = open("/dev/ttyHSL6", O_RDWR|O_NOCTTY); struct termios newtio; unsigned char buffer[13] = {0}; int bytes_read = 0; char data[4] = {0}; char *data3; int i = 0; if (fd == -1) { printf("Error! in opening port\n"); exit(-100); } memset(&newtio, 0, sizeof(struct termios)); newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; newtio.c_lflag = 0; // 配置读规则:最少读13字节(刚好一帧),超时时间1秒(单位100ms) newtio.c_cc[VTIME] = 10; newtio.c_cc[VMIN] = 13; tcflush(fd, TCIFLUSH); tcsetattr(fd, TCSANOW, &newtio); // 统一管理待发送命令列表 unsigned char cmd_list[3][13] = { {0xA5,0x80,0x95,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC2}, {0xA5,0x80,0x90,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xBD}, {0xA5,0x80,0x91,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xBE} }; while(1){ for(i=0; i<3; i++){ // 单次仅发送一条命令 write(fd, cmd_list[i], 13); tcdrain(fd); // 等待发送完成 usleep(50000); // 等待设备返回,可根据实际响应速度调整 // 读取对应返回帧 memset(buffer, 0, sizeof(buffer)); bytes_read = read(fd, buffer, sizeof(buffer)); if (bytes_read == 13 && buffer[0] == 0xA5) { // 校验帧头和长度保证帧对齐 data3 = malloc(100); memset(data3, 0, 100); for (int j=0; j<bytes_read; j++) { sprintf(data, "%02x ", buffer[j]); // 每个字节后加空格分隔 strcat(data3, data); } printf("%s\n\n", data3); // 输出单帧,加空行分隔 free(data3); // 释放内存避免泄漏 } else { tcflush(fd, TCIFLUSH); // 校验不通过清空缓冲区,重新对齐 } } // 循环间隔可根据实际需求调整 sleep(1); } close(fd); return 0; }
关键修改说明
- 调整串口读取配置,固定每次最少读13字节(刚好对应单帧返回长度),增加1秒超时避免永久阻塞
- 优化发送逻辑,一次只发一条命令,发送完成等待返回后再处理下一条,从根源避免多帧数据累积粘连
- 增加帧头和长度校验,校验不通过就清空接收缓冲区重新对齐,避免错位输出
- 修正字符串拼接逻辑,每个十六进制字节后增加空格分隔,输出格式符合预期
- 修复内存泄漏与缓冲区垃圾值问题,申请内存后初始化,使用完成后即时释放
内容的提问来源于stack exchange,提问作者blackcatTan
相关产品推荐
相关产品推荐

