暂时禁用定时器中断

Posted

技术标签:

【中文标题】暂时禁用定时器中断【英文标题】:Temporarily disable timer interrupt 【发布时间】:2012-11-29 00:25:44 【问题描述】:

我正在 stm32f4xx uC 上使用 C 语言开发一个嵌入式项目。

我有一段代码连续执行 XYZ 循环操作,有时 TIM4 中断会更改一些全局参数并导致操作 XYZ 重新启动。

代码是这样的:

for (;;) 
       //line A
    XYZ;
       //line B

XYZ 是一个复杂的操作,涉及在缓冲区和其他缓冲区之间传输数据。

TIM4 中断处理程序执行此操作:停止 XYZ 并更改一些影响 XYZ 操作的全局变量。

所以基本上我希望 XYZ 重复执行,TIM4 中断来停止 XYZ,更改参数,然后必须通过使用新的全局参数重新启动 XYZ 来重新启动循环。

问题是: 由于 XYZ 有很多指令,TIM4 IRQ 可能会在它的中间出现,并且在 IRQHandler 更改全局变量后,操作会从 XYZ 的中间恢复,这会破坏程序.

我的初始解决方案:使用 __disable_irq() 禁用线路 A 上的中断并使用 __enable_irq() 恢复线路 B 上的中断

失败,因为 XYZ 复杂操作必须使用其他中断(TIM4 除外)。

NEXT SOLUTION 仅禁用线路 A 上的 TIM4 中断:

TIM_ITConfig(TIM4, TIM_IT_Update , DISABLE) 

并在 B 行重新启用它:

TIM_ITConfig(TIM4, TIM_IT_Update , ENABLE)

失败,因为我丢失了中断:当 int 恢复时,在 XYZ 期间到达的中断被忽略。这是个大问题(其中一个原因是 TIM4 IRQHandler 改变了全局变量,然后再次激活 TIM4 以便稍后发出中断,我这样做是因为中断之间的周期不同)。

谁能给我一个解决这个问题的方法?有没有更好的方法来禁用/恢复 TIM4 IRQ 并且不会丢失任何中断?

【问题讨论】:

XYZ 出于什么原因需要停止处理?是因为它的数据由于中断覆盖信息而无效,还是因为实际上希望在新的中断到来时停止XYZ?如果只是因为数据覆盖,在 ISR 中你可以将数据复制到一个临时的并设置一个标志,然后在主循环中使用标志来知道何时对新数据进行操作... 【参考方案1】:

您可以对全局变量的副本进行操作,并在完成 XYZ 后从中断中换入新值。

从问题中不清楚您是否需要在全局变量更改时立即停止处理 XYZ,或者您是否可以等到 XYZ 完成处理以交换新的变量副本。我会在假设您需要摆脱处理 XYZ 的情况下进行操作,但这很容易做到。

代码看起来像这样:

volatile int x;
int x_prime;

int main(void)

    while(1)
    
        //copy in new global parameter value
        x_prime = x;

        while(1)
        
            //do stuff with x_prime
            if (x_prime != x)
            
                break;
            

            //do more stuff with x_prime
            if (x_prime != x)
            
                break;
            
        
    


// interrupt handler
void TIM_IT_Update(void)

    x++;

break 模式假定您没有更改 x_prime。如果您需要修改x_prime,则需要另一个副本。

由于永远不会禁用中断,因此您永远不必担心丢失任何中断。而且由于您正在操作由中断更改的参数的副本,因此中断是否在执行过程中更改参数并不重要,因为您在制作副本之前不会查看这些值。

【讨论】:

感谢您的提示,但它不适合我,因为我有一个复杂的缓冲区和全局变量系统,这些系统由 IQRHandler 更改并且 XYZ 使用这些变量进行操作。为了清楚起见,我更愿意完成 XYZ 然后处理 IRQ。【参考方案2】:

有几个可能可用的选项(我不是 100% 了解 ARM 架构):

将中断优先级/级别屏蔽寄存器更改为仅屏蔽 TIM4,让其他中断发生。希望如果 TIM4 在被遮罩时被触发,在恢复关卡遮罩时它会记住并触发 ISR。 屏蔽中断并手动检查在 XYZ 期间设置的 TIM4 中断标志​​ 将 XYZ 分成更小的部分,仅在绝对必要时屏蔽 TIM4。 对数据副本进行操作,可选择检查 TIM4 中断标志​​以决定是继续/保留结果还是丢弃并重新启动。 检查时间并避免在 TIM4 可能很快触发时启动 XYZ,或者仅在 TIM4 触发后运行 XYZ N 次。

【讨论】:

您好,您提到的第一个选项正是我的想法,但我的问题也是如何做到这一点。无论如何,现在我实现了一个解决方法,通过声明一个全局标志,其值被 IRQ 更改(IRQ 所做的只是更改全局标志)并在循环内部,完成 XYZ 后,我测试标志,如果它设置了我执行原始的 IRQ 处理程序操作,然后我重置了标志。它就像一个魅力!但是我想知道是否有办法只屏蔽 TIM4 IRQ 但同时又不会丢失 IRQ。感谢您的提示! 选项 1 可以通过将 TIM4 设置为低优先级,然后设置全局中断优先级掩码/级别(我不知道这在 ARM 上会是什么)来忽略低优先级的中断,使您仍然关心的那些足够高,它们不会被掩盖。请参阅:***.com/questions/13713064/… 以获得更模糊的指导;) @BogdanAlexandru:我怀疑 ARM 在屏蔽时会忽略中断。该位仍设置,但未触发 ISR。我假设它至少会有一个 1 个中断的缓冲区,但这可能还不够好,因为 XYZ 似乎是一个非常耗时的功能。也许可以在 NVIC 中设置这个缓冲区的深度?我在这里可能是错的,但是你检查过这个文档吗?【参考方案3】:

当我发现自己处于类似情况时,处理可能需要比中断时间更长的时间,我使用 FIFO 将处理与传入数据分离。即:TIM4 填充一个 FIFO。 XYZ(或经理)使用 FIFO 并处理数据。

(我觉得您的设计可能是错误的,因为您不应该使用全局变量来控制数据或流程。 研究该问题的参考书目:制作嵌入式系统:优秀软件的设计模式)

【讨论】:

【参考方案4】:

在 XYZ 之前从缓冲区复制所有内容并使用副本。我相信这是最好的方法,在编写 gps 解析器时有所帮助。

【讨论】:

【参考方案5】:

您是否考虑过为您的系统使用 RTOS?我意识到这需要一些重组,但它可以为您提供系统所需的任务处理灵活性和分辨率。如果您使用的是 STM32 的 CubeIDE,启用、配置和运行 RTOS 非常简单。

【讨论】:

以上是关于暂时禁用定时器中断的主要内容,如果未能解决你的问题,请参考以下文章

Arduino-中断

将单片机的外部中断1、定时器中断0打开,要求定时器0的中断优先级高于外部中断1,外部中断1采用边沿?

定时器中断

关于定时器中断怎么理解?

关于在51定时器中断语句中关闭中断的问题

51单片机定时器中断