简单理解NVIC中断优先级

关于中断

中断,就是程序执行到某个位置,突然收到了中断请求,此时程序暂停,去临时执行中断任务,执行完毕后再回到原位继续执行程序。

在STM32中,可以开启很多种中断,有系统内置的中断,比如:SysTick定时器中断。有设备中断,比如串口中断。有外部中断,比如某个引脚电平变化引起的中断。所有的中断都必须配置并开启后才会有效。

那么,加入某一时刻同时有好几个中断触发了,此时程序去执行哪个中断任务呢,因此需要给中断设置优先级,级别高的先执行,级别低的后执行。

关于优先级

中断优先级是通过NVIC来配置的,分为2步:

1.中断分组。

2.设置抢占优先级和响应优先级。

举个简单的例子,假设有5支集团军,每个集团军都有自己独特的指挥系统。以C军为例,C军指挥部有司令、政委、参谋长、作战部长。战斗编制有军长、师长、旅长、团长。那么指挥部的这4个级别就是抢占优先级,战斗编制的4个级别就是响应优先级。设置优先级,就是要分别设置抢占优先级和响应优先级。比如:(司令+军长)下达的命令,就要比(政委+团长)这个命令级别高,假如(政委+团长)这个命令先下达,并且已经执行了,此时(司令+军长)这个命令下达了,可以打断(政委+团长)命令抢先执行。相同抢占级的情况下,(司令+军长)>(司令+师长)。也就是说,先看抢占级,抢占级相同的情况下,才看响应级。

我们把5个集团军的指挥系统统一整理一下看看,

A军:没有指挥部,全部是战斗编制,按照军长、师长、旅长、团长...排列下去,一共有16个级别;

B军:指挥部设2级,司令、政委;战斗编制设8级,军长、师长、旅长、团战...。

C军:指挥部设4级,司令、政委、参谋长、作战部长;战斗编制设4级,军长、师长、旅长、团长。

D军:指挥部设8级,司令、政委、参谋长、作战部长...;战斗编制设2级,旅长、团长。

E军:指挥部设16级,司令、政委、参谋长、作战部长...;战斗编制没有。

中断分组的含义:用哪个集体军的指挥系统(所有中断用哪种方式来分级管理)

确定了指挥系统(分组),也就确定了指挥部有几级(抢占优先级),战斗编制有几级(响应优先级)。

我们再对照STM32的分组来看看:STM32共有5个分组

NVIC_PriorityGroup_0:A集团军(0级抢占,16级响应)
NVIC_PriorityGroup_1:B集团军(2级抢占,8级响应)
NVIC_PriorityGroup_2:C集团军(4级抢占,4级响应)
NVIC_PriorityGroup_3:D集团军(8级抢占,2级响应)
NVIC_PriorityGroup_4:E集团军(16级抢占,0级响应)

于是,我们配置NVIC中断优先级的步骤是:

1.先确定中断分组。

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //先确定分组

2.再分配抢占优先级和响应优先级。

NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级(共4级,可选0~3)
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;//响应优先级(共4级,可选0~3)

假如你的项目里只有1个中断,那么优先级的数字随便设(在级数范围内),反正没人会跟他抢。

实际应用中的注意点

1.实际我们的一个项目中,不会出现太多中断,为了简单方便,我们只用NVIC_PriorityGroup_4就好了,这样只需要关注抢占优先级,响应优先级根本就没有。

2.如果没有用到中断,也就不需要配置中断分组和优先级。但是一般来说我们一个项目中至少都会用到一个中断,为了避免忘记分组,无论是否需要,最好在main函数的最前面就开始分组,以后开启哪个中断,就只配置优先级就可以了。

3.经常我们用SysTick定时器来计时,开启了SysTick中断,因为计时准确性是比较关键的,因此一般会把SysTick定时器中断设定为0级(最高),防止计时出现偏差。

关于SysTick定时器的配置可以看这里,利用SysTick延时,

stm32延时函数,毫秒延时,微秒延时

示例(UART4开启接收中断)

int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//中断分组
    uart4_init(115200);

    while(1)
    {
        //do something
    }
}

void uart4_init(u32 bound)
{
  GPIO_InitTypeDef GPIOC_InitStruct;
  USART_InitTypeDef USART_InitStruct;
  NVIC_InitTypeDef NVIC_InitStruct;
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);//GPIO时钟使能
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);//串口4时钟使能
  
  GPIOC_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出(作为TX)
  GPIOC_InitStruct.GPIO_Pin = GPIO_Pin_10; //PC10
  GPIOC_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_Init(GPIOC, &GPIOC_InitStruct);//GPIO初始化配置

  GPIOC_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入(作为RX)
  GPIOC_InitStruct.GPIO_Pin = GPIO_Pin_11; //PC11
  GPIOC_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_Init(GPIOC, &GPIOC_InitStruct);//GPIO初始化配置

  USART_InitStruct.USART_BaudRate = bound; //默认115200
  USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//
  USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//发送、接收模式
  USART_InitStruct.USART_Parity = USART_Parity_No;//不使用奇偶校验
  USART_InitStruct.USART_StopBits = USART_StopBits_1;//停止位1位
  USART_InitStruct.USART_WordLength = USART_WordLength_8b;//8位字长
  USART_Init(UART4, &USART_InitStruct);//串口4初始化配置
  
  //配置中断优先级
  NVIC_InitStruct.NVIC_IRQChannel = UART4_IRQn;//串口4中断通道
  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //使能该通道
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级
  NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;//响应优先级
  NVIC_Init(&NVIC_InitStruct);//中断初始化配置


  USART_ITConfig(UART4,USART_IT_RXNE, ENABLE);//开启串口4的中断
  USART_Cmd(UART4, ENABLE);//使能串口4
}

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胡十三刀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值