430_21.  Пример программирования микроконтроллера MSP430G2452.



Если Вы хотите разобраться как работает MSP430Gxxx,
и  у  Вас есть время и желание,  то это нужно деалать.
Если   времени  нет,  то  нужно  выбрать  другой  путь.
На  данный момент,  есть оболочка програмир.  Energia,
которая  позволяет программировать быстро, используя
готовый код. Запрограммировать LCD display - 10 минут.
Сделать  многоканальный  вольтметр  -  еще  10 минут.
Вывести данные  и  сохранить на компьютере - еще 10.
Готовый вольтметр, который уже работает -  здесь.    .


  Что бы проверить какой ток потребляет микроконтроллер MSP430 придется написать небольшую программу. Как обычно, программа начинается не с кода, а с логики. Или чего мы хотим сделать. Код – это как мы это реализуем в операторах языка Си.

  Еще до программирования, на листике бумаги, пишется план или «Что я хочу сделать?».

1.    Процессор должен постоянно работать.
2.    Хочется видеть, что программа работает.
3.    Иметь возможность измерить два значения тока (внешним
амперметром).

  Теперь то же, но более детально.

1.    «Постоянно работать». Запустить микроконтроллер в «бесконечный цикл».

2.    «Видеть». Пусть микроконтроллер мигает светодиодом. Хорошо. Но тогда ток потребляемый схемой будет изменяться, в зависимости от того включен светодиод или выключен. Проблему решаем двумя светодиодами мигающими по очереди.

3.    «Измерить». Для наглядности, общим для микроконтроллера и нагрузки (светодиодов) делаем «плюс питания». То есть ток нагрузки будет течь от «+» и через ножку порта на «общий провод». Традиционно используем порт 1, выходы P1.0 и P1.6.  Принципиальная схема получается такая же, как на предыдущей странице.

  Таким образом, с проблемой №3 – покончено.

  Проблема №2. Вспоминая незабвенную фразу «Машина думать не может, машина должна ехать!» убеждаешься что это действительно так. Микроконтроллер светодиодами не мигает. Он о них ничего не знает и не должен. Он, только, последовательно выполняет команды, которые написаны в нашей программе.

    Установить на выход.
  Учитывая, что после сброса все порты микроконтроллера устанавливаются «на вход», необходимо определить, что какие то из них надо переназначить «на выход».

P1DIR |= 0x01; и P1DIR |=0x40; в результате операции «ИЛИ» устанавливают «1» в битах «0» и «6», и микроконтроллер переключает их на «выход».  01h (шестнадцатеричное) это 00000001b (двоичное). 04h = 01000000b. Сложив их вместе получим 01000001b, или 0x41. Таким образом, одна команда, которая устанавливает в «1» биты «0» и «6» будет выглядеть так:  P1DIR |=0x41;


    Установить уровни 0 или 1.

  С этого момента на ножках микроконтроллера (только на P1.0 и P1.6) появляется «что то». Что бы избежать неопределенности, сразу установим запишем в эти биты какое-нибудь значение.
 

P1OUT |=0x01; установит в «1» ножку порта P1.0 (операция “или” (|=) между текущим состоянием порта и 00000001b).

P1OUT &= ~0x40; установит в «0» ножку порта P1.6 (операция “и” (&=) с инвертированным (~)  значением  40h ). То же самое, но менее наглядно P1OUT &= 0xBF; где BFh  = ~ 40h = ~ 01000000b = 10111111b.

    Инвертировать.

  Операция  «исключающего ИЛИ»  P1OUT ^= 0xFF;  (FFh = 11111111b) инвертирует все биты P1OUT, не зависимо от их начального значения . P1OUT ^= 0x41; - только биты «0» и «6» ( 41h = 01000001b ). Таким образом, P1OUT ^= 0x41; - это то, что надо.

******************************************************************************
  Что бы программировать микроконтроллеры Вам необходимо знать три битовых оператора, которые позволяют изменять выбранные биты (не изменяя, при этом, все остальные).

Это:


P1OUT  |=  0x40;     Установить бит в «1»
(бит «6», в данном случае),

P1OUT &= ~ 0x40;   Установить бит в «0» (бит «6», в данном случае),

P1OUT ^= 0x40;       Инвертировать бит (состояние «6-го» бита, в данном случае).    

  Очень желательно понимать синтаксис битовых операторов,  как они работают  и  что делают.
******************************************************************************

  Отлично. Часть программы «вырисовывается» приблизительно такая:


P1DIR |=0x41; // биты 0 и 6 порта P1 на выход.

P1OUT |=0x01; // бит 0 порта P1 установим в «1».
P1OUT &= ~0x40; // бит 6 порта P1 установим в «0».
...
P1OUT ^= 0x41; // инвертировать биты «0» и «6».

  Можно, уже сейчас, «отдать» эти инструкции компилятору и программа начнет работать. Неприятность заключается в том, что он выполнит набор наших инструкций один раз и остановится. Проблема решается циклом for(;;). Его условия (;;) всегда выполняются и он превращается в «бесконечный цикл».

P1DIR |=0x41; // биты 0 и 6 порта P1 на выход.

P1OUT |=0x01; // бит 0 порта P1 установим в «1».
P1OUT &= ~0x40; // бит 6 порта P1 установим в «0».
for (;;)  // бесконечный цикл.
{
P1OUT ^= 0x41; // инвертировать биты «0» и «6».
}

  Вторая проблема заключается в том, что программа будет переключать выходы портов слишком быстро. Программная задержка, в цикле do-while, замедлит этот процесс.


P1DIR |=0x41;     // биты 0 и 6 порта P1 на выход.

P1OUT |=0x01;     // бит 0 порта P1 установим в «1».
P1OUT &= ~0x40;     // бит 6 порта P1 установим в «0».
for (;;)     // бесконечный цикл.
{
P1OUT ^= 0x41;       // инвертировать биты «0» и «6».
i=10000;          // начальное значение счетчика цикла i=10000.
do  i--;         // при каждом «проходе» уменьшать значения i на единицу.
while ( i != 0);        // оставаться в цикле do-while, пока значение i не равно нулю.
}

  На данный момент, у нас появилась переменная (i). Компилятор должен знать о всех переменных, еще до начала ее использования. Поэтому определим ее перед циклом do-while как целую переменную (volatile unsigned int i;) без знака (volatile unsigned int i;), которая не требует оптимизации компилятором (volatile unsigned int i;). При 16-ти битном ядре процессора, максимальное значение ,которое может принимать целая переменная без знака  =  64 000. Если переменная знаковая, то от -32.000 до +32.000 (так как первый разряд отводится для знака, то число получается уже не 16-ти битным, а 15-ти битным со знаком).

  И последнее. Любая программа, в языке Си, должна содержать хотя бы одну функцию. Иначе компилятор ее «не переварит». Поэтому добавим функцию void main (void) {}  , которая не требует входных  параметров (void main (void) {}) и ничего не возвращает (void main (void) {}), после окончания своей работы. Компилятор ожидает, что содержание этой функции  (тело функции) находится между скобками {}.
В результате должно  получиться что то похожее на:

void main (void)  {
P1DIR |=0x41;
P1OUT |=0x01;
P1OUT &= ~0x40;
    for(;;) {
        volatile unsigned int i;
        P1OUT ^= 0x41;
        i = 10000;
        do i--;
        while(i != 0);    }}

  Теперь осталось указать в начале программы «хэдер» файл, по которому компилятор узнает что такое WDTCTL, WDTPW, WDTHOLD, P1DIR, P1OUT и как их применить к  микроконтроллеру MSP430G2452.  Инструкция #include <msp430g2452.h> читается компилятором следующим образом: включить (#include <msp430g2452.h>) «хэдер» файл (#include <msp430g2452.h>), который расположен в директории «по умолчанию» (#include <msp430g2452.h>).

  Почти полностью, программа будет выглядеть так.

#include <msp430g2452.h>
void main (void)  
{
P1DIR |=0x41;
P1OUT |=0x01;
P1OUT &= ~0x40;
    for(;;)
{
        volatile unsigned int i;
        P1OUT ^= 0x41;
        i = 10000;
        do i--;
        while(i != 0);    
}}

  Этот фрагмент, уже сейчас можно скомпилировать с помощью "Code Composer Studio" и слить в микроконтроллер и прогнать пошагово, наблюдая за последовательностью переключения светодиодов. НО,  если запустить программу «в вольное плавание» (кнопкой “Run” или  F8) то светодиоды не будут подавать никаких признаков жизни.

  Почему? По умолчанию, после сброса, в микроконтроллере выключено все, кроме таймера. Он то и будет сбрасывать микроконтроллер через короткие промежутки времени, не давая нашей программе работать как мы задумали. Устраним это простым отключением таймера, строчкой WDTCTL = WDTPW + WDTHOLD; , где:
 

WDTCTL – управляющее слово таймера (16-ти битное значение).
WDTPW – пароль, присутвующий при любом обращенниии к таймеру (старшие 8-мь бит).
WDTHOLD – управляющее слово, которое отключает таймер (младшие 8-мь бит).

 Теперь, программа выглядит следующим образом.

#include <msp430g2452.h>
void main (void)  
{
WDTCTL = WDTPW + WDTHOLD;
P1DIR |=0x41;
P1OUT |=0x01;
P1OUT &= ~0x40;
    for(;;)
{
        volatile unsigned int i;
        P1OUT ^= 0x41;
        i = 10000;
        do i--;
        while(i != 0);    
}}

  Наша программа полностью закончена. Можно компилировать с помощью "Code Composer Studio" и сливать в микроконтроллер.


 Дальше -->

10.06.2012  SKootS

_

Make a free website with Yola