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

直接写入/dev/ttyUSB0无响应,socat透传正常的串口通信问题

问题:直接写入/dev/ttyUSB0无法让Arduino接收数据,仅在socat/tail监听后生效

问题场景

  • 编写Rust程序通过USB串口向连接在/dev/ttyUSB0的Arduino发送数据
  • 使用命令socat -x -v /dev/ttyUSB0,rawer,b115200,crnl PTY,link=/tmp/ttyV1,rawer,crnl嗅探时,Rust写入/tmp/ttyV1能让Arduino正常接收数据并工作
  • 直接让Rust写入/dev/ttyUSB0时,Arduino无响应;甚至执行cat src/greenwall.json > /dev/ttyUSB0也仅在提前运行tail -f /dev/ttyUSB0后才生效

Rust代码示例

use std::io::{self, Write};
use std::fs::read_to_string;

fn write_to_serial(jsondata: &[u8], port: &mut serialport::TTYPort) {
    match port.write(jsondata) {
        Ok(_) => {
            std::io::stdout().flush().unwrap();
        }
        Err(ref e) if e.kind() == io::ErrorKind::TimedOut => (),
        Err(e) => eprintln!("{:?}", e),
    }
}

fn main() {
    //let serial_port = "/dev/ttyUSB0";
    let serial_port = "/tmp/ttyV1";
    let baud_rate = 115_200;

    let mut port = serialport::new(serial_port, baud_rate)
        .open_native()
        .expect("Failed to open port");

    let jsondata = read_to_string("src/greenwall.json").unwrap();
    write_to_serial(jsondata.as_bytes(), &mut port);
}

注:使用socat时注释第18行,直接写入/dev/ttyUSB0则注释第19行并取消第18行注释

问题原因

核心问题出在串口DTR/RTS流控引脚的状态:

  • 当socat或tail -f打开串口时,会自动拉低DTR引脚,触发Arduino重启并进入接收就绪状态
  • 直接写入串口时,默认未配置DTR引脚状态,Arduino未被正确触发,处于无法接收数据的状态

解决方案

在Rust代码中打开串口后,手动配置DTR引脚状态,并确保数据完全刷出缓冲区:

修改后的Rust代码

use std::io::{self, Write};
use std::fs::read_to_string;
use std::thread;
use std::time::Duration;
use serialport::SerialPort;

fn write_to_serial(jsondata: &[u8], port: &mut serialport::TTYPort) {
    match port.write(jsondata) {
        Ok(_) => {
            std::io::stdout().flush().unwrap();
            port.flush().unwrap(); // 确保数据完全写入串口硬件缓冲区
        }
        Err(ref e) if e.kind() == io::ErrorKind::TimedOut => (),
        Err(e) => eprintln!("{:?}", e),
    }
}

fn main() {
    let serial_port = "/dev/ttyUSB0";
    let baud_rate = 115_200;

    let mut port = serialport::new(serial_port, baud_rate)
        .open_native()
        .expect("Failed to open port");

    // 触发Arduino复位:先拉高DTR再拉低,模拟串口工具的复位流程
    port.set_dtr(true).expect("Failed to set DTR high");
    thread::sleep(Duration::from_millis(100));
    port.set_dtr(false).expect("Failed to set DTR low");
    // 等待Arduino重启完成
    thread::sleep(Duration::from_millis(1000));

    let jsondata = read_to_string("src/greenwall.json").unwrap();
    write_to_serial(jsondata.as_bytes(), &mut port);
}

额外说明

  • 部分Arduino型号可能需要调整重启延迟时间,确保设备完全就绪后再发送数据
  • 若单次拉低DTR无效,可尝试先拉高再拉低的操作,模拟串口工具的标准复位流程
  • 必须调用port.flush(),避免数据滞留在软件缓冲区无法发送到硬件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 17:05:28