第四部分 中断机制
一、中断
中断响应: CPU指令执行过程中,被“紧急”事件打断。
中断处理: 停止正在运行的程序并转入处理新情况的程序。
中断返回: 处理完毕后又返回原被暂停的程序继续运行。
二、ARM Cortex M4中断机制
中断控制器IC“通知”MCU,有“事”(中断事件)啦,MCU会停止正在做的程序事件,转而中断处理。
M4给不同的事件(中断),一个唯一的中断编号(为了区分不同的中断事件)。当不同的中断事件产生时,MCU作不同的处理。
1. 中断向量表
优先级类型 | 名称 | 说明 | 地址 |
---|---|---|---|
可设置 | EXTI0 | EXTI 线 0 中断 | 0x0000 0058 |
可设置 | EXTI1 | EXTI 线 1 中断 | 0x0000 005C |
可设置 | EXTI2 | EXTI 线 2 中断 | 0x0000 0060 |
可设置 | EXTI3 | EXTI 线 3 中断 | 0x0000 0064 |
可设置 | EXTI4 | EXTI 线 4 中断 | 0x0000 0068 |
产生中断后,CPU到指定的地址取中断处理函数的函数指针,然后去执行中断响应函数。
2. 中断处理函数
在STM32F407的汇编启动文件中startup_stm32f40xx.s规定了每一个中断函数的固定的名字。
__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 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 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_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 CRYP_IRQHandler ; CRYP crypto
DCD HASH_RNG_IRQHandler ; Hash and Rng
DCD FPU_IRQHandler ; FPU
__Vectors_End
void ***_isr(void)
void EXTI0_IRQHandler(void){}
说明:
- 无返回 无入口参数
- 普通函数 申明 定义 调用(主动)但是中断响应函数 CPU被动调用
- 中断响应函数的函数名必须和中断向量表中的一致
三、STM32F4xx 中断管理
任何中断产生到CPU响应,都要经过两个阶段:
1. 中断源的控制
中断源: 产生中断的设备。
设备要能够产生中断,必须有一根中断请求线(IRQ Line),而且这根中断请求线,必须连到嵌套中断控制器(NVIC,(Nested Vectored Interrupt Controller))
2. 中断控制器的控制 NVIC
对所有的中断输入引脚进行管理和控制,给CPU内核一个中断信号,通知CPU某设备产生中断。
一个设备产生了中断首先要经过 “中断源”这一级,“中断源”可以屏蔽或使能中断(disable/enable 自己的中断),即便是外部电路上产生了一个“事件”,中断源可以不向它上一级NVIC(中断控制器)报告。若“报告”:在NVIC的输入引脚上产生一个“跳变”。
中断控制器(NVIC)它也可以控制中断,它在收到外设的中断信号后,也可以选择enable/disable这个中断,意思是,它可以选择向它的上一级(CPU)报告或不报告。
四、STM32F4XX 外部中断
异常: CPU产生的,如:指令错误
中断: 外设(出CPU以外的设备)产生(UART I2C TIM GPIO)
-
外部中断: 指GPIO的外部电路上产生的中断 (如按键中断)
EXTI: external interrupt 外部中断
STM32F4的中断控制器支持23个外部中断/事件请求(EXTI0-EXTI22)
EXTI线0~15:对应外部IO口的输入中断 如:GPIOx.1映射到EXTI1
注意:一条中断线的在同一时间只能被一个IO口映射。
例子:S1-KEY0—PA0 —EXTI0–NVIC–CPU-EXTI0_IRQHandler
GPIO外部中断的路线图
外部电路变化 -> 引脚电平变化 -> GPIO控制器 -> SYSCFG选择器-> EXTI外部中断控制器 -> NVIC中断控制器 -> CPU(Cortex M4)
GPIO控制器: 配置引脚为输入模式…
SYSCFG选择器: 选择GPIO引脚作为EXTIn的输入引脚
EXTI外部中断控制器: 边沿选择 中断屏蔽…
五、外部中断的代码实现
0. 按键原理图
首先查看按键原理图:
可知:KEY0 -> PA0 -> EXTI0 -> NVIC -> CPU EXTI0_IRQHandler
KEY1 -> PE2 -> EXTI2 -> NVIC -> CPU EXTI2_IRQHandler
KEY2 -> PE3 -> EXTI3 -> NVIC -> CPU EXTI3_IRQHandler
KEY3 -> PE4 -> EXTI4 -> NVIC -> CPU EXTI4_IRQHandler
按下输出低电平,松开输出高电平,如果要按下检测电路,即选择下降沿选择寄存器
1. 中断源的控制
-
GPIO控制器的配置
-
时钟使能:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
-
GPIO_Init 配置(input mode)
GPIO_InitTypeDef p; p.GPIO_Mode = GPIO_Mode_IN; //输入模式 p.GPIO_OType = GPIO_OType_PP; //推挽 p.GPIO_Pin = GPIO_Pin_0; //引脚编号 p.GPIO_PuPd = GPIO_PuPd_NOPULL; //无上拉、无下拉 p.GPIO_Speed = GPIO_Speed_50MHz;//输出速率50MHz GPIO_Init(GPIOA, &p); //初始化 p.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4; GPIO_Init(GPIOE, &p);
-
-
SYSCFG选择器的配置
-
时钟使能:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);
-
选择相应的GPIO引脚作为外部中断的输入引脚:
SYSCFG_EXTILineConfig用来选择相应的GPIO引脚作为外部中断的输入引脚
void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex);
- EXTI_PortSourceGPIOx:选择GPIO口分组 如:EXTI_PortSourceGPIOA
- EXTI_PinSourcex:选择引脚的编号 如:EXTI_PinSource0
例子:
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
-
-
EXTI外部中断控制器的配置
EXTI_Init用来配置EXTI外部中断控制器(边沿选择、中断屏蔽,……)
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
/** * @brief EXTI Init Structure definition */ typedef struct { uint32_t EXTI_Line; /*!< Specifies the EXTI lines to be enabled or disabled. This parameter can be any combination value of @ref EXTI_Lines */ EXTIMode_TypeDef EXTI_Mode; /*!< Specifies the mode for the EXTI lines. This parameter can be a value of @ref EXTIMode_TypeDef */ EXTITrigger_TypeDef EXTI_Trigger; /*!< Specifies the trigger signal active edge for the EXTI lines. This parameter can be a value of @ref EXTITrigger_TypeDef */ FunctionalState EXTI_LineCmd; /*!< Specifies the new state of the selected EXTI lines. This parameter can be set either to ENABLE or DISABLE */ }EXTI_InitTypeDef;
/** * @brief EXTI mode enumeration */ typedef enum { EXTI_Mode_Interrupt = 0x00, EXTI_Mode_Event = 0x04 }EXTIMode_TypeDef;
/** * @brief EXTI Trigger enumeration */ typedef enum { EXTI_Trigger_Rising = 0x08, //上升沿 指某个点的电位由低电位变成高电位的瞬间 EXTI_Trigger_Falling = 0x0C, //下降沿 指某个点的电位由高电位变成低电位的瞬间 EXTI_Trigger_Rising_Falling = 0x10 //双边沿 两个状态都可以 }EXTITrigger_TypeDef;
例子:
EXTI_InitTypeDef e; e.EXTI_Line = EXTI_Line0|EXTI_Line2|EXTI_Line3|EXTI_Line4; //要出事后的外部中断编号 e.EXTI_LineCmd = ENABLE; e.EXTI_Mode = EXTI_Mode_Interrupt; //指定外部中短线的模式 中断模式 e.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //双边沿 EXTI_Init(&e);
-
IT: InTerrupt中断
EXTI_GetITStatus用来获取EXTI_Line指定的外部中断的中断状态
SET:产生了中断 1
RESET:没产生中断 0
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
EXTI_ClearITPendingBit用来清掉相应的外部中断的Pending标记
在用户中断处理函数末尾(中断处理后)要把相应的中断pending标识给清掉,否则会一直产生中断。
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
另外:
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
void EXTI_ClearFlag(uint32_t EXTI_Line);
2. NVIC的控制
NVIC_PriorityGroupConfig:void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
/** @defgroup MISC_Preemption_Priority_Group
* @{
*/
#define NVIC_PriorityGroup_0 ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
4 bits for subpriority */
#define NVIC_PriorityGroup_1 ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
3 bits for subpriority */
#define NVIC_PriorityGroup_2 ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
2 bits for subpriority */
#define NVIC_PriorityGroup_3 ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
1 bits for subpriority */
#define NVIC_PriorityGroup_4 ((uint32_t)0x300) /*!< 4 bits for pre-emption priority
0 bits for subpriority */
NVIC_Init 初始化一个指定的中断:void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
NVIC_InitStruct: 指向初始化的结构体
typedef struct
{
uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled.
This parameter can be an enumerator of @ref IRQn_Type
enumeration (For the complete STM32 Devices IRQ Channels
list, please refer to stm32f4xx.h file) */
uint8_t NVIC_IRQChannelPreemptionPriority; /*!< Specifies the pre-emption priority for the IRQ channel
specified in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref MISC_NVIC_Priority_Table
A lower priority value indicates a higher priority */
uint8_t NVIC_IRQChannelSubPriority; /*!< Specifies the subpriority level for the IRQ channel specified
in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref MISC_NVIC_Priority_Table
A lower priority value indicates a higher priority */
FunctionalState NVIC_IRQChannelCmd; /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
will be enabled or disabled.
This parameter can be set either to ENABLE or DISABLE */
} NVIC_InitTypeDef;
例子:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef n;
n.NVIC_IRQChannel = EXTI0_IRQn; // PPP_IRQn
n.NVIC_IRQChannelCmd = ENABLE;
n.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级
n.NVIC_IRQChannelSubPriority = 2; //中断子优先级
NVIC_Init(&n);
六、 作业(按键点灯)
1. key.h
#ifndef _KEY_H_
#define _KEY_H_
#include "stm32f4xx.h"
#include "rj_led.h"
void key_init(void);
#endif
2. key.c
#include "key.h"
void key_init()
{
//0.clk_enable
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOE, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_EXTIT, ENABLE);
//1.GPIO PA0 PE2 PE3 PE4
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode =GPIO_Mode_IN; //输入模式
GPIO_InitStruct.GPIO_Pin =GPIO_Pin_0;
GPIO_InitStruct.GPIO_PuPd =GPIO_PuPd_NOPULL; //无上拉 无下拉
GPIO_InitStruct.GPIO_Speed =GPIO_Speed_50MHz; //输出速率为50MHz
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin =GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
GPIO_Init(GPIOE,&GPIO_InitStruct);
//2.PA0-EXTI Line0 PE2-EXTI2 PE3-EXTI3 PE4-EXTI4
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0); //用来指定中断/事件线的输入源
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource2);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource3);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4);
//3.EXTI CFG
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line =EXTI_Line0|EXTI_Line2|EXTI_Line3|EXTI_Line4;
EXTI_InitStruct.EXTI_LineCmd =ENABLE;
EXTI_InitStruct.EXTI_Mode =EXTI_Mode_Interrupt; //中断模式
EXTI_InitStruct.EXTI_Trigger =EXTI_Trigger_Falling; //下降沿
EXTI_Init(&EXTI_InitStruct);
//4.NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//2 bits for pre-emption priority
//2 bits for subpriority
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel =EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd =ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =2; //设置抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority =2; //设置子优先级
NVIC_Init(&NVIC_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel =EXTI2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =3;
NVIC_Init(&NVIC_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel =EXTI3_IRQn;
NVIC_Init(&NVIC_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel =EXTI4_IRQn;
NVIC_Init(&NVIC_InitStruct);
}
void EXTI0_IRQHandler(void)
{
//IRQ?
if(EXTI_GetITStatus(EXTI_Line0)==SET) //如果中断产生
{
//do
if(Bit_RESET==GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)) //确定是由于对应的按键按下
{
delay(100);
GPIO_ToggleBits(GPIOF, GPIO_Pin_9);
}
//clear
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
void EXTI2_IRQHandler(void)
{
//IRQ?
if(EXTI_GetITStatus(EXTI_Line2)==SET)
{
//do
if(Bit_RESET==GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2))
{
delay(100);
GPIO_ToggleBits(GPIOF, GPIO_Pin_10);
}
//clear
EXTI_ClearITPendingBit(EXTI_Line2);
}
}
void EXTI3_IRQHandler(void)
{
//IRQ?
if(EXTI_GetITStatus(EXTI_Line3)==SET)
{
//do
if(Bit_RESET==GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3))
{
delay(100);
GPIO_ToggleBits(GPIOE, GPIO_Pin_13);
}
//clear
EXTI_ClearITPendingBit(EXTI_Line3);
}
}
void EXTI4_IRQHandler(void)
{
//IRQ?
if(EXTI_GetITStatus(EXTI_Line4)==SET)
{
//do
if(Bit_RESET==GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4))
{
delay(100);
GPIO_ToggleBits(GPIOE, GPIO_Pin_14);
}
//clear
EXTI_ClearITPendingBit(EXTI_Line4);
}
}
第一部分 嵌入式系统概述
第二部分 ARM指令系统
第三部分 通用 I/O (GPIO)
第四部分 中断机制
第五部分 时钟定时器