当前位置: 首页 > news >正文

2.STM32F407ZGT6-外部中断

参考:
1.正点原子。

前言:
MCU最重要的一个领域–中断。总结下嵌套向量和外部中断的概念。达到:
1.NVIC是什么,了解中断的整体管理理念。
2.中断里面最简单的外部中断,怎么配置处理。
3.使用STM32CubeMX配置外部中断的流程。

16.1 NVIC 和 EXTI 简介

16.1.1 NVIC 简介

什么是 NVIC?NVIC 即嵌套向量中断控制器,全称 Nested vectored interrupt controller。它是内核的器件,所以它的更多描述可以看内核有关的资料。
M3/M4/M7 内核都是支持 256 个中断,其中包含了 16 个系统中断和 240 个外部中断,并且具有 256 级的可编程中断设置。然而芯片厂商一般不会把内核的这些资源全部用完,如 STM32F407 的系统中断有 10 个,外部中断有82 个。下面我们看看系统中断部分:
在这里插入图片描述

关于 82 个外部中断部分在《STM32F4xx 参考手册_V4(中文版).pdf》的 10.2 小节有详细的列表,这里就不列出来了。STM32F407 的中断向量表在 stm32f407xx.h 文件中被定义。

16.1.1.1 NVIC 寄存器

NVIC 相关的寄存器定义了可以在 core_cm4.h 文件中找到。我们直接通过程序的定义来分析 NVIC 相关的寄存器,其定义如下:

typedef struct
{__IOM uint32_t ISER[8U];  /* 中断使能寄存器 */uint32_t RESERVED0[24U];__IOM uint32_t ICER[8U];  /* 中断清除使能寄存器 */uint32_t RSERVED1[24U];__IOM uint32_t ISPR[8U];  /* 中断使能挂起寄存器 */uint32_t RESERVED2[24U];__IOM uint32_t ICPR[8U];  /* 中断解挂寄存器 */uint32_t RESERVED3[24U];__IOM uint32_t IABR[8U];  /* 中断有效位寄存器 */uint32_t RESERVED4[56U];__IOM uint8_t IP[240U];  /* 中断优先级寄存器(8Bit 位宽) */uint32_t RESERVED5[644U];__OM uint32_t STIR;      /* 中断触发中断寄存器 */
} NVIC_Type;

STM32F407 的中断在这些寄存器的控制下有序的执行的。只有了解这些中断寄存器,才能方便的使用 STM32F407 的中断。下面重点介绍这几个寄存器:

**ISER[8]:**ISER 全称是:Interrupt Set Enable Registers,这是一个中断使能寄存器组。上面说了 CM4 内核支持 256 个中断,这里用 8 个 32 位寄存器来控制,每个位控制一个中断。但是STM32F407 的可屏蔽中断最多只有 82 个,所以对我们来说,有用的就是两个(ISER[0-3]),总共可以表示 128 个中断。而 STM32F407 只用了其中的 82 个。ISER[0]的 bit0-31 分别对应中断0~31;ISER[1]的 bit0~31 对应中断 32~63; ISER[2]的 bit0~16 对应中断 64~81,这样总共 82 个中断就可以分别对应上了。你要使能某个中断,必须设置相应的 ISER 位为 1,使该中断被使能(这里仅仅是使能,还要配合中断分组、屏蔽、IO 口映射等设置才算是一个完整的中断设置)。
具体每一位对应哪个中断,请参考 stm32f407xx.h 里面的第 68 行。

**ICER[8]:**全称是:Interrupt Clear Enable Registers,是一个中断除能寄存器组。该寄存器组与 ISER 的作用恰好相反,是用来清除某个中断的使能的。其对应位的功能,也和 ISER 一样。
这里要专门设置一个 ICER 来清除中断位,而不是向 ISER 写 0 来清除,是因为 NVIC 的这些寄存器都是写 1 有效的,写 0 是无效的。

**ISPR[8]:**全称是:Interrupt Set Pending Registers,是一个中断使能挂起控制寄存器组。每个位对应的中断和 ISER 是一样的。通过置 1,可以将正在进行的中断挂起,而执行同级或更高级别的中断。写 0 是无效的。

**ICPR[8]:**全称是:Interrupt Clear Pending Registers,是一个中断解挂控制寄存器组。其作用与 ISPR 相反,对应位也和 ISER 是一样的。通过设置 1,可以将挂起的中断解挂。写 0 无效。

**IABR[8]:**全称是:Interrupt Active Bit Registers,是一个中断激活标志位寄存器组。对应位所代表的中断和 ISER 一样,如果为 1,则表示该位所对应的中断正在被执行。这是一个只读寄存器,通过它可以知道当前在执行的中断是哪一个。在中断执行完了由硬件自动清零。

**IP [240]:**全称是:Interrupt Priority Registers,是一个中断优先级控制的寄存器组。这个寄存器组相当重要!STM32F407 的中断分组与这个寄存器组密切相关。IP 寄存器组由 240 个 8bit的寄存器组成,每个可屏蔽中断占用 8bit,这样总共可以表示 240 个可屏蔽中断。而 STM32F407只用到了其中的 82 个。IP[81]~IP[0]分别对应中断 81~0。而每个可屏蔽中断占用的 8bit 并没有全部使用,而是只用了高 4 位。这 4 位,又分为抢占优先级和子优先级。抢占优先级在前,子优先级在后。而这两个优先级各占几个位又要根据 SCB->AIRCR 中的中断分组设置来决定。关于中断优先级控制的寄存器组我们下面详细讲解。

16.1.1.2 中断优先级

STM32 中的中断优先级可以分为:抢占式优先级和响应优先级,响应优先级也称子优先级,每个中断源都需要被指定这两种优先级。抢占式优先级和响应优先级的区别:
抢占优先级:抢占优先级高的中断可以打断正在执行的抢占优先级低的中断。
响应优先级:抢占优先级相同,响应优先级高的中断不能打断响应优先级低的中断。
还有一种情况就是当两个或者多个中断的抢占式优先级和响应优先级相同时,那么就遵循自然优先级,看中断向量表的中断排序,数值越小,优先级越高。

在 NVIC 中由寄存器 NVIC_IPR0-NVIC_IPR59 共 60 个寄存器控制中断优先级,每个寄存器的每 8 位又分为一组,可以分 4 组,所以就有了 240 组宽度为 8bit 的中断优先级控制寄存器,原则上每个外部中断可配置的优先级为 0~255,数值越小,优先级越高。但是实际上 M3 /M4/M7 芯片为了精简设计,只使用了高四位[7:4],低四位取零,这样以至于最多只有 16 级中断嵌套,即 2^4=16。
对于 NVCI 的中断优先级分组:STM32F407 将中断分为 5 个组,组 0~4。该分组的设置是由 SCB->AIRCR 寄存器的 bit10~8 来定义的。具体的分配关系如表 16.1.1.2.1 所示:
在这里插入图片描述

通过这个表,我们就可以清楚的看到组 0~4 对应的配置关系,例如优先级分组设置为 3,那么此时所有的 82 个中断,每个中断的中断优先寄存器的高四位中的最高 3 位是抢占优先级,低 1 位是响应优先级。每个中断,你可以设置抢占优先级为 0~7,响应优先级为 1 或 0。抢占优先级的级别高于响应优先级。而数值越小所代表的优先级就越高。
结合实例说明一下:假定设置中断优先级分组为 2,然后设置
中断 3(RTC_WKUP 中断)的抢占优先级为 2,响应优先级为 1。
中断 6(外部中断 0)的抢占优先级为 3,响应优先级为 0。
中断 7(外部中断 1)的抢占优先级为 2,响应优先级为 0。
那么这 3 个中断的优先级顺序为:
中断 7>中断 3>中断 6。
上面例子中的中断 3 和中断 7 都可以打断中断 6 的中断。而中断 7 和中断 3 却不可以相互打断!

16.1.1.3 NVIC 相关函数

ST 公司把 core_cm4.h 文件的 NVIC 相关函数封装到 stm32f4xx_hal_cortex.c 文件中,下面列出我们较为常用的函数进行,想了解更多其他的函数请自行查阅。

1. HAL_NVIC_SetPriorityGrouping 函数
HAL_NVIC_SetPriorityGrouping 是设置中断优先级分组函数。其声明如下:
void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup);
⚫ 函数描述:
用于设置中断优先级分组。
⚫ 函数形参:
形参 1 是中断优先级分组号,可以选择范围:NVIC_PRIORITYGROUP_0 到 NVIC_PRIORITYGROUP_4(共 5 组)。
⚫ 函数返回值:无
⚫ 注意事项:
这个函数在一个工程里基本只调用一次,而且是在程序 HAL 库初始化函数里面已经被调用,后续就不会再调用了。因为当后续调用设置成不同的中断优先级分组时,有可能造成前面设置好的抢占优先级和响应优先级不匹配。

2. HAL_NVIC_SetPriority 函数
HAL_NVIC_SetPriority 是设置中断优先级函数。其声明如下:
void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority,uint32_t SubPriority);
⚫ 函数描述:
用于设置中断的抢占优先级和响应优先级(子优先级)。
⚫ 函数形参:
形参 1 是中断号,可以选择范围:IRQn_Type 定义的枚举类型,定义在 stm32f407xx.h。
形参 2 是抢占优先级,可以选择范围:0 到 15。
形参 3 是响应优先级,可以选择范围:0 到 15。
⚫ 函数返回值:无

3. HAL_NVIC_EnableIRQ 函数
HAL_NVIC_EnableIRQ 是中断使能函数。其声明如下:
void HAL_NVIC_EnableIRQ(IRQn_Type IRQn);
⚫ 函数描述:
用于使能中断。
⚫ 函数形参:
形参 1 是中断号,可以选择范围:IRQn_Type 定义的枚举类型,定义在 stm32f407xx.h。
⚫ 函数返回值:无

4. HAL_NVIC_DisableIRQ 函数
HAL_NVIC_DisableIRQ 是中断失能函数。其声明如下:
void HAL_NVIC_DisableIRQ(IRQn_Type IRQn);
⚫ 函数描述:
用于中断除能。
⚫ 函数形参:无形参
⚫ 函数返回值:无

5. HAL_NVIC_SystemReset 函数
HAL_NVIC_SystemReset 是系统复位函数。其声明如下:
void HAL_NVIC_SystemReset(void);
⚫ 函数描述:
用于软件复位系统。
⚫ 函数形参:无形参
⚫ 函数返回值:无
其他的 NVIC 函数用得较少,我们就不一一列出来了。NVIC 的介绍就到这,下面介绍外部中断。

16.1.2 EXTI 简介

EXTI 即是外部中断和事件控制器,它是由 20 个产生事件/中断请求的边沿检测器组成。每一条输入线都可以独立地配置输入类型(脉冲或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入线都可以独立地被屏蔽。挂起寄存器保持着状态线的中断请求。
EXTI 的功能框图是最直接把有关 EXTI 的知识点连接起来的图,掌握了该图的来龙去脉,就会对 EXTI 有了一个整体熟悉,编程时候可以得心应手。EXTI 的功能框图如图 16.1.2.1。
在这里插入图片描述

从 EXTI 功能框图可以看到有两条主线,一条是由输入线到 NVIC 中断控制器,一条是由输入线到脉冲发生器。这就恰恰是 EXTI 的两大部分功能,产生中断与产生事件,两者从硬件上就存在不同。

下面让我们看一下 EXTI 功能框图的产生中断的线路,最终信号是流入 NVIC 控制器中。
输入线是线路的信息输入端,它可以通过配置寄存器设置为任何一个 GPIO 口,或者是一些外设的事件。输入线一般都是存在电平变化的信号。

标号①是一个边沿检测电路,包括边沿检测电路,上升沿触发选择寄存器(EXTI_RTSR)和下降沿触发选择寄存器(EXTI_FTSR)。边沿检测电路以输入线作为信号输入端,如果检测到有边沿跳变就输出有效信号‘1’,就输出有效信号‘1’到标号②部分电路,否则输入无效信号‘0’。
边沿跳变的标准在于开始的时候对于上升沿触发选择寄存器或下降沿触发选择寄存器对应位的设置,对应位的设置可以参照一下表 16.1.1.2.1。

标号②是一个或门电路,它的两个信号输入端分别是软件中断事件寄存器(EXTI_SWIER)和边沿检测电路的输入信号。或门电路只要输入端有信号‘1’,就会输出‘1’,所以就会输出‘1’到标号③电路和标号④电路。通过对软件中断事件寄存器的读写操作就可以启动中断/事件线,即相当于输出有效信号‘1’到或门电路输入端。

标号③是一个与门电路,它的两个信号输入端分别是中断屏蔽寄存器(EXTI_IMR)和标号②电路输出信号。与门电路要求输入都为‘1’才输出‘1’,这样子的情况下,如果中断屏蔽寄存器(EXTI_IMR)设置为 0 时,不管从标号②电路输出的信号特性如何,最终标号③电路输出的信号都是 0;假如中断屏蔽寄存器(EXTI_IMR)设置为 1 时,最终标号③电路输出的信号才由标号②电路输出信号决定,这样子就可以简单控制 EXTI_IMR 来实现中断的目的。标号②电路输出‘1’就会把请求挂起寄存器(EXTI_PR)对应位置 1。
最后,请求挂起寄存器(EXTI_PR)的内容就输出到 NVIC 内,实现系统中断事件的控制。

接下来我们看看 EXTI 功能框图的产生事件的线路。
产生事件线路是从标号 2 之后与中断线路有所不用,之前的线路都是共用的。标号④是一个与门,输入端来自标号 2 电路以及来自于事件屏蔽寄存器(EXTI_EMR)。如果 EXTI_EMR 寄存器设置为 0,那不管标号 2 电路输出的信号是‘0’还是‘1’,最终标号 4 输出的是‘0’;如果 EXTI_EMR 寄存器设置为 1,最终标号④电路输出信号就由标号②电路输出的信号决定,这样子就可以简单的控制 EXTI_EMR 来实现是否产生事件的目的。
标号④电路输出有效信号 1 就会使脉冲发生器电路产生一个脉冲,而无效信号就不会使其产生脉冲信号。脉冲信号产生可以给其他外设电路使用,例如定时器,模拟数字转换器等,这样的脉冲信号一般用来触发 TIM 或者 ADC 开始转换。
产生中断线路目的使把输入信号输入到 NVIC,进一步运行中断服务函数,实现功能。而产生事件线路目的是传输一个脉冲信号给其他外设使用,属于硬件级功能。

EXTI 支持 23 个外部中断/事件请求,这些都是信息输入端,也就是上面提及到了输入线,具体如下:
EXTI 线 0~15:对应外部 IO 口的输入中断
EXTI 线 16:连接到 PVD 输出
EXTI 线 17:连接到 RTC 闹钟事件
EXTI 线 18:连接到 USB 唤醒事件
EXTI 线 19:连接到以太网唤醒事件
EXTI 线 20:连接到 USB OTG HS(在 FS 中配置)唤醒事件
EXTI 线 21:连接到 RTC 入侵和时间戳事件
EXTI 线 22:连接到 RTC 唤醒事件。
从上面可以看出,STM32F407 供给 IO 口使用的中断线只有 16 个,但是 STM32F407 的 IO口却远远不止 16 个,所以 STM32 把 GPIO 管脚 GPIOx.0~GPIOx.15(x=A,B,C,D,E,F,G)分别对应中断线 0~15。这样子每个中断线对应了最多 7 个 IO 口,以线 0 为例:它对应了 GPIOA.0、GPIOB.0、GPIOC.0、GPIOD.0、GPIOE.0、GPIOF.0 和 GPIOG.0。而中断线每次只能连接到 1 个IO 口上,这样就需要通过配置决定对应的中断线配置到哪个 GPIO 上了。

16.2 硬件设计

1. 例程功能
通过外部中断的方式让开发板上的Key0独立按键控制 LED _0 和 LED_1灯翻转。

2. 硬件资源
1)LED 灯
LED0 – PF9
LED1 – PF10
2)独立按键
KEY0 – PE4

3. 原理图
在这里插入图片描述

这里需要注意的是:KEY0、KEY1 和 KEY2 设计为采样到按键另一端的低电平为有效,并且外部都没有上下拉电阻,所以需要在 STM32F407 内部设置上下拉。

16.3 程序设计

16.3.1 EXTI 的 HAL 库驱动

前面讲解 HAL_GPIO_Init 函数的时候有提到过:HAL 库的 EXTI 外部中断的设置功能整合到 HAL_GPIO_Init 函数里面,而不是单独独立一个文件。所以我们的外部中断的初始化函数也是用 HAL_GPIO_Init 函数。
既然是要用到外部中断,所以我们的 GPIO 的模式要从下面的三个模式中选中一个:

#define GPIO_MODE_IT_RISING (0x10110000U)          /* 外部中断,上升沿触发检测 */
#define GPIO_MODE_IT_FALLING (0x10210000U)         /* 外部中断,下降沿触发检测 */
#define GPIO_MODE_IT_RISING_FALLING (0x10310000U)  /* 外部中断,上升和下降双沿触发检测 */

程序设计按键为按下触发中断,KEY0、KEY1 和 KEY2 是低电平有效,所以我们要选择下降沿触发检测。

EXTI 外部中断配置步骤
1) 使能 IO 口时钟。
本实验用到的 GPIO 和按键输入实验是一样的,因此 GPIO 时钟使能也是一样的,请参考上一章代码。
2) 设置 IO 口模式,触发条件,开启 SYSCFG 时钟,设置 IO 口与中断线的映射关系。
这些步骤 HAL 库全部封装在 HAL_GPIO_Init 函数里面,我们只需要设置好对应的参数,再调用 HAL_GPIO_Init 函数即可完成配置。
3)配置中断优先级(NVIC),并使能中断。
配置好 GPIO 模式以后,我们需要设置中断优先级和使能中断,中断优先级我们使用HAL_NVIC_SetPriority 函数设置,中断使能我们使用 HAL_NVIC_EnableIRQ 函数设置。
4) 编写中断服务函数。
每开启一个中断,就必须编写其对应的中断服务函数,否则将导致死机(CPU 将找不到中断服务函数)。中断服务函数接口厂家已经在 startup_stm32f407xx.s 中写好了。STM32F407 的IO 口外部中断函数只有 7 个,分别为:

void EXTI0_IRQHandler();
void EXTI1_IRQHandler();
void EXTI2_IRQHandler();
void EXTI3_IRQHandler();
void EXTI4_IRQHandler();
void EXTI9_5_IRQHandler();
void EXTI15_10_IRQHandler();

中断线0-4,每个中断线对应一个中断函数,中断线5-9共用中断函数EXTI9_5_IRQHandler,中断线 10-15 共用中断函数 EXTI15_10_IRQHandler。一般情况下,我们可以把中断控制逻辑直接编写在中断服务函数中,但是 HAL 库把中断处理过程进行了简单封装,请看下面步骤 5 讲解。
5)编写中断处理回调函数 HAL_GPIO_EXTI_Callback
HAL 库为了用户使用方便,提供了一个中断通用入口函数 HAL_GPIO_EXTI_IRQHandler,在该函数内部直接调用回调函数 HAL_GPIO_EXTI_Callback。
我们先来看一下 HAL_GPIO_EXTI_IRQHandler 函数定义:

/*** @brief This function handles EXTI line4 interrupt.*/
void EXTI4_IRQHandler(void)    /*启动汇编代码里面,固定的中断调用函数*/
{/* USER CODE BEGIN EXTI4_IRQn 0 *//* USER CODE END EXTI4_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(KEY_0_Pin);/* USER CODE BEGIN EXTI4_IRQn 1 *//* USER CODE END EXTI4_IRQn 1 */
}/*** @brief  This function handles EXTI interrupt request.* @param  GPIO_Pin Specifies the pins connected EXTI line* @retval None*/
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{/* EXTI line interrupt detected */if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET){__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);    /* 清中断标志位 */HAL_GPIO_EXTI_Callback(GPIO_Pin);    /* 外部中断回调函数 */}
}/*** @brief  EXTI line detection callbacks.* @param  GPIO_Pin Specifies the pins connected EXTI line* @retval None*/
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)    /*这个就是待我们实现的中断回调函数*/
{/* Prevent unused argument(s) compilation warning */UNUSED(GPIO_Pin);/* NOTE: This function Should not be modified, when the callback is needed,the HAL_GPIO_EXTI_Callback could be implemented in the user file*/
}

该函数实现的作用非常简单,通过入口参数 GPIO_Pin 判断中断来自哪个 IO 口,然后清除相应的中断标志位,最后调用回调函数 HAL_GPIO_EXTI_Callback()实现控制逻辑。在所有的外部中断服务函数中直接调用外部中断共用处理函数 HAL_GPIO_EXTI_IRQHandler,然后在回调函数 HAL_GPIO_EXTI_Callback 中通过判断中断是来自哪个 IO 口编写相应的中断服务控制逻辑。
因此我们可以在 HAL_GPIO_EXTI_Callback 里面实现控制逻辑编写,详见本实验源码。

16.3.3 程序解析

1. 外部中断引脚定义

void MX_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOE_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOF_CLK_ENABLE();__HAL_RCC_GPIOH_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOF, LED_0_Pin|LED_1_Pin, GPIO_PIN_SET);/*Configure GPIO pin : PtPin */GPIO_InitStruct.Pin = KEY_0_Pin;GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;    /* KEY0 配置为下降沿触发中断 */GPIO_InitStruct.Pull = GPIO_PULLUP;HAL_GPIO_Init(KEY_0_GPIO_Port, &GPIO_InitStruct);/*Configure GPIO pins : PFPin PFPin */GPIO_InitStruct.Pin = LED_0_Pin|LED_1_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);/* EXTI interrupt init*/HAL_NVIC_SetPriority(EXTI4_IRQn, 1, 0);    /* 抢占 1,子优先级 0 */HAL_NVIC_EnableIRQ(EXTI4_IRQn);            /*使能外部中断4*/}

KEY0连接 PE4,即对应了 EXTI4外部中断线。这里需要注意的是 EXTI0 到 EXTI4 都是有单独的中断向量, EXTI5 到 EXTI9 是公用 EXTI9_5_IRQn , EXTI10 到 EXTI15 是公用EXTI15_10_IRQn。

2.外部中断回调函数实现
所有的外部中断服务函数里都只调用了同样一个函数 HAL_GPIO_EXTI_IRQHandler,该函数是外部中断共用入口函数,函数内部会进行中断标志位清零,并且调用中断处理共用回调函数 HAL_GPIO_EXTI_Callback。但是它们的形参不同,我们的回调函数也是根据形参去判断是哪个 IO 口的外部中断线被触发。
外部中断回调函数,其定义如下:

void LED_ONOFF(void)
{HAL_GPIO_TogglePin(LED_0_GPIO_Port, LED_0_Pin);HAL_GPIO_TogglePin(LED_1_GPIO_Port, LED_1_Pin);
}void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if (KEY_0_Pin == GPIO_Pin){LED_ONOFF();/*对LED_0 和 LED_1 灯的亮灭翻转*/}
}

外部中断回调函数 HAL_GPIO_EXTI_Callback 是用来编写真正的外部中断控制逻辑。该函数有一个形参就是 IO 引脚号。所以我们在该函数内部,一般通过判断 IO 引脚号来确定中断是来自哪个 IO 口,也就是哪个中断线,然后编写相应的控制逻辑。

3. main.c 代码
在 main.c 里面编写如下代码:

int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

首先是调用系统级别的初始化:初始化 HAL 库、系统时钟,GPIO的初始化。逻辑控制代码都在中断回调函数中完成。

16.4 STM32CubeMX

1.配置PE4引脚为外部下降沿中断触发模式
在这里插入图片描述

2.使能外部中断
在这里插入图片描述

3.设置外部中断优先级
在这里插入图片描述

4.再次生成工程
在这里插入图片描述

16.5 运行效果

按KEY_0键,LED_0和LED_1就会出现翻转。(没有实用价值,没有考虑按键的抖动情况,实际产品也不会这样用,仅仅验证外部中断的demo)
在这里插入图片描述

16.6 源码路径

git clone git@gitee.com:xiaoliangliangcong/stm32.git
STM32F407ZGT6/2.EXIT

相关文章:

2.STM32F407ZGT6-外部中断

参考: 1.正点原子。 前言: MCU最重要的一个领域–中断。总结下嵌套向量和外部中断的概念。达到: 1.NVIC是什么,了解中断的整体管理理念。 2.中断里面最简单的外部中断,怎么配置处理。 3.使用STM32CubeMX配置外部中断的…...

C# 之某度协议登录,JS逆向,手机号绑定,获取CK

.NET兼职社区 .NET兼职社区 .NET兼职社区 .NET兼职社区 有需要指导,请私信我留言V或者去社区找客服。...

0基础学前端-----CSS DAY12

视频参考:B站Pink老师 今天是CSS学习的第十二天,今天开始的笔记对应Pink老师课程中的CSS第七天的内容。 本节重点:CSS高级技巧 本章目录 本节目标1. 精灵图1.1 为什么需要精灵图1.2 精灵图使用案例:拼出自己的名字 2. 字体图标2.…...

STM32——系统滴答定时器(SysTick寄存器详解)

文章目录 1.SysTick简介2.工作原理3.SysTick寄存器4.代码延时逻辑5.附上整体代码6.一些重要解释 1.SysTick简介 Cortex-M处理器内集成了一个小型的名为SysTick(系统节拍)的定时器,它属于NVIC的一部分,且可以产生 SysTick异常(异常类型#15)。SysTick为简单的向下计数的24位计数…...

HTML5 弹跳动画(Bounce Animation)详解

HTML5 弹跳动画(Bounce Animation)详解 弹跳动画是一种动态效果,使元素在出现或消失时看起来像是在跳动。这种效果可以通过 CSS 动画或 JavaScript 来实现,增强用户体验。 1. 使用 CSS 实现弹跳动画 可以使用 CSS 的 keyframes…...

Python 模拟登录网页,或者编写爬虫时模拟登录的详细总结

参考 Python模拟登陆网页的三种方法_python模拟登录-CSDN博客 python-模拟登陆多种方法总结_python模拟登录-CSDN博客 Python模拟登录的几种方法_实现模拟登录的方式有哪些?-CSDN博客 Python爬虫——模拟登录_python 模拟登录-CSDN博客 Python3 爬虫 模拟登录_python模拟登录网…...

若依框架简介

若依(RuoYi)框架是一个基于Java语言的后台管理系统快速开发框架,它结合了多种前端和后端技术,提供了高效的开发工具。以下是对若依框架的详细解析: 一、技术架构 后端:若依框架后端采用了Spring Boot、My…...

Linux中rsync命令使用

一、rsync简介 rsync 是一种高效的文件复制和同步工具,常用于在本地或远程计算机之间同步文件和目录 主要特性增量同步:rsync 会检测源和目标文件之间的差异,只传输发生变化的部分,而不是重新传输整个文件。这样就能有效减少数据…...

opencv 学习(1)

文章目录 opencv导学部分opencv的作用ffmpeg和 opencv的关系opencv的未来 计算机视觉是什么? opencv导学部分 opencv的作用 1 : 目标识别 人脸识别 车辆识别 2 : 自动驾驶技术 – 计算机视觉 进行车道的检测 3 : 医学图像分析 通过分析光片 来分析人到底得了什么病…...

中高级运维工程师运维面试题(十一)之 Docker

目录 往期回顾前言基础知识1. 什么是 Docker?2. Docker 的核心组件有哪些?3. Docker 镜像和容器有什么区别?4. 什么是 Dockerfile? 高级知识5. 什么是多阶段构建?如何使用?6. Docker 网络有哪些模式&#x…...

Kafka如何实现顺序消费?

Kafka的消息是存储在指定的topic中的某个partition中的。并且一个topic是可以有多个partition的。同一个partition中的消息是有序的,但是跨partition,或者跨topic的消息就是无序的了。 为什么同一个partition的消息是有序的? 因为当生产者向某个parti…...

通过 ulimit 和 sysctl 调整Linux系统性能

目录 一:资源限制管理工具:ulimit1、ulimit 作用介绍2、ulimit 常用选项3、ulimit 配置文件 二:内核参数调整工具:sysctl1、sysctl 作用介绍2、sysctl 常用选项3、sysctl 配置文件 一:资源限制管理工具:uli…...

pandas基础使用

pandas基础使用 基本介绍 类似于字典形式的numpy,可以给它的不同行和不同列进行重命名。 import numpy as np import pandas as pd # 创建一个序列 s pd.Series([1,4,True,np.nan,55.0])创建date format日期矩阵 import numpy as np import pandas as pd dates…...

2024.1.5总结

今日不开心:这周本来想花点时间学习的,没想到全都花在刷视频,外出消费去了。 今日思考: 1.找对象这件事确实不能强求,顺其自然吧,单身和不单身,其实,各有各的利弊。在一次坐地铁的过程中,我一…...

解释一下:运放的输入偏置电流

输入偏置电流 首先看基础部分:这就是同相比例放大器 按照理论计算,输入VIN=0时,输出VOUT应为0,对吧 仿真与理论差距较大,有200多毫伏的偏差,这就是输入偏置电流IBIAS引起的,接着看它的定义 同向和反向输入电流的平均值,也就是Ib1、Ib2求平均,即(Ib1+Ib2)/2 按照下面…...

Federation机制的实现

1.关闭Hadoop的HDFS和YARN,依次执行“stop-yarn.sh”和“stop-dfs.sh”命令关闭Hadoop的YARN和HDFS。 2.删除3台虚拟机上的临时文件: 3.修改hdfs-site.xml配置文件,进入虚拟机liumengting1的/export/servers/hadoop-3.3.4/etc/hadoop目录&…...

120.Jenkins里的Pipeline Script

目录 1. **Declarative Pipeline** 主要部分 示例 2. **Scripted Pipeline** 主要部分 示例 3. **常用指令和功能** 环境变量 工具管理 文件操作 构建触发器 并行执行 异常处理 用户交互 4.**两种类型的特点** 1. **声明式 Pipeline (Declarative Pipeline)** 中…...

SpringBoot3-整合WebSocket指南

更多SpringBoot3内容请关注我的专栏:《SpringBoot3》 期待您的点赞👍收藏⭐评论✍ SpringBoot3-整合WebSocket指南 1. 什么是WebSocket?2. 环境准备2.1 项目依赖 3. WebSocket配置3.1 WebSocket配置类3.2 自定义WebSocket处理器 4. 控制器5. 前端实现5.…...

【npm依赖包介绍】借助rimraf依赖包,在用npm run build构建项目时,清空dist目录,避免新旧混合

文章目录 背景如何使用附上rimraf的介绍和说明主要作用使用场景安装使用示例异步删除同步删除 参考资料 背景 在npm run build时,一般都会清空项目中已有的dist目录再构建,避免新旧混合。 如何使用 可以简单使用rimraf这个npm依赖包。 目前rimraf的最…...

python学opencv|读取图像(二十四)使用cv2.putText()绘制文字进阶-倾斜文字

【1】引言 前述学习进程中,我们已经掌握了pythonopencv绘制文字的基本技能,相关链接为: python学opencv|读取图像(二十三)使用cv2.putText()绘制文字-CSDN博客 在这里,我们使用不同的字体、线条颜色和线…...

【简博士统计学习方法】第1章:3. 统计学习方法的三要素

3. 统计学习方法的三要素 3.1 监督学习的三要素 3.1.1 模型 假设空间(Hypothesis Space):所有可能的条件概率分布或决策函数,用 F \mathcal{F} F表示。 若定义为决策函数的集合: F { f ∣ Y f ( X ) } \mathcal{F…...

“AI智慧语言训练系统:让语言学习变得更简单有趣

大家好,我是你们的老朋友,一个热衷于探讨科技与教育结合的产品经理。今天,我想和大家聊聊一个让语言学习变得不再头疼的话题——AI智慧语言训练系统。这个系统可是我们语言学习者的福音,让我们一起来揭开它的神秘面纱吧&#xff0…...

机器学习笔记 - 单幅图像深度估计的最新技术

1、深度估计简述 单眼深度估计是一项计算机视觉任务,AI 模型从单个图像中预测场景的深度信息。模型估计场景中对象从一个照相机视点的距离。单目深度估计已广泛用于自动驾驶、机器人等领域。深度估计被认为是最困难的计算机视觉任务之一,因为它要求模型理解对象及其深度信息之…...

洛谷:P1540 [NOIP2010 提高组] 机器翻译

[NOIP2010 提高组] 机器翻译 题目背景 NOIP2010 提高组 T1 题目描述 小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章。 这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换。对于…...

2025第2周 | JavaScript中的函数的参数默认值和剩余参数

目录 1. 函数的默认值1.1 ES5的时候默认值写法1.2 es6的默认值1.3 babel转换之后1.4 有默认值的参数建议放到最后1.5 有默认值的函数length属性 2. 参数为对象时默认值及解构2.1 默认值和解构一起使用2.2 默认值为一个空对象 3. 剩余参数3.1 剩余参数必须放到最后3.2 剩余参数和…...

Unity学习之UGUI(三)

十二、Slider 1、作用 Slider是滑动条组件,是UGUI中用于处理滑动条相关交互的关键组件 创建Slider默认包括4个对象 父对象:Slider组件依附的对象 子对象:背景图,进度图,滑动块三组对象 2、主要参数 3、代码控制 voi…...

分享3个国内使用正版GPT的网站【亲测有效!2025最新】

1. molica 传送入口:https://ai-to.cn/url/?umolica 2. 多帮AI 传送入口:https://aigc.openaicloud.cn?inVitecodeMYAAGGKXVK 3. 厉害猫 传送入口:https://ai-to.cn/url/?ulihaimao...

ffmpeg-avio实战:打开本地文件或者网络直播流dome

使用ffmpeg打开打开本地文件或者网络直播流的一个小dome。流程产靠ffmpeg4.x系列的解码流程-CSDN博客 #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavformat/avio.h> #include <libavutil/file.h> #include &l…...

三维管线管网自动化建模工具MagicPipe3D V3.6.0

经纬管网建模系统MagicPipe3D&#xff0c;本地离线参数化构建地下管网三维模型&#xff08;包括管道、接头、附属设施等&#xff09;&#xff0c;输出标准3DTiles、Obj模型等格式&#xff0c;支持Cesium、Unreal、Unity、Osg等引擎加载进行三维可视化、语义查询、专题分析。欢迎…...

设计基于检索增强生成的个性化语言模型(RAG-based LLM)

设计基于检索增强生成的个性化语言模型&#xff08;RAG-based LLM&#xff09; 引言 在当今快速发展的自然语言处理技术中&#xff0c;生成式预训练模型&#xff08;LLM&#xff09;对个性化和可靠结果的需求不断增加。为了满足这种需求&#xff0c;基于检索增强生成&#xf…...

Oracle Dataguard(主库为单节点)配置详解(5):使用 rman 复制技术(DUPLICATE)同步主库到备库

Oracle Dataguard&#xff08;主库为单节点&#xff09;配置详解&#xff08;5&#xff09;&#xff1a;使用 rman 复制技术&#xff08;DUPLICATE&#xff09;同步主库到备库 目录 Oracle Dataguard&#xff08;主库为单节点&#xff09;配置详解&#xff08;5&#xff09;&am…...

119.使用AI Agent解决问题:Jenkins build Pipeline时,提示npm ERR! errno FETCH_ERROR

目录 1.Jenkins Build时的错误 2.百度文心快码AI智能体帮我解决 提问1&#xff1a;jenkins中如何配置npm的源 提问2&#xff1a;jenkins pipeline 类型为pipeline script from SCM时&#xff0c;如何配置npm源 3.最终解决方法-Jenkinsfile的修改 4.感触 1.Jenkins Build时…...

回归预测 | MATLAB实ELM-Adaboost多输入单输出回归预测

回归预测 | MATLAB实ELM-Adaboost多输入单输出回归预测 目录 回归预测 | MATLAB实ELM-Adaboost多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 一、极限学习机&#xff08;ELM&#xff09; 极限学习机是一种单层前馈神经网络&#xff0c;具有训练速…...

服务器漏洞修复解决方案

漏洞1、远程桌面授权服务启用检测【原理扫描】 Windows Remote Desktop Licensing Service is running: Get Server version: 0x60000604 1、解决方案&#xff1a;建议禁用相关服务避免目标被利用 方法一&#xff1a;使用服务管理器 打开“运行”对话框&#xff08;WinR&am…...

Couldn‘t resolve host name for http://mirrorlist.centos.org

【问题】 在CentOS8执行sudo yum update -y 软件包更新的时候报错 Errors during downloading metadata for repository appstream:- Curl error (6): Couldnt resolve host name for http://mirrorlist.centos.org/?release8-stream&archx86_64&repoAppStream&…...

Vue2:el-table中的文字根据内容改变颜色

想要实现的效果如图,【级别】和【P】列的颜色根据文字内容变化 1、正常创建表格 <template><el-table:data="tableData"style="width: 100%"><el-table-column prop="id" label="ID"/> <el-table-column …...

C++静态变量的使用方法?C++静态变量占用内存情况?拷贝构造函数会拷贝哪些内容?const使用注意

1.静态变量的使用 函数中使用&#xff1a;静态变量初次声明并定义作为初始值&#xff0c;后续再次运行函数&#xff0c;基于上次的结果累加类中&#xff1a;类内声明&#xff0c;类外实现&#xff08;如声明为const&#xff0c;特殊情况&#xff0c;可以类内直接声明时定义&am…...

Linux初识——基本指令

我们在linux下输入各种指令&#xff0c;其实就相当于在windows中的相关操作&#xff0c;比如双击&#xff0c;新建文件夹等。 以下是相关基本指令基本用法 一.ls&#xff08;显示当前目录下的所有文件和目录&#xff09; 那如何显示当前目录&#xff08;我们所在的位置&…...

python 实现贪心算法(Greedy Algorithm)

贪心算法&#xff08;Greedy Algorithm&#xff09;是一种在每一步选择中都采取当前最优的选择&#xff0c;希望通过局部最优解达到全局最优解的算法设计方法。以下是使用Python实现贪心算法解决几个经典问题的示例&#xff1a; 1. 活动选择问题&#xff08;Activity Selection…...

设计形成从业务特点到设计模式的关联

规范和指引在应用架构、数据架构等各架构方向上形成规范性约束指导。同一个决策要点、架构单元在统一的架构原则指导下&#xff0c;会因业务特点差异有不同的实现&#xff0c;经过总结形成了最佳实践。在开展新应用的设计时&#xff0c;根据决策要点以及相关的业务特点&#xf…...

Pytorch初学

创建虚拟环境 python控制台&#xff0c;jupyter notebook,python文件运行的差异&#xff0c;后续结合使用三者。 jupter主要可以对代码进行分割单独运行&#xff0c;主要做一些探索性工作。 数据集的常见存储模式 1、以标签命名图像。 2、单独存储图像的地址。 加载数据集…...

【动态重建】时间高斯分层的长体积视频

标题&#xff1a;Representing Long Volumetric Video with Temporal Gaussian Hierarchy 来源&#xff1a;浙江大学 链接&#xff1a;https://zju3dv.github.io/longvolcap/ 文章目录 摘要一、前言二、主要方法2.1 时间高斯分层2.2 高效渲染2.3 层次结构更新2.4 紧凑的外观模型…...

Java设计模式 —— 【行为型模式】命令模式(Command Pattern) 详解

文章目录 模式介绍优缺点适用场景结构案例实现注意事项 模式介绍 有时候需要向某些对象发送请求&#xff0c;但是并不知道请求的接收者是谁&#xff0c;也不知道被请求的操作是什么。此时希望用一种松耦合的方式来设计程序&#xff0c;使得请求发送者和请求接收者能够消除彼此…...

IOS开发如何从入门进阶到高级

针对iOS开发的学习&#xff0c;不同阶段应采取不同的学习方式&#xff0c;以实现高效提升.本文将iOS开发的学习分为入门、实战、进阶三个阶段&#xff0c;下面分别详细介绍. 一、学习社区 iOS开源中国社区 这个社区专注于iOS开发的开源项目分享与协作&#xff0c;汇集了大量开…...

数据结构与算法之二叉树: LeetCode 108. 将有序数组转换为二叉搜索树 (Ts版)

将有序数组转换为二叉搜索树 https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/description/ 描述 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列请你将其转换为一棵 平衡 二叉搜索树 示例 1 输入&#xff1a;nums [-10,-3,0,5,9…...

细说STM32F407单片机以轮询方式读写外部SRAM的方法

目录 一、实例的功能 二、工程配置 1、KEYLED 2、时钟、DEBUG、USART6、NVIC、GPIO、CodeGenerator 3、FSMC &#xff08;1&#xff09; 模式设置 &#xff08;2&#xff09; Bank 1子区3参数设置 1) NOR/PSRAM control组&#xff0c;子区控制参数 2) NOR/PSRAM timi…...

【Unity3D】AB包加密(AssetBundle加密)

加密前&#xff1a; 加密后&#xff0c;直接无法加载ab&#xff0c;所以无法正常看到ab内容。 using UnityEngine; using UnityEditor; using System.IO; public static class AssetBundleDemoTest {[MenuItem("Tools/打包!")]public static void Build(){//注意:St…...

wujie无界微前端框架初使用

先说一下项目需求&#xff1a;将单独的四套系统的登录操作统一放在一个入口页面进行登录&#xff0c;所有系统都使用的是vue3&#xff0c;&#xff08;不要问我为啥会这样设计&#xff0c;产品说的客户要求&#xff09; 1.主系统下载wujie 我全套都是vue3&#xff0c;所以直接…...

联发科MTK6771/MT6771安卓核心板规格参数介绍

MT6771&#xff0c;也被称为Helio P60&#xff0c;是联发科技(MediaTek)推出的一款中央处理器(CPU)芯片&#xff0c;可运行 android9.0 操作系统的 4G AI 安卓智能模块。MT6771芯片采用了12纳米工艺制造&#xff0c;拥有八个ARM Cortex-A73和Cortex-A53核心&#xff0c;主频分别…...

ZooKeeper Java API操作

&#xff08;1&#xff09;添加依赖&#xff0c;在pom.xml文件中添加zookeeper依赖&#xff1a; &#xff08;2&#xff09;连接zookeeper服务&#xff0c;创建cn.itcast.zookeeper包&#xff0c;在该包中创建ZooKeeperDemo类&#xff0c;该类用于实现创建会话和操作ZooKeeper&…...