超详细!新手必看!STM32-EXTI外部中断


  

一、什么是外部中断?

   外部中断是指由微处理器或微控制器外部引脚(通常是GPIO引脚)上的外部事件触发的中断。这些外部事件可以是来自外部设备、传感器或其他外部信号源的触发。

二、外部中断EXTI详细内容

   由AFIO时钟管理的寄存器有AFIO_EVCR(时间控制寄存器)、AFIO_MAPR(备用功能重映射和调试IO配置寄存器)、AFIO_EXTICRX(外部中断配置寄存器)。我们需要通过AFIO_EXTICRx配置GPIO线上的外部中断/事件,必须先使能AFIO时钟。所以在配置EXTI时需要先开启AFIO时钟。

1. 总线分布

每个不同的GPIO序号对应着不同的EXTI线,在配置时这也是至关重要的一步。
在这里插入图片描述
● EXTI线16连接到PVD输出。
● EXTI线17连接到RTC闹钟事件。
● EXTI线18连接到USB唤醒事件。
● EXTI线19连接到以太网唤醒事件(只适用于互联型产品) 。

2. 相关寄存器

在这里插入图片描述
(1)中断屏蔽寄存器(EXTI_IMR): 屏蔽(置0)或开放(置1)来自线x的中断请求。使能/失能中断。
(2) 挂起寄存器(EXTI_PR) : 没有发生(置0) /发生(置1)触发请求。
当在外部中断线上发生了选择的边沿事件,该位被置’1’。在该位中写入’1’可以清除它,也可以通过改变边沿检测的极性清除。
(3) 事件屏蔽寄存器(EXTI_EMR) : 屏蔽(置0)或开放(置1)来自线x的事件请求。使能/失能事件。
(4)上升沿触发选择寄存器(EXTI_RTSR) : 禁止(置0)或允许(置1)输入线x上的上升沿触发(中断和事件) 。
(5)下降沿触发选择寄存器(EXTI_FTSR) : 禁止(置0)或允许(置1)输入线x上的下降沿触发(中断和事件) 。
(6)软件中断事件寄存器(EXTI_SWIER) : 当该位为’0’时,写’1’将设置EXTI_PR中相应的挂起位。如果在EXTI_IMR和EXTI_EMR中允许产生该中断,则此时将产生一个中断。
注:通过清除EXTI_PR的对应位(写入’1’),可以清除该位为’0’。

3. 框架图分析

在这里插入图片描述
(1) 如果采用外设(输入线)来产生中断,可以选择上升/下降/双边沿触发中断。此时软件中断事件寄存器必须写0。因为软件中断事件寄存器和边沿检测电路通过"或门"连接。如果软件中断寄存器置1,那么会直接产生中断信号,那么外设产生或不产生中断都没有作用。 通过在软件中对软件中断/事件寄存器写 1 ,也可以产生中断/事件请求。
(2) EXTI 可分为两大部分功能,一个是产生中断,另一个是产生事件,这两个功能从硬件上就有所不同。
   ●产生中断线路目的: 是把输入信号输入到 NVIC,进一步会运行中断服务函数,实现功能,这样是软件级的。
   ●产生事件线路目的: 就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。
   ●产生中断步骤: 根据输入线外设电路需要的边沿检测设置触发寄存器,并将 “软件中断事件寄存器” 置0(原因如上述),同时在 “中断屏蔽寄存器” 的相应位写 1 使能中断请求。当外部中断线上出现选定信号沿时,便会产生中断请求,“请求挂起寄存器” 的对应的挂起位会置1。在 “请求挂起寄存器” 的对应位写 1 ,将清除该中断请求。
   ●产生事件的步骤: 根据输入线外设电路需要的边沿检测设置触发寄存器,同时在 “事件屏蔽寄存器” 的相应位写 1 允许事件请求。当事件线上出现选定信号沿时,便会产生事件脉冲。
(3)“脉冲发生器” 去触发事件响应,它主要连到其它外设,中断信号来了就激活脉冲发生器,给它连接的其它外设发射一次脉冲信号。
(4) 两个“屏蔽寄存器”。它们都和我们的信号连到了一个 “与门” 上,这就意味着如果把这个屏蔽寄存器的某些位设为 0,来的中断信号就永远过不去这个与门,达到了一个“屏蔽”的效果。例如不希望某个中断通道起作用,那就把中断屏蔽寄存器的那一位设为 0,这里来的中断信号就永远到不了 NVIC;再例如不需要事件响应的功能,那么就把事件屏蔽器全设为 0,事件响应就无效了。

4. 中断

   GPIO的端口号对应着总线,例如PA1对应总线1,PC3对应总线3。而总线EXTI0~4分别对应着自己的中断,即总线EXTI0使用EXTI0中断,总线EXTI1使用EXTI1中断…
在这里插入图片描述
总线EXTI5~9选择中断EXTI9_5在这里插入图片描述
总线EXTI10~15选择中断EXTI15_10在这里插入图片描述

5. 相关配置

(1)EXTI模式:

typedef enum
{
	EXTI_Mode_Interrupt = 0x00, //产生中断
	EXTI_Mode_Event = 0x04 //产生事件
}EXTIMode_TypeDef;

(2)EXTI触发类型:

typedef enum
{
	EXTI_Trigger_Rising = 0x08, //上升沿
	EXTI_Trigger_Falling = 0x0C, //下降沿
	EXTI_Trigger_Rising_Falling = 0x10 //上升沿和下降沿都触发
}EXTITrigger_TypeDef;

6. 配置示例(以 PA10 为例)

功能:开启外部中断,当PA10引脚为高电平时(上升沿)触发外部中断。

(1)使能时钟(因为GPIO映射外部中断,所以需要开启AFIO时钟)

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	// GPIOA 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);	// AFIO 时钟

(2)配置GPIO引脚

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;		// 以上拉输入模式为例
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

(3)配置GPIO口与外部中断线的映射关系。(PA10挂在EXTI10总线上)

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource10);//外部中断线10与PA10相映射。

(4)配置EXTI

EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line10;		// 选择总线,因为是PA10,所以选择10号线。端口为几就选择几号线。
EXTI_InitStructure.EXTI_LineCmd = ENABLE;		// 使能总线
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	// 中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;	// 上升沿触发,当PA10口为高电平时触发中断。
EXTI_Init(&EXTI_InitStructure);

(5)配置NVIC

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;		// PA10 选择EXTI15_10 
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			// 使能中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	// 抢占优先级,数值范围要注意符合前面分组的规范
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;		// 响应优先级,数值范围要注意符合前面分组的规范
NVIC_Init(&NVIC_InitStructure);

//(5)在主函数配置中断优先组
//NVIC_PriorityGroupConfig(NVIC_Priority_Group_2);

(6)编写中断服务函数

void EXTI15_10_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line10) == SET) {	// 判断 PX10 对应的挂起寄存器是否置位,如果置位说明产生了中断
		EXTI_ClearITPendingBit(EXTI_Line10);	// 清除中断标志位
		// 处理你的中断 ...
	}
}

为什么要在中断服务函数中清除中断标志位?

答:STM32在产生中断信号后,中断标志位会被硬件置1,所以在处理外部中断信号时,中断服务程序应该在最后的清除操作中将中断标志位重新设置为“0”,以保证系统正常运行。如果中断标志位没有被清除,那么即使该中断信号已经被处理完毕,处理器仍然会认为该中断信号还没有被处理,从而一直处于中断状态,无法处理下一次中断。

7. 附录

(1)软件触发中断的库函数.

void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);

三、完整代码

功能:这段代码实现了 STM32 外部中断(EXTI)配置,特别是针对 GPIOC 的第 9 引脚(通常用于按钮输入)。该配置会在按钮按下时(触发下降沿)产生外部中断。

exti.c

#include "exti.h"

void EXTI_Init(void)
{  
    GPIO_InitTypeDef GPIO_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
  
    // 1. 使能 AFIO 时钟(用于配置外部中断线)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);   // 外部中断需要使能 AFIO 时钟

    // 2. 使能 GPIOC 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); // 使能 GPIOC 端口时钟

    // 3. 配置 GPIOC 的第 9 引脚为上拉输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;              // 选择端口为 GPIOC 第 9 引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;           // 配置为上拉输入模式
    GPIO_Init(GPIOC, &GPIO_InitStructure);                  // 初始化 GPIOC 第 9 引脚

    // 4. 配置外部中断线连接到 GPIOC 第 9 引脚
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource9);

    // 5. 配置外部中断(EXTI)
    EXTI_InitStructure.EXTI_Line = EXTI_Line9;              // 选择外部中断线9(对应 GPIOC 第 9 引脚)
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;      // 设置为中断模式
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  // 设置为下降沿触发
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;               // 使能外部中断线
    EXTI_Init(&EXTI_InitStructure);                          // 初始化 EXTI 寄存器

    // 6. 配置中断优先级并使能外部中断通道
    NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;      // 配置中断通道(EXTI9_5_IRQn)
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;  // 设置抢占优先级为 2
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;          // 设置子优先级为 1
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 // 使能外部中断通道
    NVIC_Init(&NVIC_InitStructure);                                  // 初始化 NVIC 配置
}

void EXTI9_5_IRQHandler(void)
{
    // 判断 EXTI_Line9 是否触发了中断
    if (EXTI_GetITStatus(EXTI_Line9) != RESET)
    {
        // 处理 Line9 的中断(例如,控制 LED)
         led=!led; // 切换 LED 状态
        // 清除 EXTI_Line9 中断标志
        EXTI_ClearITPendingBit(EXTI_Line9);
    }
}
### STM32 使用超声波传感器时的外部中断配置及调试方法 #### 配置外部中断用于检测 Echo 信号 为了利用外部中断来捕捉超声波传感器返回的信号,需先设置 GPIO 引脚作为外部中断源。这里假设使用的是 HY-SRF05 超声波传感器,其 `Echo` 引脚连接到 STM32 的某个 GPIO 输入引脚上。 在 STM32CubeMX 中完成基本外设初始化之后: 1. **选择合适的GPIO口** - 将要使用的 GPIO 口配置成输入模式,并启用上升沿或下降沿触发的外部中断事件[^3]。 2. **编写中断服务函数 (ISR)** ```c void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){ if(GPIO_Pin == ECHO_PIN){ // 假定ECHO_PIN是你定义好的宏表示实际使用的PIN编号 static uint8_t state = 0; if(state == 0 && __HAL_GPIO_READ_PIN(ECHO_PORT, ECHO_PIN)){ // 当接收到高电平开始计时 TIM2->CNT = 0; // 清零定时器计数值 state = 1; }else if(state == 1 && !__HAL_GPIO_READ_PIN(ECHO_PORT, ECHO_PIN)){ // 接收低电平时结束计时并计算时间间隔 uint32_t time_us = TIM2->CNT * ((SystemCoreClock / 8000) / 1000); // 计算微秒级的时间差 float distance_cm = (float)(time_us / 58.0f); /* 这里可以加入对distance_cm进一步处理逻辑 */ state = 0; } } } ``` 这段代码实现了对外部中断回调函数的重写,以便能够响应由超声波模块产生的高低电平变化。每当检测到一次完整的高低跳变周期,则认为是一次有效的往返行程测量完毕,并据此推算目标物体间的直线距离[^4]。 请注意上述例子中用到了定时器来进行精确延时操作,这是因为直接依赖 CPU 循环等待的方式难以获得足够的分辨率去衡量微妙级别的延迟差异。因此推荐采用硬件定时器辅助完成这一过程。 对于具体的寄存器访问细节以及如何启动/停止定时器等功能,请参照官方数据手册和库函数文档获取更详尽的信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值