Cortex-M3/M4内核NVIC及HAL库函数详解(5):__disable_irq和HAL_NVIC_DisableIRQ、__enable_irq和HAL_NVIC_EnableIRQ的区别

0 工具准备

Keil uVision5
Cortex M3权威指南(中文)
Cortex M3与M4权威指南
stm32f407的HAL库工程
STM32F4xx中文参考手册

1 __disable_irq和HAL_NVIC_DisableIRQ、__enable_irq和HAL_NVIC_EnableIRQ的区别

1.1 函数分析

我们在执行某些语句时不希望被中断打断,往往会使用__disable_irq失能全局中断,在语句执行完毕后再使用__enable_irq使能全局中断。伪代码如下:

__disable_irq();
// 时间敏感语句
__enable_irq();

使用上述语句可以一步到位失能全部中断,避免被任何中断打断,但它有一个弊端,就是会影响到导致一些必须定时调用的中断(例如SysTick时基)被中断,导致一些问题的产生。为了避免上述的问题,有时候只会失能影响最大的中断请求,也就是使用HAL_NVIC_DisableIRQ失能特定中断,然后使用HAL_NVIC_EnableIRQ使能特定中断。伪代码如下:

HAL_NVIC_DisableIRQ(xxx_IRQn);
// 时间敏感语句
HAL_NVIC_EnableIRQ(xxx_IRQn);

除了失能中断的范围不一样,上述函数操作的寄存器也不一样:
(1)__disable_irq和__enable_irq
__disable_irq和__enable_irq操作的是PRIMASK寄存器,名为中断屏蔽寄存器。
在这里插入图片描述
(2)HAL_NVIC_DisableIRQ和HAL_NVIC_EnableIRQ
HAL_NVIC_DisableIRQ操作的是中断失能寄存器:
在这里插入图片描述
HAL_NVIC_EnableIRQ操作的是中断使能寄存器:
在这里插入图片描述

1.2 测试对比

字面上理解,中断失能后这一段时间内中断都无法生成,也就无法挂起。中断屏蔽只是不响应中断但是如果屏蔽中断这一段时间产生了中断则中断会被挂起。为了验证这一想法,我们编写了2段测试程序:

int testsw11(int argc, char *argv[])
{
    __disable_irq();
    Delay_s(10);
    printf("HAL_NVIC_GetPriorityGrouping : %08X\r\n", HAL_NVIC_GetPriorityGrouping());
    printf("HAL_NVIC_GetPendingIRQ       : %08X\r\n", HAL_NVIC_GetPendingIRQ(EXTI0_IRQn));
    __enable_irq();
    return 0;
}
int testsw12(int argc, char *argv[])
{
    HAL_NVIC_DisableIRQ(EXTI0_IRQn);
    Delay_s(10);
    printf("HAL_NVIC_GetPriorityGrouping : %08X\r\n", HAL_NVIC_GetPriorityGrouping());
    printf("HAL_NVIC_GetPendingIRQ       : %08X\r\n", HAL_NVIC_GetPendingIRQ(EXTI0_IRQn));
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
    return 0;
}

在进行测试前,我们按照前面章节的操作,将PA0初始化为下降沿触发。
(1)testsw11测试
首先打印当前中断挂起状态,然后执行testsw11函数,在Delay_s(10)中按下按键,然后打印中断挂起状态。测试结果如下:
在这里插入图片描述

可以看到__disable_irq仅仅是不响应中断,中断在我们按下SW1后仍然会产生,同时由于得不到响应会被挂起,因此挂起状态为1,在执行了__enable_irq后挂起的中断得到了响应,打印了中断服务函数里的信息。中断服务函数执行完毕后,相应的中断挂起位也清空为0。
(2)testsw12测试
首先打印当前中断挂起状态,然后执行testsw12函数,在Delay_s(10)中按下按键,然后打印中断挂起状态。测试结果如下:
在这里插入图片描述
可以看到HAL_NVIC_DisableIRQ仅仅是不响应中断,中断在我们按下SW1后仍然会产生,同时由于得不到响应会被挂起,因此挂起状态为1,在执行了HAL_NVIC_EnableIRQ后挂起的中断得到了响应,打印了中断服务函数里的信息。中断服务函数执行完毕后,相应的中断挂起位也清空为0。

2 总结

(1)__disable_irq和HAL_NVIC_DisableIRQ在执行后都不会影响中断的生成,只是不会响应中断,在失能状态下如果发生中断则会挂起,等到使能后满足条件(优先级最高)则会被执行。因此可以认为__disable_irq和HAL_NVIC_DisableIRQ只是用来决定是否响应中断,中断的生成只和外设中断使能寄存器的配置有关。
下图就是串口的中断使能寄存器说明:
在这里插入图片描述
(2)对于时间敏感语句或不可重入代码段,可以使用HAL_NVIC_DisableIRQ来替代__disable_irq,避免失能全局中断响应带来的问题
(3)如果只是需要暂时性不响应中断,使用__disable_irq之后一定要__enable_irq,使用HAL_NVIC_DisableIRQ之后一定要HAL_NVIC_EnableIRQ
(4)可以把__disable_irq和__enable_irq看做响应中断的总开关,HAL_NVIC_DisableIRQ和HAL_NVIC_EnableIRQ看做响应中断的分开关。要想响应某个中断必须保证分开关和总开关都是闭合状态的,如果不想响应某个中断必须保证总开关或分开关是断开状态
在这里插入图片描述

  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

时光飞逝的日子

感谢您的支持,让我们一起进步!

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

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

打赏作者

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

抵扣说明:

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

余额充值