1.外部中断简介
这里我们首先 STM32 IO 口中断的一些基础概念。STM32 的每个 IO 都可以作为外部中断
的中断输入口,这点也是 STM32 的强大之处。STM32F103 的中断控制器支持 19 个外部中断/
事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。STM32F103 的
19 个外部中断为:
线 0~15:对应外部 IO 口的输入中断。
线 16:连接到 PVD 输出。
线 17:连接到 RTC 闹钟事件。
线 18:连接到 USB 唤醒事件。
STM32 供 IO 口使用的中断线只有 16 个,但是 STM32 的 IO 口却远远不
止 16 个,那么 STM32 是怎么把 16 个中断线和 IO 口一一对应起来的呢于是 STM32 就这样设计,GPIO 的管教 GPIOx.0~GPIOx.15(x=A,B,C,D,E,F,G)分别对应中断线 0~15。这样每个中断线对应了最多 7 个 IO 口,以线 0 为例:它对应了 GPIOA.0、GPIOB.0、GPIOC.0、GPIOD.0、GPIOE.0、GPIOF.0、GPIOG.0。而中断线每次只能连接到 1 个 IO 口上,这样就需要通过配置来决定对应的中断线配置到哪个 GPIO 上了。下面我们看看 GPIO 跟中断线的映射关系图:
配置 GPIO 与中断线的映射关系的函数 GPIO_EXTILineConfig()来实现
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
中断线上中断的初始化是通过函数 EXTI_Init()实现的。EXTI_Init()函数的定义。
EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line=EXTI_Line3;//外部中断线 3EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//设置 EXTI 线路为中断请求EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //设置输入线路下降沿为中断请EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure); //根据 EXTI_InitStruct 中指定的//参数初始化外设 EXTI 寄存器
函数EXTI_Init 说明
EXTI_InitTypeDef structure EXTI_InitTypeDef 定义于文件“stm32f10x_exti.h”:
typedef struct {
u32 EXTI_Line; EXTIMode_TypeDef EXTI_Mode;
EXTIrigger_TypeDef EXTI_Trigger;
FunctionalState EXTI_LineCmd;
} EXTI_InitTypeDef;
参数说明
EXTI_Line
EXTI_Mode
EXTI_Trigger
EXTI_LineCmd
EXTI_LineCmd 用来定义选中线路的新状态。它可以被设为 ENABLE 或者 DISABLE。
例如: EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line
= EXTI_Line12 | EXTI_Line14; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger =
EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
我们设置好中断线和 GPIO 映射关系,然后又设置好了中断的触发模式等初始化参数。既然是外部中断,涉及到中断我们当然还要设置 NVIC 中断优先级。
NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //使能按键外部中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2,NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级 2NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道NVIC_Init(&NVIC_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);判断某个中断线上的中断是否发生(标志位是否置位):
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);是清除某个中断线上的中断标志位
2.编写中断服务程序
STM32 的 IO 口外部中断函数只有 6 个,
分别为:
EXPORT EXTI0_IRQHandler
EXPORT EXTI1_IRQHandler
EXPORT EXTI2_IRQHandler
EXPORT EXTI3_IRQHandler
EXPORT EXTI4_IRQHandler
EXPORT EXTI9_5_IRQHandler
EXPORT EXTI15_10_IRQHandler
格式
void EXTI3_IRQHandler(void){if(EXTI_GetITStatus(EXTI_Line3)!=RESET)//判断某个线上的中断是否发生 {中断逻辑…EXTI_ClearITPendingBit(EXTI_Line3); //清除 LINE 上的中断标志位 }}
3.代码程序
.c
#include "exti.h"#include "key.h"//外部中断 驱动代码 void EXTIX_Init(void){EXTI_InitTypeDef EXTI_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;Key_Init(); //按键端口初始化RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能复用功能时钟//GPIOE.3 中断线以及中断初始化配置 下降沿触发 //KEY1GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);EXTI_InitStructure.EXTI_Line=EXTI_Line3; //外部中断线 3EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //设置 EXTI 线路为中断请求EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //设置输入线路下降沿为中断请EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;//使能按键KEY1所在的外部中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;//子优先级1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器}//外部中断3服务程序void EXTI3_IRQHandler(void){if(EXTI_GetITStatus(EXTI_Line3)!=RESET) //函数一般使用在中断服务函数的开头判断中断是否发生 {GPIOE->ODR^= 0X1<<5; //这里写中断服务程序} EXTI_ClearITPendingBit(EXTI_Line3); //清除LINE3上的中断标志位 }
.h
#ifndef _EXTI_H_#define _EXTI_H_#include "stm32f10x.h"void EXTIX_Init(void);#endif
程序效果说明:按键接在PE3,用外部中断的方法控制LED灯的亮灭。
该部分代码很简单,在初始化完中断后,点亮 LED0,就进入死循环等待了,这里死循环里面通过一个 串口打印函数函数来告诉我们系统正在运行,在中断发生后,就执行中断服务函数做出相应的处理。