详细讲述STM32HAL的中断系统和基础函数参数应用

目录

一:中断概念:

中断的基本概念

STM32中断配置步骤

ISR 是 "Interrupt Service Routine"(中断服务程序)的缩写。

中断优先级:

二:STM32的外部中断:

来自于GPIO端口的引脚

三:外部中断的程序设计思路:

四:Cubemx中断初始化配置:

五:中断服务函数的编写

六、EXTI模式的中断

七:中断的函数

1. 中断初始化函数

2. 中断服务程序(ISR)

3. 中断回调函数

EXTIX_IRQn:

常见的 EXTI_IRQn

其他常见的函数:

 HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)

 HAL_NVIC_EnableIRQ(IRQn_Type IRQn)

HAL_GPIO_EXTI_IRQHandler 函数的功能

八:实战:外部中断实验

配置 EXTI 中断的步骤

九:可参考文章:


一:中断概念:

       ​​​​​​中断在嵌入式系统中是一个重要的机制,用于响应外部或内部事件,并在需要时打断当前程序的执行。STM32微控制器通过NVIC(Nested Vectored Interrupt Controller)来管理中断。以下是关于STM32中断的一些详细信息和配置示例

中断的基本概念

  1. 中断源:产生中断的事件或信号,例如外部按键、中断定时器、ADC完成等。
  2. 中断向量表:每个中断源都有一个固定的中断向量,即对应的中断服务程序(ISR)的地址。
  3. 中断服务程序(ISR):响应中断的函数,负责处理中断事件。
  4. 中断优先级:用于决定多个中断源同时发生时的处理顺序。

STM32中断配置步骤

  1. 配置中断源:初始化中断源,如外部GPIO引脚、定时器等。
  2. 配置NVIC:设置中断优先级并使能中断。
  3. 编写ISR:编写中断服务程序,处理中断事件。
  4. 编写中断回调函数:在某些情况下,ISR会调用HAL库中的回调函数,让用户在回调函数中处理特定的中断事件。

ISR 是 "Interrupt Service Routine"(中断服务程序)的缩写。

      在嵌入式系统中,中断服务程序是一个特殊的函数,它在中断发生时被硬件自动调用,用于处理特定的事件或任务。ISR 的主要特点和作用包括:

  1. 快速响应:ISR 在中断发生时立即被调用,以迅速响应和处理事件。
  2. 简洁高效:ISR 通常设计为短小精悍,尽量减少执行时间,以避免长时间占用 CPU 资源。
  3. 优先级控制:不同的中断可以设置不同的优先级,以确保高优先级的中断能优先得到处理。

ISR 的工作原理

  1. 中断发生:某个外部或内部事件触发中断(例如按键按下、定时器溢出、串口接收到数据等)。
  2. 中断向量表:中断控制器(如 NVIC)根据中断向量表找到对应 ISR 的地址。
  3. 调用 ISR:CPU 停止当前执行的任务,跳转到 ISR 地址执行中断服务程序。
  4. 处理中断:ISR 执行特定的任务,如读取数据、清除中断标志、触发其他操作等。
  5. 返回主程序:ISR 处理完毕后,CPU 返回主程序继续执行被中断的任务。

不管是什么函数里面有IT做后缀就一定跟中断相关

先看抢占优先级,后看响应优先级

NVIC:嵌套向量中断控制器

中断优先级:

        STM32 中的中断优先级可以分为:抢占式优先级和响应优先级,响应优先级也称子优先级, 每个中断源都需要被指定这两种优先级。

     抢占式优先级和响应优先级的区别:

     抢占优先级:抢占优先级高的中断可以打断正在执行的抢占优先级低的中断。

     响应优先级:抢占优先级相同,响应优先级高的中断不能打断响应优先级低的中断。

     还有一种情况就是当两个或者多个中断的抢占式优先级和响应优先级相同时,那么就遵循 自然优先级,看中断向量表的中断排序,数值越小,优先级越高。   


    HAL_NVIC_SetPriority(KEY0_INT_IRQn, 0, 2);               /* 抢占0,子优先级2 */
    HAL_NVIC_EnableIRQ(KEY0_INT_IRQn);                       /* 使能中断线4 */

    HAL_NVIC_SetPriority(KEY1_INT_IRQn, 1, 2);               /* 抢占1,子优先级2 */
    HAL_NVIC_EnableIRQ(KEY1_INT_IRQn);                       /* 使能中断线3 */
    
    HAL_NVIC_SetPriority(KEY2_INT_IRQn, 2, 2);               /* 抢占2,子优先级2 */
    HAL_NVIC_EnableIRQ(KEY2_INT_IRQn);                       /* 使能中断线2 */

    HAL_NVIC_SetPriority(WKUP_INT_IRQn, 3, 2);               /* 抢占3,子优先级2 */
    HAL_NVIC_EnableIRQ(WKUP_INT_IRQn);                       /* 使能中断线0 */

二:STM32的外部中断:

来自于GPIO端口的引脚

三:外部中断的程序设计思路:

(3)上升沿触发,下降沿触发,双边沿触发

cubemx是直接设置成中断模式(将引脚直接设置为中断引脚)

四:Cubemx中断初始化配置:

这篇文章讲述的更为详细具体:STM32——外部中断应用(EXTI)(使用CubeMX配置中断)_cubemx配置exti-CSDN博客

外部中断为前三个:(1)外部中断上升沿 (2)外部中断下降沿 (3)外部中断双边沿

使能了这个中断

五:中断服务函数的编写

清除中断标志

回调函数

在main函数中拷贝编写:先确定是哪个引脚

第一行代码是设置的优先级

第二行是中断使能

在hal_gpio的库里面会有引脚生成的中断服务函数

放在main

六、EXTI模式的中断


定义:
EXTI  可分为两大部分功能,一个是产生中断,另一个是产生事件,这两个功能从硬件上就有所不同。
产生中断线路目的是把输入信号输入到 NVIC(中断控制器,处理中断的),进一步会运行中断服务函数,实现功能,这样是软件级的。而 产生事件线路目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。
中断触发类型:
typedef enum
{
EXTI_Trigger_Rising = 0x08 , // 上升沿
EXTI_Trigger_Falling = 0x0C , // 下降沿
EXTI_Trigger_Rising_Falling = 0x10 // 上升沿和下降沿都触发
} EXTITrigger_TypeDef ;
 1、中断产生回调函数
(简而言之就是发生中断就会调用这个函数,需要我们重写)

__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

传递过来的是发生中断的GPIO口
 

七:中断的函数

1. 中断初始化函数

这些函数用于配置中断源和中断控制器(NVIC):

  • HAL_NVIC_SetPriority:设置中断优先级。
  • HAL_NVIC_EnableIRQ:使能指定的中断。
  • HAL_NVIC_DisableIRQ:禁用指定的中断。
  • HAL_GPIO_Init:初始化 GPIO,引脚可以配置为中断模式(GPIO_MODE_IT_RISING)。
void MX_GPIO_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // 使能 GPIO 时钟
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();

    // 配置 PC13 引脚为输出模式 (用于 LED)
    GPIO_InitStruct.Pin = GPIO_PIN_13;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    // 配置 PA0 引脚为外部中断输入模式 (用于按键)
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 使能并设置 EXTI 中断优先级
    HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);  //中断优先级
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);          //中断使能
}

2. 中断服务程序(ISR)

这些是具体的 ISR 函数,在中断发生时由硬件自动调用:

  • EXTI0_IRQHandler:处理外部中断 0 的 ISR。
  • TIM2_IRQHandler:处理定时器 2 的 ISR。
void EXTI0_IRQHandler(void) {
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}

void TIM2_IRQHandler(void) {
    HAL_TIM_IRQHandler(&htim2);
}

3. 中断回调函数

这些是 HAL 库中定义的回调函数,在 ISR 中调用,用于让用户处理特定的中断事件:

  • HAL_GPIO_EXTI_Callback:处理 GPIO EXTI 中断的回调函数。
  • HAL_TIM_PeriodElapsedCallback:处理定时器周期溢出中断的回调函数。
  • HAL_UART_RxCpltCallback:处理 UART 接收完成中断的回调函数。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (GPIO_Pin == GPIO_PIN_0) {
        // 切换 LED 状态
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    }
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if (htim->Instance == TIM2) {
        // 用户代码,例如切换 LED 状态
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart->Instance == USART1) {
        // 用户代码,例如处理接收到的数据
    }
}

EXTIX_IRQn:

  EXTI_IRQn 是 STM32 微控制器中断向量表中的一个枚举值,用于指定外部中断(EXTI)的中断请求号(IRQ number)。每个 GPIO 引脚都可以配置为触发一个外部中断,通过设置相应的 EXTI_IRQn 来使能和配置这些中断。

    EXTI14_IRQn 是指外部中断线 14(External Interrupt Line 14),它可以由不同端口的引脚引发,例如 PA14、PB14、PC14 等等。具体的引脚配置取决于你的微控制器的引脚映射和配置。对于 STM32 系列微控制器,外部中断线通常是多路复用的,这意味着多个引脚可以共享同一个中断线

常见的 EXTI_IRQn

在 STM32 微控制器中,不同的 GPIO 引脚对应不同的 EXTI 线和中断号。例如:

  • EXTI0_IRQn:外部中断线 0,对应 GPIO 引脚 0。
  • EXTI1_IRQn:外部中断线 1,对应 GPIO 引脚 1。
  • EXTI2_IRQn:外部中断线 2,对应 GPIO 引脚 2。
  • EXTI3_IRQn:外部中断线 3,对应 GPIO 引脚 3。
  • EXTI4_IRQn:外部中断线 4,对应 GPIO 引脚 4。
  • EXTI9_5_IRQn:外部中断线 5 到 9,对应 GPIO 引脚 5 到 9。
  • EXTI15_10_IRQn:外部中断线 10 到 15,对应 GPIO 引脚 10 到 15。

其他常见的函数:

 HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)

函数 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。

 HAL_NVIC_EnableIRQ(IRQn_Type IRQn)

函数 HAL_NVIC_EnableIRQ 是中断使能函数。

其声明如下: void HAL_NVIC_EnableIRQ(IRQn_Type IRQn);

⚫ 函数描述: 用于使能中断。

⚫ 函数形参: 形参 1 是中断号,可以选择范围:IRQn_Type 定义的枚举类型,定义在 stm32f407xx.h。

⚫ 函数返回值:无

HAL_GPIO_EXTI_IRQHandler 函数的功能

HAL_GPIO_EXTI_Callback 是由 HAL_GPIO_EXTI_IRQHandler 函数调用的

HAL_GPIO_EXTI_IRQHandler 是 STM32 HAL 库中的一个函数,用于处理 GPIO 外部中断请求。这个函数主要的作用是根据触发中断的 GPIO 引脚,调用相应的用户定义的回调函数。以下是关于 HAL_GPIO_EXTI_IRQHandler 函数的详细说明。

  • 中断处理HAL_GPIO_EXTI_IRQHandler 处理由 EXTI 线(外部中断线)触发的中断请求。
  • 调用回调函数:根据中断请求的 GPIO 引脚,HAL_GPIO_EXTI_IRQHandler 调用用户定义的回调函数 HAL_GPIO_EXTI_Callback

八:实战:外部中断实验

配置 EXTI 中断的步骤

  1. 初始化 GPIO 引脚:将 GPIO 引脚配置为外部中断模式。
  2. 配置 NVIC:设置中断优先级并使能中断。
  3. 编写中断服务程序(ISR):在中断发生时处理事件。
  4. 编写中断回调函数(可选):处理特定中断事件的用户代码。​​​​​​​

按键GPIO初始化和中断初始化都进行了

(a)exti.h

#ifndef __EXTI_H
#define __EXTI_H

#include "./SYSTEM/sys/sys.h"


/******************************************************************************************/
/* 引脚 和 中断编号 & 中断服务函数 定义 */ 

#define KEY0_INT_GPIO_PORT              GPIOE
#define KEY0_INT_GPIO_PIN               GPIO_PIN_4
#define KEY0_INT_GPIO_CLK_ENABLE()      do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0)   /* PE口时钟使能 */
#define KEY0_INT_IRQn                   EXTI4_IRQn
#define KEY0_INT_IRQHandler             EXTI4_IRQHandler

#define KEY1_INT_GPIO_PORT              GPIOE
#define KEY1_INT_GPIO_PIN               GPIO_PIN_3
#define KEY1_INT_GPIO_CLK_ENABLE()      do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0)   /* PE口时钟使能 */
#define KEY1_INT_IRQn                   EXTI3_IRQn
#define KEY1_INT_IRQHandler             EXTI3_IRQHandler

#define KEY2_INT_GPIO_PORT              GPIOE
#define KEY2_INT_GPIO_PIN               GPIO_PIN_2
#define KEY2_INT_GPIO_CLK_ENABLE()      do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0)   /* PE口时钟使能 */
#define KEY2_INT_IRQn                   EXTI2_IRQn
#define KEY2_INT_IRQHandler             EXTI2_IRQHandler

#define WKUP_INT_GPIO_PORT              GPIOA
#define WKUP_INT_GPIO_PIN               GPIO_PIN_0
#define WKUP_INT_GPIO_CLK_ENABLE()      do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)   /* PA口时钟使能 */
#define WKUP_INT_IRQn                   EXTI0_IRQn
#define WKUP_INT_IRQHandler             EXTI0_IRQHandler

/******************************************************************************************/


void extix_init(void);  /* 外部中断初始化 */

#endif

(b)exti.c


#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/BEEP/beep.h"
#include "./BSP/KEY/key.h"
#include "./BSP/EXTI/exti.h"


/**
 * @brief       KEY0 外部中断服务程序
 * @param       无
 * @retval      无
 */
void KEY0_INT_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(KEY0_INT_GPIO_PIN);         /* 调用中断处理公用函数 清除KEY0所在中断线 的中断标志位 */
    __HAL_GPIO_EXTI_CLEAR_IT(KEY0_INT_GPIO_PIN);         /* HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
}

/**
 * @brief       KEY1 外部中断服务程序
 * @param       无
 * @retval      无
 */
void KEY1_INT_IRQHandler(void)
{ 
    HAL_GPIO_EXTI_IRQHandler(KEY1_INT_GPIO_PIN);         /* 调用中断处理公用函数 清除KEY1所在中断线 的中断标志位,中断下半部在HAL_GPIO_EXTI_Callback执行 */
    __HAL_GPIO_EXTI_CLEAR_IT(KEY1_INT_GPIO_PIN);         /* HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
}

/**
 * @brief       KEY2 外部中断服务程序
 * @param       无
 * @retval      无
 */
void KEY2_INT_IRQHandler(void)
{ 
    HAL_GPIO_EXTI_IRQHandler(KEY2_INT_GPIO_PIN);        /* 调用中断处理公用函数 清除KEY2所在中断线 的中断标志位,中断下半部在HAL_GPIO_EXTI_Callback执行 */
    __HAL_GPIO_EXTI_CLEAR_IT(KEY2_INT_GPIO_PIN);        /* HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
}

/**
 * @brief       WK_UP 外部中断服务程序
 * @param       无
 * @retval      无
 */
void WKUP_INT_IRQHandler(void)
{ 
    HAL_GPIO_EXTI_IRQHandler(WKUP_INT_GPIO_PIN);        /* 调用中断处理公用函数 清除KEY_UP所在中断线 的中断标志位,中断下半部在HAL_GPIO_EXTI_Callback执行 */
    __HAL_GPIO_EXTI_CLEAR_IT(WKUP_INT_GPIO_PIN);        /* HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
}

/**
 * @brief       中断服务程序中需要做的事情
 *              在HAL库中所有的外部中断服务函数都会调用此函数
 * @param       GPIO_Pin:中断引脚号
 * @retval      无
 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    delay_ms(20);      /* 消抖 */
    switch(GPIO_Pin)
    {
        case KEY0_INT_GPIO_PIN:
            if (KEY0 == 0)
            {
                LED0_TOGGLE();  /* LED0 状态取反 */ 
            }
            break;

        case KEY1_INT_GPIO_PIN:
            if (KEY1 == 0)
            {
                LED1_TOGGLE();  /* LED1 状态取反 */ 
            }
            break;

        case KEY2_INT_GPIO_PIN:
            if (KEY2 == 0)
            {
                LED1_TOGGLE();  /* LED1 状态取反 */
                LED0_TOGGLE();  /* LED0 状态取反 */ 
            }
            break;

        case WKUP_INT_GPIO_PIN:
            if (WK_UP == 1)
            {
                BEEP_TOGGLE();  /* 蜂鸣器状态取反 */ 
            }
            break;

        default : break;
    }
}

/**
 * @brief       外部中断初始化程序
 * @param       无
 * @retval      无
 */
void extix_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;
    
    key_init();
    gpio_init_struct.Pin = KEY0_INT_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_IT_FALLING;            /* 下降沿触发 */
    gpio_init_struct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(KEY0_INT_GPIO_PORT, &gpio_init_struct);    /* KEY0配置为下降沿触发中断 */

    gpio_init_struct.Pin = KEY1_INT_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_IT_FALLING;            /* 下降沿触发 */
    gpio_init_struct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(KEY1_INT_GPIO_PORT, &gpio_init_struct);    /* KEY1配置为下降沿触发中断 */
    
    gpio_init_struct.Pin = KEY2_INT_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_IT_FALLING;            /* 下降沿触发 */
    gpio_init_struct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(KEY2_INT_GPIO_PORT, &gpio_init_struct);    /* KEY2配置为下降沿触发中断 */
    
    gpio_init_struct.Pin = WKUP_INT_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_IT_RISING;             /* 上升沿触发 */
    gpio_init_struct.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(WKUP_GPIO_PORT, &gpio_init_struct);        /* WKUP配置为上升沿触发中断 */

    HAL_NVIC_SetPriority(KEY0_INT_IRQn, 0, 2);               /* 抢占0,子优先级2 */
    HAL_NVIC_EnableIRQ(KEY0_INT_IRQn);                       /* 使能中断线4 */

    HAL_NVIC_SetPriority(KEY1_INT_IRQn, 1, 2);               /* 抢占1,子优先级2 */
    HAL_NVIC_EnableIRQ(KEY1_INT_IRQn);                       /* 使能中断线3 */
    
    HAL_NVIC_SetPriority(KEY2_INT_IRQn, 2, 2);               /* 抢占2,子优先级2 */
    HAL_NVIC_EnableIRQ(KEY2_INT_IRQn);                       /* 使能中断线2 */

    HAL_NVIC_SetPriority(WKUP_INT_IRQn, 3, 2);               /* 抢占3,子优先级2 */
    HAL_NVIC_EnableIRQ(WKUP_INT_IRQn);                       /* 使能中断线0 */

}

(a)key.h

#ifndef __KEY_H
#define __KEY_H

#include "./SYSTEM/sys/sys.h"


/******************************************************************************************/
/* 引脚 定义 */

#define KEY0_GPIO_PORT                  GPIOE
#define KEY0_GPIO_PIN                   GPIO_PIN_4
#define KEY0_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0)   /* PE口时钟使能 */

#define KEY1_GPIO_PORT                  GPIOE
#define KEY1_GPIO_PIN                   GPIO_PIN_3
#define KEY1_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0)   /* PE口时钟使能 */

#define KEY2_GPIO_PORT                  GPIOE
#define KEY2_GPIO_PIN                   GPIO_PIN_2
#define KEY2_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0)   /* PE口时钟使能 */

#define WKUP_GPIO_PORT                  GPIOA
#define WKUP_GPIO_PIN                   GPIO_PIN_0
#define WKUP_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)   /* PA口时钟使能 */

/******************************************************************************************/

#define KEY0        HAL_GPIO_ReadPin(KEY0_GPIO_PORT, KEY0_GPIO_PIN)     /* 读取KEY0引脚 */
#define KEY1        HAL_GPIO_ReadPin(KEY1_GPIO_PORT, KEY1_GPIO_PIN)     /* 读取KEY1引脚 */
#define KEY2        HAL_GPIO_ReadPin(KEY2_GPIO_PORT, KEY2_GPIO_PIN)     /* 读取KEY2引脚 */
#define WK_UP       HAL_GPIO_ReadPin(WKUP_GPIO_PORT, WKUP_GPIO_PIN)     /* 读取WKUP引脚 */


#define KEY0_PRES    1              /* KEY0按下 */
#define KEY1_PRES    2              /* KEY1按下 */
#define KEY2_PRES    3              /* KEY2按下 */
#define WKUP_PRES    4              /* KEY_UP按下(即WK_UP) */

void key_init(void);                /* 按键初始化函数 */
uint8_t key_scan(uint8_t mode);     /* 按键扫描函数 */

#endif

(b)key.c

#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"


/**
 * @brief       按键初始化函数
 * @param       无
 * @retval      无
 */
void key_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;                          /* GPIO配置参数存储变量 */
    KEY0_GPIO_CLK_ENABLE();                                     /* KEY0时钟使能 */
    KEY1_GPIO_CLK_ENABLE();                                     /* KEY1时钟使能 */
    KEY2_GPIO_CLK_ENABLE();                                     /* KEY2时钟使能 */
    WKUP_GPIO_CLK_ENABLE();                                     /* WKUP时钟使能 */

    gpio_init_struct.Pin = KEY0_GPIO_PIN;                       /* KEY0引脚 */
    gpio_init_struct.Mode = GPIO_MODE_INPUT;                    /* 输入 */
    gpio_init_struct.Pull = GPIO_PULLUP;                        /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;              /* 高速 */
    HAL_GPIO_Init(KEY0_GPIO_PORT, &gpio_init_struct);           /* KEY0引脚模式设置,上拉输入 */

    gpio_init_struct.Pin = KEY1_GPIO_PIN;                       /* KEY1引脚 */
    gpio_init_struct.Mode = GPIO_MODE_INPUT;                    /* 输入 */
    gpio_init_struct.Pull = GPIO_PULLUP;                        /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;              /* 高速 */
    HAL_GPIO_Init(KEY1_GPIO_PORT, &gpio_init_struct);           /* KEY1引脚模式设置,上拉输入 */

    gpio_init_struct.Pin = KEY2_GPIO_PIN;                       /* KEY2引脚 */
    gpio_init_struct.Mode = GPIO_MODE_INPUT;                    /* 输入 */
    gpio_init_struct.Pull = GPIO_PULLUP;                        /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;              /* 高速 */
    HAL_GPIO_Init(KEY2_GPIO_PORT, &gpio_init_struct);           /* KEY2引脚模式设置,上拉输入 */

    gpio_init_struct.Pin = WKUP_GPIO_PIN;                       /* WKUP引脚 */
    gpio_init_struct.Mode = GPIO_MODE_INPUT;                    /* 输入 */
    gpio_init_struct.Pull = GPIO_PULLDOWN;                      /* 下拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;              /* 高速 */
    HAL_GPIO_Init(WKUP_GPIO_PORT, &gpio_init_struct);           /* WKUP引脚模式设置,下拉输入 */

}

/**
 * @brief       按键扫描函数
 * @note        该函数有响应优先级(同时按下多个按键): WK_UP > KEY2 > KEY1 > KEY0!!
 * @param       mode:0 / 1, 具体含义如下:
 *   @arg       0,  不支持连续按(当按键按下不放时, 只有第一次调用会返回键值,
 *                  必须松开以后, 再次按下才会返回其他键值)
 *   @arg       1,  支持连续按(当按键按下不放时, 每次调用该函数都会返回键值)
 * @retval      键值, 定义如下:
 *              KEY0_PRES, 1, KEY0按下
 *              KEY1_PRES, 2, KEY1按下
 *              KEY2_PRES, 3, KEY2按下
 *              WKUP_PRES, 4, WKUP按下
 */
uint8_t key_scan(uint8_t mode)
{
    static uint8_t key_up = 1;  /* 按键按松开标志 */
    uint8_t keyval = 0;

    if (mode) key_up = 1;       /* 支持连按 */

    if (key_up && (KEY0 == 0 || KEY1 == 0 || KEY2 == 0 || WK_UP == 1))  /* 按键松开标志为1, 且有任意一个按键按下了 */
    {
        delay_ms(10);           /* 去抖动 */
        key_up = 0;

        if (KEY0 == 0)  keyval = KEY0_PRES;

        if (KEY1 == 0)  keyval = KEY1_PRES;

        if (KEY2 == 0)  keyval = KEY2_PRES;

        if (WK_UP == 1) keyval = WKUP_PRES;
    }
    else if (KEY0 == 1 && KEY1 == 1 && KEY2 == 1 && WK_UP == 0)         /* 没有任何按键按下, 标记按键松开 */
    {
        key_up = 1;
    }

    return keyval;              /* 返回键值 */
}

(b)main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/BEEP/beep.h"
#include "./BSP/EXTI/exti.h"


int main(void)
{    
    HAL_Init();                             /* 初始化HAL库 */
    sys_stm32_clock_init(336, 8, 2, 7);     /* 设置时钟,168Mhz */
    delay_init(168);                        /* 延时初始化 */
    usart_init(115200);                     /* 串口初始化为115200 */
    led_init();                             /* 初始化LED */
    beep_init();                            /* 初始化蜂鸣器 */
    extix_init();                           /* 初始化外部中断输入 */
    LED0(0);                                /* 先点亮红灯 */

    while(1)
    {
        delay_ms(1000);
    }
}

九:可参考文章:

STM32——外部中断应用(EXTI)(使用CubeMX配置中断)_cubemx配置exti-CSDN博客

什么是中断-CSDN博客

中断处理函数注意事项-CSDN博客

  • 19
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32HAL中,定时器中断回调函数是通过HAL库提供的回调函数机制来实现的。当定时器中断发生时,HAL库会自动调用相应的回调函数来处理中断事件。 在使用HAL库进行定时器中断编程时,需要完成以下几个步骤: 1. 初始化定时器:使用HAL库提供的函数进行定时器的初始化配置,包括定时器的时钟源、预分频系数、计数模式等。 2. 配置定时器中断:使用HAL库提供的函数配置定时器中断,包括中断触发条件、优先级等。 3. 编写回调函数:在代码中定义一个回调函数,用于处理定时器中断事件。回调函数的命名规则为`void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)`,其中`htim`是指向定时器句柄的指针。 在回调函数中,可以编写相应的代码来处理定时器中断事件,例如更新某个变量、执行某个任务等。 下面是一个示例代码,演示了如何使用HAL库进行定时器中断编程: ```c #include "stm32f4xx_hal.h" TIM_HandleTypeDef htim2; void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM2) { // 处理定时器2中断事件 // 可以在这里编写相应的代码 } } int main(void) { HAL_Init(); SystemClock_Config(); // 初始化定时器2 htim2.Instance = TIM2; htim2.Init.Prescaler = 0; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 1000; HAL_TIM_Base_Init(&htim2); // 配置定时器2中断 HAL_TIM_Base_Start_IT(&htim2); while (1) { // 主循环代码 } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值