在嵌入式C中,我们如何计算循环的延迟



我试图将LCD(NHD‐0240AZ‐FL‐YBW(连接到TM4C123GH6PMI。在这样做的时候,我应该给出以毫秒为单位的延迟,所以我在谷歌上搜索了一下。一个人用下面的循环给出了以毫秒为单位的延迟。有人能解释一下它是如何工作的吗?

void DelayMilis(unsigned long ulMilliSeconds)
{
unsigned long i = 0, j = 0;
for (i = 0; i < ulMilliSeconds; i++)
{
for (j = 0; j < 2000; j++);
}
}

恕我直言,"这家伙"在这种延迟实施方面做得很糟糕。

它的工作原理:
由于嵌套的循环,会浪费2000 * ulMilliSecondsCPU周期,从而延迟下一次执行。

为什么它可能不会以这种方式工作:
因为,编译器会感觉到嵌套循环没有做任何事情,所以这些循环很可能会被优化,永远不会执行。如果您只是做一个var = var来欺骗编译器,那么情况仍然是一样的。

我确信您知道TM4C123GH6PMI是一款32位ARM Cortex-M4F微控制器,查看数据表,除了SysTick定时器外,还有六个16/32位定时器模块和六个32/64位定时器模块。

当我还是一个新手时(我认为我是!(,我会以以下方式实现延迟。

  • 初始化计时器
  • 在定时器中断处理程序中设置标志和/或递增计数器
  • 在适当阶段检查应用程序中的标志/计数器

如果我阻止执行,除非计数器达到所需值,那么这是一种基于延迟的实现。如果我让其他应用程序代码在计数器未达到所需值时执行,则这是一个超时实现。超时通常比延迟更可取,但这可能会因需求而异。

在您的解决方案中,控制器大部分时间都处于非生产性循环中,只会浪费CPU周期和能量。一个更好的解决方案是通过频率为t/2(例如5ms(的定时器中断来驱动LCD,将要写入的数据放入环形缓冲区或类似的缓冲区,并在每个周期发送它们。只是为了确定,如果电路没有信号准备好,让它保持原样,并在下一个周期中写入。通过这种方法,cpu可以用于计算,如果什么都不做,它可以简单地闲置。顺便说一句:这种循环经常被优化掉。

@云诺施:谢谢你的建议。我希望我的观点现在更加客观和明确。

在"这个家伙"您提到一个从0计数到1999的空for循环(for (j = 0; j < 2000; j++);(大约需要一毫秒。因此,如果重复此ulMilliSeconds次,程序将执行ulMilliSeconds毫秒的延迟。

在您的平台上,这可能会有所不同,因此您可能需要测量和调整内部循环,如果您的平台的速度是"循环"的两倍,则可能需要for (j = 0; j < 4000; j++);;这家伙的";一

请注意:

for (j = 0; j < 2000; j++);

与此相同:

for (j = 0; j < 2000; j++)
{
// do nothing
}

OTOH这种创建延迟的方法可能会失败,因为编译器可能只是优化掉空循环。通常情况下,延迟是使用微控制器可能具有的定时器进行编程的。

虽然这不是编写延迟循环的更好方法,但它无疑是最简单的设计方法,尤其是在非常短的时间内;另一方面,由于执行时间的不确定性,这些循环通常需要一些调优。时间取决于编译器、处理器中的管道和缓存的优化。

一些编译器,特别是为嵌入式世界设计的编译器,可能具有特殊的#pragmas或其他功能来而不是优化空循环。例如,一些编译器以一种特殊的方式处理NOP指令(插入了一些像__no((之类的内在指令(;有时NOP也有一定的执行时间。

最新更新