一、STM32 中断的种类
STM32 基于 Cortex-M 内核(如 M3/M4),其完整的中断系统包括:
- 内核异常(Exception)
- 属于"系统级中断",由 CPU 内部触发。
- 包括:
- Reset(复位)
- NMI(不可屏蔽中断)
- HardFault(硬件错误)
- MemManage、BusFault、UsageFault(内存/总线/用法错误)
- SVCall、PendSV、SysTick(系统调用、可挂起服务、系统滴答定时器)
这些异常优先级固定,不能被普通中断打断(除 NMI 和 HardFault 等高优先级异常)。
- 外设中断(Interrupt)
- 由片上外设(如 GPIO、USART、TIM、ADC、DMA、CAN 等)触发。
- STM32F103 系列典型有 60 个可屏蔽中断通道(加上 10 个内核异常,共 70 个中断源)。
- 每个外设可配置为产生中断(需使能 + 配置 NVIC)。
⚠️ 注意:STM32 的中断总数因型号而异(如 F1 是 70 个,F4 可达 90+ 个)。
二、常见中断应用示例
- 按键中断(GPIO 外部中断)
原理:- 按键连接到 GPIO 引脚(如 PA0)。
- 配置该引脚为 输入模式 + 上拉/下拉。
- 通过 AFIO 将 GPIO 映射到 EXTI(外部中断线)。
- 配置 EXTI 触发方式(上升沿、下降沿、双边沿)。
- 在 NVIC 中使能对应 EXTI 中断(如 EXTI0_IRQn)。
- 编写中断服务函数(ISR):void EXTI0_IRQHandler(void)
示例流程(HAL 库):
// 1. 使能时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
// 2. 配置 GPIO
GPIO_InitTypeDef gpio = {0};
gpio.Pin = GPIO_PIN_0;
gpio.Mode = GPIO_MODE_IT_FALLING; // 下降沿触发(按键按下)
gpio.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &gpio);
// 3. 配置 NVIC
HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
// 4. ISR
void EXTI0_IRQHandler(void) {
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); // 调用 HAL 的通用处理
}
// 5. 回调函数(用户实现)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == GPIO_PIN_0) {
// 按键处理逻辑(如翻转 LED)
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
}
}
✅ 注意:必须在 ISR 中 清除中断标志位(HAL 自动处理;寄存器需手动 EXTI->PR = 1DR 清除标志,并处理数据。
示例(HAL 库):
// 使能接收中断
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
// 或使用 HAL 接收(带回调)
HAL_UART_Receive_IT(&huart1, &rx_byte, 1);
// HAL 自动调用回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
// 处理 rx_byte
process_data(rx_byte);
// 重新开启单字节接收
HAL_UART_Receive_IT(&huart1, &rx_byte, 1);
}
}
🔔 关键点:避免在 ISR 中做耗时操作(如 printf、复杂计算),应快速处理并退出。
三、中断服务程序(ISR)注意事项
- 执行时间要短
- ISR 应 尽快完成并返回,避免阻塞其他高优先级中断。
- 不要在 ISR 中使用 delay()、printf()(除非使用 DMA 或环形缓冲)。
- 变量访问需加 volatile
- 若 ISR 与主程序共享变量,必须声明为 volatile:
volatile uint8_t flag = 0;
- 临界区保护
-
主程序访问 ISR 共享资源时,应临时关闭中断:
__disable_irq();
// 读取/修改共享变量
__enable_irq();
或使用 __set_PRIMASK() 更精细控制。
- 中断标志必须清除
- 否则会 反复进入 ISR(死循环)。
- HAL 库通常自动清除;寄存器操作需手动清标志(如 USART_SR 读 DR,EXTI_PR 写 1 清零)。
- 优先级配置合理
- 使用 抢占优先级(Preemption Priority) 和 子优先级(Subpriority)。
- 高实时性任务(如电机控制)应设高抢占优先级。
- 避免所有中断设为同一优先级(可能导致嵌套失效)。
📌 优先级分组建议:
- 实时系统:用 NVIC_PriorityGroup_4(4 位全给抢占,无子优先级)
- 一般应用:用 NVIC_PriorityGroup_2(2 位抢占 + 2 位响应)
四、调试技巧
- 使用 Event Recorder 或 SEGGER SystemView 查看中断触发时序。
- 在 ISR 开头/结尾打 GPIO 电平,用示波器测执行时间。
- 避免在 ISR 中调用非重入函数(如 malloc、某些库函数)。
五、总结
1、中断种类 内核异常(10+) + 外设中断(60+)
2、按键中断 GPIO → EXTI → NVIC → ISR(注意消抖和清标志)
3、串口中断 USART_RXNE → ISR 读 DR → 快速处理
4、ISR 原则 短、快、清标志、volatile、关中断保护
5、优先级 抢占 > 响应,合理分组避免嵌套问题
掌握这些要点,就能安全高效地使用 STM32 中断系统了