2013-06-19 3 views
2

Я пытаюсь мигать светодиодом на плате TI MSP430 Launchpad. У меня есть два кода. Один работает, а другой - нет. Единственная разница - включение ключевого слова 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

Я предпочитаю решение, которое работает на каждом компиляторе, вызывает функцию из другого модуля, который не оптимизирован или не оптимизирован с помощью цикла. Асм - хороший пример. фиктивная функция, которая просто возвращает

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 важно, чтобы компилятор не подсчитывал значение и, следовательно, перечитывал его. Например, вы можете прочитать входной буфер, получающий внешний символ. Компилятору должно быть сказано продолжать читать, поскольку буфер обновляется чем-то из его объема знаний.

Смежные вопросы