我正在为 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)
然而,这似乎是潜在的代码味道。
另外,如果我想将此按钮结构存储在另一个结构中,则此父结构中的泛型数量很可能会非常大,除非我明确指定(因此写入两次)引脚类型。
有没有更好、更高效的方法?
给定一些全部实现的结构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。它甚至声称比手写代码有更好的性能。