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

Arduino发送二进制串口数据,C语言读取时丢失字节的问题

问题分析与解决方案

兄弟,你这问题一眼就能看出是串口数据里的0x04字节被C语言代码“吃掉”了——从你给出的输出看,原本每个帧里的04都消失了,剩下的24 85 ab 47 43循环,核心原因是0x04被当成特殊字符处理了。

为什么会出现这种情况?

0x04对应ASCII里的EOT(传输结束)字符,如果你用C语言的文本模式打开串口(比如fopen用"r"而不是"rb"),标准库会把这个字符识别为“文件结束”信号,要么直接终止读取,要么跳过这个字节,导致你看不到它。

另外,如果你用了fgetc、fscanf这类文本处理函数,它们也会对控制字符做特殊处理,进一步加剧这个问题。

解决步骤

1. 强制用二进制模式打开串口

不管是Windows还是Linux,打开串口时都要指定二进制模式:

  • Linux下:虽然系统本身不区分文本/二进制,但加上O_BINARY标志(或者fopen用"rb")更稳妥;
  • Windows下:必须用"rb"(fopen)或者O_BINARY(open),否则控制字符会被篡改。

2. 使用原始字节读取函数

别用fgetc、fgets这类文本函数,改用read()(系统调用)或者fread()(标准库)直接读取原始字节,这样就能完整获取所有二进制数据。

示例代码(Linux平台)

#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>

int main() {
    // 打开串口,指定二进制模式
    int serial_fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY | O_BINARY);
    if (serial_fd == -1) {
        perror("Failed to open serial port");
        return 1;
    }

    // 配置串口参数(必须和Arduino的设置一致,比如波特率9600、8N1)
    struct termios serial_opts;
    tcgetattr(serial_fd, &serial_opts);
    
    // 设置波特率
    cfsetispeed(&serial_opts, B9600);
    cfsetospeed(&serial_opts, B9600);
    
    // 配置数据位、停止位、奇偶校验:8位数据,无校验,1位停止位
    serial_opts.c_cflag |= (CLOCAL | CREAD);
    serial_opts.c_cflag &= ~PARENB;
    serial_opts.c_cflag &= ~CSTOPB;
    serial_opts.c_cflag &= ~CSIZE;
    serial_opts.c_cflag |= CS8;
    
    // 应用配置
    tcsetattr(serial_fd, TCSANOW, &serial_opts);

    unsigned char buffer[128];
    ssize_t bytes_read;
    
    // 循环读取串口数据
    while ((bytes_read = read(serial_fd, buffer, sizeof(buffer))) > 0) {
        // 以十六进制打印所有读取到的字节
        for (ssize_t i = 0; i < bytes_read; i++) {
            printf("%02X ", buffer[i]);
        }
        fflush(stdout); // 强制刷新输出缓冲区
    }

    close(serial_fd);
    return 0;
}

如果你习惯用标准库的fopen

也可以这样写,核心是用"rb"模式:

#include <stdio.h>

int main() {
    FILE *serial_fp = fopen("/dev/ttyUSB0", "rb");
    if (!serial_fp) {
        perror("Failed to open serial port");
        return 1;
    }

    unsigned char buffer[128];
    size_t bytes_read;
    while ((bytes_read = fread(buffer, 1, sizeof(buffer), serial_fp)) > 0) {
        for (size_t i = 0; i < bytes_read; i++) {
            printf("%02X ", buffer[i]);
        }
        fflush(stdout);
    }

    fclose(serial_fp);
    return 0;
}

额外提醒

一定要确保C语言代码里的串口参数(波特率、数据位、停止位、奇偶校验)和Arduino完全一致,参数不匹配也可能导致数据乱码或者丢失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:54:41