STM32之中断(二)

1. EXTI

1.1 EXTI的简介

• EXTI 是 External Interrupt 的缩写,表示外部中断事件控制器 。EXTI 可以监测指定 GPIO 的电平信号变化,并在检测到指定条件时,向内核的中断控制器NVIC 发出中断申请。NVIC 在裁决后,如果满足条件,会中断CPU的主程序,使CPU转而执行EXTI对应的中断服务程序。

• EXTI 支持的触发方式:上升沿、下降沿、双边沿或软件触发。并且上升沿、下降沿、双边沿这三种方式是常用触发方式,都可以在配置GPIO口的mode中配置,上升沿(GPIO_MODE_IT_RISING),下降沿(GPIO_MODE_IT_FALLING),双边沿(GPIO_MODE_IT_RISING_FALLING)。

• EXTI 支持所有的GPIO口,但需要注意的是,相同的 Pin 不能同时触发中断。例如,PA0 和 PB0 不能同时被 配置为中断源。

• EXTI 提供了16 GPIO_Pin 的中断线 ,以及额外的中断线如 PVD 输出、RTC 闹钟 、USB 唤醒和以太网唤醒。(注意只有互联网芯片才有以太网)。

1.2 中断和事件区别:

• 中断会打断CPU当前正在执行的程序,转而去执行中断服务程序,待中断服务程序执行完毕后,CPU会返回到原来的程序执行点继续执行。

• 事件只是简单地表示某个动作或状态的变化 ,而不会打断CPU当前正在执行的程序。当事件发生时,它会根据配置 来决定是否触发相应的中断。如果开放了对应的**中断屏蔽位,**事件就可以触发相应的中断,如果没有开放相应的中断屏蔽位,事件只会作为一个信号存在,不会被CPU处理。

1.3 EXTI基本结构,如图:

2. AFIO

• AFIO 是 Alternate Function Input/Output 的缩写,表示复用功能IO ,主要用于实现 IO 端口的复用功能 以及外部中断的控制

• STM32上有很多 IO口以及内置外设(如I2C、ADC、SPI、USART等)。为了节省引出引脚的数量,这些内置外设通常与 IO 口共用管脚,即 IO 管脚具有复用功能。例如,一个 GPIO 管脚除了可以作为普通的 IO端口外,还可以被复用为某个内置外设的功能引脚。

• 然而,为了优化64脚或100脚封装的外设数量,有时需要将一些复用功能重新映射到其他引脚上。这时,就可以使用AFIO的复用重映射功能。通过设置复用重映射和调试IO配置寄存器(AFIO_MAPR),可以实现引脚的重新映射,使得复用功能不再映射到它们的原始分配上。

• 此外,AFIO 还用于控制外部中断用来配置 EXTI 中断线 0~15 对应哪个具体 IO

• 当需要使能外部中断线进行外部中断线的映射 时,通常需要开启AFIO 的时钟

• AFIO与IO对应关系,如图:

3. EXIT的配置流程

• 使能GPIO时钟__HAL_RCC_GPIOx_CLK_Enable();

• 设置GPIO输入模式

• 设置AFIO(开启时钟,IO映射)

• 设置EXTI(屏蔽,上下沿)

• 以上三步均在HAL_GPIO_init()函数进行配置,HAL库函数已经对相应寄存器进行封装了

• 设置NVIC(优先级分组,设置优先级,使能中断)

• 设置中断服务函数(EXTIx_IRQHandler())

4. 实操,按键电灯(中断法),按下 KEY1 翻转 LED1 状态,而 LED2 一直保持 500ms 的频率闪烁。

4.1 main.c

cpp 复制代码
#include "sys.h"
#include "exti.h"
#include "delay.h"
#include "led.h"


int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();                         /* LED初始化 */
    exti_init();

    while(1)//流水灯实验
    { 
        led2_on();
        delay_ms(500);
        led2_off();
        delay_ms(500);
    }
}

4.2 led.c

cpp 复制代码
#include "led.h"

void led_init(){
    GPIO_InitTypeDef gpio_init = {0};
    __HAL_RCC_GPIOB_CLK_ENABLE();//使能GPIO时钟
    gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_init.Pin = GPIO_PIN_8 | GPIO_PIN_9;//推挽输出
    gpio_init.Pull = GPIO_PULLUP;//默认上拉
    gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB,&gpio_init);//初始化gpio
    led1_off();//关灯
    led2_off();

}


void led1_on(){
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
}

void led1_off(){
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
}


void led1_toggle(){
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
}

void led2_on(){
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
}

void led2_off(){
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);
}


void led2_toggle(){
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);
}

4.3 exti.c

cpp 复制代码
#include "exti.h"
#include "delay.h"
#include "led.h"

void exti_init(){
    GPIO_InitTypeDef gpio_init = {0};
    __HAL_RCC_GPIOA_CLK_ENABLE();//使能GPIO时钟
    gpio_init.Mode = GPIO_MODE_IT_FALLING;//下降沿触发中断
    gpio_init.Pin = GPIO_PIN_0;//推挽输出
    gpio_init.Pull = GPIO_PULLUP;//默认上拉
    gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA,&gpio_init);//初始化gpio
    HAL_NVIC_SetPriority(EXTI0_IRQn,2,0);//设置优先级
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);//使能中断
}

void EXTI0_IRQHandler(){//中断服务函数没参数和返回值
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);//中断服务公共函数

}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
    delay_ms(20);//消抖
    if(GPIO_Pin == GPIO_PIN_0){
        if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)
             led1_toggle();
    }
}
相关推荐
Y1rong2 小时前
STM32之中断(一)
stm32·单片机·嵌入式硬件
LaoZhangGong1233 小时前
学习TCP/IP的第3步:和SYN相关的数据包
stm32·单片机·网络协议·tcp/ip·以太网
小郭团队3 小时前
2_1_七段式SVPWM (经典算法)算法理论与 MATLAB 实现详解
嵌入式硬件·算法·硬件架构·arm·dsp开发
持戒波罗蜜3 小时前
ubuntu20解决intel wifi 驱动问题
linux·驱动开发·嵌入式硬件·ubuntu
不做无法实现的梦~3 小时前
使用ros2来跑通mid360的驱动包
linux·嵌入式硬件·机器人·自动驾驶
bai5459363 小时前
STM32 CubeIDE 使用蓝牙模块实现手机控制LED灯
stm32·单片机·嵌入式硬件
gihigo19985 小时前
基于DSP28335 SCI模块控制ESP8266 WiFi模块的实现方案
单片机·嵌入式硬件
想放学的刺客5 小时前
单片机嵌入式嵌入式试题(第16期):硬件可靠性设计与复杂状态机架构设计
c语言·stm32·单片机·嵌入式硬件·物联网
qq_7391753696 小时前
stm32h743单片机驱动dac8568失效问题分析
stm32·单片机·嵌入式硬件