STM32F103C8外部中断无法正常工作问题排查
问题排查与修复
你的代码存在两个关键问题,导致启用中断后LED停止闪烁:
1. 共享变量未加volatile修饰
全局变量signal被主循环和中断服务函数(ISR)共享,但没有用volatile修饰。编译器会对未标记为volatile的变量做优化,将其缓存到寄存器中,主循环会一直读取寄存器里的初始值,完全看不到ISR对signal的修改,自然不会切换LED的闪烁逻辑。
2. PB8引脚配置错误
你目标是使用PB8控制LED,但代码里错误配置了PB3的输出模式(GPIOB->CRH &= 0xFFFFFFF0; GPIOB->CRH |= 0x00000002;)。PB8对应GPIOB_CRH的第0-3位,需要正确操作这几个位来配置输出模式。
次要优化点
- ISR中清除EXTI中断标志时,建议先判断标志位再清除,避免误处理其他中断;用
EXTI->PR = (1<<5);直接赋值清除对应位,比|=更安全。 - 配置AFIO映射时,用位清除再赋值的方式,代码可读性更强,不容易出错。
- 主循环里的LED toggle用异或(
^=)更简洁,省去先置位再清零的步骤。
修正后的完整代码
#include "stm32f10x.h" // Device header void delay(int rep); void EXTI9_5_IRQHandler(); // 标记为volatile,防止编译器优化 volatile int signal = 0; int main(void) { // 同时使能PortB和PortC的APB2时钟 RCC->APB2ENR |= (1 << 3) | (1 << 4); // 配置PC13为通用推挽输出(50MHz) GPIOC->CRH &= ~(0xF << 20); GPIOC->CRH |= (0x2 << 20); // 配置PB8为通用推挽输出(50MHz) GPIOB->CRH &= ~(0xF << 0); GPIOB->CRH |= (0x2 << 0); // 配置PB5为上拉输入 GPIOB->CRL &= ~(0xF << 20); GPIOB->CRL |= (0x8 << 20); GPIOB->ODR |= (1 << 5); // 使能内部上拉 // 配置PB5的外部中断 __disable_irq(); // 将EXTI5映射到PortB AFIO->EXTICR[1] &= ~(0xF << 4); AFIO->EXTICR[1] |= (0x1 << 4); EXTI->IMR |= (1 << 5); // 使能EXTI5的中断请求 EXTI->FTSR |= (1 << 5); // 设置下降沿触发 NVIC_EnableIRQ(EXTI9_5_IRQn); // 使能NVIC中的EXTI9_5中断通道 __enable_irq(); while(1) { if(signal == 0) { GPIOC->ODR ^= (1 << 13); delay(10); } else { GPIOB->ODR ^= (1 << 8); delay(10); } } } void EXTI9_5_IRQHandler() { // 检查是否是EXTI5的中断请求 if(EXTI->PR & (1 << 5)) { EXTI->PR = (1 << 5); // 清除中断标志 signal = !signal; // 切换signal状态 } } void delay(int rep) { for(; rep > 0; rep--) { for(int i = 0; i < 100000; i++) { // 空循环延迟 } } }
内容的提问来源于stack exchange,提问作者Fadi EID
相关产品推荐
相关产品推荐

