STM32_08_中断(☆☆☆)
中断介绍
中断和轮询
中断的硬件连接
EXTI0
- 类似这种梯形就是多选一,例如PB1这个引脚的电平变化会映射到EXTI1硬联。
- STM32 通过SYSCFG(或 F1 系列的 AFIO)的 EXTICR 配置寄存器,将特定 GPIO 引脚(如 PA0、PB1 等)“绑定” 到对应的 EXTI 中断线(EXTIn);当该引脚发生电平变化(上升沿、下降沿等)时,就会触发对应 EXTI 线,进而产生中断请求或事件信号。
- 通过AFIO_EXTICRx配置GPIO线上的外部中断/事件,而如果想让GPIO线映射过来,首先要使能AFIO时钟。
- GPIO变化过程映射到EXTI线上
打开AFIO时钟- EXTI控制器内部
上升沿/下降沿
中断/事件
清除中断到来位
使能中断 - 不能屏蔽
NVIC介绍
NVIC中断优先级
速记:抢占式优先级是主优先级,响应优先级是子优先级。
- 中断A:主1子0
中断B:主0子2
-> 同时到 -> B- 中断A:主1子0
中断B:主0子2
-> A先到,执行, B到了 -> B会抢占A的资源- 中断A:主1子0
中断B:主1子2
-> 同时到 -> A先执行- 中断A:主1子0
中断B:主1子2
-> B先到, 执行, A到了 -> A不会抢占B的资源- 中断A:主1子2
中断B:主1子2
-> 同时到 -> 看表(谁在前谁先运行)
4bit:
主4子0
主:0-15子: ( < 2的n次方)
主3子1
主:0-7子:0-1
主2子2
主:0-3子:0-3
主1子3
主:0-1子:0-7
主0子4
主: 子:0-15
外部EXTI配置
中断处理
思考:
PA0 - EXTI0 - EXTI - NVIC - CPU
谁触发的中断?
EXTI0触发的中断 ,并不是PA0,是PA0映射到了EXTI0,EXTI0一步步触发的中断。
stm32 - 中断处理函数 - 名字定好了 - 启动文件中
打开启动文件: XXX_IRQHandler
EXTI0_IRQHandler
1.中断处理函数
2.EXIT0触发的中断调用该函数
中断处理函数没有定义, 需要开发人员自定义
中断处理流程
中断处理函数
1.APP/EXTI目录
2.APP/EXTI
新建exti.c exti.h
3.添加工程组/ C/C++头文件路径
4.工程组添加 stm32f10x_exti.c - EXTI库函数
KEY0按键
相关库函数和结构体
代码示例:
KEY0按键
思路:
KEY0一旦按下,GPIOE4就映射到了EXTI4上,然后会有一个下降沿,EXTI4设置中断模式,又能检测下降沿,然后发送一个中断信号到NVIC,NVIC发现是EXTI4的中断,给你分配了一个主优先级和子优先级,然后NVIC把中断信号发送到CPU里。
相关库函数和结构体
代码示例:
注意:
EXTI和NVIC有时钟,但是它们自动使能。IRQn在stm32f10x.h头文件的第167行,下面就是各个中断源。
xxxx_IRQn - 中断源 - 谁触发的中断 -
NVIC_InitTypeDef - IRQChannel - 赋值
接下来调用中断处理函数
实战演练
代码示例:
exti.h:
// exti.h
#ifndef __EXTI_H__
#define __EXTI_H__#include "stm32f10x.h"// KEY0
extern void My_EXTI_Init(void);
#endif
exti.c:
// exti.c
#include "exti.h"
#include "systick.h"
#include "beep.h"
#include "key.h"
//
// 中断的初始化 - 发送中断的流程
// KEY0 - GPIOE4
// KEY0 - GPIOE4 - EXTI4 - EXTI控制器 - NVIC - CPU核
//
void My_EXTI_Init(void){// 1.KEY0 - 配置为上拉输入// 2.GPIOE4映射到EXTI4上// 2.1打开AFIO时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);// 2.2将GPIOE3映射到EXTI4上GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4);// 3.EXTI控制器的配置// EXTI4 - 中断模式 - 下降沿触发EXTI_InitTypeDef EXTI_Config;EXTI_Config.EXTI_Line = EXTI_Line4; // EXTI4EXTI_Config.EXTI_Mode = EXTI_Mode_Interrupt; // 中断模式EXTI_Config.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿EXTI_Config.EXTI_LineCmd = ENABLE; // 使能EXTI_Init(&EXTI_Config);// 4.NVIC控制器的配置// EXTI4触发的中断 - 主1 - 子2 - 使能NVIC_InitTypeDef NVIC_Config; NVIC_Config.NVIC_IRQChannel = EXTI4_IRQn; // EXTI4触发的中断NVIC_Config.NVIC_IRQChannelPreemptionPriority = 1;NVIC_Config.NVIC_IRQChannelSubPriority = 2;NVIC_Config.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_Config);
}
//
// 中断处理函数到启动文件(.s)中找
// 中断处理函数
// 触发该函数 - KEY0按下 - 蜂鸣器控制
//
void EXTI4_IRQHandler(void){// 判断是否是EXTI4触发的中断if(EXTI_GetITStatus(EXTI_Line4) == SET){// 业务处理delay_ms(10); // 去抖动if(KEY0 == 0)BEEP = !BEEP;}// 清除中断到来位EXTI_ClearITPendingBit(EXTI_Line4);
}
main.c:
// main.c
#include "stm32f10x.h"
#include "led.h"
#include "beep.h"
#include "system.h"
#include "systick.h"
#include "key.h"
#include "exti.h"int main(void)
{// |--|--|NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// LED初始化 LED_Init();// BEEP初始化 BEEP_Init();// systick初始化 Systick_Init();// KEY初始化KEY_Init();// EXTI初始化// 作用:按下KEY0 - EXTI4 - EXTI -NVIC -> 中断信号 -> CPU核My_EXTI_Init();while(1){// 业务逻辑 - 做其他事情LED1 = !LED1;delay_ms(1000);}// 启动文件 - main函数 - 初始化 - while(1)// while(1) -------(1)-----------------> 执行// ^CPU核// /// 按下KEY0->中断信号// CPU核从(1)停止 -> 执行中断处理函数// EXTI4_IRQHandler// 执行完返回(1)继续
}
补充:
- 和中断相关的三类函数:
xxx_ITConfig - 打开/关闭控制器的某个中断
xxx_GetITStatus - 判断某个中断是否到来
xxx_ClearITPendingBit - 中断中断到来位- EXTI_GetITStatus(EXTI_Line4) == SET的作用
例如:
EXTI6触发了中断, 调用其中断处理函数
// EXTI5 6 7 8 9 触发的中断调用该函数
// 问 - 是哪个硬件线触发的中断调用的该函数
void EXTI9_5_IRQHandler(void){
if(EXTI_GetITStatus(EXTI_Line5) == SET){...}
else if(EXTI_GetITStatus(EXTI_Line6) == SET){...}
else if(EXTI_GetITStatus(EXTI_Line7) == SET){...}
else if(EXTI_GetITStatus(EXTI_Line8) == SET){...}
else if(EXTI_GetITStatus(EXTI_Line9) == SET){...}
}
拓展:
循环开关灯,按下key0触发中断,开启蜂鸣器;按下key_up触发中断,关闭蜂鸣器。
。
KEY_UP使用中断来触发:
PA0 - 下拉输入
低电平 - 高电平 - 低电平
检测 - 上升沿
谁触发的中断 - EXTI0初始化函数:
1.PA0 映射到EXTI0
2.EXTI配置 - EXTI0, 中断模式, 上升沿, 使能
3.NVIC配置 - EXTI0, 主1, 子0, 使能中断处理函数:
EXTI0_IRQHandler
exti.c:
// exti.c
#include "exti.h"
#include "systick.h"
#include "beep.h"
#include "key.h"
//
// 中断的初始化 - 发送中断的流程
// KEY0 - GPIOE4
// KEY0 - GPIOE4 - EXTI4 - EXTI控制器 - NVIC - CPU核
// KEY_UP - GPIOA0 - EXTI0 - EXTI控制器 - NVIC - CPU核
//
void My_EXTI_Init(void){// 1.KEY0 - 配置为上拉输入// 1.2KEY_UP配置为下拉输入// 2.GPIOE4映射到EXTI4上// 2.1打开AFIO时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);// 2.2将GPIOE3映射到EXTI4上GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4);// 2.2将GPIOA0映射到EXTI0上GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);// 3.EXTI控制器的配置// EXTI4 - 中断模式 - 下降沿触发EXTI_InitTypeDef EXTI_Config;EXTI_Config.EXTI_Line = EXTI_Line4; // EXTI4EXTI_Config.EXTI_Mode = EXTI_Mode_Interrupt; // 中断模式EXTI_Config.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿EXTI_Config.EXTI_LineCmd = ENABLE; // 使能EXTI_Init(&EXTI_Config);// 3.2EXTI0 - 中断模式 - 上升沿触发EXTI_Config.EXTI_Line = EXTI_Line0;EXTI_Config.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_Config.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_Config.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_Config);// 4.NVIC控制器的配置// EXTI4触发的中断 - 主1 - 子2 - 使能NVIC_InitTypeDef NVIC_Config; NVIC_Config.NVIC_IRQChannel = EXTI4_IRQn; // EXTI4触发的中断NVIC_Config.NVIC_IRQChannelPreemptionPriority = 1;NVIC_Config.NVIC_IRQChannelSubPriority = 2;NVIC_Config.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_Config);// 4.2EXTI0触发的中断 - 主1 - 子0 - 使能NVIC_Config.NVIC_IRQChannel = EXTI0_IRQn;NVIC_Config.NVIC_IRQChannelPreemptionPriority = 1;NVIC_Config.NVIC_IRQChannelSubPriority = 0;NVIC_Config.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_Config);
}
//
// 中断处理函数到启动文件(.s)中找
// 中断处理函数
// 触发该函数 - KEY0按下 - 蜂鸣器控制
//
void EXTI4_IRQHandler(void){// 判断是否是EXTI4触发的中断if(EXTI_GetITStatus(EXTI_Line4) == SET){// 业务处理delay_ms(10); // 去抖动if(KEY0 == 0)BEEP = 1;}// 清除中断到来位EXTI_ClearITPendingBit(EXTI_Line4);
}void EXTI0_IRQHandler(void){// 判断是否是EXTI0触发的中断if(EXTI_GetITStatus(EXTI_Line0) == SET){// 业务处理delay_ms(10);if(KEY_UP == 1)BEEP = 0;}// 清除中断到来位EXTI_ClearITPendingBit(EXTI_Line0);
}
main.c:
// main.c
#include "stm32f10x.h"
#include "led.h"
#include "beep.h"
#include "system.h"
#include "systick.h"
#include "key.h"
#include "exti.h"int main(void)
{// |--|--|NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// |--|--|NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);// LED初始化 LED_Init();// BEEP初始化 BEEP_Init();// systick初始化 Systick_Init();// KEY初始化KEY_Init();// EXTI初始化// 作用:按下KEY0 - EXTI4 - EXTI -NVIC -> 中断信号 -> CPU核My_EXTI_Init();while(1){// 业务逻辑 - 做其他事情LED1 = !LED1;delay_ms(1000);}// 启动文件 - main函数 - 初始化 - while(1)// while(1) -------(1)-----------------> 执行// ^CPU核// /// 按下KEY0->中断信号// CPU核从(1)停止 -> 执行中断处理函数// EXTI4_IRQHandler// 执行完返回(1)继续
}