STM32微控制器:中断处理程序内部的SysTick延迟不起作用

4
所以我用C语言为STM32F103C8T6微控制器编写了一个程序,使用RTC(实时时钟)和显示模块。RTC和显示都正常工作,但是当我尝试从RTC中断处理程序内部更新显示时,它无法正常工作。当我在main()函数内写入显示内容时,它可以正常工作。中断处理程序也能够正常工作,因此我认为问题在于写入显示的函数内部。该函数使用小延迟位对与显示控制器的通信进行操作。我之前使用SysTick生成延迟,如下所示:
void delay(uint32_t n){
    uint32_t start =  systick_count;
    while (systick_count - start < n);
    return;
}

但是一些奇怪的事情发生了,在RTC中断处理程序中它失效了。因此,我用这个函数替换了我的延迟函数,不使用SysTick:

for (; i>0; i--) {
    for (int j = 0; j < 72; ++j) {
        __asm__ __volatile__("nop\n\t":::"memory");
    }
}

现在一切都正常。

我正在尝试理解,为什么SysTick在RTC中断处理程序中似乎不起作用。

我想可能是由于中断优先级引起的,但根据数据表,默认情况下SysTick中断的优先级高于RTC中断的优先级。

也许有人可以解释一下这是为什么?

编辑1:好的,所以我阅读了更多关于中断优先级的资料,看来我需要正确配置NVIC_IRQChannelPreemptionPriority。我会尽快尝试一下...

关于中断内部的延迟,我知道那不是正确的方法,但我仍然想了解程序的行为方式。

编辑2:我刚刚尝试以以下方式更改了中断优先级:

// set RTC interrupt priority to 15 (lowest)
NVIC_SetPriority(RTC_IRQn, 15);
// set interrupt priority of SysTick to 0 (highest)
NVIC_SetPriority(SysTick_IRQn, 0);

现在SysTick延迟可以在RTC中断处理程序中工作。


5
延时函数不能在中断中使用,因为中断会增加系统滴答定时器的时间。由于你已经处于RTC中断中,为什么还要考虑在中断中使用延时函数呢?请不要在中断中使用延时函数。 - ringbuffer_peek
STM32中断优先级是可配置的。也许您已经以某种方式配置了中断,使得SysTick中断无法中断RTC中断。请展示SysTick和RTC中断配置的代码。但同时,请养成不在中断服务例程中延迟的习惯。 - kkrambo
中断处理程序中超过几个周期的延迟通常是不可取的。您应该找到另一种处理慢总线的方法,例如使用定时器和高优先级中断。话虽如此,systick_count是什么?它在哪里增加?它既不是STM32硬件寄存器,也不是C标准。 - too honest for this site
1个回答

7
使用SysTick来实现延时的方法与来自ST的HAL库中的HAL_Delay相同。其工作方式是,SysTick持续增加(通常在1ms间隔内)一个变量 - 在你的情况下为systick_count - 该变量与延迟函数内的本地变量 - 在你的情况下为start进行比较。
需要注意两件事情:
  1. systick_count需要被声明为volatile以强制在每次比较之前重新读取它的值。它由中断修改而不是在该函数内部修改。你的编译器可能会选择优化这部分代码。

  2. 在调用延迟函数时,SysTick中断需要"运行"。如果它没有运行,例如因为你处于更高优先级(数值较低)的中断中,则会发生死锁,并且延迟函数永远不会完成,因为计数器永远不会被SysTick递增。关于这一点-不要假设什么,只依赖于数据表。请验证在延迟期间是否正在运行。在调用延迟函数时检查NVIC寄存器的值,或者在RTC中断中设置一个断点-它应该在你在延迟函数中时触发该断点。如果没有-你可能需要调整中断优先级。

关于在中断中加入延迟的整个想法-通常被认为是一种不好的实践。中断应该用于非常快速地完成非常小的工作,例如设置一个标志,表示需要在主程序代码中完成某些工作,或将接收到的字节放入队列中以供稍后处理。虽然在只有一个中断(如果计算Systick,则有两个)的简单程序中可能并不明显,但一旦添加更多中断,它很快就会变得棘手,并遇到问题,例如由于中断相互阻塞并且它们不能被快速调用而导致信息丢失。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接