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

如何让RP2040的DynPin适配OneShot模式的ADC读取

解决RP2040中DynPin转ADC引脚的Channel约束问题

核心结论

你可以使用GPIO26-29中的任意引脚,不需要局限于Gpio26,但不能直接通过DynPin类型擦除后的对象满足Channel<Adc>约束,需要换用保留具体引脚类型信息的存储方式。

问题根源

DynPin是类型擦除后的通用GPIO类型,编译时丢失了具体引脚(比如Gpio26<FloatingInput>)的类型信息。而Channel<Adc> trait是通过宏针对具体的GPIO引脚类型(仅GPIO26-29)实现的,DynPin或其转换后的FloatingInput类型本身并没有实现这个trait,因此直接转换后无法调用adc.read()。

解决方案:用枚举存储具体ADC引脚

因为支持ADC的引脚只有固定的4个(GPIO26-29),可以定义一个枚举来封装这些引脚的具体类型,从而保留编译期类型信息,满足Channel<Adc>约束:

代码实现

use rp_pico::hal::{
    adc::{Adc, OneShot},
    gpio::FloatingInput,
    pins::{Gpio26, Gpio27, Gpio28, Gpio29},
};

// 枚举封装所有支持ADC的引脚类型
pub enum AdcPin {
    Gpio26(Gpio26<FloatingInput>),
    Gpio27(Gpio27<FloatingInput>),
    Gpio28(Gpio28<FloatingInput>),
    Gpio29(Gpio29<FloatingInput>),
}

pub struct PhProbe {
    analog_read_pin: AdcPin,
}

impl PhProbe {
    // 支持传入任意ADC引脚
    pub fn new(pin: impl Into<AdcPin>) -> Self {
        Self { analog_read_pin: pin.into() }
    }

    pub fn read(&mut self, adc: &mut Adc) -> u16 {
        match &mut self.analog_read_pin {
            AdcPin::Gpio26(pin) => adc.read(pin).unwrap(),
            AdcPin::Gpio27(pin) => adc.read(pin).unwrap(),
            AdcPin::Gpio28(pin) => adc.read(pin).unwrap(),
            AdcPin::Gpio29(pin) => adc.read(pin).unwrap(),
        }
    }
}

// 为每个ADC引脚实现Into<AdcPin>
impl From<Gpio26<FloatingInput>> for AdcPin {
    fn from(pin: Gpio26<FloatingInput>) -> Self {
        AdcPin::Gpio26(pin)
    }
}

impl From<Gpio27<FloatingInput>> for AdcPin {
    fn from(pin: Gpio27<FloatingInput>) -> Self {
        AdcPin::Gpio27(pin)
    }
}

impl From<Gpio28<FloatingInput>> for AdcPin {
    fn from(pin: Gpio28<FloatingInput>) -> Self {
        AdcPin::Gpio28(pin)
    }
}

impl From<Gpio29<FloatingInput>> for AdcPin {
    fn from(pin: Gpio29<FloatingInput>) -> Self {
        AdcPin::Gpio29(pin)
    }
}

使用示例

// 可以用GPIO26-29中任意一个引脚
let ph_pin = pins.gpio27.into_floating_input();
let mut ph_meter = PhProbe::new(ph_pin);

// 初始化ADC
let mut adc = Adc::new(peripherals.ADC, &mut peripherals.RESETS);
let reading = ph_meter.read(&mut adc);

为什么不推荐用DynPin?

DynPin的设计目标是通用GPIO操作(如电平读写、模式切换),它牺牲了具体类型信息来换取通用性。但ADC的Channel trait依赖具体引脚类型的编译期检查,类型擦除后无法满足这一约束,因此不适合用于ADC场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 04:15:27