具有递增全局变量的循环如何在没有volatile修饰符的情况下工作?

时间:2016-05-28 20:12:33

标签: c embedded volatile msp430

我一直在使用mspgcc编译器处理MSP430G2553,作为介绍性程序,我开始使用闪烁的LED。我使用的代码如下:

#include <msp430.h> 
unsigned int i;
void main(void) 
{
    WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    P1DIR |= 0x01; //Set P1.0 to output
    for(;;)
    {
        P1OUT ^= 0x01;
        i=0;
        while(i<50000)
        {
            i++;
        }
    }
}

while循环执行提供延迟的工作。

我认为,由于上面的i从0递增到某个值的while循环,为什么我不能使用递减循环。所以我尝试了以下代码。

#include <msp430.h> 
unsigned int i;
void main(void) 
{
    WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    P1DIR |= 0x01; //Set P1.0 to output
    for(;;)
    {
        P1OUT ^= 0x01;
        i=50000
        while(i>0)
        {
            i--;
        }
    }
}

这段代码没有工作,找不到原因,我开始知道全局变量i需要提供&#34; volatile&#34;以防止编译器的优化,因为i的值可以随时改变。

我的问题是在第一种情况下,i的值也从0变为49999,那么为什么我们不使用&#34; volatile&#34;在那种情况下的修饰语?

上述每种情况的汇编代码如下:

案例1(递增循环)

main:
   40B2 5A80 0120      MOV.W   #0x5a80,&Watchdog_Timer_WDTCTL
   P1DIR |= 0x01; //Set P1.0 to output
   D3D2 0022           BIS.B   #1,&Port_1_2_P1DIR
   P1OUT ^= 0x01;
$C$L1:
   E3D2 0021           XOR.B   #1,&Port_1_2_P1OUT
   i=0;
   4382 0200           CLR.W   &i
   while(i<50000)
      90B2 C350 0200      CMP.W   #0xc350,&i
      2FF8                JHS     ($C$L1)
      i++;
$C$L2:
   5392 0200           INC.W   &i
   90B2 C350 0200      CMP.W   #0xc350,&i
   2FF2                JHS     ($C$L1)
   3FF9                JMP     ($C$L2)

案例2(减少循环)

main:
   40B2 5A80 0120      MOV.W   #0x5a80,&Watchdog_Timer_WDTCTL
   P1DIR |= 0x01; //Set P1.0 to output
   D3D2 0022           BIS.B   #1,&Port_1_2_P1DIR
   P1OUT ^= 0x01;
$C$L1:
   E3D2 0021           XOR.B   #1,&Port_1_2_P1OUT
   i=50000;
   40B2 C350 0200      MOV.W   #0xc350,&i
   while(i>0)
      9382 0200           TST.W   &i
      27F8                JEQ     ($C$L1)
      i--;
      4382 0200           CLR.W   &i
      3FF5                JMP     ($C$L1)

1 个答案:

答案 0 :(得分:3)

简而言之,volatile限定符告诉编译器一个对象具有超出其“视觉”的副作用。所以它不能优化对它的访问。

如果没有这个,编译器可以自由地优化掉整个循环,如果它可以证明这不会改变程序的可观察行为。请注意,这不能得到保证,在您的情况下,编译器似乎识别出一种代码模式,而不是另一种代码模式。但是你不能依赖于这个(而且那些编写代码的人缺乏基本的编码实践)。

在这两种情况下,volatile都是必要的,但为了安全起见。请注意,编译器仍然可以优化代码;最好是另外将NOP汇编器内在函数放入循环中。

注意:请参阅生成的汇编程序代码。优化后的代码很可能包含i = 0而不是循环,或只是将i保留为静态变量的默认值(也是0)。