移植玩具应用到RTFM框架时,如何通过GPIO触发中断?
搞定RTFM框架下STM32F103的GPIO中断配置
看了你贴的代码,目前只完成了EXTI中断屏蔽和部分触发配置,还缺几个关键步骤,咱们一步步补全,把中断跑起来:
1. 补全EXTI触发方式的完整配置
你代码里ftsr的配置没写完,得明确是下降沿还是上升沿触发,比如要配置下降沿触发的话:
dp.EXTI.ftsr.write(|w| w.tr0().set_bit()); // 如果需要上升沿触发,还要加上这行: // dp.EXTI.rtsr.write(|w| w.tr0().set_bit());
2. 关键:配置SYSCFG把GPIO引脚映射到EXTI线
STM32F1的EXTI必须通过SYSCFG来关联GPIO引脚,PA0对应EXTI0,所以得加这段配置:
// 先获取SYSCFG外设,注意要依赖APB2时钟 let mut syscfg = dp.SYSCFG.constrain(&mut rcc.apb2); // 把PA0映射到EXTI0线 syscfg.exticr1.exti0().set_pa0();
这一步很容易忘,没做的话EXTI根本不知道要监听哪个GPIO引脚。
3. 在RTFM框架中声明中断资源
RTFM是基于宏的框架,必须在#[rtfm::app]里声明要使用的中断,才能让框架正确生成中断处理逻辑。完整的代码结构应该是这样:
#[rtfm::app(device = stm32f103xx, peripherals = true)] const APP: () = { #[init] fn init(cx: init::Context) -> init::LateResources { let dp = cx.device; let mut rcc = dp.RCC.constrain(); let mut gpioa = dp.GPIOA.split(&mut rcc.apb2); // 配置PA0为浮空输入 let _int = gpioa.pa0.into_floating_input(&mut gpioa.crl); // 配置SYSCFG引脚映射 let mut syscfg = dp.SYSCFG.constrain(&mut rcc.apb2); syscfg.exticr1.exti0().set_pa0(); // 解除EXTI0的中断屏蔽 dp.EXTI.imr.write(|w| w.mr0().set_bit()); // 配置下降沿触发 dp.EXTI.ftsr.write(|w| w.tr0().set_bit()); init::LateResources {} } // 声明EXTI0的中断处理函数 #[interrupt] fn EXTI0() { // 这里写你的中断处理逻辑 // !!必须清除中断标志位,否则会一直触发中断!! cortex_m::interrupt::free(|cs| { let dp = stm32f103xx::Peripherals::steal(cs); dp.EXTI.pr.write(|w| w.pr0().set_bit()); }); } // 可选的空闲任务,让CPU进入低功耗等待中断 #[idle] fn idle(_cx: idle::Context) -> ! { loop { cortex_m::asm::wfi(); } } };
4. 容易踩坑的注意点
- 清除中断标志位:每次中断触发后一定要清除EXTI_PR寄存器对应的位,我在上面的中断处理函数里加了,这是最容易犯的错误,不清除的话中断会无限触发。
- 时钟使能:确保SYSCFG和GPIO的时钟已经正确打开,RTFM的
split和constrain方法一般会帮你处理,但手动配置时要留意。 - RTFM中断声明:必须用
#[interrupt]宏标记中断函数,框架才会把它加入中断向量表,否则写了也不会执行。
调试小妙招
如果中断还是不触发,可以按这个顺序排查:
- 检查PA0的输入模式是否正确(浮空输入没问题,也可以根据需求用上拉/下拉)。
- 用调试器查看SYSCFG_EXTICR1寄存器,确认PA0已经映射到EXTI0。
- 检查EXTI的IMR、FTSR/RTSR寄存器配置是否正确。
- 查看EXTI_PR寄存器,看看有没有中断标志位被置位,判断是没触发还是没处理。
内容的提问来源于stack exchange,提问作者Michael Böckling
相关产品推荐
相关产品推荐

