gpt4 book ai didi

rust 嵌入式将 GPIO 引脚从输出更改为输入

转载 作者:行者123 更新时间:2023-12-03 11:33:39 25 4
gpt4 key购买 nike

访问 GPIO 的 Rust STM32xxx_hal 代码片段

let gpioa = dp.GPIOA.split(&mut rcc);

let mut p12 = gpioa.pa12;

loop {
p12.into_push_pull_output().set_low().unwrap();
//after some processing, time to switch p12 to input
p12.into_floating_input();

}

编译器提示 into_push_pull_output() 之后p12 已“移动”。
目标是能够动态地将一个 GPIO 引脚从输出切换到输入。
如何在 Rust 中实现这一点?
[编辑]
在遵循 Mark(见下文)的回答后,这里是 Charlieplexing 6 个 LED 的 STM32G0 代码和 STM32G031J SO-8 的 3 个 GPIO 引脚
#![deny(warnings)]
#![deny(unsafe_code)]
#![no_main]
#![no_std]

// #[allow(unused)]
// use panic_halt;

#[allow(unused)]
use panic_semihosting;

use cortex_m_rt::entry;
use stm32g0xx_hal as hal;

use hal::prelude::*;
use hal::rcc::Config;
use hal::stm32;

#[entry]
fn main() -> ! {
let dp = stm32::Peripherals::take().expect("cannot take peripherals");
let mut rcc = dp.RCC.freeze(Config::lsi());
let mut delay = dp.TIM16.delay(&mut rcc);

let gpioa = dp.GPIOA.split(&mut rcc);
let gpiob = dp.GPIOB.split(&mut rcc);

let mut l3 = gpioa.pa12.into_push_pull_output();
let mut l2 = gpioa.pa11.into_push_pull_output();
let mut l1 = gpiob.pb7.into_push_pull_output();

loop {
let _l1b = l1.into_floating_input();
l3.set_high().unwrap();
l2.set_low().unwrap();
delay.delay(500.ms());

l2.set_high().unwrap();
l3.set_low().unwrap();
delay.delay(500.ms());
l1 = _l1b.into_push_pull_output();


let _l2b = l2.into_floating_input();
l1.set_high().unwrap();
l3.set_low().unwrap();
delay.delay(500.ms());

l3.set_high().unwrap();
l1.set_low().unwrap();
delay.delay(500.ms());
l2 = _l2b.into_push_pull_output();


let _l3b = l3.into_floating_input();
l1.set_high().unwrap();
l2.set_low().unwrap();
delay.delay(500.ms());

l2.set_high().unwrap();
l1.set_low().unwrap();
delay.delay(500.ms());
l3 = _l3b.into_push_pull_output();

}
}

最佳答案

为什么 p12 已经“移动”了
为了澄清“移动”消息:您正在使用的 API(例如, into_push_pull_output() 函数)具有以下签名:

pub fn into_push_pull_output(
self,
moder: &mut MODER,
otyper: &mut OTYPER
) -> PA12<Output<PushPull>>
那里有很多,但要注意的重要一点是第一个参数是 self ,而不是 &self&mut self .这意味着如果您调用 p12.into_push_pull_output() ,然后是 ownership值(value) p12被转移出你的功能并进入 into_push_pull_output功能。由于所有权转移, p12 的值您正在编写的函数不再可以使用。换句话说,即使没有循环,您也可能遇到此错误:
let p12 = gpioa.pa12;
p12.into_push_pull_output().set_low().unwrap();
return p12; // ERROR! `p12` has already moved!
但是为什么开发人员会制作一个 API 来阻止我使用 p12 值呢?
在其他语言和框架中,一种常见的模式是让单个对象代表外围设备,拥有改变该对象的方法,然后将您可以使用该外围设备做的所有可能的事情作为方法。代码最终可能如下所示:
let mut p12 = gpioa.pa12;
p12.into_floating_input();
p12.set_low();
这段代码有问题。而 set_low如果 IO 引脚处于“输出”状态,则可能是有效操作,如果代码在 IO 引脚处于输入状态时尝试运行此操作,则可能是一个错误。理想情况下,我们希望能够在编译时检测此类问题。
许多 Rust 嵌入式项目中的 API 会在编译时发现这些类型的错误,而不是使用“类型状态”模式。这将使用 Rust 语言的所有权特性来强制您在切换状态时获取新值。该新值可能具有不同的类型,并且该新类型将仅具有对引脚状态有效的方法。
例如,在调用 into_floating_input() 之后,您的 pin 将由类型为 PA12<Input<Floating>> 的值表示.同样,在调用 into_push_pull_output() 之后,您的 pin 将由类型为 PA12<Output<PushPull>> 的值表示.这两种类型为它们实现了不同的方法。
因此,使用 Rust 的许多嵌入式 API 会要求您在编写代码时改变思维方式。而不是拥有 p12代表一个引脚的值,您可能有多个 p12值,每个值都代表处于特定状态的引脚。 Rust 编译器将确保您一次只能操作一个这样的值,并且您调用的任何方法都只会在引脚处于特定状态时才被允许。当以这种方式查看时,我上面显示的错误代码在编译时被捕获:
let p12 = gpioa.pa12;

// `into_floating_input()` returns a new value, which represents the pin in
// the "floating input" state.
let new_p12 = p12.into_floating_input();
// This will cause a compiler error, since the type `PA12<Input<Floating>>`
// of `new_p12` wouldn't have a `set_low()` method.
new_p12.set_low();
如果您还没有,请查看 Rust Embedded Book 中的“静态保证”一章有关此模式的更多信息。
好的,这听起来很不错,但是我该如何循环使用它呢?
一种简单的方法是为备用状态定义一个起始变量,然后确保在循环结束时将一个值重新分配回起始状态变量。当然,这个值需要有正确的类型(即引脚需要处于相同的“状态”)。
// Define a value which has a specific type `PA12<Output<PushPull>>`
let mut p12 = gpioa.pa12.into_push_pull_output().set_low().unwrap();

loop {
// Use `let` to assign a new value, which has the type `PA12<Input<Floating>>`.
let p12_input = p12.into_floating_input();

// Perform method calls on `p12_input`
// ...

// Get ourselves back to a `PA12<Output<PushPull>>` value.
p12 = p12_input.into_push_pull_output().set_low().unwrap();
}

关于rust 嵌入式将 GPIO 引脚从输出更改为输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65755746/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com