在no_std环境下如何无需重复获取Peripherals实例复用dp变量?
优化AVR平台Peripherals重复调用的方案
当前代码通过多次调用arduino_hal::Peripherals::take().unwrap()获取外设实例,这种做法不符合Rust所有权规则,且存在潜在风险。以下是合理的优化方案,核心思路是拆分Peripherals中的具体外设,按需传递所有权,而非重复获取整个单例。
步骤1:修改init_pwm函数参数
原函数接收整个Peripherals实例,但实际只用到其中的TWI外设。我们将参数改为直接接收TWI外设,而非完整的Peripherals:
pub fn init_pwm(i2c: Option<I2c>, twi: TWI, pins: Pins) -> Result<Pca9685<I2c>, MotorError> { let i2c = if let Some(i2c) = i2c { i2c } else { I2c::new( 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) }
步骤2:重构main函数,仅获取一次Peripherals
在main中只调用一次Peripherals::take(),然后拆分出所需的具体外设,分别传递给对应初始化逻辑:
#![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); // 拆分出TWI外设,传递给init_pwm let mut pwm = init_pwm(None, dp.TWI, pins).unwrap(); let mut dc_motor = DcMotor::try_new(&mut pwm, Motor::Motor1).unwrap(); // 拆分出WDT和CPU.mcusr,初始化看门狗 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(); } }
方案说明
Peripherals的每个字段(如TWI、WDT)都是独立的所有权对象,可以安全拆分并转移所有权到需要的函数中。- 避免了重复调用
take()带来的不符合单例设计的问题,同时符合Rust的所有权安全规则。 - 解决了目标函数不接受引用、
Peripherals无法克隆的限制,通过传递具体外设实例而非整个单例或引用,满足函数的参数要求。
内容的提问来源于stack exchange,提问作者user17193891
相关产品推荐
相关产品推荐

