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

Rust结构体中分离线程循环的GPIO计数实现问题

Rust树莓派GPIO引脚检测与并发计数实现

核心方案

用Arc<Mutex<u32>>实现跨线程安全的计数共享,GPIO输入引脚由检测线程独占持有(InputPin不支持跨线程共享),主线程通过互斥锁安全读取计数。

完整代码示例

首先在Cargo.toml中添加依赖:

[dependencies]
rppal = "0.14.0"

src/main.rs代码:

use rppal::gpio::{Gpio, InputPin, PullUpDown};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

// 封装GPIO计数逻辑的结构体
struct GpioEdgeCounter {
    count: Arc<Mutex<u32>>,
    _worker_thread: thread::JoinHandle<()>,
}

impl GpioEdgeCounter {
    // 构造函数:传入引脚编号,初始化计数器并启动检测线程
    fn new(pin_number: u8) -> Result<Self, Box<dyn std::error::Error>> {
        // 初始化GPIO控制器,获取指定引脚并设置为输入模式
        let gpio = Gpio::new()?;
        let mut pin = gpio.get(pin_number)?.into_input();
        // 根据硬件连接设置上拉/下拉,这里设置为下拉(引脚默认低电平)
        pin.set_pull_up_down(PullUpDown::PullDown);

        // 创建线程安全的共享计数变量
        let count = Arc::new(Mutex::new(0u32));
        let count_clone = Arc::clone(&count);

        // 启动检测线程,转移引脚所有权到线程内部
        let worker_thread = thread::spawn(move || {
            loop {
                // 等待引脚上升沿(低→高电平),超时1秒后继续循环
                match pin.wait_for_rising_edge(Duration::from_secs(1)) {
                    Ok(true) => {
                        // 成功检测到上升沿,加锁并递增计数
                        let mut counter = count_clone.lock().unwrap();
                        *counter += 1;
                        println!("检测到上升沿,当前计数:{}", *counter);
                    }
                    Ok(false) => continue, // 超时,继续等待
                    Err(e) => {
                        eprintln!("引脚检测失败:{}", e);
                        break;
                    }
                }
            }
        });

        Ok(Self {
            count,
            _worker_thread: worker_thread,
        })
    }

    // 安全获取当前计数的方法
    fn current_count(&self) -> u32 {
        *self.count.lock().unwrap()
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 初始化计数器,使用引脚17(根据实际硬件修改)
    let counter = GpioEdgeCounter::new(17)?;

    // 主线程循环读取计数
    loop {
        println!("主线程读取计数:{}", counter.current_count());
        thread::sleep(Duration::from_secs(2));
    }
}

变量声明与循环逻辑说明

  • 引脚变量pin:在构造函数中初始化后,通过move关键字转移给检测线程,让线程独占引脚所有权——因为InputPin不实现Sync trait,无法跨线程共享,必须由单个线程持有。
  • 计数变量count:用Arc<Mutex<u32>>包裹,Arc允许线程间共享所有权,Mutex保证同一时刻只有一个线程能访问计数,彻底避免数据竞争。构造函数中克隆一份Arc给检测线程,实现双线程对计数的安全访问。
  • 检测循环:使用wait_for_rising_edge阻塞等待引脚上升沿,比主动轮询更高效;检测到上升沿时,先获取Mutex锁,再递增计数,确保操作原子性。
  • 主线程读取:通过current_count方法获取锁并读取计数,保证读取到的是最新的有效值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 02:45:17