外部中断
EXTI(外部中断/事件控制器)
STM32的中断控制器支持19个外部中断/事件请求,每一个IO口都可以作为外部中断的中断输入口
0-15为GPIO引脚的外部中断,刚好每个GPIO都有至多16个引脚。
- 线16连接的是PVD电源检测系统
- 线17连接的是RTC闹钟事件
- 线18连接的是USB唤醒事件
蓝色路线为外部中断路线,红色路线为外部事件走的路线。两种中断都是通过外部引脚输入。
1.中断从输入线开始先经过边沿检测电路,可以由上升或下降沿触发,也可以两者同时触发。
2.除了外部引脚可以触发中断事件外,软件也可以触发中断(例如用定时器定时触发中断),这里在经过边 沿触发电路后经过一个或门。
3.如果此时cpu正在执行更高级别的中断,这时候发起的中断请求无法被执行,只能等待。
4.中断被挂起后经过与门判断,也就是通过中断屏蔽寄存器判断,如果中断屏蔽寄存器为0,则该中断不执行,反之则执行。
5.事件屏蔽寄存器同理,当事件屏蔽寄存器为1时,该事件执行,经过脉冲发生器后发生脉冲。
中断与事件的区别:
虽然都是由外部激励信号产生,但是中断是需要cpu参与的,触发后由中断处理函数执行代码来实现中断的触发结果。而事件不需要经过cpu,只需要在触发后产生一个脉冲,将该脉冲直接交给硬件来处理,从而实现对应的功能。(例如DMA操作,AD转换等),这种事件触发减轻了cpu处理的负担,而且响应的速度更快。
每个管脚都会对应到相应的中断线上,但是每个中断线在使用时只能使用一个管脚。
编程实现:
- 初始化需要连接到EXTI的GPIO
- 初始化EXTI用于产生中断/事件
- 初始化NVIC,用于处理中断
- 编写中断处理函数
1、由于外部中断都是由外部引脚触发,因此在使用外部中断时需要先对对应的GPIO端口进行初始化:
void EXTI_GPIO_Init() {
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
}
初始化对应GPIO口,并打开GPIO端口的对应的RCC时钟,由于这里的IO口被外部中断使用,使用到了外部中断(EXTI)控制寄存器,因此还需要打开AFIO时钟。
2、初始化外设 EXTI 寄存器
void EXTI_init() {
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line = EXTI_Line0; //选择使能或者失能的外部线路
EXTI_InitStruct.EXTI_LineCmd = ENABLE; //选择使能或失能
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; //被使能线路的模式,这里设置 EXTI 线路为中断请求
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; //设置被使能线路的触发边沿,这里设置输入线路上升沿为中断请求
EXTI_Init(&EXTI_InitStruct);
}
3、由于使用到了中断,所以还需要对中断作优先级的配置
void NVIC_init() {
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; //指定使能的 IRQ 通道,在stm32f10x.h中找到
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; //从优先级
NVIC_Init(&NVIC_InitStruct);
}
4、编写外部中断触发后的处理函数,选择对应中断线上的中断处理函数,在启动文件中找到
void EXTI0_IRQHandler() {
if(EXTI_GetITStatus(EXTI_Line0) != RESET) {
PBout(8) = ~PBout(8);
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
判断是否进入中断,完成中断处理后清除中断标志位。
外部中断函数的调用:
其中中断线5-9共用中断函数EXTI9_5_IRQHandler();
中断线10-15共用中断函数EXTI15_10_IRQHandler();
共用同一中断函数的中断线判断,只需要判断中断线对应的中断标志位。