外部中断
Last updated
Last updated
中断是由(NVIC寄存器)Nested vectored interrupt controller,嵌套向量中断控制器管理的,这是内核级别的寄存器,在F103的数据参考手册找不到资料,需要在Coretx-M3权威指南查看。比如设置中断优先级分组就是在设置SCB->AIRCR寄存器,可以在==Coretx-M3权威指南==第七章查看。
NVIC 共256个中断源,其中支持 1 至 240 个外部中断输入(其实就是外设的中断,通常写作 IRQs),也就是内核中断16个,但实际只用到10个内核中断,具体的中断类型可以在==Coretx-M3权威指南==查看。
内核级别的中断:
外设的中断没有具体
查看本笔记的第6章节
在启动文件中设置了中断向量表,这里其实就是中断服务函数名,并且在启动文件中进行了弱定义,因此我们只需在.c文件对对应的中断服务函数进行重定义即可。
__Vectors DCD __initial_sp ; Top of Stack 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 ; External Interrupts DCD WWDG_IRQHandler ; Window Watchdog DCD PVD_IRQHandler ; PVD through EXTI Line detect DCD TAMPER_IRQHandler ; Tamper DCD RTC_IRQHandler ; RTC DCD FLASH_IRQHandler ; Flash DCD RCC_IRQHandler ; RCC 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 DMA1_Channel1_IRQHandler ; DMA1 Channel 1 DCD DMA1_Channel2_IRQHandler ; DMA1 Channel 2 DCD DMA1_Channel3_IRQHandler ; DMA1 Channel 3 DCD DMA1_Channel4_IRQHandler ; DMA1 Channel 4 DCD DMA1_Channel5_IRQHandler ; DMA1 Channel 5 DCD DMA1_Channel6_IRQHandler ; DMA1 Channel 6 DCD DMA1_Channel7_IRQHandler ; DMA1 Channel 7 DCD ADC1_2_IRQHandler ; ADC1 & ADC2 DCD USB_HP_CAN1_TX_IRQHandler ; USB High Priority or CAN1 TX DCD USB_LP_CAN1_RX0_IRQHandler ; USB Low Priority or CAN1 RX0 DCD CAN1_RX1_IRQHandler ; CAN1 RX1 DCD CAN1_SCE_IRQHandler ; CAN1 SCE DCD EXTI9_5_IRQHandler ; EXTI Line 9..5 DCD TIM1_BRK_IRQHandler ; TIM1 Break DCD TIM1_UP_IRQHandler ; TIM1 Update DCD TIM1_TRG_COM_IRQHandler ; TIM1 Trigger and Commutation 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 ; EXTI Line 15..10 DCD RTC_Alarm_IRQHandler ; RTC Alarm through EXTI Line DCD USBWakeUp_IRQHandler ; USB Wakeup from suspend DCD TIM8_BRK_IRQHandler ; TIM8 Break DCD TIM8_UP_IRQHandler ; TIM8 Update DCD TIM8_TRG_COM_IRQHandler ; TIM8 Trigger and Commutation DCD TIM8_CC_IRQHandler ; TIM8 Capture Compare DCD ADC3_IRQHandler ; ADC3 DCD FSMC_IRQHandler ; FSMC DCD SDIO_IRQHandler ; SDIO DCD TIM5_IRQHandler ; TIM5 DCD SPI3_IRQHandler ; SPI3 DCD UART4_IRQHandler ; UART4 DCD UART5_IRQHandler ; UART5 DCD TIM6_IRQHandler ; TIM6 DCD TIM7_IRQHandler ; TIM7 DCD DMA2_Channel1_IRQHandler ; DMA2 Channel1 DCD DMA2_Channel2_IRQHandler ; DMA2 Channel2 DCD DMA2_Channel3_IRQHandler ; DMA2 Channel3 DCD DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5 __Vectors_End
在 stm32f103xe.h枚举了中断类型,HAL_NVIC_EnableIRQ函数的参数就可选以下的
NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ HardFault_IRQn = -13, /*!< 3 Cortex-M3 Hard Fault Interrupt */ MemoryManagement_IRQn = -12, /*!< 4 Cortex-M3 Memory Management Interrupt */ BusFault_IRQn = -11, /*!< 5 Cortex-M3 Bus Fault Interrupt */ UsageFault_IRQn = -10, /*!< 6 Cortex-M3 Usage Fault Interrupt */ SVCall_IRQn = -5, /*!< 11 Cortex-M3 SV Call Interrupt */ DebugMonitor_IRQn = -4, /*!< 12 Cortex-M3 Debug Monitor Interrupt */ PendSV_IRQn = -2, /*!< 14 Cortex-M3 Pend SV Interrupt */ SysTick_IRQn = -1, /*!< 15 Cortex-M3 System Tick Interrupt */ /****** STM32 specific Interrupt Numbers *********************************************************/ WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */ PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */ TAMPER_IRQn = 2, /*!< Tamper Interrupt */ RTC_IRQn = 3, /*!< RTC global Interrupt */ 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_Channel1_IRQn = 11, /*!< DMA1 Channel 1 global Interrupt */ DMA1_Channel2_IRQn = 12, /*!< DMA1 Channel 2 global Interrupt */ DMA1_Channel3_IRQn = 13, /*!< DMA1 Channel 3 global Interrupt */ DMA1_Channel4_IRQn = 14, /*!< DMA1 Channel 4 global Interrupt */ DMA1_Channel5_IRQn = 15, /*!< DMA1 Channel 5 global Interrupt */ DMA1_Channel6_IRQn = 16, /*!< DMA1 Channel 6 global Interrupt */ DMA1_Channel7_IRQn = 17, /*!< DMA1 Channel 7 global Interrupt */ ADC1_2_IRQn = 18, /*!< ADC1 and ADC2 global Interrupt */ USB_HP_CAN1_TX_IRQn = 19, /*!< USB Device High Priority or CAN1 TX Interrupts */ USB_LP_CAN1_RX0_IRQn = 20, /*!< USB Device Low Priority or CAN1 RX0 Interrupts */ 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_IRQn = 24, /*!< TIM1 Break Interrupt */ TIM1_UP_IRQn = 25, /*!< TIM1 Update Interrupt */ TIM1_TRG_COM_IRQn = 26, /*!< TIM1 Trigger and Commutation 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 through EXTI Line Interrupt */ USBWakeUp_IRQn = 42, /*!< USB Device WakeUp from suspend through EXTI Line Interrupt */ TIM8_BRK_IRQn = 43, /*!< TIM8 Break Interrupt */ TIM8_UP_IRQn = 44, /*!< TIM8 Update Interrupt */ TIM8_TRG_COM_IRQn = 45, /*!< TIM8 Trigger and Commutation Interrupt */ TIM8_CC_IRQn = 46, /*!< TIM8 Capture Compare Interrupt */ ADC3_IRQn = 47, /*!< ADC3 global 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_IRQn = 54, /*!< TIM6 global Interrupt */ TIM7_IRQn = 55, /*!< TIM7 global Interrupt */ DMA2_Channel1_IRQn = 56, /*!< DMA2 Channel 1 global Interrupt */ DMA2_Channel2_IRQn = 57, /*!< DMA2 Channel 2 global Interrupt */ DMA2_Channel3_IRQn = 58, /*!< DMA2 Channel 3 global Interrupt */ DMA2_Channel4_5_IRQn = 59, /*!< DMA2 Channel 4 and Channel 5 global Interrupt */
STM32F103 的 19 个外部中断为:
EXTI 线 015:对应外部 IO 口的输入中断。
EXTI 线 16:连接到 PVD 输出。
EXTI 线 17:连接到 RTC 闹钟事件。
EXTI 线 18:连接到 USB 唤醒事件。
EXTI 线 19:连接到以太网唤醒事件。
从上面可以看出, STM32F1 供 IO 口使用的中断线只有 16 个,但是 STM32F1 的 IO 口却 远远不止 16 个,那么 STM32F1 是怎么把 16 个中断线和 IO 口一一对应起来的呢?GPIO 的管脚GPIOx.0GPIOx.15(x=A,B,C,D,E, F,G,H,I)分别对应中断线 0~15。这
样每个中断线对应了最多 9 个 IO 口,以线 0 为例:它对应了 GPIOA.0、 GPIOB.0、 GPIOC.0、
GPIOD.0、 GPIOE.0、 GPIOF.0、 GPIOG.0。而中断线每次只能连接到 1 个 IO 口上,这样就需要 通过配置相应的寄存器,即外部中断配置寄存器AFIO_EXTICRx,来决定对应的中断线配置到哪个 GPIO 上了。
以正点原子的HAL库外部中断例程为例
//外部中断初始化
void EXTI_Init(void)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
__HAL_RCC_GPIOE_CLK_ENABLE(); //开启GPIOE时钟
GPIO_Initure.Pin=GPIO_PIN_0; //PA0
GPIO_Initure.Mode=GPIO_MODE_IT_RISING; //上升沿触发
GPIO_Initure.Pull=GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
GPIO_Initure.Pin=GPIO_PIN_3|GPIO_PIN_4; //PE3,4
GPIO_Initure.Mode=GPIO_MODE_IT_FALLING; //下降沿触发
GPIO_Initure.Pull=GPIO_PULLUP;
HAL_GPIO_Init(GPIOE,&GPIO_Initure);
//中断线0-PA0
HAL_NVIC_SetPriority(EXTI0_IRQn,2,0); //抢占优先级为2,子优先级为0
HAL_NVIC_EnableIRQ(EXTI0_IRQn); //使能中断线0
//中断线3-PE3
HAL_NVIC_SetPriority(EXTI3_IRQn,2,2); //抢占优先级为2,子优先级为2
HAL_NVIC_EnableIRQ(EXTI3_IRQn); //使能中断线2
//中断线4-PE4
HAL_NVIC_SetPriority(EXTI4_IRQn,2,3); //抢占优先级为2,子优先级为3
HAL_NVIC_EnableIRQ(EXTI4_IRQn); //使能中断线4
}
//中断服务函数
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); //调用中断处理公用函数
}
void EXTI3_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3); //调用中断处理公用函数
}
void EXTI4_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4); //调用中断处理公用函数
}
先初始化GPIO时钟
初始化AFIO时钟,这边没有体现是因为在初始化USART时已经初始化了
初始化GPIO,设置中断触发类型,并设置上下拉
配置NVIC,设置中断优先级,并开启中断
配置中断服务函数,EXTI0_IRQHandler函数与启动文件的中断向量表设置一致,在该函数中又调用了HAL_GPIO_EXTI_IRQHandler函数
首先通过__HAL_GPIO_EXTI_GET_IT函数判断是哪个中断被触发,然后通过__HAL_GPIO_EXTI_CLEAR_IT函数清除中断标志位。最后调用HAL_GPIO_EXTI_Callback函数,该函数有HAL库先进性弱定义,再由用户自己编写覆盖重定义,用于实现自己的业务逻辑。
该函数具体如下
/**
* @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) != 0x00u)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
HAL_GPIO_EXTI_Callback需要自行编写,里面是真正的自己需要让中断完成的业务逻辑
值得注意的是上述代码看似并没有对中断线进行设置,及设置中断线0映射到GPIOA0还是GPIOB0又或是GPIOE0,这是因为HAL_GPIO_Init函数里对此进行了处理,它对形如GPIO_MODE_IT_RISING这样的中断模式进行了判断,当判断到模式为中断类型的话,就对AFIO->EXTICR寄存器进行设置
是只要使用到重映射或者IO复用就要需要开启吗?不是的,只有需要对AFIO寄存器进行读写才需要开启,而什么时候需要用到呢?AFIO共有以下几个寄存器:
1、 事件控制寄存器(AFIO_EVCR) 2、 复用重映射和调试I/O 配置寄存器(AFIO_MAPR) :配置JTAG/SWD调试接口的IO口功能。 3、 外部中断配置寄存器1(AFIO_EXTICR1) 4、 外部中断配置寄存器2(AFIO_EXTICR2) 5、 外部中断配置寄存器3(AFIO_EXTICR3) 6、 外部中断配置寄存器4(AFIO_EXTICR4)
具体来说:1、使用重映射时需要。2、使用外部中断时需要
AFIO_MAPR寄存器用以配置是否开启JTAG/SWD调试,但是查看官方的文件SystemInit里面并没有对其进行设置,因为查看参考手册,发现默认复位状态,就是开启JTAG和SWD接口调试的,
由于我们并没有对AFIO_MAPR寄存器进行读写,自然也无需开启AFIO时钟