中断概览
什么是中断?
- 中断是指计算机运行过程中,出现某些意外情况需要主机干预时,机器自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行
- 异常和中断的概念相近,异常可以说是内核活动产生(比如执行指令出错)。中断一般是指,由连接到外部器间(外设)产生(比如外设产生中断。提示数据传输完成)。它们的触发或者说处理方式相同。使用中一般并不严格区分异常和中断。
- 如果没有特殊说明,后面所叙述的异常,特指系统异常,中断特指外中断,也就是外设中断。
STM32异常一览表
| 编号 | 类型 | 优先级 | 简介 |
|---|---|---|---|
| 0 | N/A | N/A | 没有异常在运行 |
| 1 | 复位 | -3(最高) | 复位 |
| 2 | NMI | -2 | 不可屏蔽中断(来自外部NMI输入脚) |
| 3 | 硬(hard) fault | -1 | 所有被除能的fault,都将”上访”成硬件fault,除能的原因包括当前被禁用,或者被PRIMASK或BASPRI掩蔽。 |
| 4 | MemManage fault | 可编程 | 存储器管理fault,MPU访问犯规一级访问非法位置均可引发此fault |
| 5 | 总线fault | 可编程 | 从总线系统收到了错误响应,原因可以是预取流产(Abort)或数据流产,或者企图访问协处理器 |
| 6 | 用法(usage) Fault | 可编程 | 由于程序错误导致的异常,通常是使用了一条无效指令,或者是非法的状态转换,例如尝试切换到ARM状态 |
| 7-10 | 保留 | N/A | N/A |
| 11 | SVCall | 可编程 | 执行系统服务调用指令(SVC)引发的异常 |
| 12 | 调试监视器 | 可编程 | 调试监视器(断点,数据观察点,或者是外部调试请求) |
| 13 | 保留 | N/A | N/A |
| 14 | PendSV | 可编程 | 为系统设备而设置的”可悬挂请求”(pendable request) |
| 15 | SysTick | 可编程 | 系统滴答定时器 |
STM32中断一览表
| 16 | IRQ #0 | 可编程 | 外中断 #0 |
|---|---|---|---|
| 17 | IRQ #1 | 可编程 | 外中断 #1 |
| …. | … | …. | … |
| 255 | IRQ #239 | 可编程 | 外中断 #239 |
在.s文件中找到/* External Interrupts */(外部中断)
/* External Interrupts */.word WWDG_IRQHandler /* Window WatchDog */.word PVD_IRQHandler /* PVD through EXTI Line detection */.word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */.word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */.word FLASH_IRQHandler /* FLASH */.word RCC_IRQHandler /* RCC */.word EXTI0_IRQHandler /* EXTI Line0 */.word EXTI1_IRQHandler /* EXTI Line1 */.word EXTI2_IRQHandler /* EXTI Line2 */.word EXTI3_IRQHandler /* EXTI Line3 */.word EXTI4_IRQHandler /* EXTI Line4 */.word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */.word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */.word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */.word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */.word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */.word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */.word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */.word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */.word CAN1_TX_IRQHandler /* CAN1 TX */.word CAN1_RX0_IRQHandler /* CAN1 RX0 */.word CAN1_RX1_IRQHandler /* CAN1 RX1 */.word CAN1_SCE_IRQHandler /* CAN1 SCE */.word EXTI9_5_IRQHandler /* External Line[9:5]s */.word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */.word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */.word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */.word TIM1_CC_IRQHandler /* TIM1 Capture Compare */.word TIM2_IRQHandler /* TIM2 */.word TIM3_IRQHandler /* TIM3 */.word TIM4_IRQHandler /* TIM4 */.word I2C1_EV_IRQHandler /* I2C1 Event */.word I2C1_ER_IRQHandler /* I2C1 Error */.word I2C2_EV_IRQHandler /* I2C2 Event */.word I2C2_ER_IRQHandler /* I2C2 Error */.word SPI1_IRQHandler /* SPI1 */.word SPI2_IRQHandler /* SPI2 */.word USART1_IRQHandler /* USART1 */.word USART2_IRQHandler /* USART2 */.word USART3_IRQHandler /* USART3 */.word EXTI15_10_IRQHandler /* External Line[15:10]s */.word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */.word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */.word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */.word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */.word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */.word TIM8_CC_IRQHandler /* TIM8 Capture Compare */.word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */.word FSMC_IRQHandler /* FSMC */.word SDIO_IRQHandler /* SDIO */.word TIM5_IRQHandler /* TIM5 */.word SPI3_IRQHandler /* SPI3 */.word UART4_IRQHandler /* UART4 */.word UART5_IRQHandler /* UART5 */.word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */.word TIM7_IRQHandler /* TIM7 */.word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */.word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */.word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */.word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */.word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */.word ETH_IRQHandler /* Ethernet */.word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */.word CAN2_TX_IRQHandler /* CAN2 TX */.word CAN2_RX0_IRQHandler /* CAN2 RX0 */.word CAN2_RX1_IRQHandler /* CAN2 RX1 */.word CAN2_SCE_IRQHandler /* CAN2 SCE */.word OTG_FS_IRQHandler /* USB OTG FS */.word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */.word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */.word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */.word USART6_IRQHandler /* USART6 */.word I2C3_EV_IRQHandler /* I2C3 event */.word I2C3_ER_IRQHandler /* I2C3 error */.word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */.word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */.word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */.word OTG_HS_IRQHandler /* USB OTG HS */.word DCMI_IRQHandler /* DCMI */.word 0 /* CRYP crypto */.word HASH_RNG_IRQHandler /* Hash and Rng */.word FPU_IRQHandler /* FPU
对于STM32的异常或者中断外设而言:
- 1、它的中断(/异常)是可以被编号标识的
- 2、它没有特定的类型
3、优先级
通过优先级分组,可以管理中断响应顺序。
- 只有抢占优先级才有抢占中断权限,发生中断嵌套
- 例: B中断正在执行,A中断抢占优先级比B中断小(A中断优先级要比B高),A中断则抢过B中断的使用权,响应A的中断服务函数,A中断执行完再交回B
- 如果抢占优先级相同,不发生抢占行为。
如果多个挂起的中断具有相同的抢占优先级,则子优先级高的先行,如果子优先级相同,则IRQ编号小的先行。
- A,B,C,D中D中断在运行,A,B,C的优先级无法抢断D中断;等D中端完成后,A,B,C的抢占优先级相同,就要判断子优先级,如果A的子优先级要比B和C的要大,则先运行A中断; 如果B和C的子优先级相同,则由IRQ编号小的先行\
- 查看: system_stm32f4xx.c -> #include “stm32f4xx.h” -> 找到特定的包(我这里时F407)
亮的图标Ctrl + 点击找到#if defined(STM32F405xx)#include "stm32f405xx.h"#elif defined(STM32F415xx)#include "stm32f415xx.h"#elif defined(STM32F407xx)#include "stm32f407xx.h"#elif defined(STM32F417xx)#include "stm32f417xx.h"#elif defined(STM32F427xx)#include "stm32f427xx.h"#elif defined(STM32F437xx)#include "stm32f437xx.h"#elif defined(STM32F429xx)#include "stm32f429xx.h"#elif defined(STM32F439xx)#include "stm32f439xx.h"#elif defined(STM32F401xC)#include "stm32f401xc.h"#elif defined(STM32F401xE)#include "stm32f401xe.h"#elif defined(STM32F410Tx)#include "stm32f410tx.h"#elif defined(STM32F410Cx)#include "stm32f410cx.h"#elif defined(STM32F410Rx)#include "stm32f410rx.h"#elif defined(STM32F411xE)#include "stm32f411xe.h"#elif defined(STM32F446xx)#include "stm32f446xx.h"#elif defined(STM32F469xx)#include "stm32f469xx.h"#elif defined(STM32F479xx)#include "stm32f479xx.h"#elif defined(STM32F412Cx)#include "stm32f412cx.h"#elif defined(STM32F412Zx)#include "stm32f412zx.h"#elif defined(STM32F412Rx)#include "stm32f412rx.h"#elif defined(STM32F412Vx)#include "stm32f412vx.h"#elif defined(STM32F413xx)#include "stm32f413xx.h"#elif defined(STM32F423xx)#include "stm32f423xx.h"#else#error "Please select first the target STM32F4xx device used in your application (in stm32f4xx.h file)"#endif
这些都是中断的IRQ编号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;
- 查看: system_stm32f4xx.c -> #include “stm32f4xx.h” -> 找到特定的包(我这里时F407)
- A,B,C,D中D中断在运行,A,B,C的优先级无法抢断D中断;等D中端完成后,A,B,C的抢占优先级相同,就要判断子优先级,如果A的子优先级要比B和C的要大,则先运行A中断; 如果B和C的子优先级相同,则由IRQ编号小的先行\
可编程的优先级,通过嵌套向量中断控制器(NVIC)实现。
所以: 抢占优先级 > 子优先级 > IRQ优先级
嵌套向量中断控制器(NVIC)功能(负荷CMSIS标准的NVIC库函数)
| NVIC库函数 | 描述 |
|---|---|
| void NVIC_EnableIRQ(TRQn_Type IRQn) | 使能中断 |
| void NVIC_DisableIRQ(TRQn_Type IRQn) | 使能中断 |
| void NVIC_SetPendingIRQ(TRQn_Type IRQn) | 设置中断悬起位 |
| void NVIC_ClearPendingIRQ(TRQn_Type IRQn) | 清除中断悬起位 |
| uint32_t NVIC_GetPendingIRQ(TRQn_Type IRQn) | 获取悬起中断编号 |
| void NVIC_SetPrionty(TRQn_Type IRQn, uint32_t prionty) | 设置中断优先级 |
| uint32_t NVIC_GetPrionty(TRQn_Type IRQn) | 获取中断优先级 |
| void NVIC_SystemReset(void) | 系统复位 |
找到#include "core_cmx.h"文件(有关NVIC相关内容)(x:是M几),Ctrl+点击
可以找像
#else#define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping#define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping#define NVIC_EnableIRQ __NVIC_EnableIRQ#define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ#define NVIC_DisableIRQ __NVIC_DisableIRQ#define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ#define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ#define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ#define NVIC_GetActive __NVIC_GetActive#define NVIC_SetPriority __NVIC_SetPriority#define NVIC_GetPriority __NVIC_GetPriority#define NVIC_SystemReset __NVIC_SystemReset#endif /* CMSIS_NVIC_VIRTUAL */
/**\brief Enable Interrupt\details Enables a device specific interrupt in the NVIC interrupt controller.\param [in] IRQn Device specific interrupt number.\note IRQn must not be negative.*/__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn){if ((int32_t)(IRQn) >= 0){NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));}}
在主函数中输入HAL_NVIC_SetPendingIRQ()再Ctrl+点击
void HAL_NVIC_SetPendingIRQ(IRQn_Type IRQn){/* Check the parameters */assert_param(IS_NVIC_DEVICE_IRQ(IRQn));/* Set interrupt pending */NVIC_SetPendingIRQ(IRQn);}
EXTI-扩展中断和事件控制器
事件的概念
- STM32上许许多多的外设,是通过内部信号来协助工作的。这个信号,可以理解为事件,比如一个定时器(TIM),当我们使用定时器来计数的时候,怎么知道定时器已经计数完毕?这个时候就往往通过一个”计数完成事件”来告知(系统/用户)计数器已经完成。
- 有些事件是可见的,有些事件是不可见的。事件的可不可见,具体体现在寄存器里可不可以查到这些事件的标志。那如果我们想使用这些事件的时候,该怎么做?查询事件标志吗?
- 在STM32中,绝大部分数事件是不可见的,但是事件几乎斗鱼中断功能绑定在一起/所以通常我们回开启中断的功能,来使用相应的事件。
- 事件 —-> 中断 ; 事件 ——-> 事件
EXTI-扩展中断和事件控制器
- EXTI扩展中断和事件控制器,是STM32上的一个外设。它可以捕获外部输入线电平的变化等等的一些事件。EXTI捕获到了事件后,还可以生成相应的EXTI中断及等等的一些中断。
- 捕获外部输入等事件。
- 生成EXTI中断等中断请求
实验工程讲解
按照STM32F103ZET6的芯片(正点原子的精英板)来配置
- Serial Wire: 串行线
时钟配置

选择PB5的GPIO_EXTI5

GPIO模式
- Extemal Interrupt Mode: 外部中断模式
- Rising edge trigger detection : 上升沿触发
- Falling edge trigger detection : 下降沿触发
- 外部中断模式
- Extemal Interrupt Mode with Rising edge trigger detection
- Extemal Interrupt Mode with Falling edge trigger detection
- Extemal Interrupt Mode with Rising/Falling edge trigger detection
- 事件模式
Priorinty Group : 优先级分组
- Preemption Priorinty : 抢占优先级
- Sub Priorinty : 子优先级
Project Manager进行项目的配置
vscode 中的STM32F103ZET6
找到void MX_GPIO_Init(void) (gpio.c中)
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_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);/*Configure GPIO pin : PtPin */GPIO_InitStruct.Pin = LED1_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(LED1_GPIO_Port, &GPIO_InitStruct);/*Configure GPIO pin : PtPin */GPIO_InitStruct.Pin = LED0_Pin;GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; //使用了上升沿下降沿中断GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(LED0_GPIO_Port, &GPIO_InitStruct);/* EXTI interrupt init*/HAL_NVIC_SetPriority(EXTI9_5_IRQn, 5, 0); //使用HAL库的设置优先级的函数来使能EXTI9_5_IRQn中断编号的中断使能HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);//使用HAL库的初始化的函数来使能EXTI9_5_IRQn中断编号的中断使能}
设置板级支持包(就是功能配置)
配置Makefile
####################################### source####################################### C sourcesC_SOURCES = \Core/Src/main.c \Core/Src/gpio.c \Core/Src/stm32f1xx_it.c \Core/Src/stm32f1xx_hal_msp.c \Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio_ex.c \Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim.c \Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim_ex.c \Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c \Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c \Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc_ex.c \Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio.c \Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c \Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c \Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pwr.c \Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash.c \Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash_ex.c \Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_exti.c \Core/Src/system_stm32f1xx.c \User/bsp_exti.c #添加这段,是你的位于项目根目录下存放.c路径...# C includesC_INCLUDES = \-ICore/Inc \-IDrivers/STM32F1xx_HAL_Driver/Inc \-IDrivers/STM32F1xx_HAL_Driver/Inc/Legacy \-IDrivers/CMSIS/Device/ST/STM32F1xx/Include \-IDrivers/CMSIS/Include \-IUser #添加这段,前面'-I'是固定格式,添加'.h'的目录
编写的板级支持包与hal库生成的相同功能,可以不写,只是了解
#include "bsp_exti.h"void EXTI_Key_Config(void){GPIO_InitTypeDef GPIO_InitStructure;/*开启按键GPIO口的时钟*/__HAL_RCC_GPIOE_CLK_ENABLE();/*设置按键1的引脚*/GPIO_InitStructure.Pin = KEY1_INT_GPIO_PIN; //#define KEY1_INT_GPIO_PIN GPIO_PIN_3/*设置引脚的输入模式*/GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING; //上升沿/*设置引脚不上拉,不下拉*/GPIO_InitStructure.Pull = GPIO_NOPULL;/*初始化*/HAL_GPIO_Init(KEY1_GPIO_Port,&GPIO_InitStructure);//#define KEY1_GPIO_Port GPIOE/*配置EXTI中断源到Key1引脚、配置中断优先级*/HAL_NVIC_SetPriority(KEY1_INT_EXTI_IRQ,0,0);//#define KEY1_INT_EXTI_IRQ EXTI3_IRQn/*使能中断*/HAL_NVIC_EnableIRQ(KEY1_INT_EXTI_IRQ);/*设置按键0的引脚*/GPIO_InitStructure.Pin = KEY0_INT_GPIO_PIN; //#define KEY0_INT_GPIO_PIN GPIO_PIN_4/*设置引脚的输入模式*/GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING; //上升沿/*设置引脚不上拉,不下拉*/GPIO_InitStructure.Pull = GPIO_NOPULL;/*初始化*/HAL_GPIO_Init(KEY0_GPIO_Port,&GPIO_InitStructure);//#define KEY0_GPIO_Port GPIOE/*配置EXTI中断源到Key1引脚、配置中断优先级*/HAL_NVIC_SetPriority(KEY0_INT_EXTI_IRQ,0,0);//#define KEY0_INT_EXTI_IRQ EXTI3_IRQn/*使能中断*/HAL_NVIC_EnableIRQ(KEY0_INT_EXTI_IRQ);}
#ifndef __BSP_EXTI_H_#define __BSP_EXTI_H_#ifdef __cplusplusextern "C"{#endif#define KEY1_INT_GPIO_PIN GPIO_PIN_3#define KEY1_INT_EXTI_IRQ EXTI3_IRQn#define KEY1_GPIO_Port GPIOE#define KEY0_INT_GPIO_PIN GPIO_PIN_4#define KEY0_INT_EXTI_IRQ EXTI3_IRQn#define KEY0_GPIO_Port GPIOE//Include .........#include "stm32f1xx_hal.h"void EXTI_Key_Config(void);#ifdef __cplusplus}#endif#endif
查看GPIO_MODE_IT_RISING(中断上升沿模式)
#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 */
/*--------------------- EXTI Mode Configuration ------------------------*/ //EXTI模式的配置/* Configure the External Interrupt or event for the current IO */if ((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE){/* Enable AFIO Clock */ //使能IO配置__HAL_RCC_AFIO_CLK_ENABLE();temp = AFIO->EXTICR[position >> 2u];CLEAR_BIT(temp, (0x0Fu) << (4u * (position & 0x03u)));SET_BIT(temp, (GPIO_GET_INDEX(GPIOx)) << (4u * (position & 0x03u)));AFIO->EXTICR[position >> 2u] = temp;/* Configure the interrupt mask */if ((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT){SET_BIT(EXTI->IMR, iocurrent);//置位}else{CLEAR_BIT(EXTI->IMR, iocurrent);//复位}/* Configure the event mask */if ((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT){SET_BIT(EXTI->EMR, iocurrent);}else{CLEAR_BIT(EXTI->EMR, iocurrent);}/* Enable or disable the rising trigger */if ((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE){SET_BIT(EXTI->RTSR, iocurrent);}else{CLEAR_BIT(EXTI->RTSR, iocurrent);}/* Enable or disable the falling trigger */if ((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE){SET_BIT(EXTI->FTSR, iocurrent);}else{CLEAR_BIT(EXTI->FTSR, iocurrent);}}
EXTI中断 -> 中断向量 -> 偏移:入口地址 -> 中断服务函数
....word WWDG_IRQHandler.word PVD_IRQHandler.word TAMPER_IRQHandler.word RTC_IRQHandler.word FLASH_IRQHandler.word RCC_IRQHandler.word EXTI0_IRQHandler.word EXTI1_IRQHandler.word EXTI2_IRQHandler.word EXTI3_IRQHandler.word EXTI4_IRQHandler...
大量的Handler,这些函数就是中断的服务函数也就是说中断向量表中存放的都是这些函数
不同的输入线对应着不同的一个中断服务函数,当我们触发中断的时候CPU就会到中断服务向量表中根据中断的编号进行偏移,偏移之后就会到中断向量表中对应位置去取出函数的入口地址
可以在
stm32f1xx_it.c句柄- NMI_Handler() : 不可屏蔽中断的句柄
- HardFault_Handler() : 硬件错误的句柄
- …
- 这些中断句柄都是弱定义来的(也就是说你中断服务函数放在哪个位置都可以)
void KEY0_IRQHandler(void){ //板机支持包中的宏定义: #define KEY0_IRQHandler EXTI4_IRQHandler//确保是否产生了EXTI Line中断if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_4) != RESET){HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);//清除标志位__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4);}}
通过EXTI线,获取EXTI线事件,并且去生成中断,并清除EXTI中断标志(中断标志要清除,不然就会一直产生中断)
没写板级支持包也可以:
/*** @brief This function handles EXTI line4 interrupt.*/void EXTI4_IRQHandler(void){/* USER CODE BEGIN EXTI4_IRQn 0 */if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_4) != RESET){HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4);}/* USER CODE END EXTI4_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(KEY0_Pin);/* USER CODE BEGIN EXTI4_IRQn 1 *//* USER CODE END EXTI4_IRQn 1 */}

