STM32外设EXTI(外部中断/事件控制器)详解与功能优化

前言

在嵌入式开发中,经常需要处理外部设备产生的信号,如按键、传感器等。STM32微控制器提供了强大的EXTI(External Interrupt/Event Controller)模块来处理这些外部事件。本文将详细介绍如何使用STM32标准库配置和使用EXTI,并提供一个简单的示例代码,帮助大家理解和掌握这一功能。

一、EXTI简介

EXTI是STM32中用于处理外部中断和事件的模块。通过EXTI,可以监测GPIO口电平变化(上升沿、下降沿或双边沿),当EXTI检测到电平变化,将立刻向NVIC发出中断申请,经过NVIC裁决后,中断CPU中断主程序,让CPU执行EXTI对应的中断程序。

主要功能

1)外部中断:当检测到指定GPIO引脚上的电平变化时,产生一个中断请求。

2)外部事件:当检测到指定GPIO引脚上的电平变化时,产生一个事件信号,可用于软件轮询或其他外设(如DMA)。

  • 触发方式:上升沿、下降沿、双边沿、软件触发。

  • 所支持的IO:所有IO,但是相同的Pin不能同时触发中断(例如PA1、PB1这种)

  • 原因:AFIO(类似数据选择器)在筛选的过程中,只有一根线是连接EXTI,以下是图片说明:

  • 外部设备触发:任何外设产生的信号,如果需要即时处理而不是等待当前任务周期结束,都可以通过配置相应的EXTI线路来实现。

  • 触发响应方式:中断响应/事件响应

    按键功能的话尽量用定时器的方式来做。

  • 提一下NVIC

  • 1)抢占优先级:和中断嵌套相关。直接中断病人看病,让医生帮他看。

    2)响应优先级:响应优先级高的可以插队看病

    二、中断/事件线介绍

    STM32的每个IO都可以作为外部中断输入,STM32的中断控制器支持19个外部中断/事件请求,中断线分配:

  • EXTI_Line0 到 EXTI_Line15:对应GPIO端口的所有引脚(PA0-PF15)。

  • EXTI_Line16 到 EXTI_Line27:对应其他一些特殊事件源,如独立看门狗复位事件、PVD输出等。

  • 每个外部中断线可以独立的配置触发方式(上升沿,下降沿或者双边沿触发),触发/屏蔽,专用的状态位。

    三、代码编写

    总结步骤是:

    1、配置系统时钟。

    SystemInit();

    2、配置GPIO。使能引脚时钟,配置输入输出管脚

    void GPIO_Configuration(void)
    {
        GPIO_InitTypeDef GPIO_InitStructure;
    ​
        // 使能GPIOA和GPIOC的时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);
    ​
        // 配置PA0为输入模式(浮空输入)
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
        GPIO_Init(GPIOA, &GPIO_InitStructure);
    ​
        // 配置PC13为推挽输出模式
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOC, &GPIO_InitStructure);
    }

    3、配置EXTI。使能AFIO时钟,映射EXTI线到GPIO引脚,配置EXTI线参数,配置NVIC的中断优先级

    void EXTI_Configuration(void)
    {
        EXTI_InitTypeDef EXTI_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
    ​
        // 使能AFIO时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    ​
        // 连接EXTI Line0到PA0
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
    ​
        // 配置EXTI Line0
        EXTI_InitStructure.EXTI_Line = EXTI_Line0;
        EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发
        EXTI_InitStructure.EXTI_LineCmd = ENABLE;
        EXTI_Init(&EXTI_InitStructure);
    ​
        // 使能并配置EXTI0中断向量
        NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
    }

    4、编写中断服务程序

  • 检查中断标志位:使用EXTI_GetITStatus函数检查是否发生了预期的中断事件。

  • 执行中断处理逻辑:在中断服务程序中实现具体的业务逻辑,比如切换LED状态。

  • 清除中断标志位:使用EXTI_ClearITPendingBit函数清除中断标志位,避免重复中断。

    // EXTI0中断服务程序
    void EXTI0_IRQHandler(void)
    {
        if (EXTI_GetITStatus(EXTI_Line0) != RESET)
        {
            // 切换PC13的状态
            GPIO_WriteBit(GPIOC, GPIO_Pin_13, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13)));
    ​
            // 清除EXTI Line0中断标志位
            EXTI_ClearITPendingBit(EXTI_Line0);
        }
    }

  • 5、编写主程序。主循环中不需要频繁操作,只需保持系统运行即可。

    int main(void)
    {
        // 初始化系统时钟
        SystemInit();
    ​
        // 配置GPIO
        GPIO_Configuration();
    ​
        // 配置EXTI
        EXTI_Configuration();
    ​
        while (1)
        {
            // 主循环中不需要执行其他操作
        }
    }

    总代码

    #include "stm32f10x.h"
    ​
    void GPIO_Configuration(void);
    void EXTI_Configuration(void);
    ​
    int main(void)
    {
        // 初始化系统时钟
        SystemInit();
    ​
        // 配置GPIO
        GPIO_Configuration();
    ​
        // 配置EXTI
        EXTI_Configuration();
    ​
        while (1)
        {
            // 主循环中不需要执行其他操作
        }
    }
    ​
    void GPIO_Configuration(void)
    {
        GPIO_InitTypeDef GPIO_InitStructure;
    ​
        // 使能GPIOA和GPIOC的时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);
    ​
        // 配置PA0为输入模式(浮空输入)
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
        GPIO_Init(GPIOA, &GPIO_InitStructure);
    ​
        // 配置PC13为推挽输出模式
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOC, &GPIO_InitStructure);
    }
    ​
    void EXTI_Configuration(void)
    {
        EXTI_InitTypeDef EXTI_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
    ​
        // 使能AFIO时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    ​
        // 连接EXTI Line0到PA0
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
    ​
        // 配置EXTI Line0
        EXTI_InitStructure.EXTI_Line = EXTI_Line0;
        EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发
        EXTI_InitStructure.EXTI_LineCmd = ENABLE;
        EXTI_Init(&EXTI_InitStructure);
    ​
        // 使能并配置EXTI0中断向量
        NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
    }
    ​
    // EXTI0中断服务程序
    void EXTI0_IRQHandler(void)
    {
        if (EXTI_GetITStatus(EXTI_Line0) != RESET)
        {
            // 切换PC13的状态
            GPIO_WriteBit(GPIOC, GPIO_Pin_13, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13)));
    ​
            // 清除EXTI Line0中断标志位
            EXTI_ClearITPendingBit(EXTI_Line0);
        }
    }

    四、应用场景:

    1)按键输入:当需要检测用户通过按键进行的输入时,可以使用EXTI。这种方式能够及时响应用户的操作,而不需要CPU不断地轮询按键状态。

    2)传感器数据采集:某些传感器在检测到特定事件或达到阈值时,可以通过产生一个中断信号通知处理器。例如,温度超过设定值、光强度变化等场景下,使用EXTI可以实现快速响应。

    3)通信接口:在一些异步通信协议中,比如UART,可能会用到EXTI来捕获起始位从而开始数据接收过程,这允许更有效的数据处理流程。

    4)定时唤醒:在低功耗应用中,为了从睡眠或待机模式中唤醒MCU(微控制器单元),可以设置外部中断以响应特定事件,如时间到达、电池电量低等。

    5)紧急停止信号:在工业控制和其他安全关键型应用中,使用EXTI来立即响应紧急停止信号是非常重要的,这样可以在发生危险时迅速停机。

    作者:小张要努力o!

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32外设EXTI(外部中断/事件控制器)详解与功能优化

    发表回复