Кнопки панели запуска MSP430 работают неправильно и не видят переменных

Я только что получил панель запуска MSP430F5529 и сделал одно руководство, в котором заставляю мигать светодиод, расположенный на P1.0. Я использую студию композитора кода в качестве своей IDE

Теперь я пытаюсь заставить светодиод на P1.0 (красный) и светодиод на P4.7 (зеленый) чередоваться в зависимости от того, нажата ли кнопка, расположенная на P2.1.

Что бы я ни делал, кнопка ничего не меняет. Что еще более странно, так это то, что нажатие кнопки изменяет несколько битов в P2IN, а не только в P2.1.

Я попытался использовать кнопку на P1.1 (на самом деле я попробовал это первым), и у меня было похожее поведение, когда кнопка меняет несколько битов, а иногда вообще ничего не меняет. Но хуже всего то, что даже если биты меняются и он сравнивает бит ввода с тем, что он должен быть для нажатия, он никогда не регистрируется как нажатый.

Кроме того, я не вижу свои переменные, поэтому я добавил переменную «бла» и попытался установить ее в 0x00, чтобы заставить себя войти в цикл, но это ничего не делает !!!! Это похоже на то, что он просто удаляет переменную blah.

Вот код, который я пытаюсь заставить работать:

#include <msp430f5529.h>

//defines
#define red_LED   BIT0 //red LED @ P1.0
#define grn_LED   BIT7 //green LED @ P4.7
#define BTN       BIT1 //button is located a P2.1
#define BTN_PRESSED      0x00

//prototypes
void delay(int n);

//main
void main(void) {
    WDTCTL = WDTPW + WDTHOLD; //disable watchdog timer

    unsigned int flash; //variable to store LED flash flag

    P1OUT = 0; //set output as low
    P1DIR |= red_LED;  // set LED pins to outputs

    P4OUT = 0; //set output low
    P4DIR |= grn_LED; //set green LED as output

    /* Setting up Switch */
    P2OUT = 0;                                   //set output as low
    P2DIR &= ~BTN;                               // Set the switch pin to input
    P2REN |= BTN;                                // Use an internal resistor
    P2OUT |= BTN;                                // The internal resistor is pullup

    for (;;) {//inf loop

        for (flash=0; flash<7; flash++) {
            P1OUT |= red_LED;    // red LED on
            delay(60000);             // call delay function
            P1OUT &= ~red_LED;   // red LED off
            delay(60000);             // delay again
        }

        while ((P2IN & BTN) == BTN);  // wait for button press, loop forever while P1IN is high (button unpressed)

        for (flash=0; flash<7; flash++) {
            P4OUT |= grn_LED;    // green LED on
            delay(60000);            // call delay function
            P4OUT &= ~grn_LED;   // green LED off
            delay(60000);            // delay again
        }

        while ((P1IN & BTN) == BTN);  // wait for button press, loop forever while P1IN is high (button unpressed)

    }//end inf loop
} // main


//functions
void delay(int n) {
    //delays for a count of 60000 ticks
    unsigned int count;
    for (count=0; count<n; count++);
} // delay

и вот тестовый код, который я пытаюсь отлаживать безрезультатно (кнопка работает, если я попадаю в цикл delay(), но я никогда не могу попасть в него!

#include <msp430f5529.h>

//defines
#define red_LED   BIT0
#define grn_LED   BIT7
#define BTN       BIT1
#define BTN_PRESSED      0x00

//prototypes
void delay(int n);

//main
void main(void) {
    WDTCTL = WDTPW + WDTHOLD; //disable watchdog timer

    unsigned int flash; //variable to store LED flash flag

    P1OUT = 0; //set output as low
    P1DIR |= red_LED;  // set LED pins to outputs

    P4OUT = 0; //set output low
    P4DIR |= grn_LED; //set green LED as output

    /* Setting up Switch */
    P2OUT = 0;                                   //set output as low
    P2DIR &= ~BTN;                               // Set the switch pin to input
    P2REN |= BTN;                                // Use an internal resistor
    P2OUT |= BTN;                                // The internal resistor is pullup

    int blah = 0;

    for(;;){
        if((blah) == BTN_PRESSED){
            delay(5);             // call delay function
        }
    }

//functions
void delay(int n) {
    //delays for a count of 60000 ticks
    unsigned int count;
    for (count=0; count<n; count++);
} // delay

Должно быть, я делаю что-то принципиально неправильное, потому что бла никогда не появляется в моем списке переменных отладчика, а задержка (5) никогда не запускается!

Итак, какая часть вашего кода работает? Что-либо? Могу ли я предложить сделать шаг назад и просто заставить один из светодиодов мигать без использования кнопки, просто в цикле с задержкой между включением и выключением? Как только это сработает, двигайтесь дальше. Это подтвердит правильность установки IDE и части.
Я сделал это, я даже могу заставить два светодиода чередоваться, но вторая попытка использовать кнопку для управления включением одного из них, похоже, не работает. Кажется, я не могу попасть в оператор if, который проверяет, когда кнопка нажата.
Итак, до этого утверждения (в вашем первом фрагменте кода) while ((P2IN & BTN) == BTN);работает? То есть вы видите вспышку красного светодиода?
Убедитесь, что оптимизация отключена в настройках компилятора. Оптимизатор мог оптимизировать ваш код так, что отладчик показывает неожиданное поведение.
Вы не можете получить желаемое поведение без использования прерывания на кнопке. Попробуйте удерживать кнопку нажатой не менее секунды и посмотрите, начнет ли мигать зеленый светодиод. Я подозреваю, что MSP430 не видит нажатия кнопки.
отключив оптимизацию компилятора, я получил желаемое поведение, за исключением того факта, что бит регистра, соответствующий этой кнопке, не является единственным битом, который изменяется, когда я нажимаю кнопку. нормально ли, что эта кнопка случайно изменяет другие биты в регистре?
также, отключив оптимизацию компилятора, я теперь могу видеть все свои локальные и глобальные переменные. что делает оптимизация компилятора? Почему он избавился от моих локальных переменных?
По сути, оптимизатор видит, что ваш цикл не делает ничего полезного , и отрезает его. Он слишком умен для своего же блага.
Что касается P2IN, изменяющего более одного бита, да, потому что состояние вывода по умолчанию при сбросе — это Input. Входные контакты, которые не установлены на высокий или низкий уровень извне или с внутренними подтяжками/понижениями, являются ПЛАВАЮЩИМИ и могут меняться, улавливая статические помехи в воздухе, как маленькие антенны. Вы можете либо включить внутренние подтяжки, чтобы перевести их в известное состояние, либо установить для них высокий или низкий уровень выходного сигнала.

Ответы (1)

Компилятор видит, что delay()цикл пуст, поэтому он умно делает вывод, что функция может вычислить тот же результат намного быстрее, если полностью исключить цикл.

У переменной blahта же проблема: компилятор видит, что ее значение никогда не изменяется внутри программы, поэтому она фактически является константой, и ее не нужно где-либо хранить. (И это никогда неif((blah) == BTN_PRESSED) может произойти, поэтому его можно опустить.)

Чтобы сообщить компилятору, что он действительно должен получить доступ к некоторой переменной, вы должны объявить эту переменную как volatile:

volatile int blah = 0;        // allows changes with the debugger
...
volatile unsigned int count;  // force the compiler to actually count up, even
                              // if the compiler does not see any effect

Обратите внимание, что все регистры типа P2INобъявлены как as volatile, потому что они могут изменяться без присваивания, видимого компилятором.

Также обратите внимание, что компилятор не знает, что обработчики прерываний могут прерывать другие функции, поэтому он может не утруждать себя повторным чтением некоторых переменных, которые могли быть изменены прерыванием. Таким образом, переменные, которые являются общими для некоторого обработчика прерываний и основной программы, также должны быть объявлены volatile.


По умолчанию все контакты GPIO настроены как входы. Эти входы реализованы с помощью полевых МОП-транзисторов, а их затвор настолько мал, что может принимать случайный заряд от любых ближайших сигналов или даже по воздуху, если вы не активируете вход на высоком или низком уровне. Это называется "плавающий ввод".

Хуже того, вход, который оказался наполовину заряженным, наполовину включает и соединения «1», и «0», и ток от источника питания будет течь к земле.

Руководство пользователя говорит в разделе 12.2.8:

Настройка неиспользуемых контактов порта

Неиспользуемые контакты ввода-вывода должны быть настроены как функция ввода-вывода, направление вывода и оставлены неподключенными на печатной плате, чтобы предотвратить плавающий ввод и снизить энергопотребление. Значение бита PxOUT не имеет значения, потому что вывод не подключен. В качестве альтернативы встроенный подтягивающий/подтягивающий резистор можно включить, установив бит PxREN на неиспользуемом выводе для предотвращения плавающего входа.

Делать переменные изменчивыми, чтобы их можно было просматривать в отладчике, — плохой совет. У Volatile есть свои цели, и это не одна из них. Это побочный эффект летучих. Вместо этого просто отключите оптимизатор. Это прямое и явное решение проблемы. Когда вы закончите отладку, вы можете снова включить оптимизатор для увеличения скорости и размера кода. Вы бы не хотели возвращаться к своему коду и удалять все ненужные летучие элементы в этот момент.
Эта конкретная переменная была введена в первую очередь для отладки.