[STM32F4] __disable_irq () 和 __enable_irq () 不起作用

[复制链接]
49|3
Treasure101 发表于 2026-10-27 22:59 | 显示全部楼层 |阅读模式
在 STM32F446 需要在执行一段特定临界函数时关闭全部中断。
我在代码中写了下面几行:
__disable_irq();
Critical_function();
__enable_irq();
但是在执行Critical_function()期间,仍然会进入中断。
我在工程里查找__disable_irq和__enable_irq,只在cmsis_armcc.h里面看到被注释掉的声明:
/**
\brief  Disable IRQ Interrupts
\details Disables IRQ interrupts by setting the I-bit in the CPSR.
          Can only be executed in Privileged modes.
*/
/* intrinsic void __disable_irq();   */
编译没有任何错误或警告,调试时看这两个函数似乎完全不起作用。
我使用 Keil v5.28。

香水城 发表于 2026-10-28 09:32 | 显示全部楼层
__disable_irq() 可以屏蔽优先级可配置的各类异常及中断,包括各种普通外设中断和 SysTick等内核中断,但不能屏蔽 HardFault 和 NMI。在 STM32F446 上,它通过设置 PRIMASK = 1 实现,前提是在特权模式下执行。要注意,它并不会停止外设,更不会清除中断的 pending 状态。

在你提到的 ARM Compiler 5/armcc 环境下,__disable_irq() 和 __enable_irq() 是编译器内建函数,通常直接生成汇编指令:

CPSID i    ; 屏蔽
CPSIE i    ; 解除屏蔽

因此不需要普通的函数调用、跳转和返回。不过,其他工具链可能通过内联汇编等方式实现相同的 CMSIS 接口,不一定都是同名的编译器内建函数。
麻花油条 发表于 2026-10-28 10:44 | 显示全部楼层
cmsis_armcc.h 里那行被注释掉的声明是正常的,__disable_irq 是编译器 intrinsic 函数,定义在 Keil 安装目录的 arm_compat.h 里,不在工程源码中。
elephant00 发表于 2026-10-28 10:59 | 显示全部楼层
对于 STM32F4 系列,如果需要更精细的中断控制,建议使用 __set_BASEPRI() 来屏蔽特定优先级以下的中断,而不是粗暴地关闭所有中断,这样既能保护临界区,又允许高优先级的紧急中断(如故障处理)正常响应。
classroom 发表于 2026-10-28 12:20 | 显示全部楼层
编译不报错就说明编译器已经识别并内联了这个函数,它实际会生成 CPSID i 指令去设置 PRIMASK 寄存器,不是空函数。
cr315 发表于 2026-10-28 12:56 | 显示全部楼层
调试时如果只看 C 代码单步,确实看不到函数体,因为它是内联的汇编指令,要打开反汇编窗口看是否出现了 CPSID i 才能确认真的生效。
duo点 发表于 2026-10-28 13:45 | 显示全部楼层
__disable_irq 关的是 PRIMASK,它屏蔽所有可配置优先级的中断,但 NMI 和 HardFault 是关不掉的,如果“仍然进中断”指的是这两个,那属于正常现象。
flycamelaaa 发表于 2026-10-28 14:30 | 显示全部楼层
如果你在中断服务函数里面调用了 __disable_irq,然后又在同一个 ISR 里等待某个标志,那个标志可能依赖其他中断来置位,这就死锁了,看起来像“没关住”。
jcky001 发表于 2026-10-28 15:17 | 显示全部楼层
有一种常见情况:Critical_function() 执行期间中断确实没有进入,但 __enable_irq() 之后立刻跳进了中断,让人误以为临界区没生效,实际上中断被挂起了。
onlycook 发表于 2026-10-28 15:50 | 显示全部楼层
检查一下工程里有没有其他地方在 Critical_function() 内部或者之前调用了 __enable_irq 或者写了 PRIMASK = 0,把屏蔽给提前解除了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

225

主题

225

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部