嵌入式 HAL 结构泛型的使用

use*_*862 7 embedded hal rust

我正在为 STM32 微控制器编写嵌入式程序。我希望能够将代表按钮的 GPIO 引脚存储在一个漂亮的、统一的结构中。

由于embedded-hal使用泛型对“Pin”结构的状态进行编码,因此每个GPIO都有不同的Rust类型,但是对于我的情况(按钮),它们都实现了embedded_hal::digital::v2::InputPin特征。

我可以明确指定每个成员的类型,但是在进行配置时我还必须为每个按钮编写引脚和端口,即:

    let mut middle = gpioa
        .pa6
        .into_pull_up_input(&mut gpioa.moder, &mut gpioa.pupdr);
Run Code Online (Sandbox Code Playgroud)

这意味着在结构中指定类型会导致冗余,如果我需要更改硬件中的引脚,我将需要在代码中的多个位置更改它。

存储这些引脚的规范方法是什么?当然,我不能使用特征对象,因为它位于嵌入式上下文中。

目前我有以下内容:

use embedded_hal::digital::v2::InputPin;

struct Buttons<M, R, L, U, D>
where
    M: InputPin,
    R: InputPin,
    L: InputPin,
    U: InputPin,
    D: InputPin,
{
    middle: M,
    right: R,
    left: L,
    up: U,
    down: D
}
Run Code Online (Sandbox Code Playgroud)

然而,这似乎是潜在的代码味道。

另外,如果我想将此按钮结构存储在另一个结构中,则此父结构中的泛型数量很可能会非常大,除非我明确指定(因此写入两次)引脚类型。

有没有更好、更高效的方法?

pah*_*olg 1

给定一些全部实现的结构InputPin

struct M;
struct R;
struct L;
struct U;
struct D;
Run Code Online (Sandbox Code Playgroud)

您可以构造一个还实现以下功能的枚举InputPin

enum Pin {
    M(M),
    R(R),
    L(L),
    U(U),
    D(D),
}

impl InputPin for Pin {
    type Error = ...;

    fn is_high(&self) -> Result<bool, Self::Error> {
        match self {
            Pin::M(pin) => pin.is_high(),
            Pin::R(pin) => pin.is_high(),
            Pin::L(pin) => pin.is_high(),
            Pin::U(pin) => pin.is_high(),
            Pin::D(pin) => pin.is_high(),
        }
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        match self {
            Pin::M(pin) => pin.is_low(),
            Pin::R(pin) => pin.is_low(),
            Pin::L(pin) => pin.is_low(),
            Pin::U(pin) => pin.is_low(),
            Pin::D(pin) => pin.is_low(),
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以Pin在任何地方使用枚举而无需泛型。

由于这可能会变得麻烦且重复,因此有一个方便的箱子可以为您完成此操作:enum_dispatch。它甚至声称比手写代码有更好的性能。