You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌入式Rust通过外设句柄清除定时器中断及相关问题排查

编译错误问题解决

你最初遇到的#[interrupt]属性找不到的错误,是因为导入的cortex_m::interrupt是提供临界区能力的模块,不是中断定义属性宏。你后续调整导入的方向是正确的,需要从你使用的stm32g0 PAC包中导入interrupt属性宏,注意避免和cortex_m::interrupt模块重名即可,你拆分导入free和Mutex的写法已经解决了名字冲突问题。

Mutex封装全局外设的写法正确性

你参考嵌入式Rust手册写的Mutex<RefCell<Option<外设>>>的全局共享写法是完全正确的,这是无HAL裸机开发时共享外设的标准实现,不需要依赖任何HAL crate即可正常使用。

ISR中if let判断为false、中断循环触发的原因及解决

核心原因

你遇到的问题是两个常见的裸机开发错误共同导致的:

  • 第一是外设所有权逻辑错误:你修改为使用TIM2后,没有同步修改全局G_TIM的类型,也没有将p.TIM2的所有权存入G_TIM,导致G_TIM的值始终为None,if let判断自然永远失败。如果你同步修改了G_TIM类型,那另一个可能的错误是你先取了定时器的引用用于配置,再尝试移动所有权到全局变量,导致外设实例被意外释放,全局变量最终存入None。
  • 第二是中断开启时机错误:你在代码中先执行NVIC::unmask开启了定时器中断,之后才配置定时器、将外设实例存入全局变量。如果定时器在全局变量赋值完成前就触发了中断,G_TIM此时还是None,无法清除中断标志位,就会导致中断循环触发。

修复方案

按以下步骤调整代码即可:

  1. 统一外设类型,全程使用同一定时器,不要混用TIM2和TIM3的定义:
// 全局变量修改为对应你使用的定时器类型,这里以TIM2为例
static G_TIM: Mutex<RefCell<Option<stm32g071::TIM2>>> =
    Mutex::new(RefCell::new(None));
  1. 调整初始化顺序,先完成定时器配置、全局变量赋值,最后再开启NVIC中断,避免中断提前触发:
#[entry]
fn main() -> ! {
    let p = stm32g071::Peripherals::take().unwrap();
    let rcc_r = &p.RCC;
    // 直接拿到定时器的所有权,不要提前取引用导致所有权转移失败
    let tim2 = p.TIM2;

    // 开定时器时钟
    rcc_r.apbenr1.write(|w| w.tim2en().set_bit());
    // 配置定时器参数
    prepare_timer2(&tim2);

    // 先将定时器实例存入全局变量
    free(|cs| {
        G_TIM.borrow(cs).replace(Some(tim2));
    });

    // 所有准备工作完成后,最后再开启NVIC中断
    unsafe {
        NVIC::unmask(Interrupt::TIM2);
    };

    loop {}
}

// 定时器配置函数对应修改为TIM2的参数
fn prepare_timer2(tim2_r_handle: &TIM2) {
    tim2_r_handle.cr1.write(|w| w.cen().clear_bit());
    tim2_r_handle.psc.write(|w| unsafe { w.psc().bits(16000) });
    tim2_r_handle.arr.write(|w| unsafe { w.arr_l().bits(100) });
    tim2_r_handle.egr.write(|w| w.ug().set_bit());
    tim2_r_handle.dier.write(|w| w.uie().set_bit());
    tim2_r_handle.cr1.write(|w| w.cen().set_bit());
}
  1. 调整ISR逻辑,和你C语言的实现对齐,先判断中断标志位再清除,简化引用获取写法:
#[interrupt]
fn TIM2() {
    free(|cs| {
        // 直接用as_mut获取可变引用,不需要手动调用deref_mut
        if let Some(tim2) = G_TIM.borrow(cs).borrow_mut().as_mut() {
            // 先读SR寄存器判断更新中断是否触发,和C逻辑完全一致
            if tim2.sr.read().uif().bit_is_set() {
                // 清除更新中断标志位
                tim2.sr.write(|w| w.uif().clear_bit());
            }
        }
    });
}

内容的提问来源于stack exchange,提问作者dunajski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 21:45:07