- 中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行
- 中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源
- 中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回
NVIC优先级分组
| 分组方式 |
抢占优先级 |
响应优先级 |
| 分组0 |
0位,取值为0 |
4位,取值为0~15 |
| 分组1 |
1位,取值为0~1 |
3位,取值为0~7 |
| 分组2 |
2位,取值为0~3 |
2位,取值为0~3 |
| 分组3 |
3位,取值为0~7 |
1位,取值为0~1 |
| 分组4 |
4位,取值为0~15 |
0位,取值为0 |
EXTI 外部中断
- EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
- 支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断
- 通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
graph LR
%% 定义样式类
classDef gpio fill:#e1f5fe,stroke:#4fc3f7,stroke-width:2px,color:#0277bd,rx:8,ry:8;
classDef afio fill:#ffebee,stroke:#ef9a9a,stroke-width:2px,color:#c62828,rx:8,ry:8;
classDef exti fill:#fff3e0,stroke:#ffcc80,stroke-width:2px,color:#ef6c00,rx:8,ry:8;
classDef nvic fill:#e8f5e9,stroke:#a5d6a7,stroke-width:2px,color:#2e7d32,rx:8,ry:8;
classDef source fill:#f3e5f5,stroke:#ce93d8,stroke-width:2px,color:#6a1b9a,rx:8,ry:8;
classDef other fill:#eceff1,stroke:#b0bec5,stroke-width:2px,color:#455a64,rx:8,ry:8;
%% 左侧 GPIO 组
subgraph GPIO [GPIO 端口]
direction TB
A[GPIOA]:::gpio
B[GPIOB]:::gpio
C[GPIOC]:::gpio
D[...]:::gpio
end
%% AFIO
AFIO[AFIO
中断引脚选择]:::afio
%% 下方信号源组
subgraph Signals [内部/外部信号源]
direction TB
PVD[PVD]:::source
RTC[RTC]:::source
USB[USB]:::source
ETH[ETH]:::source
end
%% EXTI
EXTI[EXTI
边沿检测及控制]:::exti
%% NVIC
NVIC[NVIC
嵌套向量中断控制器]:::nvic
%% 其它外设
Other[其它外设]:::other
%% 连接关系
A -- "16根线" --> AFIO
B -- "16根线" --> AFIO
C -- "16根线" --> AFIO
AFIO -- "16根线" --> EXTI
PVD --> EXTI
RTC --> EXTI
USB --> EXTI
ETH --> EXTI
EXTI --> EXTI0[EXTI0]
EXTI --> EXTI1[EXTI1]
EXTI --> EXTI2[EXTI2]
EXTI --> EXTI9_5[EXTI9_5]
EXTI --> EXTI15_10[EXTI15_10]
EXTI0 --> NVIC
EXTI1 --> NVIC
EXTI2 --> NVIC
EXTI9_5 --> NVIC
EXTI15_10 --> NVIC
EXTI --> PVD_in[PVD] --> NVIC
EXTI --> RTC_in[RTC] --> NVIC
EXTI --> USB_in[USB] --> NVIC
EXTI --> ETH_in[ETH] --> NVIC
EXTI -- "20根线" --> Other
%% 整体样式设置
style GPIO fill:#f8fbff,stroke:#d6e4f0,stroke-width:2px,stroke-dasharray: 5 5
style Signals fill:#f8fbff,stroke:#d6e4f0,stroke-width:2px,stroke-dasharray: 5 5
AFIO 复用IO口
- 在STM32中,AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择
掌握函数
| 函数 |
说明 |
| GPIO_EXTILineConfig |
将外部中断的线映射到GPIOX |
| EXTI_InitTypeDef |
定义结构体变量 |
| EXTI_Init |
配置EXTI外设 |
| NVIC_PriorityGroupConfig |
NVIC中断分组 |
| NVIC_InitTypeDef |
定义结构体变量 |
| NVIC_Init |
配置NVIC外设 |
| EXTI_GetITStatus |
确认某个 EXTI 中断线是否真正产生了有效的中断请求 |
| EXTI_ClearITPendingBit |
清除外部中断的中断标志位 |
配置步骤
- 开启时钟
- GPIO初始化
- AFIO选择中断引脚
- EXTI初始化
- NVIC中断分组
- NVIC配置
代码演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| void Encoder_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0); GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1); EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_Init(&EXTI_InitStructure); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_Init(&NVIC_InitStructure); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void EXTI0_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line0) == SET) { if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0) { if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0) { Encoder_Count --; } } EXTI_ClearITPendingBit(EXTI_Line0); } }
|