目前,我正在多次重新定义同一个变量(
dp
)以使程序正常运行。然而,这感觉不对,我认为会有更好的方法来做到这一点。对于上下文,我处于 no_std
环境中,并使用 avr-hal-template 为 avr-atmega328p (Arduino Uno) 进行编译。
#![no_std]
#![no_main]
use arduino_hal::hal::wdt;
use motor_shield::{dc::DcMotor, init_pwm, Motor};
use panic_halt as _;
#[arduino_hal::entry]
fn main() -> ! {
let dp = arduino_hal::Peripherals::take().unwrap();
let pins = arduino_hal::pins!(dp);
let dp = arduino_hal::Peripherals::take().unwrap();
let mut pwm = init_pwm(None, dp, pins).unwrap();
let mut dc_motor = DcMotor::try_new(&mut pwm, Motor::Motor1).unwrap();
let dp = arduino_hal::Peripherals::take().unwrap();
let mut watchdog = wdt::Wdt::new(dp.WDT, &dp.CPU.mcusr);
watchdog.start(wdt::Timeout::Ms4000).unwrap();
loop {
let _ = dc_motor.set_throttle(&mut pwm, 0.5);
arduino_hal::delay_ms(1000);
let _ = dc_motor.set_throttle(&mut pwm, 0.0);
arduino_hal::delay_ms(1000);
watchdog.feed();
}
}
对于上下文,这是
init_pwm
函数:
pub fn init_pwm(i2c: Option<I2c>, dp: Peripherals, pins: Pins) -> Result<Pca9685<I2c>, MotorError> {
let i2c = if let Some(i2c) = i2c {
i2c
} else {
I2c::new(
dp.TWI,
pins.a4.into_pull_up_input(),
pins.a5.into_pull_up_input(),
50000,
)
};
let address = Address::from(60);
let mut pwm = Pca9685::new(i2c, address).map_err(|_| MotorError::PwmError)?;
pwm.enable().map_err(|_| MotorError::PwmError)?;
pwm.set_prescale(4).map_err(|_| MotorError::PwmError)?;
Ok(pwm)
}
我能想到做的一件事是借用 dp,但这行不通,因为函数不接受引用。我也无法克隆 dp,因为它没有实现克隆特征。
感谢 Chayim Friedman 的评论,我终于找到了解决方案。我将
init_pwm
函数更改为需要 WDT
而不是完整的外设,因为这就是它所需要的。然后,我可以仅使用 dp.TWI
而不是 dp
来调用该函数。
pub fn init_pwm(i2c: Option<I2c>, twi: TWI, pins: Pins) -> Result<Pca9685<I2c>, MotorError> {
// ...
else {
I2c::new(
twi,
pins.a4.into_pull_up_input(),
pins.a5.into_pull_up_input(),
50000,
)
}
// in main.rs
fn main() -> ! {
let dp = Peripherals::take().unwrap();
let pins = arduino_hal::pins!(dp);
let mut pwm = init_pwm(None, dp.TWI, pins).unwrap();
let mut dc_motor = DcMotor::try_new(&mut pwm, Motor::Motor1).unwrap();
let mut watchdog = wdt::Wdt::new(dp.WDT, &dp.CPU.mcusr);
watchdog.start(wdt::Timeout::Ms4000).unwrap();
// ...
}