当前位置: 首页 > news >正文

STM32的中断系统

先想象你在写作业(主程序),突然有人敲门(外部事件)。你先放下手里的笔,去开门(处理中断),然后回来继续写作业(回到主程序)。中断也如此。

什么是中断?

中断 = 程序在运行中,遇到某个特殊事件时,暂停当前任务 → 去执行一个专门的中断处理程序 → 再返回原任务。

STM32 中的中断有很多来源:

外部中断(EXTI):来自外部引脚的事件(按键、传感器信号等)。

内部外设中断:来自外设的事件(串口收到数据、定时器溢出、ADC转换完成等)。

异常(Exception):比如硬件故障(硬Fault)、系统滴答 SysTick。

1.STM32 中断的硬件基础

中断的物理来源
STM32 中断的信号来源主要有两大类:

外部硬件事件

来自 MCU 引脚的电平变化(高变低、低变高、双边沿)。

如:按键、传感器信号、外部模块的状态输出。

电气路径:引脚 → GPIO 输入缓冲器 → AFIO 选择器 → EXTI 模块 → NVIC。

内部外设事件

来自 MCU 内部外设的事件。

如:USART 接收到数据、TIM 定时器溢出、ADC 转换完成。

电气路径:外设状态寄存器(SR)设置中断标志位 → NVIC。

外部中断硬件流向

以 PA0 外部中断 为例:

PA0 引脚 ──> TTL 施密特触发器(整形去抖) ──> GPIO 输入电路  ↓AFIO(Alternate Function I/O,多功能映射)↓EXTI0(外部中断线0)↓NVIC(嵌套向量中断控制器)↓CPU 跳转到 ISR(中断服务程序)

重点:GPIO 只是信号入口,EXTI 才是中断检测单元。

中断响应流程

当事件发生时,底层流程是这样:

事件触发

例如 PA0 下降沿 → EXTI0 寄存器标志位 PR0 = 1。

EXTI 检查

EXTI 使能位 IMR0 = 1 且触发类型匹配(FTSR / RTSR)。

NVIC 检查

NVIC 使能该中断,且没有被屏蔽。

CPU 处理

保存当前执行环境(寄存器、程序计数器 PC、程序状态寄存器 xPSR)。

从中断向量表取 ISR 地址。

执行 ISR

执行用户定义的中断服务函数。

中断返回

恢复寄存器和 PC,回到被打断的地方继续执行。

2.举例红外传感器计次

开时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 开 GPIOB 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);  // 开 AFIO 时钟(用于引脚与中断线的映射)

STM32 外设要先有时钟才能工作,GPIOB 和 AFIO 都要开。

AFIO 是 Alternate Function IO,外部中断要靠它把“引脚”映射到“EXTI 线”。

配置 GPIO 输入模式

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;     // 上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;        // 选择 PB14
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO 速度(输入模式无实质作用)
GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_Mode_IPU:输入模式,上拉(空闲时保持高电平)。

当外部设备拉低 PB14,就会产生一个下降沿,触发中断。

GPIO 与 EXTI 线绑定

GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);

STM32 有 16 条 EXTI 线(0~15),分别对应引脚号相同的 GPIO。

这里把 PB14 映射到 EXTI14。

注意:PB14、PC14、PA14 不能同时用 EXTI14,因为 EXTI14 只能绑定一个。

配置 EXTI(中断线)

EXTI_InitStructure.EXTI_Line = EXTI_Line14;              // 选择 EXTI14
EXTI_InitStructure.EXTI_LineCmd = ENABLE;                // 使能这条线
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;      // 设置为中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  // 下降沿触发
EXTI_Init(&EXTI_InitStructure);

EXTI_Mode_Interrupt:触发时进入中断函数。

EXTI_Trigger_Falling:下降沿触发。

这样 PB14 从高电平变低电平时就会触发中断。

配置 NVIC(中断控制器)

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置优先级分组
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;     // EXTI10~15 共用一个中断号
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;          // 使能通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级 1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;       // 子优先级 1
NVIC_Init(&NVIC_InitStructure);

EXTI15_10_IRQn:PB14 对应 EXTI14,属于 EXTI10~15 范围内的共享中断向量。

抢占优先级 + 子优先级 决定中断响应顺序。

中断执行过程(你的 EXTI15_10_IRQHandler)

void EXTI15_10_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line14) == SET) // 判断是不是 EXTI14 触发{CountSensor_Count++;                  // 计数 +1}EXTI_ClearITPendingBit(EXTI_Line14);      // 清除挂起标志,否则会一直进中断
}

PB14 检测到下降沿 → EXTI14 触发 → NVIC 调用中断函数。

EXTI_GetITStatus() 检查是不是 EXTI14 引起的中断(因为 EXTI10~15 共用一个函数)。

计数器 CountSensor_Count 自增。

EXTI_ClearITPendingBit() 清除中断标志位,否则下一次不会触发。

主程序如何使用中断计数

int main(void)
{OLED_Init();            // 初始化 OLEDCountSensor_Init();     // 初始化传感器中断OLED_ShowString(1,1,"Count:");while(1){OLED_ShowNum(1, 7, CountSensor_Get(), 5); // 显示中断计数值}
}

主程序并不去检测 PB14 状态,而是直接从 CountSensor_Get() 读取中断里更新的变量。

每次 PB14 有下降沿,就会进入中断加一,主循环只负责显示。

PB14 引脚变化↓
GPIO 检测到下降沿↓
EXTI14 触发中断请求↓
NVIC 根据优先级响应↓
执行 EXTI15_10_IRQHandler()↓
CountSensor_Count++
清除中断标志位

3.中断优先级的细节

STM32 优先级由两部分组成:

抢占优先级(Preemption Priority)
决定能否打断别人。

响应优先级 / 子优先级(Subpriority)
同级别抢占时,谁先执行。

STM32F1 的优先级分组(NVIC_PriorityGroupConfig())会把这两种优先级分配到不同位数:

分组抢占优先级位数子优先级位数
Group 004
Group 113
Group 222
Group 331
Group 440

4.STM32 中断配置函数速查表

模块函数名功能说明典型用途备注
EXTI(外部中断)EXTI_DeInit()将 EXTI 外设寄存器恢复默认值重新配置 EXTI 前清空配置关闭所有中断线、清触发设置
EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)配置中断线(模式、触发方式、使能)配置按键、传感器等外部信号中断必须先 GPIO_EXTILineConfig() 选端口
EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct)填充默认配置避免结构体未初始化一般先调用它再改字段
EXTI_GenerateSWInterrupt(uint32_t EXTI_Line)软件触发中断测试 ISR开发调试用
EXTI_GetFlagStatus(uint32_t EXTI_Line)读取挂起标志位(Pending)轮询检测事件不判断中断是否被屏蔽
EXTI_ClearFlag(uint32_t EXTI_Line)清除挂起标志位轮询处理完成后调用ISR 中推荐 EXTI_ClearITPendingBit()
EXTI_GetITStatus(uint32_t EXTI_Line)判断中断触发 使能ISR 判断当前中断线触发GetFlagStatus 更精确
EXTI_ClearITPendingBit(uint32_t EXTI_Line)清除中断挂起位(写 1 清零)ISR 末尾调用,防止重复进中断对应 EXTI_PR 寄存器
NVIC(内核中断控制)NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)配置优先级分组(抢占优先级 vs 子优先级位数)初始化前设置优先级策略影响所有中断优先级结构
NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)配置中断通道的优先级、使能状态开启 EXTI15_10、USART 等中断需先设置优先级分组
NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset)设置中断向量表基地址和偏移Bootloader 跳转到应用程序可选 SRAM / Flash
NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState)设置低功耗模式下 NVIC 行为节能应用模式有 NVIC_LP_SEVONPENDNVIC_LP_SLEEPDEEP
SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)配置 SysTick 定时器时钟源选择 HCLK 或 HCLK/8SysTick 常用于 OS 节拍或延时

使用顺序建议(外部中断场景)

GPIO 配置 → GPIO_Init() + GPIO_EXTILineConfig()

EXTI 配置 → EXTI_Init()(触发方式 + 使能)

NVIC 配置 → NVIC_PriorityGroupConfig() → NVIC_Init()

ISR 编写 → 判断 EXTI_GetITStatus() → 业务逻辑 → EXTI_ClearITPendingBit()

5.除此之外,还有内部中断

内部中断类型说明
定时器中断 (TIMx)定时器溢出、更新事件、捕获比较等产生的中断
USART 中断数据发送完成、中断接收、错误等事件
ADC 中断转换完成中断
DMA 中断数据传输完成或错误
I2C、SPI 中断通信事件、中断
SysTick 中断系统节拍计时器周期到达中断
RTC 中断实时时钟闹钟或秒脉冲中断
PVD 中断电压检测器(PVD)产生的电压异常中断
USB 中断USB 事件产生的中断
看门狗中断(WWDG、IWDG)看门狗超时触发的中断
核心异常(Fault)硬件异常,如硬件故障、总线错误、使用错误等

内部中断和外部中断的区别

特点外部中断(EXTI)内部中断
触发源外部引脚电平变化内部外设事件或者系统模块产生
触发机制由 GPIO 引脚电平变化触发由定时器、通信接口、ADC 等产生
应用场景按键、传感器、外部脉冲采集等定时周期任务、通信数据处理、模拟采样等
http://www.dtcms.com/a/322863.html

相关文章:

  • 数据分析框架从 “工具堆砌” 转向 “智能协同”
  • java -jar xxx.jar 提示xxx.jar中没有主清单属性报错解决方案
  • PAT 1052 Linked List Sorting
  • 第16届蓝桥杯Scratch选拔赛初级及中级(STEMA)2024年10月20日真题
  • 求和算法的向后稳定性 backward stable
  • 【Python 高频 API 速学 ③】
  • 优化器:SGD、Adam、RMSprop等优化算法对比与机器翻译应用
  • 99-基于Python的京东手机数据分析及预测系统
  • I2CHAL库接口
  • c++ opencv调用yolo onnx文件
  • 用天气预测理解分类算法-从出门看天气到逻辑回归
  • SymPy 表达式的变量获取:深入理解与正确实践
  • 对数运算法则(rule of logarithmic operations)和对应导数关系
  • 带冷端补偿的热电偶采集方案MAX31855
  • Python(6) -- 数据容器
  • 《原型链的柔性骨架:JavaScript面向对象架 构的动态设计与演化逻辑》
  • 【线性代数】线性方程组与矩阵——(1)线性方程组与矩阵初步
  • Python中的Lambda函数详解
  • 北京JAVA基础面试30天打卡05
  • PowerShell 实战:第 6 章动手实验全攻略(含命令详解与示例)
  • Ubuntu和Windows系统Kafka配置方法
  • 模式组合应用-适配器模式
  • 光伏面板损伤检出率↑91%!陌讯多模态识别算法在无人机巡检的落地实践
  • 基于clodop和Chrome原生打印的标签实现方法与性能对比
  • 深入理解Maven BOM
  • 基于MATLAB的Halo轨道设计与可视化实现
  • [SC]SystemC 常见的编译/语法错误与解法(三)
  • PDF 转 HTML API 数据接口
  • 在Spring Boot项目中如何动态切换数据源、数据库?
  • Redis分布式锁详解:原理、实现与实战案例