STM32 学习笔记:中断系统与 EXTI 外部中断

STM32 学习笔记:中断系统与 EXTI 外部中断

对应课程:[5-1] EXTI 外部中断(理论部分)

课堂录音:2026-08-30 19_01 EXIT 外部中断_原文.docx

芯片/板卡:STM32F103C8T6

老师 PPT:第 41~51 页

师兄笔记:STM32笔记.pdf 第 33~36 页

官方资料:STM32F10xxx 参考手册、STM32F103x8/B 数据手册、STM32F10xxx Cortex-M3 编程手册

整理日期:2026-08-30

本节边界:本段只讲中断、NVIC、EXTI、AFIO 和旋转编码器原理;外部中断初始化与中断函数代码放在下一小节。
文件名中的 EXIT 是转写/命名错误,正确缩写是 EXTI,即 External Interrupt/Event Controller。

1. 老师的整条思路

老师用"对射式红外传感器计次"和"旋转编码器加减计数"两个现象引出问题:外部脉冲来得突然、持续时间短,主程序如果一直轮询会浪费 CPU,轮询不及时又可能漏掉边沿。因此需要由硬件监测边沿,在事件到来时自动打断主程序。
#mermaid-svg-4HEA0odHG85Tm4nM{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4HEA0odHG85Tm4nM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4HEA0odHG85Tm4nM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4HEA0odHG85Tm4nM .error-icon{fill:#552222;}#mermaid-svg-4HEA0odHG85Tm4nM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4HEA0odHG85Tm4nM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4HEA0odHG85Tm4nM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4HEA0odHG85Tm4nM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4HEA0odHG85Tm4nM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4HEA0odHG85Tm4nM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4HEA0odHG85Tm4nM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4HEA0odHG85Tm4nM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4HEA0odHG85Tm4nM .marker.cross{stroke:#333333;}#mermaid-svg-4HEA0odHG85Tm4nM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4HEA0odHG85Tm4nM p{margin:0;}#mermaid-svg-4HEA0odHG85Tm4nM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-4HEA0odHG85Tm4nM .cluster-label text{fill:#333;}#mermaid-svg-4HEA0odHG85Tm4nM .cluster-label span{color:#333;}#mermaid-svg-4HEA0odHG85Tm4nM .cluster-label span p{background-color:transparent;}#mermaid-svg-4HEA0odHG85Tm4nM .label text,#mermaid-svg-4HEA0odHG85Tm4nM span{fill:#333;color:#333;}#mermaid-svg-4HEA0odHG85Tm4nM .node rect,#mermaid-svg-4HEA0odHG85Tm4nM .node circle,#mermaid-svg-4HEA0odHG85Tm4nM .node ellipse,#mermaid-svg-4HEA0odHG85Tm4nM .node polygon,#mermaid-svg-4HEA0odHG85Tm4nM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4HEA0odHG85Tm4nM .rough-node .label text,#mermaid-svg-4HEA0odHG85Tm4nM .node .label text,#mermaid-svg-4HEA0odHG85Tm4nM .image-shape .label,#mermaid-svg-4HEA0odHG85Tm4nM .icon-shape .label{text-anchor:middle;}#mermaid-svg-4HEA0odHG85Tm4nM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-4HEA0odHG85Tm4nM .rough-node .label,#mermaid-svg-4HEA0odHG85Tm4nM .node .label,#mermaid-svg-4HEA0odHG85Tm4nM .image-shape .label,#mermaid-svg-4HEA0odHG85Tm4nM .icon-shape .label{text-align:center;}#mermaid-svg-4HEA0odHG85Tm4nM .node.clickable{cursor:pointer;}#mermaid-svg-4HEA0odHG85Tm4nM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-4HEA0odHG85Tm4nM .arrowheadPath{fill:#333333;}#mermaid-svg-4HEA0odHG85Tm4nM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4HEA0odHG85Tm4nM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4HEA0odHG85Tm4nM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4HEA0odHG85Tm4nM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-4HEA0odHG85Tm4nM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4HEA0odHG85Tm4nM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-4HEA0odHG85Tm4nM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4HEA0odHG85Tm4nM .cluster text{fill:#333;}#mermaid-svg-4HEA0odHG85Tm4nM .cluster span{color:#333;}#mermaid-svg-4HEA0odHG85Tm4nM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-4HEA0odHG85Tm4nM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-4HEA0odHG85Tm4nM rect.text{fill:none;stroke-width:0;}#mermaid-svg-4HEA0odHG85Tm4nM .icon-shape,#mermaid-svg-4HEA0odHG85Tm4nM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4HEA0odHG85Tm4nM .icon-shape p,#mermaid-svg-4HEA0odHG85Tm4nM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-4HEA0odHG85Tm4nM .icon-shape .label rect,#mermaid-svg-4HEA0odHG85Tm4nM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4HEA0odHG85Tm4nM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-4HEA0odHG85Tm4nM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-4HEA0odHG85Tm4nM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 观察计次现象
理解中断与嵌套
NVIC统一管理优先级
EXTI检测外部边沿
AFIO选择具体GPIO端口
分析EXTI内部框图
判断适用场景
理解旋转编码器正交波形
回到官方手册定位

录音时间 课堂内容
00:07--01:26 红外计次、旋转编码器演示
01:26--05:07 中断、优先级、中断嵌套和执行流程
05:07--08:56 STM32 中断、向量表和 NVIC 基本结构
08:56--11:23 抢占/响应优先级与五种分组
11:23--13:45 EXTI 功能、触发沿、通道和事件响应
13:45--16:11 EXTI 总体结构和 AFIO 引脚选择
16:11--18:59 EXTI 内部框图、门电路和寄存器
18:59--20:12 哪些信号适合外部中断
20:12--24:32 旋转编码器、正交波形和硬件电路
24:32--结束 Cortex-M3、STM32 参考手册中的查阅位置

2. 课堂现象:中断要解决什么问题

2.1 对射式红外传感器计次

传感器输出在遮挡/放开时发生高低电平变化。程序选择其中一个边沿触发 EXTI,每发生一次有效边沿,中断服务函数将计数变量加一,主循环再把计数显示到 OLED。

text 复制代码
物体经过 → 红外光被遮挡/恢复 → DO产生边沿
        → EXTI检测 → NVIC通知CPU → 中断函数计数+1

2.2 旋转编码器计数

编码器旋转时输出 A、B 两路相位相差 90° 的方波:

  • 边沿数量反映旋转增量;
  • 边沿频率反映旋转速度;
  • A、B 谁领先谁反映旋转方向。

CPU 不知道这些外部边沿何时到来,且快速旋转时脉冲间隔可能很短,因此适合交给 EXTI 及时捕获。


3. 中断、优先级与中断嵌套

3.1 中断是什么

中断是:特定事件发生后,CPU 暂停当前程序,自动转去执行对应的中断服务函数;处理结束后,再回到原位置继续运行。

中断源可以来自:

  • GPIO 电平边沿:EXTI;
  • 定时时间到达:TIM;
  • ADC 转换完成;
  • USART 收到数据;
  • SPI/I²C 事件;
  • RTC 闹钟、看门狗等。

中断并不会让 CPU 同时执行两段代码。单核 CPU 仍是按顺序执行,只是硬件临时改变了执行路线。

3.2 为什么中断比一直查询更高效

#mermaid-svg-Swyt57ziCx7GhsaJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Swyt57ziCx7GhsaJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Swyt57ziCx7GhsaJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Swyt57ziCx7GhsaJ .error-icon{fill:#552222;}#mermaid-svg-Swyt57ziCx7GhsaJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Swyt57ziCx7GhsaJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Swyt57ziCx7GhsaJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Swyt57ziCx7GhsaJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Swyt57ziCx7GhsaJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Swyt57ziCx7GhsaJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Swyt57ziCx7GhsaJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Swyt57ziCx7GhsaJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Swyt57ziCx7GhsaJ .marker.cross{stroke:#333333;}#mermaid-svg-Swyt57ziCx7GhsaJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Swyt57ziCx7GhsaJ p{margin:0;}#mermaid-svg-Swyt57ziCx7GhsaJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Swyt57ziCx7GhsaJ .cluster-label text{fill:#333;}#mermaid-svg-Swyt57ziCx7GhsaJ .cluster-label span{color:#333;}#mermaid-svg-Swyt57ziCx7GhsaJ .cluster-label span p{background-color:transparent;}#mermaid-svg-Swyt57ziCx7GhsaJ .label text,#mermaid-svg-Swyt57ziCx7GhsaJ span{fill:#333;color:#333;}#mermaid-svg-Swyt57ziCx7GhsaJ .node rect,#mermaid-svg-Swyt57ziCx7GhsaJ .node circle,#mermaid-svg-Swyt57ziCx7GhsaJ .node ellipse,#mermaid-svg-Swyt57ziCx7GhsaJ .node polygon,#mermaid-svg-Swyt57ziCx7GhsaJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Swyt57ziCx7GhsaJ .rough-node .label text,#mermaid-svg-Swyt57ziCx7GhsaJ .node .label text,#mermaid-svg-Swyt57ziCx7GhsaJ .image-shape .label,#mermaid-svg-Swyt57ziCx7GhsaJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-Swyt57ziCx7GhsaJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Swyt57ziCx7GhsaJ .rough-node .label,#mermaid-svg-Swyt57ziCx7GhsaJ .node .label,#mermaid-svg-Swyt57ziCx7GhsaJ .image-shape .label,#mermaid-svg-Swyt57ziCx7GhsaJ .icon-shape .label{text-align:center;}#mermaid-svg-Swyt57ziCx7GhsaJ .node.clickable{cursor:pointer;}#mermaid-svg-Swyt57ziCx7GhsaJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Swyt57ziCx7GhsaJ .arrowheadPath{fill:#333333;}#mermaid-svg-Swyt57ziCx7GhsaJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Swyt57ziCx7GhsaJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Swyt57ziCx7GhsaJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Swyt57ziCx7GhsaJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Swyt57ziCx7GhsaJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Swyt57ziCx7GhsaJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Swyt57ziCx7GhsaJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Swyt57ziCx7GhsaJ .cluster text{fill:#333;}#mermaid-svg-Swyt57ziCx7GhsaJ .cluster span{color:#333;}#mermaid-svg-Swyt57ziCx7GhsaJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Swyt57ziCx7GhsaJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Swyt57ziCx7GhsaJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-Swyt57ziCx7GhsaJ .icon-shape,#mermaid-svg-Swyt57ziCx7GhsaJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Swyt57ziCx7GhsaJ .icon-shape p,#mermaid-svg-Swyt57ziCx7GhsaJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Swyt57ziCx7GhsaJ .icon-shape .label rect,#mermaid-svg-Swyt57ziCx7GhsaJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Swyt57ziCx7GhsaJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Swyt57ziCx7GhsaJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Swyt57ziCx7GhsaJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 中断
事件到来
主程序做其他事情
硬件等待事件
自动进入ISR
轮询


主程序
事件来了吗
处理事件

轮询并非错误。信号持续时间长、实时性要求低时,轮询更简单;中断更适合异步、突发、短促且不能漏掉的事件。

3.3 中断执行和现场保护

图 1 老师 PPT 第 42 页:主程序被中断、嵌套,再逐层返回。
中断服务函数ISR CPU/NVIC硬件 主程序 中断服务函数ISR CPU/NVIC硬件 主程序 #mermaid-svg-yCNGHUhoDGLYOnKh{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yCNGHUhoDGLYOnKh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yCNGHUhoDGLYOnKh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yCNGHUhoDGLYOnKh .error-icon{fill:#552222;}#mermaid-svg-yCNGHUhoDGLYOnKh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yCNGHUhoDGLYOnKh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yCNGHUhoDGLYOnKh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yCNGHUhoDGLYOnKh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yCNGHUhoDGLYOnKh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yCNGHUhoDGLYOnKh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yCNGHUhoDGLYOnKh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yCNGHUhoDGLYOnKh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yCNGHUhoDGLYOnKh .marker.cross{stroke:#333333;}#mermaid-svg-yCNGHUhoDGLYOnKh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yCNGHUhoDGLYOnKh p{margin:0;}#mermaid-svg-yCNGHUhoDGLYOnKh .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-yCNGHUhoDGLYOnKh text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-yCNGHUhoDGLYOnKh .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-yCNGHUhoDGLYOnKh .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-yCNGHUhoDGLYOnKh .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-yCNGHUhoDGLYOnKh .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-yCNGHUhoDGLYOnKh #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-yCNGHUhoDGLYOnKh .sequenceNumber{fill:white;}#mermaid-svg-yCNGHUhoDGLYOnKh #sequencenumber{fill:#333;}#mermaid-svg-yCNGHUhoDGLYOnKh #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-yCNGHUhoDGLYOnKh .messageText{fill:#333;stroke:none;}#mermaid-svg-yCNGHUhoDGLYOnKh .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-yCNGHUhoDGLYOnKh .labelText,#mermaid-svg-yCNGHUhoDGLYOnKh .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-yCNGHUhoDGLYOnKh .loopText,#mermaid-svg-yCNGHUhoDGLYOnKh .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-yCNGHUhoDGLYOnKh .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-yCNGHUhoDGLYOnKh .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-yCNGHUhoDGLYOnKh .noteText,#mermaid-svg-yCNGHUhoDGLYOnKh .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-yCNGHUhoDGLYOnKh .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-yCNGHUhoDGLYOnKh .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-yCNGHUhoDGLYOnKh .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-yCNGHUhoDGLYOnKh .actorPopupMenu{position:absolute;}#mermaid-svg-yCNGHUhoDGLYOnKh .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-yCNGHUhoDGLYOnKh .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-yCNGHUhoDGLYOnKh .actor-man circle,#mermaid-svg-yCNGHUhoDGLYOnKh line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-yCNGHUhoDGLYOnKh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 正常执行中断请求到来并通过优先级裁决保存必要现场与返回地址跳转到对应中断函数快速处理并清标志位异常返回恢复现场,从原位置继续

Cortex-M3 异常入口会由硬件自动压栈部分寄存器,如 R0--R3、R12、LR、PC、xPSR;编译器根据中断函数使用情况保存其他寄存器。

表述校正 :课堂把主程序被暂停的位置称为"断点",便于形象理解;更准确的术语是返回地址/被中断位置。调试器中的 breakpoint(断点)是开发者主动设置的停机点,两者不是同一个概念。

3.4 中断嵌套

如果 CPU 正在执行低抢占优先级 ISR,又来了更高抢占优先级中断,新的中断可以抢占当前 ISR:

text 复制代码
主程序 → ISR_A → 更高优先级 ISR_B → 返回 ISR_A → 返回主程序

如果新中断不能抢占,它会保持挂起,等当前 ISR 结束后再根据优先级进入。


4. 中断向量表:硬件怎样找到中断函数

硬件只能根据异常号去固定的向量表位置取入口地址,而链接器可能把 C 函数放在不同 Flash 地址。因此启动文件提供中断向量表,将每个异常号映射到规定名称的处理函数。
#mermaid-svg-n67dfjvgQhxPnxR4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-n67dfjvgQhxPnxR4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-n67dfjvgQhxPnxR4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-n67dfjvgQhxPnxR4 .error-icon{fill:#552222;}#mermaid-svg-n67dfjvgQhxPnxR4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-n67dfjvgQhxPnxR4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-n67dfjvgQhxPnxR4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-n67dfjvgQhxPnxR4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-n67dfjvgQhxPnxR4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-n67dfjvgQhxPnxR4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-n67dfjvgQhxPnxR4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-n67dfjvgQhxPnxR4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-n67dfjvgQhxPnxR4 .marker.cross{stroke:#333333;}#mermaid-svg-n67dfjvgQhxPnxR4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-n67dfjvgQhxPnxR4 p{margin:0;}#mermaid-svg-n67dfjvgQhxPnxR4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-n67dfjvgQhxPnxR4 .cluster-label text{fill:#333;}#mermaid-svg-n67dfjvgQhxPnxR4 .cluster-label span{color:#333;}#mermaid-svg-n67dfjvgQhxPnxR4 .cluster-label span p{background-color:transparent;}#mermaid-svg-n67dfjvgQhxPnxR4 .label text,#mermaid-svg-n67dfjvgQhxPnxR4 span{fill:#333;color:#333;}#mermaid-svg-n67dfjvgQhxPnxR4 .node rect,#mermaid-svg-n67dfjvgQhxPnxR4 .node circle,#mermaid-svg-n67dfjvgQhxPnxR4 .node ellipse,#mermaid-svg-n67dfjvgQhxPnxR4 .node polygon,#mermaid-svg-n67dfjvgQhxPnxR4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-n67dfjvgQhxPnxR4 .rough-node .label text,#mermaid-svg-n67dfjvgQhxPnxR4 .node .label text,#mermaid-svg-n67dfjvgQhxPnxR4 .image-shape .label,#mermaid-svg-n67dfjvgQhxPnxR4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-n67dfjvgQhxPnxR4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-n67dfjvgQhxPnxR4 .rough-node .label,#mermaid-svg-n67dfjvgQhxPnxR4 .node .label,#mermaid-svg-n67dfjvgQhxPnxR4 .image-shape .label,#mermaid-svg-n67dfjvgQhxPnxR4 .icon-shape .label{text-align:center;}#mermaid-svg-n67dfjvgQhxPnxR4 .node.clickable{cursor:pointer;}#mermaid-svg-n67dfjvgQhxPnxR4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-n67dfjvgQhxPnxR4 .arrowheadPath{fill:#333333;}#mermaid-svg-n67dfjvgQhxPnxR4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-n67dfjvgQhxPnxR4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-n67dfjvgQhxPnxR4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-n67dfjvgQhxPnxR4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-n67dfjvgQhxPnxR4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-n67dfjvgQhxPnxR4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-n67dfjvgQhxPnxR4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-n67dfjvgQhxPnxR4 .cluster text{fill:#333;}#mermaid-svg-n67dfjvgQhxPnxR4 .cluster span{color:#333;}#mermaid-svg-n67dfjvgQhxPnxR4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-n67dfjvgQhxPnxR4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-n67dfjvgQhxPnxR4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-n67dfjvgQhxPnxR4 .icon-shape,#mermaid-svg-n67dfjvgQhxPnxR4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-n67dfjvgQhxPnxR4 .icon-shape p,#mermaid-svg-n67dfjvgQhxPnxR4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-n67dfjvgQhxPnxR4 .icon-shape .label rect,#mermaid-svg-n67dfjvgQhxPnxR4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-n67dfjvgQhxPnxR4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-n67dfjvgQhxPnxR4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-n67dfjvgQhxPnxR4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 某中断源产生请求
NVIC得到异常号
按异常号索引向量表
取出ISR入口地址
执行EXTI0_IRQHandler等函数

这就是为什么中断函数名不能随意写错。标准外设库不会主动调用 ISR;中断入口由启动文件、链接器和 CPU 异常机制共同完成。


5. NVIC:中断的统一调度器

图 2 老师 PPT 第 44 页:EXTI、TIM、ADC、USART 等请求先进入 NVIC,再由 NVIC 通知 CPU。

NVICNested Vectored Interrupt Controller,嵌套向量中断控制器,属于 Cortex-M3 内核外设。

它主要负责:

  • 使能/禁用某个中断通道;
  • 保存挂起和活动状态;
  • 配置每个外部中断的优先级;
  • 在多个请求之间裁决;
  • 支持更高优先级中断抢占当前 ISR;
  • 根据异常号完成向量跳转。

师兄笔记把 NVIC 比作"CPU 的助手",老师把它比作医院叫号系统:外设只负责提出请求,NVIC 负责排队和抢占,CPU 专注执行选中的处理程序。

型号校正 :老师 PPT 和师兄笔记写"68 个可屏蔽中断通道",这是 STM32F1 系列最大配置的概括。当前 STM32F103x8/B 数据手册 PDF 第 7 页写的是最多 43 个可屏蔽中断通道,具体项目必须以所用芯片的数据手册和启动文件为准。


6. NVIC 优先级分组

图 3 老师 PPT 第 45 页:STM32F1 使用的 4 个有效优先级位可切分为抢占优先级和响应优先级。

6.1 先记三条规则

  1. 优先级数值越小,优先级越高,0 最高;
  2. 抢占优先级决定能否打断正在运行的 ISR;
  3. **响应优先级(子优先级)**只在抢占优先级相同、多个中断都处于挂起状态时决定先服务谁。

响应优先级高不能打断正在执行的同抢占优先级 ISR。课堂"插队"比喻应理解为:当前 ISR 结束后,它能在同一抢占等级的待处理中断里先被选择,而不是立刻抢占。

6.2 五种分组

标准库分组 抢占优先级位数/范围 响应优先级位数/范围
NVIC_PriorityGroup_0 0 位,只能为 0 4 位,0~15
NVIC_PriorityGroup_1 1 位,0~1 3 位,0~7
NVIC_PriorityGroup_2 2 位,0~3 2 位,0~3
NVIC_PriorityGroup_3 3 位,0~7 1 位,0~1
NVIC_PriorityGroup_4 4 位,0~15 0 位,只能为 0

例如选择分组 2:

  • 中断 A:抢占 1,响应 0
  • 中断 B:抢占 2,响应 0
  • A 能抢占 B,因为 1 < 2
  • 若 A、B 抢占级都为 1,响应级分别 01,它们不能互相抢占;都在等待时,响应 0 先执行。

若抢占优先级和响应优先级都相同,硬件按照异常号进行固定仲裁,异常号较小者优先。不要依赖"谁先来谁先执行"。

6.3 分组为什么整个工程只设置一次

分组配置写入 SCB_AIRCR.PRIGROUP,改变的是整个系统解释优先级位的方式,不属于某一个中断。后一次设置会覆盖前一次设置,因此工程中通常统一调用一次,然后所有 NVIC 通道按同一分组填写合法范围。

图 4 师兄笔记 PDF 第 34 页:五种优先级分组、EXTI 触发方式和事件/中断响应对比。


7. EXTI 是什么

EXTI 是 STM32F1 的外部中断/事件控制器。它监测输入线的边沿,并可沿两条路径响应:

  • 中断路径:设置挂起位,经 NVIC 让 CPU 执行 ISR;
  • 事件路径:产生事件脉冲,不进入 ISR,可用于事件/唤醒链路。

7.1 支持的触发方式

触发方式 电平变化 常见用途
上升沿 0 → 1 信号变高瞬间
下降沿 1 → 0 低有效传感器被触发
双边沿 两种边沿 测量完整变化或脉宽
软件触发 程序写软件中断寄存器 测试或软件触发事件

EXTI 是边沿检测,不是"只要维持低电平就不断触发"。电平不发生新变化时,不会产生新的边沿请求。

7.2 中断响应和事件响应的区别

#mermaid-svg-NtlhAxlk1hfWFjtq{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NtlhAxlk1hfWFjtq .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NtlhAxlk1hfWFjtq .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NtlhAxlk1hfWFjtq .error-icon{fill:#552222;}#mermaid-svg-NtlhAxlk1hfWFjtq .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NtlhAxlk1hfWFjtq .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NtlhAxlk1hfWFjtq .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NtlhAxlk1hfWFjtq .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NtlhAxlk1hfWFjtq .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NtlhAxlk1hfWFjtq .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NtlhAxlk1hfWFjtq .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NtlhAxlk1hfWFjtq .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NtlhAxlk1hfWFjtq .marker.cross{stroke:#333333;}#mermaid-svg-NtlhAxlk1hfWFjtq svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NtlhAxlk1hfWFjtq p{margin:0;}#mermaid-svg-NtlhAxlk1hfWFjtq .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NtlhAxlk1hfWFjtq .cluster-label text{fill:#333;}#mermaid-svg-NtlhAxlk1hfWFjtq .cluster-label span{color:#333;}#mermaid-svg-NtlhAxlk1hfWFjtq .cluster-label span p{background-color:transparent;}#mermaid-svg-NtlhAxlk1hfWFjtq .label text,#mermaid-svg-NtlhAxlk1hfWFjtq span{fill:#333;color:#333;}#mermaid-svg-NtlhAxlk1hfWFjtq .node rect,#mermaid-svg-NtlhAxlk1hfWFjtq .node circle,#mermaid-svg-NtlhAxlk1hfWFjtq .node ellipse,#mermaid-svg-NtlhAxlk1hfWFjtq .node polygon,#mermaid-svg-NtlhAxlk1hfWFjtq .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NtlhAxlk1hfWFjtq .rough-node .label text,#mermaid-svg-NtlhAxlk1hfWFjtq .node .label text,#mermaid-svg-NtlhAxlk1hfWFjtq .image-shape .label,#mermaid-svg-NtlhAxlk1hfWFjtq .icon-shape .label{text-anchor:middle;}#mermaid-svg-NtlhAxlk1hfWFjtq .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NtlhAxlk1hfWFjtq .rough-node .label,#mermaid-svg-NtlhAxlk1hfWFjtq .node .label,#mermaid-svg-NtlhAxlk1hfWFjtq .image-shape .label,#mermaid-svg-NtlhAxlk1hfWFjtq .icon-shape .label{text-align:center;}#mermaid-svg-NtlhAxlk1hfWFjtq .node.clickable{cursor:pointer;}#mermaid-svg-NtlhAxlk1hfWFjtq .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NtlhAxlk1hfWFjtq .arrowheadPath{fill:#333333;}#mermaid-svg-NtlhAxlk1hfWFjtq .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NtlhAxlk1hfWFjtq .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NtlhAxlk1hfWFjtq .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NtlhAxlk1hfWFjtq .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NtlhAxlk1hfWFjtq .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NtlhAxlk1hfWFjtq .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NtlhAxlk1hfWFjtq .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NtlhAxlk1hfWFjtq .cluster text{fill:#333;}#mermaid-svg-NtlhAxlk1hfWFjtq .cluster span{color:#333;}#mermaid-svg-NtlhAxlk1hfWFjtq div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NtlhAxlk1hfWFjtq .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NtlhAxlk1hfWFjtq rect.text{fill:none;stroke-width:0;}#mermaid-svg-NtlhAxlk1hfWFjtq .icon-shape,#mermaid-svg-NtlhAxlk1hfWFjtq .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NtlhAxlk1hfWFjtq .icon-shape p,#mermaid-svg-NtlhAxlk1hfWFjtq .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NtlhAxlk1hfWFjtq .icon-shape .label rect,#mermaid-svg-NtlhAxlk1hfWFjtq .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NtlhAxlk1hfWFjtq .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NtlhAxlk1hfWFjtq .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NtlhAxlk1hfWFjtq :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} IMR中断路径
EMR事件路径
输入线出现选定边沿
EXTI边沿检测
开启哪条路径
PR挂起位置位
NVIC
CPU执行ISR
事件脉冲
唤醒/芯片规定的事件消费者

准确性补充 :事件路径确实不让 CPU 进入中断函数,但并不代表任意 EXTI 线都能随意触发任意 ADC、DMA 或外设。具体能连接到什么功能要看该芯片的触发源表和内部互连。对 Cortex-M 来说,事件还可配合 WFE 用于唤醒。

7.3 当前芯片到底有多少条 EXTI 线

老师 PPT 按完整 STM32F1 系列框图列出:

  • GPIO EXTI0~EXTI15:16 条;
  • PVD、RTC 闹钟、USB 唤醒;
  • 互联型产品还有 Ethernet 唤醒。

参考手册 PDF 第 134 页明确区分:互联型产品有 20 条输入线,其他产品有 19 条。STM32F103C8T6 不带 Ethernet,因此当前芯片应按 19 条 EXTI 输入线理解,而不是把 ETH 线也算进来。


8. GPIO → AFIO → EXTI → NVIC → CPU

图 5 老师 PPT 第 47 页:GPIO 经 AFIO 选择后进入 EXTI,再分别去 NVIC 或事件路径。

这是本节最重要的整条信号链:
#mermaid-svg-sFvSlXSsXtYeU876{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-sFvSlXSsXtYeU876 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sFvSlXSsXtYeU876 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sFvSlXSsXtYeU876 .error-icon{fill:#552222;}#mermaid-svg-sFvSlXSsXtYeU876 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sFvSlXSsXtYeU876 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sFvSlXSsXtYeU876 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sFvSlXSsXtYeU876 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sFvSlXSsXtYeU876 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sFvSlXSsXtYeU876 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sFvSlXSsXtYeU876 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sFvSlXSsXtYeU876 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sFvSlXSsXtYeU876 .marker.cross{stroke:#333333;}#mermaid-svg-sFvSlXSsXtYeU876 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sFvSlXSsXtYeU876 p{margin:0;}#mermaid-svg-sFvSlXSsXtYeU876 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-sFvSlXSsXtYeU876 .cluster-label text{fill:#333;}#mermaid-svg-sFvSlXSsXtYeU876 .cluster-label span{color:#333;}#mermaid-svg-sFvSlXSsXtYeU876 .cluster-label span p{background-color:transparent;}#mermaid-svg-sFvSlXSsXtYeU876 .label text,#mermaid-svg-sFvSlXSsXtYeU876 span{fill:#333;color:#333;}#mermaid-svg-sFvSlXSsXtYeU876 .node rect,#mermaid-svg-sFvSlXSsXtYeU876 .node circle,#mermaid-svg-sFvSlXSsXtYeU876 .node ellipse,#mermaid-svg-sFvSlXSsXtYeU876 .node polygon,#mermaid-svg-sFvSlXSsXtYeU876 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-sFvSlXSsXtYeU876 .rough-node .label text,#mermaid-svg-sFvSlXSsXtYeU876 .node .label text,#mermaid-svg-sFvSlXSsXtYeU876 .image-shape .label,#mermaid-svg-sFvSlXSsXtYeU876 .icon-shape .label{text-anchor:middle;}#mermaid-svg-sFvSlXSsXtYeU876 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-sFvSlXSsXtYeU876 .rough-node .label,#mermaid-svg-sFvSlXSsXtYeU876 .node .label,#mermaid-svg-sFvSlXSsXtYeU876 .image-shape .label,#mermaid-svg-sFvSlXSsXtYeU876 .icon-shape .label{text-align:center;}#mermaid-svg-sFvSlXSsXtYeU876 .node.clickable{cursor:pointer;}#mermaid-svg-sFvSlXSsXtYeU876 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-sFvSlXSsXtYeU876 .arrowheadPath{fill:#333333;}#mermaid-svg-sFvSlXSsXtYeU876 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-sFvSlXSsXtYeU876 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-sFvSlXSsXtYeU876 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sFvSlXSsXtYeU876 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-sFvSlXSsXtYeU876 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sFvSlXSsXtYeU876 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-sFvSlXSsXtYeU876 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-sFvSlXSsXtYeU876 .cluster text{fill:#333;}#mermaid-svg-sFvSlXSsXtYeU876 .cluster span{color:#333;}#mermaid-svg-sFvSlXSsXtYeU876 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-sFvSlXSsXtYeU876 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-sFvSlXSsXtYeU876 rect.text{fill:none;stroke-width:0;}#mermaid-svg-sFvSlXSsXtYeU876 .icon-shape,#mermaid-svg-sFvSlXSsXtYeU876 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sFvSlXSsXtYeU876 .icon-shape p,#mermaid-svg-sFvSlXSsXtYeU876 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-sFvSlXSsXtYeU876 .icon-shape .label rect,#mermaid-svg-sFvSlXSsXtYeU876 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sFvSlXSsXtYeU876 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-sFvSlXSsXtYeU876 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-sFvSlXSsXtYeU876 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 外部器件
GPIO输入电平
AFIO选择端口来源
EXTI边沿检测与屏蔽
NVIC使能与优先级
CPU
固定名称ISR
处理并清除挂起位

以后写外部中断代码时,可以按这条链逐层配置和排错:

  1. GPIO 是否正确读取电平;
  2. AFIO 是否把正确端口映射到 EXTI 线;
  3. EXTI 是否选择正确线、模式和触发沿;
  4. NVIC 是否使能正确 IRQ 通道并设置合法优先级;
  5. ISR 名称是否正确,是否判断并清除挂起位。

9. 为什么相同 Pin 号不能同时作为 EXTI

AFIO 中的 EXTICR 是多路选择器。EXTI 线号只由 Pin 编号决定:

GPIO 引脚 可能连接的 EXTI 线
PA0、PB0、PC0...... EXTI0,只能选其中一个端口
PA1、PB1、PC1...... EXTI1,只能选其中一个端口
PA14、PB14、PC14...... EXTI14,只能选其中一个端口

所以:

  • PA0 + PB0:冲突,二者都要占用 EXTI0;
  • PA0 + PB1:不冲突,分别使用 EXTI0、EXTI1;
  • PB0 + PB1:不冲突,当前编码器工程就是这种选择。

AFIO 不是把所有端口的 16 根线都同时送给 EXTI,而是对每个 Pin 编号选一个端口来源。

图 6 师兄笔记 PDF 第 35 页:EXTI 总体结构、AFIO 数据选择器和常见门电路符号。

AFIO 挂在 APB2,总线时钟必须开启后才能修改 AFIO_EXTICR1~4。它还有另一个任务:配置片上外设复用引脚的重映射。


10. EXTI 到 NVIC 为什么不是 16 个独立 IRQ

GPIO 有 EXTI0~EXTI15 共 16 条线,但 NVIC 侧进行了合并:

EXTI 线 NVIC IRQ/中断函数
EXTI0 EXTI0_IRQn / EXTI0_IRQHandler
EXTI1 EXTI1_IRQn / EXTI1_IRQHandler
EXTI2 EXTI2_IRQn / EXTI2_IRQHandler
EXTI3 EXTI3_IRQn / EXTI3_IRQHandler
EXTI4 EXTI4_IRQn / EXTI4_IRQHandler
EXTI5~9 EXTI9_5_IRQn / EXTI9_5_IRQHandler
EXTI10~15 EXTI15_10_IRQn / EXTI15_10_IRQHandler

共享中断函数中必须读取挂起标志,判断具体是哪条线触发;处理后还要清除对应挂起位。

例如 EXTI14 进入 EXTI15_10_IRQHandler(),不能只看到函数被调用就直接计数,否则同组的 EXTI10~15 任何已启用线都可能让逻辑误动作。


11. EXTI 内部框图怎样读

图 7 老师 PPT 第 49 页:边沿选择、软件触发、挂起、屏蔽和事件脉冲路径。

从右侧输入线向左读:

  1. 输入线进入边沿检测电路;
  2. RTSR 选择是否检测上升沿;
  3. FTSR 选择是否检测下降沿;
  4. 软件可通过 SWIER 产生同类触发;
  5. 触发后设置 PR 挂起位;
  6. IMR 打开时,请求进入 NVIC;
  7. EMR 打开时,触发脉冲发生器产生事件。

11.1 六个核心寄存器

寄存器 全称/作用 记忆方法
EXTI_IMR 中断屏蔽 中断路径开关
EXTI_EMR 事件屏蔽 事件路径开关
EXTI_RTSR 上升沿触发选择 Rising
EXTI_FTSR 下降沿触发选择 Falling
EXTI_SWIER 软件中断事件 Software
EXTI_PR 挂起标志 Pending

PR 是下一节代码中最容易漏掉的点:对应位写 1 清除 ,不是写 0。若 ISR 不清挂起位,退出后可能再次进入中断,看起来像主程序被卡死。

图 8 师兄笔记 PDF 第 36 页:EXTI 内部框图的中断/事件路径,以及编码器正交信号。


12. 什么设备适合使用外部中断

适合 EXTI 的信号通常具有三项特征:

  • 外部驱动:由传感器、编码器、接收器等外部设备决定;
  • 突发/异步:发生时刻不可预知;
  • 边沿短促:处理晚了可能漏脉冲。

典型应用:

  • 对射式红外传感器计次;
  • 低速旋转编码器边沿计数;
  • 红外遥控接收波形;
  • 外部芯片的中断请求引脚。

12.1 为什么不推荐用 EXTI 直接读普通按键

按键虽是外部突发事件,但它:

  • 按下和松开都存在机械抖动;
  • 电平维持时间较长,不容易被普通轮询漏掉;
  • 在 ISR 中延时消抖会长时间占用中断;
  • 若开双边沿,抖动会制造大量中断请求。

普通人机按键更适合主循环扫描,或用定时器周期扫描实现非阻塞消抖。若确需 EXTI,可让中断只记录事件/时间戳,真正消抖在主循环或定时任务中完成。


13. 旋转编码器与正交波形

图 9 老师 PPT 第 50 页:机械触点式、霍尔式和光栅式旋转编码器。

13.1 单路输出为什么不能判断方向

单路方波只能告诉程序"出现了多少个周期"和"周期多快"。无论正转还是反转,都可能得到相同方波,因此无法区分方向。

13.2 两路正交信号怎样判断方向

A、B 两相相差 90°:

text 复制代码
正转:A 先变化,B 后变化
反转:B 先变化,A 后变化

一种常见判断方法是:在 A 的某个边沿触发中断时立即读取 B 的电平;B 的当时状态不同,对应两个方向。也可以 A、B 两路都设中断,在任一相下降沿时读取另一相。
#mermaid-svg-n6VMbIF731KbPcwX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-n6VMbIF731KbPcwX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-n6VMbIF731KbPcwX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-n6VMbIF731KbPcwX .error-icon{fill:#552222;}#mermaid-svg-n6VMbIF731KbPcwX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-n6VMbIF731KbPcwX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-n6VMbIF731KbPcwX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-n6VMbIF731KbPcwX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-n6VMbIF731KbPcwX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-n6VMbIF731KbPcwX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-n6VMbIF731KbPcwX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-n6VMbIF731KbPcwX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-n6VMbIF731KbPcwX .marker.cross{stroke:#333333;}#mermaid-svg-n6VMbIF731KbPcwX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-n6VMbIF731KbPcwX p{margin:0;}#mermaid-svg-n6VMbIF731KbPcwX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-n6VMbIF731KbPcwX .cluster-label text{fill:#333;}#mermaid-svg-n6VMbIF731KbPcwX .cluster-label span{color:#333;}#mermaid-svg-n6VMbIF731KbPcwX .cluster-label span p{background-color:transparent;}#mermaid-svg-n6VMbIF731KbPcwX .label text,#mermaid-svg-n6VMbIF731KbPcwX span{fill:#333;color:#333;}#mermaid-svg-n6VMbIF731KbPcwX .node rect,#mermaid-svg-n6VMbIF731KbPcwX .node circle,#mermaid-svg-n6VMbIF731KbPcwX .node ellipse,#mermaid-svg-n6VMbIF731KbPcwX .node polygon,#mermaid-svg-n6VMbIF731KbPcwX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-n6VMbIF731KbPcwX .rough-node .label text,#mermaid-svg-n6VMbIF731KbPcwX .node .label text,#mermaid-svg-n6VMbIF731KbPcwX .image-shape .label,#mermaid-svg-n6VMbIF731KbPcwX .icon-shape .label{text-anchor:middle;}#mermaid-svg-n6VMbIF731KbPcwX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-n6VMbIF731KbPcwX .rough-node .label,#mermaid-svg-n6VMbIF731KbPcwX .node .label,#mermaid-svg-n6VMbIF731KbPcwX .image-shape .label,#mermaid-svg-n6VMbIF731KbPcwX .icon-shape .label{text-align:center;}#mermaid-svg-n6VMbIF731KbPcwX .node.clickable{cursor:pointer;}#mermaid-svg-n6VMbIF731KbPcwX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-n6VMbIF731KbPcwX .arrowheadPath{fill:#333333;}#mermaid-svg-n6VMbIF731KbPcwX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-n6VMbIF731KbPcwX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-n6VMbIF731KbPcwX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-n6VMbIF731KbPcwX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-n6VMbIF731KbPcwX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-n6VMbIF731KbPcwX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-n6VMbIF731KbPcwX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-n6VMbIF731KbPcwX .cluster text{fill:#333;}#mermaid-svg-n6VMbIF731KbPcwX .cluster span{color:#333;}#mermaid-svg-n6VMbIF731KbPcwX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-n6VMbIF731KbPcwX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-n6VMbIF731KbPcwX rect.text{fill:none;stroke-width:0;}#mermaid-svg-n6VMbIF731KbPcwX .icon-shape,#mermaid-svg-n6VMbIF731KbPcwX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-n6VMbIF731KbPcwX .icon-shape p,#mermaid-svg-n6VMbIF731KbPcwX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-n6VMbIF731KbPcwX .icon-shape .label rect,#mermaid-svg-n6VMbIF731KbPcwX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-n6VMbIF731KbPcwX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-n6VMbIF731KbPcwX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-n6VMbIF731KbPcwX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 状态组合1
状态组合2
A相出现选定边沿
进入EXTI中断
读取B相电平
计数+1
计数-1

"哪个状态是正转"取决于 A/B 接线和软件定义,交换两相后方向会反过来。

13.3 模块硬件电路

图 10 老师 PPT 第 51 页:A/B 上拉与 RC 滤波,模块 A 接 PB0、B 接 PB1。

模块端子 连接 说明
VCC 3.3 V 模块供电
GND GND 共地
A PB0 EXTI0 候选输入
B PB1 EXTI1 候选输入
C GND 编码器 A/B 两路机械触点的公共端;不是轴按键输出

模块电路用约 10 kΩ 上拉使触点断开时为高电平;触点闭合接地时为低电平。串联电阻和电容形成低通滤波,减弱机械触点抖动与尖峰,但不能保证完全消除所有抖动。

机械编码器适合旋钮等低速人机输入;高速电机测速更适合非接触式编码器和定时器编码器接口,避免 CPU 为每个高速边沿频繁进入 ISR。


14. 下一节代码前先建立配置地图

以下是配套源码交叉验证得到的预习地图,当前录音尚未逐行讲解。

对射式红外传感器计次

text 复制代码
PB14上拉输入
→ AFIO选择PB14连接EXTI14
→ EXTI14下降沿、中断模式
→ NVIC使能EXTI15_10_IRQn
→ EXTI15_10_IRQHandler判断Line14
→ 计数并清除Line14挂起位

旋转编码器计次

text 复制代码
PB0/PB1上拉输入
→ AFIO分别映射到EXTI0/EXTI1
→ 两线下降沿触发
→ NVIC分别使能EXTI0_IRQn/EXTI1_IRQn
→ 边沿中断内读取另一相电平判断方向
→ 计数后清除对应挂起位

两份配套工程均采用 NVIC_PriorityGroup_2。分组配置整个工程只应统一设置一次,多次调用时最后一次会覆盖之前的分组方式。


15. 中断函数的工程规则

  1. ISR 要短:只做必须立即完成的采样、计数、置标志;
  2. 不在 ISR 中长时间 Delay_ms()、等待按键松手或刷新整屏 OLED;
  3. 进入共享 IRQ 后先判断具体 EXTI 挂起位;
  4. 处理结束清除对应挂起位;
  5. 主程序与 ISR 共享且可能异步变化的简单变量,通常需要考虑 volatile
  6. 多字节共享数据或"读取后清零"要考虑原子性,必要时短暂关中断或使用安全交换方式;
  7. ISR 函数名必须与启动文件向量表一致;
  8. 高频信号优先考虑定时器输入捕获、编码器接口或 DMA,避免中断风暴。

配套教学源码中的计数变量未使用 volatile,在当前低优化入门工程中通常能观察到预期现象;从语言和工程可靠性角度,凡会被 ISR 异步修改、又被主程序读取的变量,应审视是否需要 volatilevolatile 解决编译器缓存/省略访问问题,不解决复合操作的原子性和并发竞争。


16. 易错点与转写校正

  1. EXIT 应为 EXTIExternal Interrupt 是外部中断,STM32 模块全称还包括 Event。
  2. 转写中的 NYC 应为 NVICAFL 应为 AFIO
  3. 中断不是并行执行,而是 CPU 保存现场后改变执行路线。
  4. 中断返回地址不是调试器 breakpoint。
  5. 优先级数值越小越高。
  6. 只有更高抢占优先级能嵌套;响应优先级不能抢占正在运行的 ISR。
  7. PA0/PB0/PC0 共享 EXTI0 来源选择,不能同时映射;PB0/PB1 可以。
  8. EXTI5~9 和 EXTI10~15 各自共享一个 NVIC 通道,ISR 内必须看挂起位。
  9. STM32F103C8T6 不是"68 个可屏蔽中断"的最大 F1 配置;数据手册给出最多 43 个。
  10. 当前芯片按 19 条 EXTI 输入线理解,Ethernet 唤醒线只属于相关互联型产品。
  11. EXTI_PR 对应位写 1 清除,不是写 0
  12. 事件响应不执行 ISR,也不能凭空连接任意外设。
  13. 机械编码器和按键会抖动,外部中断会把抖动放大成多个请求。

17. 复习自测

  1. 中断与轮询各适合什么信号?
  2. 中断发生后,CPU 为什么能回到原程序继续执行?
  3. NVIC 在外设与 CPU 之间承担哪些任务?
  4. 抢占优先级和响应优先级的区别是什么?
  5. 分组 2 中两种优先级的合法范围分别是多少?
  6. 为什么 PA0 和 PB0 不能同时映射到 EXTI,而 PA0 和 PB1 可以?
  7. EXTI 中断路径和事件路径有什么区别?
  8. 为什么 EXTI10~15 的 ISR 必须检查挂起标志?
  9. EXTI_PR 应怎样清除?
  10. 为什么普通按键通常不建议直接用 EXTI 加延时消抖?
  11. 单路编码器为什么无法判断方向?
  12. A 相边沿到来时读取 B 相,为什么能判断旋转方向?
  13. 当前 STM32F103C8T6 应按多少个可屏蔽中断、多少条 EXTI 输入线理解?

18. 资料定位

内容 资料位置
中断概念、优先级、嵌套 老师 PPT 第 41~42 页;录音 01:26--05:07
中断向量表与 STM32 中断概览 老师 PPT 第 43 页;录音 05:07--07:48;参考手册 PDF 第 130~133 页
NVIC 基本结构 老师 PPT 第 44 页;师兄笔记 PDF 第 33 页;录音 07:48--08:56
NVIC 分组 老师 PPT 第 45 页;师兄笔记 PDF 第 34 页;录音 08:56--11:23
NVIC 寄存器与优先级 STM32F10xxx Cortex-M3编程手册.pdf 第 118~129 页;分组寄存器 SCB_AIRCR 第 134 页
当前型号最多 43 个可屏蔽中断 STM32F103x8B数据手册(中文).pdf 第 7 页
EXTI 功能与触发方式 老师 PPT 第 46 页;师兄笔记 PDF 第 34 页;录音 11:23--13:45
EXTI 总体结构 老师 PPT 第 47 页;师兄笔记 PDF 第 35 页;录音 13:45--15:27
AFIO 中断引脚选择 老师 PPT 第 48 页;师兄笔记 PDF 第 35 页;参考手册 PDF 第 126~129、137 页
EXTI 框图和寄存器 老师 PPT 第 49 页;师兄笔记 PDF 第 36 页;参考手册 PDF 第 134~141 页
旋转编码器原理与硬件 老师 PPT 第 50~51 页;师兄笔记 PDF 第 36 页;录音 20:12--24:32
下一节红外计次源码 程序源码/STM32Project-有注释版/5-1 对射式红外传感器计次/Hardware/CountSensor.c
下一节编码器源码 程序源码/STM32Project-有注释版/5-2 旋转编码器计次/Hardware/Encoder.c

PDF 页码均按项目文件在阅读器中的 PDF 页码记录。师兄笔记为扫描件,正文已实际查看对应页面后引用。

19. 一句话总结

外部信号的边沿先由 AFIO 选择 GPIO 来源,再由 EXTI 检测和挂起,经 NVIC 按优先级交给 CPU;ISR 应快速处理、清除标志并返回,而正交编码器正是利用两相边沿先后关系完成增量与方向判断。

相关推荐
摇滚侠19 分钟前
《SpringBoot 3:入门与应用实战》第 9 章 使用 WebMvc 开发应用 阅读笔记 21
java·spring boot·笔记
jianqiang.xue24 分钟前
低功耗产品架构专项优化:电池供电设备休眠、唤醒、漏电流、待机功耗极致优化
stm32·单片机·mcu·物联网·架构·esp32
艾莉丝努力练剑30 分钟前
【AI大模型接入SDK】WebSocket & SSE 协议
网络·c++·websocket·网络协议·学习·面试
Mount25632 分钟前
STM32CubeIDE使用教程(自用)
stm32·嵌入式硬件
xieliyu.33 分钟前
计算机网络‑IP 协议解析:核心特性总结
网络·笔记·网络协议·学习·tcp/ip·计算机网络
陈年老古董38 分钟前
PyTorch 实现 MNIST 手写数字识别学习笔记
笔记·python·深度学习·学习
其实防守也摸鱼39 分钟前
智能体推荐:精选 AI Agent 工具与实战指南
运维·开发语言·人工智能·学习·web安全·自动化
风123456789~43 分钟前
【架构设计】3.2 信息化系统的典型应用 3/6
笔记·系统架构设计
风123456789~1 小时前
【架构设计】第3章 信息系统基础知识 1/6
笔记·系统架构设计