STM32——外部中断(EXTI)

embedded/2024/9/23 1:41:02/

目录

前言

一、外部中断基础知识

二、使用步骤

 三、固件库实现

四、STM32CubeMX实现

总结



前言

        外部中断(External Interrupt,简称EXTI)是微控制器用于响应外部事件的一种方式,当外部事件发生时(如按键按下、传感器信号变化等),微控制器会暂时停止当前正在执行的程序,转而执行相应的中断服务程序(ISR),处理完中断后再回到原来的程序继续执行。STM32的外部中断是STM32微控制器中一个重要的功能,用于接收和处理来自外部设备的信号或事件,在一定程度上提升了系统的实时性能。STM32的每个GPIO(通用输入输出)端口都支持外部中断功能,这使得STM32能够灵活地处理各种外部事件。

        对中断概念不清晰的可以参考:什么是中断-CSDN博客


一、外部中断基础知识

        STM32 的每个 IO 都可以作为外部中断 的中断输入口,在STM32F103 的中断控制器支持 19 个外部中断/ 事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。STM32F103 的 19 个外部中断分别为:

        线 0~15:对应外部 IO 口的输入中断。

        线 16:连接到 PVD 输出。

        线 17:连接到 RTC 闹钟事件。

        线 18:连接到 USB 唤醒事件。

外部的GPIO引脚与线0~15对应,16条中断线都可以映射给GPIO口,但是每条线只能映射给一个个端口,如0线已经映射给 PA0端口,则就不能再映射给Px0端口(x为B、C、D、E、F等),如下图所示:

STM32中断具有以下特性:

        1、每个中断/事件都有独立的触发和屏蔽:可以独立配置每个中断/事件的触发条件和屏蔽状态。

        2、每个中断线都有专用的状态位:可以方便地查询和清除中断请求的状态。

        3、支持多达20个软件的中断/事件请求:STM32F1系列等型号具有丰富的外部中断资源。

        4、 检测脉冲宽度低于APB2时钟宽度的外部信号:能够准确检测快速变化的外部信号。

二、使用步骤

初始化 IO 口为输入将需要用作外部中断的GPIO口配置为输入模式,并设置合适的上下拉电阻(如果需要)。

开启 AFIO 时钟使能GPIO和外部中断控制器的时钟。STM32的外部中断控制器的时钟通常挂载在APB2时钟组下。

设置 IO 口与中断线的映射关系通过配置AFIO(模拟功能输入输出)的寄存器,将GPIO口与外部中断线连接起来。STM32的GPIO端口号与外部中断号之间存在对应关系,如所有GPIO组的0管脚对应外部中断0。

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
// 如,把PA0与中断线line0连接起来
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);

配置中断触发方式设置外部中断的触发方式(上升沿触发、下降沿触发或上升下降沿触发)。

typedef struct
{uint32_t EXTI_Line; // 中断线选择,EXTI_Line0~EXTI_Line15EXTIMode_TypeDef EXTI_Mode; //中断模式,可选值为中断 EXTI_Mode_Interrupt 和事件EXTI_Mode_EventEXTITrigger_TypeDef EXTI_Trigger; //触发方式,EXTI_Trigger_Falling,EXTI_Trigger_Rising,EXTI_Trigger_Rising_Falling。FunctionalState EXTI_LineCmd; //是否使能中断线
}EXTI_InitTypeDef;

初始化NVIC(嵌套向量中断控制器)配置中断分组,配置中断的优先级和使能中断。STM32支持抢占式优先级和子优先级,可以根据需要配置中断的优先级。

编写中断服务函数编写与中断号对应的中断服务函数,并在其中处理中断逻辑,在多条线共用的中断函数中需要添加具体判断。

EXPORT EXTI0_IRQHandler 
EXPORT EXTI1_IRQHandler 
EXPORT EXTI2_IRQHandler 
EXPORT EXTI3_IRQHandler 
EXPORT EXTI4_IRQHandler 
EXPORT EXTI9_5_IRQHandler 
EXPORT EXTI15_10_IRQHandler

 三、固件库实现

        配置PA0引脚为外部中断,下降沿触发中断。

//外部中断0配置
void EXTIX_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE); //使能 PORTA,PORTE 时钟和使能 AFIO 时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IUP; //PA0 设置成输入,上拉
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA0GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStructure); //初始化 EXTI 寄存器NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能外部中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2,NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级 2NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道NVIC_Init(&NVIC_InitStructure);//初始化 NVIC
}

        中断服务函数:

void EXTI0_IRQHandler(void)
{if(EXTI_GetITStatus(EXTI_Line0)!=RESET)//判断某个线上的中断是否发生 {//中断任务EXTI_ClearITPendingBit(EXTI_Line0); //清除 LINE0 上的中断标志位 }}

         其他相关函数:

        中断优先级分组,但凡涉及到中断,必须进行中断优先级分组,系统才能进行中断优先级的设定。

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置 NVIC 中断分组 2

四、STM32CubeMX实现

         同样配置上面固件库的内容。

         配置完成后,生成Keil工程,然后在其中编写中断服务函数。     

         可以在Keil中的任何地方实现该函数,系统会自动搜索识别,如下:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin == GPIO_PIN_0){//中断任务实现}
}

        在这里,不需要在进行中断标志位的清除,系统已经帮我们处理好了(如上图所示),我们只需要完成中断任务的功能即可,但是我们需要判断中断线,即GPIO端口。


五、总结

        1、在配置外部中断时,需要确保GPIO口已经正确配置为输入模式,并且已经使能了相应的时钟。

        2、外部中断的触发方式(上升沿、下降沿或上升下降沿)需要根据实际应用场景进行选择。

        3、在中断服务函数中,需要尽快处理完中断逻辑并清除中断标志位,以避免中断嵌套或重复触发。

        4、中断服务函数应该快进快出,避免长时间在中断里跳不出来,影响系统实时性。

       5、尽量不要在中断服务函数里进行延时,特别是HAL_Delay()函数,具体原因请查阅:为什么在中断里调用HAL_Delay时会出现卡死的情况?


http://www.ppmy.cn/embedded/90277.html

相关文章

git操作流程笔记

1、在本地项目文件夹右击鼠标点击Git Bash Here 2、输入git init,这个目录变成git可以管理的仓库,会出现一个.git文件夹,如果没出现的话需要选择“显示隐藏文件”(不会的同学自行百度一下) 3、绑定本地仓库与远程仓库…

PHP中如何实现函数的可变参数列表

在PHP中,实现函数的可变参数列表主要有两种方式:使用func_get_args()函数和使用可变数量的参数(通过...操作符,自PHP 5.6.0起引入)。 1. 使用func_get_args()函数 func_get_args()函数用于获取传递给函数的参数列表&…

Gitlab中access token 和Deploy token的区别

在GitLab中,Access Token和Deploy Token是两种不同类型的令牌,用于不同的目的。以下是它们的主要区别: ### Access Token 1. **用途**: - 用于用户身份验证,允许用户以编程方式访问GitLab API。 - 可以用于克隆…

RabbitMq架构原理剖析及应用

文章目录 RabbitMQ 架构组件1. **Broker** (Broker Server)2. **Exchange**3. **Queue**4. **Producer** (消息生产者)5. **Consumer** (消息消费者)6. **Virtual Hosts** (虚拟主机) 工作流程内部原理1. **队列管理**2. **集群**3. **持久化与内存**4. **性能优化** 高级特性1…

C# 知识点总结

入门 C#程序在.NET上运行,.NET framework包含两个部分: ①:.NET framework类库 ②:公共语言运行库CLR(.NET虚拟机) CLS(公共语言规范) CTS(通用类型系统) .N…

详解C/C++输入输出

前言 C/C输入输出很多,在不同的情况会用不同的输入输出,有的题目在输入时可能换一种输入输出就能不会TLE,有的输入可能要循环输入,但是可以换一种输入直接就能把所有数据输入进去。C/C有哪些常用的输入输出,在什么时候…

c++数组

数组:相同数据类型的元素组成的集合。 如果说变量是一个盒子,那么数组就是一堆盒子为了区分这些盒子,每个盒子都会依次进行编号。 一维数组:单个变量类似于一个空间,一维数组是指在一排,有多个连续的空间。…

【Vulnhub靶机tomato渗透】

第一步:端口扫描 我使用的是webrobot 访问这个ip,就是它了 第二步:目录扫描 打开kali使用dirb命令扫描http://192.168.189.154下的目录 dirb http://192.168.189.154扫描到目录。 第三步:访问目录地址 看到有几个php的文件 第…