2

我正在尝试使 TI MSP430 Launchpad 板上的 LED 闪烁。我有两段代码。一个有效,而另一个无效。唯一的区别是在工作版本中包含了 volatile 关键字。为什么程序执行需要这个关键字?

此代码有效...

void main(void) {
    WDTCTL = WDTPW | WDTHOLD;           // Stop watchdog timer

    // Configure Port Directions
    P1DIR |= 0x01;                      // 0000 0001

    volatile unsigned int i;

    for(;;)
    {
        P1OUT ^= 0x01;                  // Set P1.0 LED on
        for (i = 20000; i > 0; i--);    // Delay
    }
}

虽然此代码不...

void main(void) {
    WDTCTL = WDTPW | WDTHOLD;           // Stop watchdog timer

    // Configure Port Directions
    P1DIR |= 0x01;                      // 0000 0001

    unsigned int i;

    for(;;)
    {
        P1OUT ^= 0x01;                  // Set P1.0 LED on
        for (i = 20000; i > 0; i--);    // Delay
    }
}
4

6 回答 6

4

如果没有volatile,编译器可以更自由地优化它确定什么都不做的代码,以及重新排序内存访问。不使用时,您的延迟循环正在优化volatile

于 2013-06-19T17:37:59.770 回答
3

这两个版本都不好,编译器的未来版本可能会生成截然不同的代码。

__delay_cycles()大多数 MSP430 开发工具都提供了在您想要等待特定数量的周期时使用的内在函数。

例如:

#include <intrinsics.h>
void main(void)
{
  WDTCTL = WDTPW | WDTHOLD;           // Stop watchdog timer

  // Configure Port Directions
  P1DIR |= 0x01;                      // 0000 0001

  for(;;)
  {
    P1OUT ^= 0x01;                  // Set P1.0 LED on
    __delay_cycles(40000);
  }
}

请注意,为此生成的代码将以全处理器速度执行。如果您在功率受限的环境中需要更长的延迟,请考虑使用计时器并将处理器置于低功率模式。

于 2013-06-22T18:32:57.377 回答
1

如果您NOP在循环中的第二个版本中添加 a:

for (i = 20000; i > 0; i--) {
    asm volatile("nop");
}

它也应该工作。在这两种情况下,volatile都需要防止优化。在第一个版本中,它阻止编译器完全删除循环。在第二个版本asm中,它告诉编译器将它留在原处(因此它不会移动到另一个位置)。

令人遗憾的是,这两个版本都被认为不是好的风格:考虑使用计时器来准确延迟繁忙。如果核心频率改变,循环不会做你想做的事。

于 2013-06-19T19:05:05.333 回答
1

在检查 IAR 编译器(MSP430F5438 的 V4.21.9)的汇编输出时,无论使用或不使用 volatile 关键字,都始终编译无限循环。(高达中等优化设置。)所以这可能是编译器依赖项。当然,请尝试在关闭优化的情况下进行编译。

volatile 关键字很重要的地方是告诉编译器不要依赖一个值并因此重新读取它。例如,您可能正在读取接收外部字符的输入缓冲区。需要告诉编译器继续阅读,因为缓冲区是由超出其知识范围的东西更新的。

于 2013-10-18T21:38:40.863 回答
0

我更喜欢适用于每个编译器的解决方案,从另一个未优化或未使用循环优化的模块调用函数。Asm 就是一个很好的例子。一个只返回的虚拟函数

dummy:
   ret

...

void dummy ( unsigned int );

unsigned int ra;
for(ra=0;ra<10000;ra++) dummy(ra);

编译器可以根据需要展开循环,但必须以正确的顺序使用正确的参数调用 dummy,您可以在 C 代码上使用最大优化而无需担心。

于 2013-06-25T16:56:28.857 回答
0

如果您不将其声明为 volatile,那么许多编译器将执行运行时优化,因此您可能无法接受更改

于 2013-06-25T16:57:48.877 回答