问题描述
我试图将LCD(NHD-0240AZ-FL-YBW)连接到TM4C123GH6PMI。这样做时,我应该延迟几毫秒,因此我在Google上进行了搜索。一个人使用以下循环来延迟毫秒。谁能解释它的工作原理?
void DelayMilis(unsigned long ulMilliSeconds)
{
unsigned long i = 0,j = 0;
for (i = 0; i < ulMilliSeconds; i++)
{
for (j = 0; j < 2000; j++);
}
}
解决方法
在所有人的应有的尊重下,“这个家伙”在这种实施上做得很糟糕,拖延了时间。
它被认为是如何工作的:
由于嵌套循环,将浪费2000 * ulMilliSeconds
个CPU周期,从而延迟了下一次执行。
为什么可能无法这样工作:
因为,编译器会感觉到嵌套循环没有执行任何操作,因此很有可能会优化嵌套循环并从不执行它们。如果您只是执行var = var
来欺骗编译器,情况将保持不变。
我很肯定您知道TM4C123GH6PMI是32位ARM Cortex-M4F微控制器,除SysTick之外,数据表中还有6个16/32位定时器模块和6个32/64位定时器模块计时器。
当我是新手时(我想我是!),我将通过以下方式实施延迟。
- 初始化计时器
- 在计时器中断处理程序中设置标志和/或增加计数器
- 在适当的阶段检查应用程序中的标志/计数器
如果我阻止执行,除非计数器达到期望值,则它是基于延迟的实现。如果我让其他应用程序代码在计数器未达到期望值的情况下执行,则它是超时实现。通常优先选择超时而不是延迟,但是超时可能因需求而异。
,看来,在“这个家伙”的平台上,您提到一个空的for
循环,该循环从0到1999(for (j = 0; j < 2000; j++);
)大约需要一毫秒。因此,如果您重复ulMilliSeconds
次,程序将执行ulMilliSeconds
毫秒的延迟。
在您的平台上这可能有所不同,因此您可能需要确定并适应内部for循环,如果您的平台速度是“此人”的两倍,则可能需要for (j = 0; j < 4000; j++);
。
请注意:
for (j = 0; j < 2000; j++);
与此相同:
for (j = 0; j < 2000; j++)
{
// do nothing
}
OTOH这种创建延迟的方法可能会失败,因为编译器可能只是优化了空循环。通常,延迟是使用您的微控制器可能具有的计时器进行编程的。
,在您的解决方案中,控制器将大部分时间浪费在无用的循环中,这浪费了CPU周期和能源。 更好的解决方案是通过频率为t / 2(例如5ms)的定时器中断驱动LCD,将要写入的数据放入环形缓冲区中,或类似地在每个周期发送一次。 只需确定,如果电路未准备好信号,则将其全部保留并在下一个周期写入。 通过这种方法,CPU可以用于计算,并且如果不执行任何操作,则可以完全空闲。 顺便说一句:这种循环经常被优化掉。
@Yunnosch:谢谢您的建议。我希望我的观点现在更加客观和明确。
,虽然写延迟循环不是更好的方法,但肯定是最简单的设计,尤其是在很短的时间内。另一方面,由于执行时间的不确定性,这些循环通常需要进行一些调整。时间取决于编译器的优化,处理器中的管道和缓存。
一些专门为嵌入式世界设计的编译器可能具有特殊的#pragmas或其他功能,以不优化空循环。例如,某些编译器以特殊方式处理NOP指令(插入了诸如__nop()之类的内在函数)。有时NOP也有一定的执行时间。