为何使用rppal的Uart读取树莓派软件串口时缓冲区无变化
问题原因分析
- 普通用户运行时
write返回0是权限问题:/dev/ttySOFT0设备默认仅root用户和dialout用户组有读写权限,普通用户无权限写入时就会出现返回0的情况。 - sudo运行后读缓冲区全为0的核心原因是Rust串口库的默认行为和Python
pyserial存在差异:- Python的
pyserial默认启用阻塞模式,write会等待所有数据写完再返回,read(9)会阻塞等待直到读满9字节数据才返回; - 你使用的
rppal、serial等Rust串口库默认可能为非阻塞模式,write可能出现部分写入(你当前虽然观察到返回9,但没有做兜底校验),read如果在传感器返回数据前调用,会直接返回0字节,缓冲区保持初始的全0状态,不会抛出错误。 - 你没有在写入命令后预留传感器响应时间,也没有校验读写的完整度。
- Python的
解决步骤
- 解决权限问题(可选,避免每次sudo运行):
执行以下命令将当前用户加入dialout用户组,注销重登录后生效:
sudo usermod -aG dialout $USER
- 修正Rust串口操作逻辑:
- 初始化串口时显式配置超时时间、禁用硬件流控;
- 写入数据使用
write_all替代write,确保所有命令字节都写入串口; - 写入完成后添加短延迟,或配置串口为阻塞读模式,使用
read_exact读满9字节再处理。
修正后的代码示例(基于rppal)
use rppal::uart::{Uart, Parity}; use std::time::Duration; use std::thread; fn main() { let mut port = Uart::with_path("/dev/ttySOFT0", 9_600, Parity::None, 8, 1).unwrap(); // 禁用硬件流控 port.set_hardware_flow_control(false).unwrap(); // 设置读超时为1秒,写超时为1秒 port.set_read_timeout(Some(Duration::from_secs(1))).unwrap(); port.set_write_timeout(Some(Duration::from_secs(1))).unwrap(); let mut buffer = [0u8; 9]; let command = [0xFFu8, 0x01u8, 0x86u8, 0, 0, 0, 0, 0, 0x79u8]; // 使用write_all确保所有数据写入 port.write_all(&command) .expect("Could not write to the serial port"); // 可选:添加100ms延迟等待传感器响应,阻塞模式下可省略 thread::sleep(Duration::from_millis(100)); // 使用read_exact确保读满9字节 port.read_exact(&mut buffer) .expect("Could not read enough bytes from the serial port"); let mhz19_high = buffer[2] as u32; let mhz19_low = buffer[3] as u32; let reading = mhz19_high * 256u32 + mhz19_low; println!("CO2浓度: {} ppm", reading); println!("原始缓冲区: {:?}", buffer); }
内容的提问来源于stack exchange,提问作者Marvin
相关产品推荐
相关产品推荐

