一、外部中断简介
1、中断系统
-
中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行
-
中断优先级︰当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源
-
中断嵌套∶当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回
2、EXTI简介
-
EXTI (Extern Interrupt)外部中断
-
EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
-
支持的触发方式:上升沿/下降沿/双边沿/软件触发
-
支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断 通道数︰16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
-
触发响应方式︰中断响应/事件响应
在这里难以理解的是:EXTI0包含的是PA0、PB0、PC0到PG0,EXTI1包含的是PA1、PB1、PC1到PG1,通过ETXI的数据选择器来确定EXTIx与哪一个端口相连,形成中断线路。
二、外部中断函数
使用中断需要开启GPIO、AFIO时钟,EXTI的时钟与MCU核心同时开启,无需配置使能。将GPIO引脚与AFIO连接,将AFIO与EXTI连接形成中断线路。
1、开启时钟
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
(1)开启GPIO外设时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx,ENABLE);
选择GPIOx的端口,开启GPIOx的时钟,可以查看库函数的解释来确定所用外设时钟在哪一个时钟线
(2)开启AFIO复用时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
开启AFIO的时钟
2、AFIO函数
(1)清除AFIO配置
void GPIO_AFIODeInit(void);
(2)锁定AFIO配置
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
指定某个GPIOx端口的GPIO_Pin引脚的配置被锁定,防止意外修改
(3)
void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
(4)
void GPIO_EventOutputCmd(FunctionalState NewState);
(5)引脚重映射
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
(6)配置AFIO的数据选择器
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
其中GPIO_PortSource为外部中断源,GPIO_PinSource为外设中断线
@param GPIO_PortSource: selects the GPIO port to be used as source for EXTI lines. This parameter can be GPIO_PortSourceGPIOx where x can be (A..G).
为EXTI中断线选择GPIO端口作为中断源,这个参数可以是x为A~G的GPIO_PortSourceGPIOx
@param GPIO_PinSource: specifies the EXTI line to be configured. This parameter can be GPIO_PinSourcex where x can be (0..15).
指定要配置的EXTI中断线,这个参数可以是x为0~15的GPIO_PinSourcex
例如,将EXTI1与PB1相连形成中断线路
GPIO_EXTILineConfig(GPIO_PortSourceB,GPIO_PinSource1)
(7)以太网外设
void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);
3、EXTI函数
(1)清除EXTI配置
void EXTI_DeInit(void);
(2)初始化EXTI配置
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
(3)参数结构体变量赋默认值
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);
(4)软件触发外部中断
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);
使用该函数可以触发一次指定的外部中断线EXTI_Line,软件模拟外部引脚触发中断。
(5)获取指定标志位是否置1
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
该函数读取EXTI中断寄存器的标志位,对中断是否有效不做判断。
(6)清除指定标志位
void EXTI_ClearFlag(uint32_t EXTI_Line);
(7)获取中断状态
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
与(5)类似,但该函数不仅读取EXTI的中断寄存器的标志位,还对中断是否有效(没有被EXT_IMR寄存器中断屏蔽)做出判断。
(8)清除指定中断线的挂起位
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
与(6)类似,区别与(5)和(7)一样。
4、NVIC函数
(1)中断分组
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
配置先占优先级(抢占优先级)和从占优先级(响应优先级),整个MCU只有一种优先级分组,只需要调用一次。
(2)初始化NVIC
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
根据指定结构体变量初始化NVIC
(3)设置中断向量表
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);
(4)系统低功耗配置
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);
三、外部中断
1、GPIO初始化
当GPIO用作EXTI输入线时,GPIO应使用浮空输入、上拉输入或下拉输入
GPIO_Mode_IN_FLOATING = 0x04,
GPIO_Mode_IPD = 0x28,
GPIO_Mode_IPU = 0x48,
GPIO完全配置示例如下
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
2、EXTI外部中断初始化
创建EXTI结构体变量
EXTI_InitTypeDef EXTI_InitStructure;
结构体变量包含以下四个变量
typedef struct { uint32_t EXTI_Line; /*!< Specifies the EXTI lines to be enabled or disabled. This parameter can be any combination 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 EXTIMode_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;
-
EXTI_Line:指定外部中断线,包含EXTI_Line0~EXTI_Line15
-
EXTI_Mode:指定外部中断线的模式
参数 作用 EXTI_Mode_Interrupt 中断模式 EXTI_Mode_Event 时间模式 -
EXTI_Trigger:指定触发信号的有效边沿
参数 作用 EXTI_Trigger_Rising 上升沿触发 EXTI_Trigger_Falling 下降沿触发 EXTI_Trigger_Rising_Falling 上升沿和下降沿都触发 -
EXTI_LineCmd:指定选择的中断线的新状态,ENABLE或DISABLE
初始化外部中断结构体变量示例
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStructure);
3、NVIC配置
确定中断分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/** * @brief Configures the priority grouping: pre-emption priority and subpriority. * @param NVIC_PriorityGroup: specifies the priority grouping bits length. * This parameter can be one of the following values: * @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority * 4 bits for subpriority * @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority * 3 bits for subpriority * @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority * 2 bits for subpriority * @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority * 1 bits for subpriority * @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority * 0 bits for subpriority * @retval None */
创建NVIC结构体变量
NVIC_InitTypeDef NVIC_InitStructure;
结构体变量包含以下四个变量
typedef struct
{
uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled.
This parameter can be a value of @ref IRQn_Type
(For the complete STM32 Devices IRQ Channels list, please
refer to stm32f10x.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 NVIC_Priority_Table */
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 NVIC_Priority_Table */
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_IRQChannel:指定通道开启或关闭,可以通过对当前工程查找IRQn_Type来查询所需通道
由于使用的是STM32F103C8T6,选择在STM32F10X_MD查找
NVIC_IRQChannelCmd:指定中断通道是使能或失能,参 数为ENABLE或DISABLE
NVIC_IRQChannelPreemptionPriority:指定抢占优先级,0~15
NVIC_IRQChannelSubPriority:指定响应优先级,0~15
抢占优先级和响应优先级需按照中断分组来确定
4、编写中断函数
中断函数名为固定唯一的,可以在启动文件startup_stm32f10x_md.s中查找
例如,中断线EXTI0的中断函数,在进入中断函数后要清除EXTI中断线的挂起位,以防进入死循环。
void EXTI0_IRQHandler(void){
//函数体
EXTI_ClearITPendingBit(EXTI_Line0);
}
值得注意的是,EXTI_Line10到EXTI_Line15使用的是同一条中断线,需要使用判断语句来进行区分是哪一个中断。
void EXTI15_10_IRQHandler(void){
if(EXTI_GetITStatus(EXTI_Line10) == SET){
//函数体
EXTI_ClearITPendingBit(EXTI_Line10);
}
}
四、示例代码
主函数或头文件
//开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//配置EXTI
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStructure);
//配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
中断函数
void EXTI0_IRQHandler(void){
//函数体
}