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

为何使用rppal的Uart读取树莓派软件串口时缓冲区无变化

问题原因分析

  1. 普通用户运行时write返回0是权限问题:/dev/ttySOFT0设备默认仅root用户和dialout用户组有读写权限,普通用户无权限写入时就会出现返回0的情况。
  2. sudo运行后读缓冲区全为0的核心原因是Rust串口库的默认行为和Python pyserial 存在差异:
    • Python的pyserial默认启用阻塞模式,write会等待所有数据写完再返回,read(9)会阻塞等待直到读满9字节数据才返回;
    • 你使用的rppal、serial等Rust串口库默认可能为非阻塞模式,write可能出现部分写入(你当前虽然观察到返回9,但没有做兜底校验),read如果在传感器返回数据前调用,会直接返回0字节,缓冲区保持初始的全0状态,不会抛出错误。
    • 你没有在写入命令后预留传感器响应时间,也没有校验读写的完整度。

解决步骤

  1. 解决权限问题(可选,避免每次sudo运行):
    执行以下命令将当前用户加入dialout用户组,注销重登录后生效:
sudo usermod -aG dialout $USER
  1. 修正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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 05:36:04