[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Немного теории
TerminatorДата: Пятница, 13.06.2014, 17:05 | Сообщение # 1
Группа: Администраторы
Сообщений: 134
Награды: 3
Репутация: 14
Статус: Оффлайн
Представляю вам учебный курс по микроконтроллерам MSP430.

Хочу сразу предупредить — данный тип МК несколько тяжеловат для
рядового пользователя. Его используют в основном профессиональные
разработчики, но… Я хочу сделать его доступным для всех. Так, что
смотрим и не боимся.
Да, и ещё — этот урок на ассемблере. Потом будет и С.

Данный тип контроллеров построен по Фон-Неймановской архитектуре, т.е.
имеет одну адресную ось. Деления на память программ и данных нет, просто
они располагаются по разным адресам. Чуть позже приведу разбивку.
Мануалы пока читать не будем, просто покажу основное.
Контроллер 16-ти разрядный, в составе ядра есть 16 регистров, четыре из
которых специального назначения (R0 или PC — счетчик команд, R1 или SP —
указатель стека, R2 или SR — регистр состояния, R3 или CG — генератор
констант). Остальные (R4-R15) доступны как регистры общего назначения.
Есть одна отличная вещь — любой регистр может быть указателем.
Пока сведений достаточно.

С чего начать? Со среды программирования, ибо первые шаги можно делать не имея аппаратуры.

Внимание! Кто захочет начать с аппаратуры — запомните! Контроллер питается от напряжения 3,3 вольта, 5 вольт для него смертельны! Будьте осторожны.

Итак, среда разработки. Во всём мире большинство разработчиков  пользуются программами фирмы IAR Systems — www.iar.com.
Не будем изобретать велосипед, последуем их рекомендациям. С
официального сайта можно скачать 30-дневную бесплатную версию. Заморочка
в том, что придется заполнить длинную форму личных данных. Также есть
более продвинутый Code Composer Studio и он тоже платный. Но это уже для
профессионалов.

Так что поехали))
После установки и запуска мы видим (у меня 4-я версия, текущая на официальном сайте — 5-я, но отличий немного):


Жмём кнопку «Создать новый проект в текущем рабочем пространстве» («Create new project in current workspace»).
Смотрим на окошко и выбираем «asm/asm».


Нажимаем «Ok» сохраняем файл проекта в нужное нам место. Рекомендую, каждый проект сохранять в отдельный каталог.

Получаем следующее:


Комментирую полученный код.

Код
[font=Arial]#include "msp430.h"

Ну тут всё ясно, подключаем заголовочный файл.

Код
NAME    main                    ; module name    

    PUBLIC  main                    ; make the main label vissible    
    ; outside this module


Это стандартное объявление имени модуля и его видимости из других модулей.

Код
ORG     0FFFEh    
    DC16    init                    ; set reset vector to 'init' label


Тут мы объявляем вектор перехода по сигналу «Reset». Я делаю это несколько иначе, чуть ниже покажу как.
У MSP430 вектора прерываний располагаются в конце памяти — от адреса
FFFFh и вниз. Для серии F1xxx и F1xx их 16 штук. Да, и ещё существенное
отличие — в вектор заносится адрес, а не команда перехода! Т.е., в данном случае, адрес метки «init».

Код
RSEG    CSTACK                  ; pre-declaration of segment    
    RSEG    CODE                    ; place program in 'CODE' segment


Тут объявляем сегмент стека и кода.
Вот собственно с этого и начинается программа.

Код
init:   MOV     #SFE(CSTACK), SP        ; set up stack


Вот она метка «init», её адрес компилятор потом подставит в вектор сброса.
Первая команда — инициализация стека. Директива SFE вычисляет конец сегмента. А # нужен, чтобы подставлять вычисленное значение, а не рассматривать его как адрес. К примеру:

Код
mov   #1, R1 - поместить 1 в R1,    
    а    
    mov   1, R1 - поместить значение из ячейки памяти с адресом 1 в R1


Вот такие хитрости.
Идём далее.
Команда «nop» у нас просто для задержки.

А вот это важная вещь:

Код
MOV.W   #WDTPW+WDTHOLD,&WDTCTL  ; Stop watchdog timer


Дело в том, что по умолчанию у MSP430 включен сторожевой таймер. Чтобы не было неожиданностей, выключаем его данной командой.
Да, и обратите внимание: все команды пишутся немного не так как у AVR, x51 или x86 — источник сначала, затем приёмник.

Код
JMP $                           ; jump to current location '$'    
    ; (endless loop)


Это прыжок «сам на себя». Просто, чтобы создать замкнутый цикл.

Ну и не забываем «END» в конце программы, также как и у PIC в MPLAB. После этого волшебного слова программа заканчивается.

Что сейчас делает наша программа? Почти ничего. Давайте наполним её
смыслом. А в качестве примера сделаем сортировку случайных чисел.
Задача следующая:
1. Имеем данные в ПЗУ (набор из 16 случайных чисел).
2. Переместим данные из ПЗУ в ОЗУ.
3. Отсортируем данные в ОЗУ.

Для начала настроим проект.
Выберем тип контроллера. Открываем меню «Projects->Options»:


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


Далее выберем тип отладчика:

Счастливые владельцы аппаратного эмулятора могут выбрать «FET Debugger», ну а нам пока сойдет и «Simulator».

Для начала настроек достаточно. Жмём «Ok».

Далее, вставляем вместо всего в окошке текста следующий код (пока без самой сортировки):

Код
[font=Arial]#include "msp430.h"                     ; подключаем заголовочный файл    

    NAME    main                    ; имя модуля    
    PUBLIC  main                    ; установить видимость модуля из других    

    ; Определение констант    
    ArrLn   EQU     16                      ; длина массива    

    ; Вектора прерываний    
    RSEG    INTVEC    
    ORG     RESET_VECTOR           ; вектор сброса    
    DC16    init    

    RSEG    CSTACK                  ; объявление сегмента стека    

    RSEG    CODE                    ; объявление сегмента кода    

    init:   MOV     #SFE(CSTACK), SP        ; инициализация регистра стека    

    main:                    ; начало основной части    
    MOV.W   #WDTPW+WDTHOLD,&WDTCTL  ; запрет сторожевого таймера    

    SortMain:    
    ; Переписать из ПЗУ в ОЗУ массив данных    
    mov     #ArrLn, R4              ; инициализируем счётчик количества данных    
    mov     #RamArr, R5             ; установим R5 как указатель на данные в ОЗУ    
    mov     #RomArr, R6             ; установим R6 как указатель на данные в ПЗУ    

    MoveRomToRam:    
    mov     @R6+, 0(R5)             ; копирование слова    
    add     #2, R5                  ; продвинем указатель    
    dec     R4                      ; уменьшим счётчик    
    jnz     MoveRomToRam            ; если не ноль, то повторим    

    BasicCycle:    
    JMP $                           ; jump to current location '$'    

    ;       определение данных в ОЗУ    
    RSEG    DATA16_N    
    RamArr:    
    DS16    ArrLn    

    ;       определение данных в ПЗУ    
    RSEG    DATA16_C    
    RomArr:    
    DC16    101, 11, 25, 657, 567, 217, 5732, 896, 123, 5467, 12, 65, 2345, 23, 98, 2398    

    END

Разберём по частям. Но для начала научимся запускать программу на выполнение.
Скомпилируем проект — пункт меню «Project -> Make» или значок на панели инструментов:

Появится окошко «Messages», в котором отражен процесс компиляции. В
случае успеха (а данный текст должен нормально скомпилироваться)
появится сообщение об этом.

Далее жмем «Project -> Debug» или кнопку:

Должен запуститься собственно отладчик. IAR поддерживает два набора окон — раздельно для редактирования и отладки.
Закроем лишнее. Структура проекта при отладке не нужна, окно «Disassembly» используется редко, да и «Messages» не нужно.
А вот регистры и память хотелось бы видеть. Жмём «View -> Registers»
и два раза «View -> Memory». Перетаскиваем окошки в нужные углы и
получаем картинку (на мой вкус, можете сделать по своему):


В окошках «Memory» выбираем типы памяти «RAM» и «Flash», так будет
удобнее просматривать. Также, в каждом кошке памяти щёлкаем правой
кнопкой и выбираем из контекстного меню «2x Units» (для просмотра
16-ти разрядных данных) и «Data Coverage -> Enable» (будет показано
обращение к текущим ячейкам — удобно).
К отладке готовы!

С помощью кнопки F10 (не входить в подпрограммы) или F11 (входить в подпрограммы)
проходим по шагам и любуемся результатом. Техника нам подвластна!

Дальше все уроки будут исключительно на языке семейства С. Здесь мы
углубились во внутрь того, что происходит в реальной жизни
контроллера(стеки, регистры, память) , а не того, что мы пишем в С.


 
  • Страница 1 из 1
  • 1
Поиск: