直接写入/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
相关产品推荐
相关产品推荐

