STM32之外部中断
- 开发环境:Window 10
- 开发工具:Keil uVision5 MDK
- 硬件:STM32F103
资料参考:
【正点原子】STM32F103开发板资料(A盘);
STM32F103ZE 简介
https://www.keil.com/dd2/stmicroelectronics/stm32f103ze/
内核:ARM Cortex-M3,72MHz
内存:64kB RAM,512kB ROM
时钟和电源:2.00V—3.60V,72 MHz
通信 :SPI、I2C、UART、I2S、CAN、USART、USB、Device
定时器/计数器/PWM :8 × 16 位定时器
模拟:2通道 12位DAC,21通道 12位ADC
I/O 和封装: -40℃—85℃,144-QFP,144-BGA
外部中断介绍
STM32 的每个IO都可以作为外部中断的中断输入口,STM32F103的中断控制器共支持19个外部中断事件请求。每个中断事件都有独立的触发和屏蔽设置。 STM32 F103 的19 个外部中断为:
线0~15 :对应外部 IO 口的输入中断。
线16 :连接到 PVD 输出。
线17 :连接到 RTC 闹钟事件。
线18 :连接到 USB 唤醒事件。
GPIO跟中断线的映射关系如下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F9Ac0h1Q-1629201693748)(…/2.笔记图片/STM32之外部中断/01.GPIO映射.png)]
GPIO 的管脚 GPIOx.0~GPIOx.15(x=A,B,C,D,E F,G 分别对应中断线 0~ 15 ,如PA0对应中断线0,PA1对应中断线1,…,PA15对应中断线15,同样,B~G系列的各个引脚与A系列相同。
且中断线每次只能连接到1个 IO 口上,也就是说如果已经设置了中断线0连接PA0口,同样对应中断线0的PB0,PC0,…,PG0就不能再设置了。
外部中断的使用步骤
1)使能时钟
2)配置GPIO与中断线的映射关系
3)外部中断的初始化
4)配置中断分组优先级
5)编写中断服务函数
1)使能时钟
外部中断(ADIO)来自于APB2总线
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
2)配置GPIO与中断线的映射关系
在库函数中,配置GPIO 与中断线的映射关系用 GPIO_EXTILineConfig() 来实现
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
第一个参数:连接映射的IO口的系列号(GPIO_PortSourceGPIOx,x=A~G)
第二个参数:映射IO口系列的具体引脚(GPIO_PinSourcen,n=0~15)
针对 GPIOE.3 端口与中断线3映射起来的范例:
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
根据上面提及的映射关系可以知道,IO口PE3 对应中断线3,通过该配置函数,即可将二者连接起来。
3)外部中断的初始化
中断线上中断的初始化用 EXTI_Init() 来实现。
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
参数 EXTI_InitTypeDef 是配置中断初始化的结构体。
typedef struct
uint32_t EXTI_Line;
EXTIMode_TypeDef EXTI_Mode;
EXTITrigger_TypeDef EXTI_Trigger;
Function alState EXTI_LineCmd;
}EXTI_
- EXTI_Line:中断线标号,取值范围为 EXTI_Line0~EXTI_Line15;
- EXTI_Mode:中断的模式,取值为中断请求 EXTI_Mode_Interrupt 和 事件请求 EXTI_Mode_Event;
- EXTI_Trigger:触发方式,取值为下降沿触发 EXTI_Trigger_Falling ,上升沿触发 EXTI_Trigger_ Rising ,或者任意电平(上升沿和下降沿触发)EXTI_Trigger_Rising_Falling;
- EXTI_LineCmd:中断是否使能能
针对中断线3配置下降沿触发的范例:
EXTI _InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line3;//中断线3
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断请求
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能
EXTI_Init(&EXTI_InitStructure);// 根据 EXTI_InitStructure 中指定的参数初始化外设 EXTI 寄存器
4)配置中断分组优先级
4.1 中断函数的介绍
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
中断线0~4的每个中断线对应一个中断函数,
中断线5~9 共用中断函数 EXTI9_5_IRQHandler ,
中断线10~15 共用中断函数 EXTI15_10_IRQHandler 。
4.2 配置中断优先级
用 NVIC_Init()函数实现中断优先级的设置
NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
NVIC_InitTypeDef定义于文件“misc.h”
typedef struct
{
u8 NVIC_IRQChannel;
u8 NVIC_IRQChannelPreemptionPriority;
u8 NVIC_IRQChannelSubPriority;
FunctionalState NVIC_IRQChannelCmd;
} NVIC_InitTypeDef;
- NVIC_IRQChannel:定义初始化哪个中断
- NVIC_IRQChannelPreemptionPriority:定义中断的抢占优先级别
- NVIC_IRQChannelSubPriority:定义这个中断的子优先级别
- NVIC_IRQChannelCmd:该中断是否使能
针对 中断线3设置优先级的范例:
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_ IRQChannel = EXTI3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVI C_InitStructure);
4.3 NVIC 的优先级组的解析
STM32用4位寄存器位的表示中断优先级,其的分组方式如下:
第0组:所有4位用于指定响应优先级
第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级,抢占级有2^1 =2 级;子优先级2^3=8级,共2*8=16级嵌套
第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级,抢占级有2^2 =4 级;子优先级2^2=4级,共4*4=16级嵌套
第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级,抢占级有2^3 =8 级;子优先级2^1=2级,共8*2=16级嵌套
第4组:所有4位用于指定抢占式优先级
中断响应的优先级由抢占优先级和响应优先级(子优先级)确定,若抢占优先级相同,则看响应优先级,数字越小优先级越高。
1.抢占相同,子优先级不同:按照子优先级顺序排序 2.抢占和子优先级都相同但有先后:此时无抢占剥夺,依照FIFO(先进先出),前一个执行完了再执行后者; 3.抢占和子优先级都相同且同时到达:按照中断向量表顺序排先后
5)编写中断服务函数
第一个函数是判断某个中断线上的中断是否发生,一般使用在中断服务函数的开头判断中断是否发生:
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)
第二个函数是中断发生后,清除某个中断线上的中断标志位,一般应用在中断服务函数结束之前:
void EXTI_ClearITPendingBit(uint32_t EXTI_Line)
常用的中断服务函数格式为:
void EXTI3_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line3)!=RESET)//判断某个线上的中断是否发生
{
中断逻辑……
}
EXTI_ClearITPendingBit(EXTI_Line3); // 清除 LINE 上的中断标志位
}
针对外部中断3 实现LED1亮灭变换的范例:
void EXTI3_IRQHandler(void)
{
delay_ms(10);//消抖
if(KEY1==0) //按键KEY1
{
LED1=!LED1;
}
EXTI_ClearITPendingBit(EXTI_Line2); //清除LINE3上的中断标志位
}
|