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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 10:09:03