STM32中断处理教程【HAL库】
目录
一、什么是中断
1.1、中断的定义
1.2、中断的作用和意义
1.3、STM32 GPIO外部中断简图
二、NVIC
2.1、NVIC基本概念
2.2、NVIC相关寄存器介绍
2.3、NVIC工作原理
2.4、STM32中断优先级基本概念
2.5、STM32中断优先级分组
2.6、STM32 NVIC的使用
2.6.1、设置中断分组
2.6.2、设置中断优先级
2.6.3、使能中断
三、EXTI
3.1、EXTI基本概念
3.2、EXTI主要特性
3.3、EXTI工作原理(F1/F4/F7)
四、EXTI和IO映射关系
4.1、SYSCFG简介(F4/F7/H7)
4.2、EXTI与IO对应关系
五、如何使用中断
5.1、配置流程图
5.2、STM32 EXTI 的配置步骤(外部中断)
5.3、STM32 EXTI 的 HAL 库设置步骤(外部中断)
5.4、HAL库中断回调处理机制原理图
六、编程实战
通过外部中断控制一个灯亮灭
一、什么是中断
1.1、中断的定义
打断 CPU 执行正常的程序,转而处理紧急程序,然后返回原暂停的程序继续运行,就叫中断
1.2、中断的作用和意义
实时控制:在确定时间内对相应事件作出响应,如温度监控
故障处理:检测到故障,需要第一时间处理,如电梯门夹人了
数据传输:不确定数据何时会来,如串口数据接收
中断的意义:高效处理紧急程序,不会一直占用 CPU 资源
1.3、STM32 GPIO外部中断简图
二、NVIC
2.1、NVIC基本概念
NVIC(Nested vectored interrupt controller),嵌套向量中断控制器,属于内核(M3/4/7)
NVIC 支持:256 个中断(16 内核 + 240 外部),支持:256 个优先级,允许裁剪!
中断向量表的概念
定义一块固定的内存,以 4 字节对齐,存放各个中断服务函数程序的首地址
中断向量表定义在启动文件,当发生中断,CPU 会自动执行对应的中断服务函数
在启动文件中定义的 10 个内核中断,从上往下自然优先级依次降低
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
在启动文件中定义的 82 个外部中断,从上往下自然优先级依次降低
DCD WWDG_IRQHandler ; Window WatchDog
DCD PVD_IRQHandler ; PVD through EXTI Line detection
DCD TAMP_STAMP_IRQHandler ; Tamper and TimeStamps through the EXTI line
DCD RTC_WKUP_IRQHandler ; RTC Wakeup through the EXTI line
DCD FLASH_IRQHandler ; FLASH
DCD RCC_IRQHandler ; RCC
DCD EXTI0_IRQHandler ; EXTI Line0
DCD EXTI1_IRQHandler ; EXTI Line1
DCD EXTI2_IRQHandler ; EXTI Line2
DCD EXTI3_IRQHandler ; EXTI Line3
DCD EXTI4_IRQHandler ; EXTI Line4
DCD DMA1_Stream0_IRQHandler ; DMA1 Stream 0
DCD DMA1_Stream1_IRQHandler ; DMA1 Stream 1
DCD DMA1_Stream2_IRQHandler ; DMA1 Stream 2
DCD DMA1_Stream3_IRQHandler ; DMA1 Stream 3
DCD DMA1_Stream4_IRQHandler ; DMA1 Stream 4
DCD DMA1_Stream5_IRQHandler ; DMA1 Stream 5
DCD DMA1_Stream6_IRQHandler ; DMA1 Stream 6
DCD ADC_IRQHandler ; ADC1, ADC2 and ADC3s
DCD CAN1_TX_IRQHandler ; CAN1 TX
DCD CAN1_RX0_IRQHandler ; CAN1 RX0
DCD CAN1_RX1_IRQHandler ; CAN1 RX1
DCD CAN1_SCE_IRQHandler ; CAN1 SCE
DCD EXTI9_5_IRQHandler ; External Line[9:5]s
DCD TIM1_BRK_TIM9_IRQHandler ; TIM1 Break and TIM9
DCD TIM1_UP_TIM10_IRQHandler ; TIM1 Update and TIM10
DCD TIM1_TRG_COM_TIM11_IRQHandler ; TIM1 Trigger and Commutation and TIM11
DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare
DCD TIM2_IRQHandler ; TIM2
DCD TIM3_IRQHandler ; TIM3
DCD TIM4_IRQHandler ; TIM4
DCD I2C1_EV_IRQHandler ; I2C1 Event
DCD I2C1_ER_IRQHandler ; I2C1 Error
DCD I2C2_EV_IRQHandler ; I2C2 Event
DCD I2C2_ER_IRQHandler ; I2C2 Error
DCD SPI1_IRQHandler ; SPI1
DCD SPI2_IRQHandler ; SPI2
DCD USART1_IRQHandler ; USART1
DCD USART2_IRQHandler ; USART2
DCD USART3_IRQHandler ; USART3
DCD EXTI15_10_IRQHandler ; External Line[15:10]s
DCD RTC_Alarm_IRQHandler ; RTC Alarm (A and B) through EXTI Line
DCD OTG_FS_WKUP_IRQHandler ; USB OTG FS Wakeup through EXTI line
DCD TIM8_BRK_TIM12_IRQHandler ; TIM8 Break and TIM12
DCD TIM8_UP_TIM13_IRQHandler ; TIM8 Update and TIM13
DCD TIM8_TRG_COM_TIM14_IRQHandler ; TIM8 Trigger and Commutation and TIM14
DCD TIM8_CC_IRQHandler ; TIM8 Capture Compare
DCD DMA1_Stream7_IRQHandler ; DMA1 Stream7
DCD FMC_IRQHandler ; FMC
DCD SDIO_IRQHandler ; SDIO
DCD TIM5_IRQHandler ; TIM5
DCD SPI3_IRQHandler ; SPI3
DCD UART4_IRQHandler ; UART4
DCD UART5_IRQHandler ; UART5
DCD TIM6_DAC_IRQHandler ; TIM6 and DAC1&2 underrun errors
DCD TIM7_IRQHandler ; TIM7
DCD DMA2_Stream0_IRQHandler ; DMA2 Stream 0
DCD DMA2_Stream1_IRQHandler ; DMA2 Stream 1
DCD DMA2_Stream2_IRQHandler ; DMA2 Stream 2
DCD DMA2_Stream3_IRQHandler ; DMA2 Stream 3
DCD DMA2_Stream4_IRQHandler ; DMA2 Stream 4
DCD ETH_IRQHandler ; Ethernet
DCD ETH_WKUP_IRQHandler ; Ethernet Wakeup through EXTI line
DCD CAN2_TX_IRQHandler ; CAN2 TX
DCD CAN2_RX0_IRQHandler ; CAN2 RX0
DCD CAN2_RX1_IRQHandler ; CAN2 RX1
DCD CAN2_SCE_IRQHandler ; CAN2 SCE
DCD OTG_FS_IRQHandler ; USB OTG FS
DCD DMA2_Stream5_IRQHandler ; DMA2 Stream 5
DCD DMA2_Stream6_IRQHandler ; DMA2 Stream 6
DCD DMA2_Stream7_IRQHandler ; DMA2 Stream 7
DCD USART6_IRQHandler ; USART6
DCD I2C3_EV_IRQHandler ; I2C3 event
DCD I2C3_ER_IRQHandler ; I2C3 error
DCD OTG_HS_EP1_OUT_IRQHandler ; USB OTG HS End Point 1 Out
DCD OTG_HS_EP1_IN_IRQHandler ; USB OTG HS End Point 1 In
DCD OTG_HS_WKUP_IRQHandler ; USB OTG HS Wakeup through EXTI
DCD OTG_HS_IRQHandler ; USB OTG HS
DCD DCMI_IRQHandler ; DCMI
DCD 0 ; Reserved
DCD HASH_RNG_IRQHandler ; Hash and Rng
DCD FPU_IRQHandler ; FPU
2.2、NVIC相关寄存器介绍
NVIC 还有:中断挂起,解挂,激活标志等非常用功能,不做介绍!
2.3、NVIC工作原理
2.4、STM32中断优先级基本概念
1,抢占优先级(pre):高抢占优先级可以打断正在执行的低抢占优先级中断
2,响应优先级(sub):当抢占优先级相同时,响应优先级高的先执行,但是不能互相打断
3,抢占和响应都相同的情况下,自然优先级越高的,先执行
4,自然优先级:中断向量表的优先级
5,数值越小,表示优先级越高
2.5、STM32中断优先级分组
特别提示:一个工程中,一般只设置一次中断优先级分组
举个例子,中断优先级分组设置为 2
EXTI1 和 RTC 可以打断:EXTI0 和 Systick 的中断,获得优先执行!
2.6、STM32 NVIC的使用
2.6.1、设置中断分组
HAL库驱动函数:HAL_NVIC_SetPriorityGrouping()
/**
* @brief Sets the priority grouping field (preemption priority and subpriority)
* using the required unlock sequence.
* @param PriorityGroup The priority grouping bits length.
* This parameter can be one of the following values:
* @arg NVIC_PRIORITYGROUP_0: 0 bits for preemption priority
* 4 bits for subpriority
* @arg NVIC_PRIORITYGROUP_1: 1 bits for preemption priority
* 3 bits for subpriority
* @arg NVIC_PRIORITYGROUP_2: 2 bits for preemption priority
* 2 bits for subpriority
* @arg NVIC_PRIORITYGROUP_3: 3 bits for preemption priority
* 1 bits for subpriority
* @arg NVIC_PRIORITYGROUP_4: 4 bits for preemption priority
* 0 bits for subpriority
* @note When the NVIC_PriorityGroup_0 is selected, IRQ preemption is no more possible.
* The pending IRQ priority will be managed only by the subpriority.
* @retval None
*/
void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup);
对应的可选参数有
/** @defgroup CORTEX_Preemption_Priority_Group CORTEX Preemption Priority Group
* @{
*/
#define NVIC_PRIORITYGROUP_0 0x00000007U /*!< 0 bits for pre-emption priority
4 bits for subpriority */
#define NVIC_PRIORITYGROUP_1 0x00000006U /*!< 1 bits for pre-emption priority
3 bits for subpriority */
#define NVIC_PRIORITYGROUP_2 0x00000005U /*!< 2 bits for pre-emption priority
2 bits for subpriority */
#define NVIC_PRIORITYGROUP_3 0x00000004U /*!< 3 bits for pre-emption priority
1 bits for subpriority */
#define NVIC_PRIORITYGROUP_4 0x00000003U /*!< 4 bits for pre-emption priority
0 bits for subpriority */
特别提醒:例程中,中断分组已经在 HAL_Init() 函数中设置了分组 2
2.6.2、设置中断优先级
HAL库驱动函数:HAL_NVIC_SetPriority()
/**
* @brief Sets the priority of an interrupt.
* @param IRQn External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f4xxxx.h))
* @param PreemptPriority The preemption priority for the IRQn channel.
* This parameter can be a value between 0 and 15
* A lower priority value indicates a higher priority
* @param SubPriority the subpriority level for the IRQ channel.
* This parameter can be a value between 0 and 15
* A lower priority value indicates a higher priority.
* @retval None
*/
void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority);
第一个参数 IRQn_Type IRQn
/**
* @brief STM32F4XX Interrupt Number Definition, according to the selected device
* in @ref Library_configuration_section
*/
typedef enum
{
/****** Cortex-M4 Processor Exceptions Numbers ****************************************************************/
NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */
MemoryManagement_IRQn = -12, /*!< 4 Cortex-M4 Memory Management Interrupt */
BusFault_IRQn = -11, /*!< 5 Cortex-M4 Bus Fault Interrupt */
UsageFault_IRQn = -10, /*!< 6 Cortex-M4 Usage Fault Interrupt */
SVCall_IRQn = -5, /*!< 11 Cortex-M4 SV Call Interrupt */
DebugMonitor_IRQn = -4, /*!< 12 Cortex-M4 Debug Monitor Interrupt */
PendSV_IRQn = -2, /*!< 14 Cortex-M4 Pend SV Interrupt */
SysTick_IRQn = -1, /*!< 15 Cortex-M4 System Tick Interrupt */
/****** STM32 specific Interrupt Numbers **********************************************************************/
WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */
PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */
TAMP_STAMP_IRQn = 2, /*!< Tamper and TimeStamp interrupts through the EXTI line */
RTC_WKUP_IRQn = 3, /*!< RTC Wakeup interrupt through the EXTI line */
FLASH_IRQn = 4, /*!< FLASH global Interrupt */
RCC_IRQn = 5, /*!< RCC global Interrupt */
EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */
EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */
EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */
EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */
EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */
DMA1_Stream0_IRQn = 11, /*!< DMA1 Stream 0 global Interrupt */
DMA1_Stream1_IRQn = 12, /*!< DMA1 Stream 1 global Interrupt */
DMA1_Stream2_IRQn = 13, /*!< DMA1 Stream 2 global Interrupt */
DMA1_Stream3_IRQn = 14, /*!< DMA1 Stream 3 global Interrupt */
DMA1_Stream4_IRQn = 15, /*!< DMA1 Stream 4 global Interrupt */
DMA1_Stream5_IRQn = 16, /*!< DMA1 Stream 5 global Interrupt */
DMA1_Stream6_IRQn = 17, /*!< DMA1 Stream 6 global Interrupt */
ADC_IRQn = 18, /*!< ADC1, ADC2 and ADC3 global Interrupts */
CAN1_TX_IRQn = 19, /*!< CAN1 TX Interrupt */
CAN1_RX0_IRQn = 20, /*!< CAN1 RX0 Interrupt */
CAN1_RX1_IRQn = 21, /*!< CAN1 RX1 Interrupt */
CAN1_SCE_IRQn = 22, /*!< CAN1 SCE Interrupt */
EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */
TIM1_BRK_TIM9_IRQn = 24, /*!< TIM1 Break interrupt and TIM9 global interrupt */
TIM1_UP_TIM10_IRQn = 25, /*!< TIM1 Update Interrupt and TIM10 global interrupt */
TIM1_TRG_COM_TIM11_IRQn = 26, /*!< TIM1 Trigger and Commutation Interrupt and TIM11 global interrupt */
TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */
TIM2_IRQn = 28, /*!< TIM2 global Interrupt */
TIM3_IRQn = 29, /*!< TIM3 global Interrupt */
TIM4_IRQn = 30, /*!< TIM4 global Interrupt */
I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */
I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */
I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */
I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */
SPI1_IRQn = 35, /*!< SPI1 global Interrupt */
SPI2_IRQn = 36, /*!< SPI2 global Interrupt */
USART1_IRQn = 37, /*!< USART1 global Interrupt */
USART2_IRQn = 38, /*!< USART2 global Interrupt */
USART3_IRQn = 39, /*!< USART3 global Interrupt */
EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */
RTC_Alarm_IRQn = 41, /*!< RTC Alarm (A and B) through EXTI Line Interrupt */
OTG_FS_WKUP_IRQn = 42, /*!< USB OTG FS Wakeup through EXTI line interrupt */
TIM8_BRK_TIM12_IRQn = 43, /*!< TIM8 Break Interrupt and TIM12 global interrupt */
TIM8_UP_TIM13_IRQn = 44, /*!< TIM8 Update Interrupt and TIM13 global interrupt */
TIM8_TRG_COM_TIM14_IRQn = 45, /*!< TIM8 Trigger and Commutation Interrupt and TIM14 global interrupt */
TIM8_CC_IRQn = 46, /*!< TIM8 Capture Compare global interrupt */
DMA1_Stream7_IRQn = 47, /*!< DMA1 Stream7 Interrupt */
FSMC_IRQn = 48, /*!< FSMC global Interrupt */
SDIO_IRQn = 49, /*!< SDIO global Interrupt */
TIM5_IRQn = 50, /*!< TIM5 global Interrupt */
SPI3_IRQn = 51, /*!< SPI3 global Interrupt */
UART4_IRQn = 52, /*!< UART4 global Interrupt */
UART5_IRQn = 53, /*!< UART5 global Interrupt */
TIM6_DAC_IRQn = 54, /*!< TIM6 global and DAC1&2 underrun error interrupts */
TIM7_IRQn = 55, /*!< TIM7 global interrupt */
DMA2_Stream0_IRQn = 56, /*!< DMA2 Stream 0 global Interrupt */
DMA2_Stream1_IRQn = 57, /*!< DMA2 Stream 1 global Interrupt */
DMA2_Stream2_IRQn = 58, /*!< DMA2 Stream 2 global Interrupt */
DMA2_Stream3_IRQn = 59, /*!< DMA2 Stream 3 global Interrupt */
DMA2_Stream4_IRQn = 60, /*!< DMA2 Stream 4 global Interrupt */
ETH_IRQn = 61, /*!< Ethernet global Interrupt */
ETH_WKUP_IRQn = 62, /*!< Ethernet Wakeup through EXTI line Interrupt */
CAN2_TX_IRQn = 63, /*!< CAN2 TX Interrupt */
CAN2_RX0_IRQn = 64, /*!< CAN2 RX0 Interrupt */
CAN2_RX1_IRQn = 65, /*!< CAN2 RX1 Interrupt */
CAN2_SCE_IRQn = 66, /*!< CAN2 SCE Interrupt */
OTG_FS_IRQn = 67, /*!< USB OTG FS global Interrupt */
DMA2_Stream5_IRQn = 68, /*!< DMA2 Stream 5 global interrupt */
DMA2_Stream6_IRQn = 69, /*!< DMA2 Stream 6 global interrupt */
DMA2_Stream7_IRQn = 70, /*!< DMA2 Stream 7 global interrupt */
USART6_IRQn = 71, /*!< USART6 global interrupt */
I2C3_EV_IRQn = 72, /*!< I2C3 event interrupt */
I2C3_ER_IRQn = 73, /*!< I2C3 error interrupt */
OTG_HS_EP1_OUT_IRQn = 74, /*!< USB OTG HS End Point 1 Out global interrupt */
OTG_HS_EP1_IN_IRQn = 75, /*!< USB OTG HS End Point 1 In global interrupt */
OTG_HS_WKUP_IRQn = 76, /*!< USB OTG HS Wakeup through EXTI interrupt */
OTG_HS_IRQn = 77, /*!< USB OTG HS global interrupt */
DCMI_IRQn = 78, /*!< DCMI global interrupt */
RNG_IRQn = 80, /*!< RNG global Interrupt */
FPU_IRQn = 81 /*!< FPU global interrupt */
} IRQn_Type;
这是一个枚举类型,内容包括 10 个内核中断和 82 个外部中断
后面两个参数 uint32_t PreemptPriority 和 uint32_t SubPriority 分别是抢占优先级和响应优先级
2.6.3、使能中断
HAL库驱动函数:HAL_NVIC_EnableIRQ()
/**
* @brief Enables a device specific interrupt in the NVIC interrupt controller.
* @note To configure interrupts priority correctly, the NVIC_PriorityGroupConfig()
* function should be called before.
* @param IRQn External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f4xxxx.h))
* @retval None
*/
void HAL_NVIC_EnableIRQ(IRQn_Type IRQn);
参数和上面的第一个参数完全一样,包括 10 个内核中断和 82 个外部中断
三、EXTI
3.1、EXTI基本概念
EXTI(External(Extended) interrupt/event Controller),外部(扩展)中断事件控制器
包含 23 个产生事件/中断请求的边沿检测器,即总共:23 条 EXTI 线(F4)
中断和事件的理解
中断:要进入 NVIC,有相应的中断服务函数,需要 CPU 处理
事件:不进入 NVIC,仅用于内部硬件自动控制的,如:TIM、DMA、ADC
3.2、EXTI主要特性
F1/F4/F7 系列
每条 EXTI 线都可以单独配置:选择类型(中断或者事件)、触发方式(上升沿,下降沿或者双边沿触发)、支持软件触发、开启/屏蔽、有挂起状态位
H7 系列
由其它外设对 EXTI 产生的事件分为可配置事件和直接事件
可配置事件:简单概括,基本和 F1/F4/F7 系列类似
直接事件:固定上升沿触发、不支持软件触发、无挂起状态位(由其它外设提供)
3.3、EXTI工作原理(F1/F4/F7)
① 边沿检测
② 软件触发
③ 中断屏蔽/清除
④ 事件屏蔽
常用的寄存器有:EXTI_FTSR、EXTI_RTSR、EXTI_IMR、EXTI_PR
四、EXTI和IO映射关系
4.1、SYSCFG简介(F4/F7/H7)
SYSCFG(System configuration controller),即系统配置控制器,用于外部中断映射配置等
外部中断配置寄存器 SYSCFG_EXTICR 1~4,配置 EXTI 中断线 0~15 对应具体哪个 IO 口
特别注意:配置 SYSCFG 寄存器之前要使能 SYSCFG 时钟,方法如下
__HAL_RCC_SYSCFG_CLK_ENABLE();
4.2、EXTI与IO对应关系
AFIO_EXTICR1 的 EXTI0[3:0] 位控制(F1)
SYSCFG_EXTICR1 的 EXTI0[3:0] 位控制(F4/F7/H7)
Px0映射到EXTI0
Px1映射到EXTI1
…
Px14映射到EXTI14
Px15映射到EXTI15
五、如何使用中断
5.1、配置流程图
5.2、STM32 EXTI 的配置步骤(外部中断)
1、使能 GPIO 时钟
2、设置 GPIO 输入模式,上/下拉/浮空输入
3、使能 SYSCFG 时钟,设置 SYSCFG 时钟开启寄存器
4、设置 EXTI 和 IO 对应关系,选择 PA~PK 其中某组 IO 对应 EXTI 输入线,SYSCFG_EXTICR
5、设置 EXTI 对应通道的屏蔽和上升沿/下降沿触发,IMR、RTSR/FTSR
6、设置 NVIC,分三步:设置优先级分组、设置优先级、使能中断
7、设计中断服务函数,编写对应中断的中断服务函数,清除中断标志位
注意:步骤 2 – 5,使用 HAL_GPIO_Init() 一步到位
5.3、STM32 EXTI 的 HAL 库设置步骤(外部中断)
1、使能 GPIO 时钟:使用 __HAL_RCC_GPIOx_CLK_ENABLE()
2、GPIO/SYSCFG/EXTI:使用 HAL_GPIO_Init()
3、设置中断分组:使用 HAL_NVIC_SetPriorityGrouping(),此函数仅需设置一次
4、设置中断优先级:使用 HAL_NVIC_SetPriority()
5、使能中断:使用 HAL_NVIC_EnableIRQ()
6、设计中断服务函数:编写 EXTIx_IRQHandler() 中断服务函数,清除中断标志位
STM32仅有:EXTI0~4、EXTI9_5、EXTI15_10,7个外部中断服务函数
5.4、HAL库中断回调处理机制原理图
六、编程实战
通过外部中断控制一个灯亮灭
main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/KEY/key.h"
#include "./BSP/EXTI/exti.h"
int main(void)
{
HAL_Init(); // 初始化HAL库
sys_stm32_clock_init(336, 8, 2, 7); // 设置时钟,168Mhz
delay_init(168); // 延时初始化
led_init(); // 初始化LED
key_init(); // 初始化按键
extix_init(); // 初始化外部中断输入
LED0(0); // 先点亮红灯
while (1)
{
delay_ms(1000);
}
}
由于 KEY0 和 KEY1 共用了同一个外部中断服务函数 EXTI9_5_IRQHandler(),进入该中断服务函数后还需要通过 EXTI_PR 寄存器来判断具体是哪个中断线触发的
exti.c
#include "./BSP/EXTI/exti.h"
/* 外部中断初始化程序 */
void extix_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
key_init();
gpio_init_struct.Pin = KEY0_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_IT_FALLING; /* 下降沿触发 */
gpio_init_struct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(KEY0_GPIO_PORT, &gpio_init_struct); /* KEY0配置为下降沿触发中断 */
gpio_init_struct.Pin = KEY1_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_IT_FALLING; /* 下降沿触发 */
gpio_init_struct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(KEY1_GPIO_PORT, &gpio_init_struct); /* KEY1配置为下降沿触发中断 */
gpio_init_struct.Pin = WKUP_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(EXTI9_5_IRQn, 0, 2); /* 抢占0,子优先级2 */
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); /* 使能中断线4 */
HAL_NVIC_SetPriority(EXTI0_IRQn, 1, 2); /* 抢占3,子优先级2 */
HAL_NVIC_EnableIRQ(EXTI0_IRQn); /* 使能中断线0 */
}
/* KEY0 KEY1 外部中断服务程序 */
void EXTI9_5_IRQHandler(void)
{
if (__HAL_GPIO_EXTI_GET_IT(KEY0_GPIO_PIN) != RESET) /* 判断发现是KEY0中断线触发 */
{
HAL_GPIO_EXTI_IRQHandler(KEY0_GPIO_PIN); /* 调用中断处理公用函数 清除KEY0所在中断线 的中断标志位 */
__HAL_GPIO_EXTI_CLEAR_IT(KEY0_GPIO_PIN); /* HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
}
if (__HAL_GPIO_EXTI_GET_IT(KEY1_GPIO_PIN) != RESET) /* 判断发现是KEY1中断线触发 */
{
HAL_GPIO_EXTI_IRQHandler(KEY1_GPIO_PIN); /* 调用中断处理公用函数 清除KEY0所在中断线 的中断标志位 */
__HAL_GPIO_EXTI_CLEAR_IT(KEY1_GPIO_PIN); /* HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
}
}
/* WK_UP 外部中断服务程序 */
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(WKUP_GPIO_PIN); /* 调用中断处理公用函数 清除KEY_UP所在中断线 的中断标志位,中断下半部在HAL_GPIO_EXTI_Callback执行 */
__HAL_GPIO_EXTI_CLEAR_IT(WKUP_GPIO_PIN); /* HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
}
/* 中断服务程序中需要做的事情,在HAL库中所有的外部中断服务函数都会调用此函数 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
delay_ms(20); /* 消抖 */
switch (GPIO_Pin)
{
case KEY0_GPIO_PIN:
if (KEY0 == 0)
{
LED0_TOGGLE(); /* LED0 状态取反 */
}
break;
case KEY1_GPIO_PIN:
if (KEY1 == 0)
{
LED1_TOGGLE(); /* LED1 状态取反 */
}
break;
case WKUP_GPIO_PIN:
if (WK_UP == 1)
{
LED0_TOGGLE(); /* LED0 状态取反 */
LED1_TOGGLE(); /* LED1 状态取反 */
}
break;
default:
break;
}
}
exti.c 中使用的宏定义在上一章【4】STM32·HAL库·GPIO 的 key.h 对应,这里直接引入就好了
exti.h
#ifndef __EXTI_H
#define __EXTI_H
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/KEY/key.h"
#include "./BSP/LED/led.h"
void extix_init(void); /* 外部中断初始化 */
#endif
作者:HZU_Puzzle