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

Linux环境C语言读取Duet2开发板串口出现目标数据丢失问题

C语言读取Duet2开发板串口数据丢失问题分析

问题描述

尝试使用C语言编写程序读取Duet2开发板的串口数据,预期输出为两类内容:

  • 以N开头、后跟若干数值的目标数据行
  • 偶发的加热器相关警告信息
    实际运行C代码时仅能输出加热器警告内容,N开头的目标数据行完全丢失。已知Duet2开发板串口输出正常,使用Python代码可完整读取所有串口数据。

相关代码

存在问题的C代码

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

int main(int argc, char ** argv) 
{
  int fd;
  struct termios SerialPortSettings;

  // Open the Port. We want read/write, no "controlling tty" status, and open it no matter what state DCD is in
  fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY | O_NDELAY);
  
  // setting baud rates 

  cfsetispeed(&SerialPortSettings,B115200); 
  cfsetospeed(&SerialPortSettings,B115200);
        
  if (fd == -1) 
  {
    perror("open_port: Unable to open /dev/ttyACM0 - ");
    return(-1);
  }

  fcntl(fd, F_SETFL, 0);

 
  // Read up to 255 characters from the port if they are there

  char buf[256];
  
  while (1)
  {
    int k = read(fd, (void*)buf, 255);
    if (k < 0) 
    {
      perror("Read failed - ");
      return -1;
    } 
    else if (k == 0) 
    {
      printf("No data on port\n");
    }
    else 
    {
      printf("Read line is : %s \n",buf);
      
    }
  }
  
  close(fd);
  return 0;
}

可正常运行的Python代码

import serial
import time
import subprocess

LINUX = 1

output = subprocess.check_output("python -m serial.tools.list_ports", shell=True) # sending command to terminal 
output = output.decode('utf-8') # the output is of type b'somestring' This removes that
output = output.splitlines() # so we can access the COM part

if LINUX:
    temp = output[0].split()
    port = temp[0]
else:
    port =  output[0]
    
data = open("Input.txt", "w")
ser = serial.Serial(port, 115200, timeout=30)
print("Serial Port opened on : " + ser.name)

counter = 0
while (1):
    response = ser.readline().decode('utf-8')
    print(response)
    data.write(response)
    if response == "":
        break

time.sleep(1)
data.close()

问题原因

你的C代码存在3个核心错误,共同导致了目标数据丢失:

  • 串口配置完全未生效,参数错误:你定义的SerialPortSettings是未初始化的局部变量,内部全是垃圾值,仅修改了波特率参数,既没有读取当前串口的默认配置,也没有调用tcsetattr将配置写入串口设备。Python的serial库默认配置为8N1(8数据位、1停止位、无奇偶校验)、无流控,C代码未做对应配置的情况下,短的警告行可能凑巧被识别,长的N开头数据行直接因为校验/帧错误被内核丢弃。
  • 未给读取到的字节添加字符串结束符:read函数仅返回读取到的字节数,不会自动在缓冲区末尾添加\0,你直接用printf("%s")打印会导致越界读取栈上的脏数据,长行内容大概率会被破坏。
  • 未实现按行读取逻辑:串口是字节流,单次read调用可能只返回半行数据,你的代码没有缓存拆分的行片段,直接输出会导致长的N行被拆分、内容混乱,无法被识别。

修复建议

  1. 串口打开成功后,先调用tcgetattr(fd, &SerialPortSettings)读取当前默认配置,再修改波特率、配置8N1模式、关闭流控、开启原始模式,最后调用tcsetattr(fd, TCSANOW, &SerialPortSettings)让配置生效。
  2. 每次read返回后,在buf[k]位置写入\0,保证缓冲区是合法的C字符串。
  3. 自行实现行缓存逻辑,将每次读取到的字节存入全局缓存,检测到换行符再整行输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 03:15:07