背景

上一讲 STM32 CubeMX 学习:GPIO的使用 介绍了如何配置以及操作GPIO引脚。

这一讲我们通过中断来控制按键。关于中断的概念不做介绍。

HOST-OS : Windows-10

STM32 Cube :v5.6

MCU : STM32F429

LIB : stm32cube_fw_f4_v1250

知识

cortex-M4支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级的可编程中断设置。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。

NVIC是嵌套向量中断控制器(Nested Vectored Interrupt Controller),控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。但是各个芯片厂商在设计芯片的时候会对Cortex-M4内核里面的NVIC进行裁剪,把不需要的部分去掉,所以说STM32NVICCortex-M4NVIC的一个子集。

NVIC负责控制中断响应,主要有三个参数:中断使能(Interrupts Enabled),抢占优先级(Preemption Priority),次优先级(Sub Priority,也叫响应优先级)。(优先级数值越小,优先级别越高)

  • 中断使能:表面是否开启中断,如果开启中断,则满足中断触发条件时程序会跳到中断服务程序运行,否则不响应中断主程序继续运行。
  • 抢占优先级:用来判断一个中断是否可以打断另外一个中断的中断服务程序抢先运行。

例如A中断触发,正在运行A中断的服务程序,此时B中断也触发,如果B中断的抢占优先级比A的高,则程序会打断A的中断服务程序,去运行B的中断服务程序,即中断嵌套。等B的中断服务程序运行完后继续运行A的中断服务程序。如果B的抢占优先级没有高过A的抢占优先级,则程序不会打断A的中断服务程序,而是待定A的中断服务程序运行完成后才运行B的中断服务程序。

  • 次优先级:用来判断抢占优先级相同的几个中断那个中断会优先响应。如果几个抢占优先相同的中断同时触发,那么次优先级高的最先运行。

判断中断的优先级,先看抢占优先级,抢占优先级高的中断优先级别高。抢占优先级相同的情况下,响应优先高的中断优先级别高。抢占优先级和次优先级相同的情况下,根据中断向量表确定。

其实把Sub Priority翻译成次优先级就很好理解了:先看主优先级,再看次优先级,都相同则根据中断向量表的顺序。

优先级分组(Priority Group)

STM32以4个比特位表示中断的抢占优先级和次优先级。中断优先级分组是为了给抢占式优先级次优先级在中断优先级寄丛器的四个比特位分配各个优先级数字所占的位数。

例如3位用于抢占优先级(优先级有23=8种优先级),1位用于次优先级(优先级有21=2种优先级)。

STM32F4的每个IO都可以作为外部中断的中断输入口,这点也是STM32F4的强大之处。

有关的定义(位于文件stm32f4xx_hal_gpio.h中)

下面的代码会引申出2个概念:中断/事件、触发方式。

#define  GPIO_MODE_IT_RISING          0x10110000U   /*!< External Interrupt Mode with Rising edge trigger detection          */
#define GPIO_MODE_IT_FALLING 0x10210000U /*!< External Interrupt Mode with Falling edge trigger detection */
#define GPIO_MODE_IT_RISING_FALLING 0x10310000U /*!< External Interrupt Mode with Rising/Falling edge trigger detection */ #define GPIO_MODE_EVT_RISING 0x10120000U /*!< External Event Mode with Rising edge trigger detection */
#define GPIO_MODE_EVT_FALLING 0x10220000U /*!< External Event Mode with Falling edge trigger detection */
#define GPIO_MODE_EVT_RISING_FALLING 0x10320000U /*!< External Event Mode with Rising/Falling edge trigger detection */

我们会发现,GPIO_MODE_IT_xxx(中断, interrupt)GPIO_MODE_EVT_xxx(事件, event) 2种定义。那么它们有什么不同呢?

  • GPIO_MODE_IT_RISING 等能够触发中断,用在中断方式编程。
  • GPIO_MODE_EVT_RISING 等只设置中断标志位,不产生中断,可以用在轮询方式。(比较少用)

中断/事件 的触发方式(没有边沿触发)

RISING : 上升沿触发。

FALLING: 下降沿触发。

RISING_FALLING:上升沿和下降沿都触发。

CubeMx 对 中断 的配置

只要我们使用到外部中断,就必须打开SYSCFG时钟。

1)在Pinout& Confiurgation页的Pinout view中,点击引脚,设置为GPIO_EXTI..

EXTI后面跟着的数字n代表第n个中断线,这会代表在哪个中断处理函数来响应它

2)点击左栏的GPIO,选择配置的引脚,在界面下方中部靠左的位置可以看到 类似PF4 Configuration这一栏,有以下选项:

  • GPIO mode(模式)

External Interrupt Mode with Rising edge trigger detection(上升沿式外部中断模式)External Interrupt Mode with Falling edge trigger detection(下降沿式外部中断模式)External Interrupt Mode with Rising/Falling edge trigger detection(上升下降沿式外部中断模式)

External Event Mode with Rising edge trigger detection(上升沿式外部置位模式)External Event Mode with Falling edge trigger detection(下降沿式外部置位模式)External Event Mode with Rising/Falling edge trigger detection(上升下降沿式外部置位模式)

GPIO_MODE_IT_RISING能够触发中断,用在中断方式编程。而GPIO_MODE_EVT_RISING只设置中断标志位,不产生中断,可以用在查询方式

  • GPIO Pull-up/Pull-down(上下拉):默认设置为 No pull-up and no pull-down
  • User Label(用户标签): 可以标记这个引脚是做什么用的,提高可读性。

3)点击左侧NVIC

  • 根据需要设置Priority Group
  • 勾选对应的中断使能(Enabled)
  • 根据需要填写抢占优先级(Preemption Priority),次优先级(Sub Priority)

4)点击右上角的GENERATE CODE生成工程

5)使用外部的工具链编译工程,确保没有问题。

代码分析

通过配置以后,在GPIO的初始化函数中就有了 中断的配置与使能

static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE(); /*Configure GPIO pin : PF7 */
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); /*Configure GPIO pin : PB14 */
GPIO_InitStruct.Pin = GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 1, 2);
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
// 补充,关闭中断的函数为:
// void HAL_NVIC_DisableIRQ(IRQn_Type IRQn);
}

同时,CubeMx已经根据配置的情况在./Src/stm32f4xx_it.c文件中。

虽然外部中断可以来自不同的中断线,但在HAL库的机制中,外部中断函数都会先在HAL_GPIO_EXTI_IRQHandler清除中断标志位,再调用同一个中断回调函数:HAL_GPIO_EXTI_Callback

MX_GPIO_Init不难看出,我已经配置了2个中断,在下文中的EXTI9_5_IRQHandlerEXTI15_10_IRQHandler都会调用HAL_GPIO_EXTI_Callback,并给出对应的中断引脚作为参数;所以,我们只需要重写HAL_GPIO_EXTI_Callback时,判断参数就可以正确地做出响应

/**
* @brief This function handles EXTI line[9:5] interrupts.
*/
void EXTI9_5_IRQHandler(void)
{
/* USER CODE BEGIN EXTI9_5_IRQn 0 */ /* USER CODE END EXTI9_5_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7);
/* USER CODE BEGIN EXTI9_5_IRQn 1 */ /* USER CODE END EXTI9_5_IRQn 1 */
} /**
* @brief This function handles EXTI line[15:10] interrupts.
*/
void EXTI15_10_IRQHandler(void)
{
/* USER CODE BEGIN EXTI15_10_IRQn 0 */ /* USER CODE END EXTI15_10_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
/* USER CODE BEGIN EXTI15_10_IRQn 1 */ /* USER CODE END EXTI15_10_IRQn 1 */
}

此时,根据startup_stm32f429xx.s中的描述,每个中断服务函数代表一个(0~4)或者一类([9:5]为一类;[15:10]为另一类)

即:只要是中断线在EXTI_Line9_5,或者 EXTI_Line在10_15 的,中断服务函数就只有一个。

你可能会想,那这么多中断,我同时启动2个中断,会不会造成冲突。

由于中断线只有唯一性,可以在中断服务函数里面判断到底是哪个中断线触发,这也保证不会误触发或者是占线的一系列的问题。

; 中断线与中断处理函数 来自 startup_stm32f429xx.s
DCD EXTI0_IRQHandler ; EXTI Line 0 //只是管脚的中断服务函数,还有串口等等中断服务函数
DCD EXTI1_IRQHandler ; EXTI Line 1
DCD EXTI2_IRQHandler ; EXTI Line 2
DCD EXTI3_IRQHandler ; EXTI Line 3
DCD EXTI4_IRQHandler ; EXTI Line 4
...
DCD EXTI9_5_IRQHandler ; EXTI Line 9..5
...
DCD EXTI15_10_IRQHandler ; EXTI Line 15..10

添加代码

通过上面的分析,我们对于HAL处理外部中断有了一个系统的认识,那么我们目前唯一欠缺的就是重写HAL_GPIO_EXTI_Callback函数。注意,代码应该插在 USER CODE BEGINUSER CODE END 之间。

/* USER CODE BEGIN 4 */

/**
* @brief EXTI line detection callbacks
* @param GPIO_Pin: Specifies the pins connected EXTI line
* @retval None
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
switch(GPIO_Pin)
{
case GPIO_PIN_7:
// do_someting_A();
break;
case GPIO_PIN_14:
// do_someting_B();
break;
default : break;
} return ;
} /* USER CODE END 4 */

STM32 CubeMX 学习:002-外部中断的使用的更多相关文章

  1. stm32学习笔记——外部中断的使用

    stm32学习笔记——外部中断的使用 基本概念 stm32中,每一个GPIO都可以触发一个外部中断,但是,GPIO的中断是以组为一个单位的,同组间的外部中断同一时间只能使用一个.比如说,PA0,PB0 ...

  2. stm32中断优先级管理与外部中断编程

    stm32中断优先级管理与外部中断编程 中断优先级管理 外部中断编程 官方示例程序 exti.h #ifndef __EXTI_H #define __EXIT_H #include "sy ...

  3. STM32(3)——外部中断的使用

    1 .简介 ARM Coetex-M3内核共支持256个中断,其中16个内部中断,240个外部中断和可编程的256级中断优先级的设置.STM32目前支持的中断共84个(16个内部+68个外部),还有1 ...

  4. STM32学习笔记(九) 外部中断,待机模式和事件唤醒

    学会知识只需要不段的积累和提高,但是如何将知识系统的讲解出来就需要深入的认知和系统的了解.外部中断和事件学习难度并不高,不过涉及到STM32的电源控制部分,还是值得认真了解的,在本文中我将以实际代码为 ...

  5. stm32寄存器版学习笔记03 外部中断

    stm32的每个I/O口都可以作为中断输入,要把I/O口设置为外部中断输入,必须将I/O口设置为上拉/下拉输入 或 浮空输入(但浮空的时候外部一定要带上拉或下拉电阻,否则可能导致 中断不停的触发),干 ...

  6. STM32本学习笔记EXTI(外部中断)

    参考资料:STM32数据表.网络信息 =========================================切割线===================================== ...

  7. STM32学习笔记(三)——外部中断的使用

    开发板芯片:STM32F407ZGT6 硬件连接:PE3-KEY1 一.STM32F4的中断介绍 STM32F4的每个IO都可以作为外部中断输入,很强大的功能吧!以前学习的51只有两个外部中断. ST ...

  8. STM32学习笔记之EXTI(外部中断)

    參考资料:STM32数据手冊.网络资料 =========================================切割线==================================== ...

  9. stm32 外部中断学习

    今天我们看看STM32的外部中断实验. STM32 供 IO 口使用的中断线只有 16 个,但是 STM32 的 IO 口却远远不止 16 个,那么 STM32 是怎么把 16 个中断线和 IO 口一 ...

  10. (stm32f103学习总结)—stm32外部中断

    一.外部中断介绍 1.1 EXTI简介 EXTI简介 STM32F10x外部中断/事件控制器(EXTI)包含多达 20 个用于产生事 件/中断请求的边沿检测器.EXTI的每根输入线都可单独进行配置,以 ...

随机推荐

  1. 011_元件封装FootPrint处理

    011_元件封装FootPrint处理 原理图的引脚与PCB的引脚数量一一对应,IC的PCB Foot Print属性添加好属性,后面就不用一个个添加了.

  2. ansible系列(20)--ansible的变量详解

    目录 1. Ansible Variables 1.1 变量定义的方式 1.2 在playbook中定义变量 1.2.1 使用vars方式定义变量 1.2.2 使用vars_file方式定义变量 1. ...

  3. Java面试题:Spring中的循环依赖,给程序员带来的心理阴影

    循环依赖通常发生在两个或多个Spring Bean之间,它们通过构造器.字段(使用@Autowired)或setter方法相互依赖,从而形成一个闭环.下面是一个使用字段注入(即使用@Autowired ...

  4. 日常Bug排查-偶发性读数据不一致

    日常Bug排查-偶发性读数据不一致 前言 日常Bug排查系列都是一些简单Bug的排查.笔者将在这里介绍一些排查Bug的简单技巧,同时顺便积累素材. Bug现场 业务场景 先描述这个问题出现的业务场景. ...

  5. 如何启动?win11下的Linux子系统【4种方法】

    实验室的开发环境在Linux操作系统下,时不时就需要打开Linux环境去操作,而且需要本地编译或者远程SSH.这时候window和Linux切换很不方便.本科的做法就是window+虚拟机的Linux ...

  6. 给师妹写的《Java并发编程之线程池十八问》被表扬啦!

    写在开头     之前给一个大四正在找工作的学妹发了自己总结的关于Java并发中线程池的面试题集,总共18题,将之取名为<Java并发编程之线程池十八问>,今天聊天时受了学妹的夸赞,心里很 ...

  7. 8.4考试总结(NOIP模拟30)[毛一琛·毛二琛·毛三琛]

    最有名的莫过于想死一次吗. 前言 至今都不知道题目是个啥... T1 毛一琛 解题思路 \(\mathcal{Meet\;In\;The\;Middle}\) 其实就是一个爆搜... 把整个区间分为两 ...

  8. css圆圈慢慢放大

    <!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8 ...

  9. 前端传参中文需要utf-8转一下给后端

    const Msg = this.form.Msg.replace( (/%(u[0-9A-F]{4})|(%[0-9A-F]{2})/gm, $0 => { return escape($0) ...

  10. vue-cli 单文件组件 工具安装

    https://cli.vuejs.org/zh/ 在很多 Vue 项目中,我们使用 Vue.component 来定义全局组件,紧接着用 new Vue({ el: '#container '}) ...