外部中断
中断函数:检测到外部中断后将自动跳转执行的函数;(stm32F103的外部中断函数只有7个)
中断引脚:可以引起中断的引脚(stm32中的所有引脚);
中断线:由于中断引脚数目多,所以中断线是真实产生的中断信号,有16条中断线,第一条对应(GPIOA、B-F,的第0引脚) 当中断引脚和中断线连接起时才可以产生中断(这时可以产生16个外部中断信号,但是只有7个外部中断函数)所以,0-4中断线的中断信号都有一个中断函数处理,5-9的是一个中断函数处理,10-f的是一个中断函数处理;(外部中断线有16个,但是中断线有20个)
外部中断函数定义如下:
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 EXTI9_5_IRQHandler ; EXTI Line 9..5
DCD EXTI15_10_IRQHandler ; EXTI Line 15..10
外部中断使用流程:
-
要使用中断所以要用到NVIC配置中断优先级
-
先要配置NVIC优先级分组:
void NVIC_PriorityGroupConfig(uint32_t *NVIC_PriorityGroup*);
-
配置中断的优先级:
NVIC_InitTypeDef nvic_init_config; //目标中断函数 其值可以在stm32f10x.h 中的 #ifdef STM32F10X_HD 宏中找到 nvic_init_config.NVIC_IRQChannel=EXTI9_5_IRQn; nvic_init_config.NVIC_IRQChannelCmd=ENABLE;//开启中断通道 nvic_init_config.NVIC_IRQChannelPreemptionPriority=2;//配置中断通道的抢占优先级 nvic_init_config.NVIC_IRQChannelSubPriority=2;//配置中断通道的子优先级(响应优先级) NVIC_Init(&nvic_init_config);//将配置写入
-
-
使用外部中断需要实现引脚、中断线、中断函数间的映射.(其中中断线和中断函数的映射已经自动定义好了不需要我们写)
-
将引脚和中断线映射:
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);//将port的pin引脚映射到对应的中断线上去,因为中断线有16条,对应(0-15个引脚)所以只需要给出端口和其引脚,就可以确定中断线。
-
中断线触发配置使用EXTI_Init函数
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct); exit_init_config.EXTI_Line=EXTI_Line8;//需要配置的中断线:中断线的名称在stm32f10x_exti.h中定义 exit_init_config.EXTI_LineCmd=ENABLE;//打开中断线 exit_init_config.EXTI_Mode=EXTI_Mode_Interrupt;//中断线的模式 有中断和事件两种模式,这里用中断模式 exit_init_config.EXTI_Trigger=EXTI_Trigger_Falling;//触发方式,有上升和下降沿触发,这里选下降 EXTI_Init(&exit_init_config);//将配置写入
-
-
开启响应的时钟:(时钟应该在最早开启然后是配置);
- 外部中断 涉及到引脚,需要开启相应的引脚时钟;
- 外部中断 特殊情况需要AFIO(复用)时钟;(这个复用时钟的使用查看引脚的复用时钟)
-
中断函数的编写:
-
由于中断函数可能接到不同的中断,所以需要对中断进行判断:(中断线上的中断产生信号需要手动清除)
ITStatus EXTI_GetITStatus(uint32_t *EXTI_Line*);//判断某个中断线上是否发生中断 void EXTI_ClearITPendingBit(uint32_t EXTI_Line);//清除某个中断线上的中断信号
-
中断有特殊的名称:在.s启动文件中有声明
例子:
void EXTI9_5_IRQHandler(){ if(EXTI_GetITStatus(EXTI_Line8)){ delay_ms(10); LedTurn(); while(ScanKey()); EXTI_ClearITPendingBit(EXTI_Line8); } }
-
外部中断编程实例:(外部中断通过按钮控制led灯的亮灭)
#include <led_my.h>
#include <key_my.h>
#include <stm32f10x.h>
#include <stm32f10x_gpio.h>
#include <stm32f10x_rcc.h>
#include <delay.h>
void EXTIInputterButtonDown();//自定义外部中断初始化函数
void EXTI9_5_IRQHandler(){
if(EXTI_GetITStatus(EXTI_Line8)){
delay_ms(10);
LedTurn();
while(ScanKey());
EXTI_ClearITPendingBit(EXTI_Line8);
}
}
int main(){
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置优先级分组
EXTIInputterButtonDown();//调用外部中断初始化函数
LedInit();
KeyInit();
delay_init();
while (1);
return 0;
}
void EXTIInputterButtonDown(){
NVIC_InitTypeDef nvic_init_config;
EXTI_InitTypeDef exit_init_config;
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA端口时钟
GPIO_EXTILineConfig(RCC_APB2Periph_GPIOA,GPIO_PinSource8);//配置GPIOA
exit_init_config.EXTI_Line=EXTI_Line8;//配置的目标中断线
exit_init_config.EXTI_LineCmd=ENABLE;//开启
exit_init_config.EXTI_Mode=EXTI_Mode_Interrupt;//配置中断信息
exit_init_config.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发
EXTI_Init(&exit_init_config);
nvic_init_config.NVIC_IRQChannel=EXTI9_5_IRQn;
nvic_init_config.NVIC_IRQChannelCmd=ENABLE;
nvic_init_config.NVIC_IRQChannelPreemptionPriority=2;
nvic_init_config.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&nvic_init_config);
}