2013-06-19 110 views
2

我試圖在TI MSP430 Launchpad主板上閃爍LED。我有兩段代碼。一個工作,而另一個不工作。唯一的區別是在工作版本中包含volatile關鍵字。爲什麼該關鍵字需要執行該程序?易失性關鍵字 - MSP430

此代碼的工作...

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

沒有volatile,編譯器有更多的自由度優化了其決定確實碼沒有什麼,以及重新排序內存訪問。當您不使用volatile時,您的延遲循環正在優化。

1

如果你在你的第二個版本,在循環中添加NOP

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

它應該正常工作。在這兩種情況下,需要volatile來防止優化。在第一個版本中,它可以防止編譯器完全移除循環。在asm的第二個版本中,它告訴編譯器將它保留在原來的位置(所以它不會移動到另一個位置)。

令人傷心的是,這兩個版本都不被認爲是很好的風格:考慮使用計時器來確切的忙碌延遲。如果核心頻率發生變化,循環將無法做到您想要的。

2

這兩個版本都不是很好,編譯器的將來版本可能會生成大不相同的代碼。

大多數MSP430開發工具提供的內在功能__delay_cycles()打算在等待特定數量的週期時使用。

例如:

#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); 
    } 
} 

注意,對於此生成的代碼將以全處理器速度執行。如果您在功率受限的環境中需要更長的延遲時間,請考慮使用定時器並將處理器置於低功耗模式。

0

我更喜歡一種適用於每個編譯器的解決方案,從另一個未優化或未使用循環優化的模塊調用一個函數。 Asm就是一個很好的例子。一個虛擬函數,僅僅返回

dummy: 
    ret 

...

void dummy (unsigned int); 

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

編譯器可以展開循環,如果一些就是了,但將有正確的順序調用虛用正確的參數,可以無需擔心在C代碼上使用最大化優化。

0

,如果你不聲明它揮發的話,很多的編譯器將執行運行時優化,因此你可能無法拿起變化

1

在審查IAR編譯器的組件輸出(V4.21.9爲MSP430F5438)無限循環總是被編譯進來,有或沒有volatile關鍵字。 (高達中等優化設置。)所以這可能是一個編譯器依賴。當然,嘗試編譯優化關閉。

凡volatile關鍵字是非常重要的是要告訴編譯器不要指望一個值,從而再讀一遍。例如,您可能正在讀取接收外部字符的輸入緩衝區。編譯器需要被告知繼續閱讀,因爲緩衝區是通過超出其知識範圍的某些東西來更新的。