STM32学习笔记(6)中断优先级及EXTI外部中断

中断优先级分组(NVIC)

CM3 内核支持 256 个中断,其中包含了 16 个内核中断和 240 个外部中断,并且具有 256级的可编程中断设置。但STM32 只有 其中84 个中断,包括 16 个内核中断和 68 个可屏蔽中断,具有 16 级可编程的中断优先级。在 STM32F103 系列上面,又只有 60 个(在 107 系列有 68 个)。本文将对STM32F103 系列这 60 个可屏蔽中断进行介绍。

相关寄存器介绍

ISER[8]:( Interrupt Set-Enable Registers),中断使能寄存器组。由 8 个 32 位寄存器来控制,每个位控制一个中断。对于STM32F103,有用的就是两个(ISER[0]ISER[1]), ISER[0]的 bit0~bit31 分别对应中断 0~31。 ISER[1]的 bit0~27 对应中断 32~59;要使能某个中断,必须设置相应的 ISER 位为 1。具体每一位对应哪个中断,请参考 stm32f10x.h 里面的第 140 行处(针对编译器 MDK5 来说)。

ICER[8]:( Interrupt Clear-Enable Registers),中断除能寄存器组。与 ISER 的作用相反,用来清除某个中断的使能的。其对应位的功能,也和 ICER 一样。这里要专门设置一个 ICER 来清除中断位(即写1),而不是向 ISER 写 0 来清除。

CM3 中可以有 240 对使能位/除能位,每个中断拥有一对。这 240 个对子分布在 8 对 32 位寄存器中(最后一对没有用完)。欲使能一个中断,你需要写 1 到对应 SETENA 的位中;欲除能一个中断,你需要写 1 到对应的 CLRENA 位中;如果往它们中写 0,不会有任何效果。通过这种方式,使能/除能中断时只需把“当事位”写成1,其它的位可以全部为零。
防止有些位被写入 0 而破坏其对应的中断设置(写 0 没有效果),从而实现每个中断都可以自顾地设置,而互不侵犯

ISPR[8]:( Interrupt Set-Pending Registers),中断挂起控制寄存器组。每个位对应的中断和 ISER 是一样的。通过置 1,可以将正在进行的中断挂起,而执行同级或更高级别的中断。 (不常用)

ICPR[8]:( Interrupt Clear-Pending Registers),中断解挂控制寄存器组。其作用与 ISPR 相反,对应位也和 ISER 是一样的。通过设置 1,可以将挂起的中断接挂。(不常用)

IABR[8]:( Interrupt Active Bit Registers),中断激活标志位寄存器组。对应位所代表的中断和 ISER 一样,如果为 1,则表示该位所对应的中断正在被执行。这是一个只读寄存器,通过它可以知道当前在执行的中断是哪一个。在中断执行完了由硬件自动清零。 (不常用)

IP[240]:( Interrupt Priority Registers),中断优先级控制寄存器组。 240 个 8bit 的寄存器组成,每个可屏蔽中断占用 8bit,总共表示 240 个可屏蔽中断。 而 STM32 只用到了其中的前 60 个。 IP[59]~IP[0]分别对应中断 59~0。 而每个可屏蔽中断占用的 8bit 并没有全部使用,而是 只用了高 4 位。这 4 位,又分为抢占优先级和子优先级。抢占优先级在前,子优先级在后。而这两个优先级各占几个位又要根据 SCB>AIRCR 中的中断分组设置来决定。

抢占优先级和子优先级的解释:
抢占优先级:高优先级可打断正在进行的低优先级。
子优先级:中断同时发生,高优先级先执行。
若两个中断的两种优先级相同,则先发生先执行。(值越低,优先级越高)

STM32 的中断分组: STM32 将中断分为 5 个组,组 0~4。该分组的设置是由 SCB->AIRCR 寄存器的 bit10~8 来定义的。具体的分配关系 :
在这里插入图片描述

例如选择2组,则每种优先级通过两位来设置,则各有2^2,即0~3共4种等级差别。

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_X); //X=0~4,该函数在系统中只能被调用一次来确定组别

优先级设定

设定相关的结构体:

typedef struct
{
uint8_t NVIC_IRQChannel;//定义初始化的是哪个中断 
uint8_t NVIC_IRQChannelPreemptionPriority;//定义该中断的抢占优先级别。 
uint8_t NVIC_IRQChannelSubPriority;//定义该中断的子优先级别。 
FunctionalState NVIC_IRQChannelCmd; //该中断是否使能。 
} NVIC_InitTypeDef; 

以初始化串口 1 的中断,同时设置抢占优先级为 1,子优先级位 2 为例:

NVIC_InitTypeDef NVIC_InitStructure;//初始化相应结构体
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口 1 中断对应名
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;// 抢占优先级为 1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;// 子优先级位 2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道(中断请求通道)使能
NVIC_Init(&NVIC_InitStructure); //根据上面指定的参数初始化 NVIC 寄存器 

EXIT外部中断相关

概述

STM32每个IO口都可以作为外部中断输入,其中断控制器支持19个外部中断/事件请求,分别为:
线 0~15:对应外部 IO 口的输入中断。
线 16:连接到 PVD 输出。
线 17:连接到 RTC 闹钟事件。
线 18:连接到 USB 唤醒事件。

对STM32的IO口,可分为GPIOx.0~GPIOx.15(x=A,B,C,D,E,F,G)分别对应中断线 0~15。这样每个中断线对应了最多 7 个 IO 口。如图:(同一时刻,一组GPIO只能有一个IO口映射到中断线)
在这里插入图片描述
中断线对应中断服务函数

EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
EXTI9_5_IRQHandler
EXTI15_10_IRQHandler 

中断控制器框图

在这里插入图片描述

相关寄存器简介

1.EXTI_IMR:中断屏蔽寄存器,控制是否屏蔽来自线上的中断请求;
2.EXTI_EMR:事件屏蔽寄存器,控制是否屏蔽来自线上的事件请求;

事件:是表示检测到某一动作(电平边沿)触发事件发生了。
中断:有某个事件发生并产生中断,并跳转到对应的中断处理程序中。
事件只是一个触发信号(脉冲),而中断则是一个固定的电平信号 。

3.EXTI_RTSR:上升沿触发选择寄存器,控制是否允许输入线x上的上升沿触发(中断和事件);
4. EXTI_FTSR:下降沿触发选择寄存器,控制是否允许输入线x上的下降沿触发(中断和事件);
5.EXTI_SWIER:软件中断事件寄存器,当该位为’0’时,写’1’将设置EXTI_PR中相应的挂起位。如果在EXTI_IMR和EXTI_EMR中允许
产生该中断,则此时将产生一个中断。
6.EXTI_PR:挂起寄存器,控制是否发生触发请求;
寄存器相关位配置参考相关资料(中文参考手册第九章)

EXIT_Init函数

相应结构体:

typedef struct
{
  uint32_t EXTI_Line;//指定配置的中断线        
  EXTIMode_TypeDef EXTI_Mode;//中断模式      
  EXTITrigger_TypeDef EXTI_Trigger; //触发方式
  FunctionalState EXTI_LineCmd;//使能/失能    
}EXTI_InitTypeDef;

使用步骤

( 1)初始化 IO 口为输入。
(2)开启 AFIO 时钟
(3) 设置 IO 口与中断线的映射关系。

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

(4)初始化线上中断,设置触发条件(上升沿触发,下降沿触发,边沿触发等)等。

void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);

(5)配置中断分组(NVIC),并使能中断。
(6)编写中断服务函数。

例:

void EXTIX_Init(void)//自定义相关初始化函数
{
 EXTI_InitTypeDef EXTI_InitStrue;//初始化相关结构体
 NVIC_InitTypeDef NVIC_InitStrue; 
 
 KEY_Init();//按键初始化,为中断服务函数准备
 
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO时钟 
  
 GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);//设置 IO 口与中断线的映射关系
 
 EXTI_InitStrue.EXTI_Line=EXTI_Line4;
 EXTI_InitStrue.EXTI_Mode=EXTI_Mode_Interrupt;
 EXTI_InitStrue.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发
 EXTI_InitStrue.EXTI_LineCmd=ENABLE;
  EXTI_Init(&EXTI_InitStrue);//初始化线上中断
 
 NVIC_InitStrue.NVIC_IRQChannel=EXTI4_IRQn;
 NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=2;
 NVIC_InitStrue.NVIC_IRQChannelSubPriority=2;
 NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE;
 NVIC_Init(&NVIC_InitStrue);//初始化优先级设置
}
 
void EXTI4_IRQHandler(void)//相关中断服务函数
{
 delay_ms(10);//防抖
 if(KEY0==0)//低电平被触发
 {
 LED0=!LED0;
 LED1=!LED1;
  }
 EXTI_ClearITPendingBit(EXTI_Line4);//清除标志位
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章