Из чего состоит программа под МК 1886ВЕ2У
Чтобы программа под МК 1886ВЕ2У скомпилировалась должным образом, для этого она должна содержать несколько стандартных инструкций, называемых директивами.
Директива – это стандартная инструкция компилятора (препроцессора), определяющая какое-либо действие. Для выполнения стандартных операций, посвящать в которые обычного рядового пользователя не имеет смысла, для компилятора MPASM разработали необходимое количество готовых инструкций, которые также можно считать правилами или директивами. Также директивой можно назвать команду препроцессора.
Как уже писалось выше, создавая проект под требуемый МК при помощи мастера, появляется возможность сразу произвести все необходимые настройки. Но это не всегда удобно, да и требования могут меняться каждую минуту. Также если отсутствует интегрированная среда MPLAB IDE, а имеется только компилятор MPASM, то настройку проекта вообще невозможно произвести из-за его отсутствия. Для этого нужно подключить файл, называемый заголовочным и содержащий все необходимое для правильной настройки и работы МК.
Директива #include
Чтобы сообщить компилятору о том, откуда брать информацию, нужно воспользоваться стандартной директивой - #include, которая производит подключение любого из требуемых файлов. Мы подключим заголовочный файл с именем p17С756А.inc.
Все из существующих директив могут принимать в качестве параметров определённое количество аргументов. Директива #include принимает имя файла, либо путь к нему. В примере используется стандартный способ подключения заголовочных файлов. Существуют также альтернативные, которые отличаются способностью поиска, но их мы рассмотрим позже.
#include<p17С756А.inc> ; подключение заголовочного файла
; для МК 1886ВЕ2У
На самом деле, если быть точным, то слово include – дословно переводится, как включение. В целом всё так и происходит. При компиляции та часть файла с кодом, которая якобы должна быть подключена, просто полностью копируется, а после подвергается процессу обработки. Чтобы в этом убедиться, достаточно открыть заголовочный файл с именем p17С756А.inc, находящийся в подкаталоге программы MPLAB IDE\ MPASM Suite\, где в качестве комментария будет представлена следующая информация:
«This header file defines configurations, registers, and other useful bits of information for the 17С756А microcontroller. These names are taken to match the data sheets as closely as possible».
Что дословно можно перевести как: «Этот заголовочный файл (header) определяет конфигурацию, регистры, и другие используемые биты, несущие информацию о МК 17С756А. Данные имена взяты из документации».
Имена директив не чувствительны к регистру символов, так что вы могли написать предыдущий код вот так:
#INCLUDE<p17С756А.inc> ; подключение заголовочного файла
; для МК 1886ВЕ2У
Обратившись к соответствующей документации от разработчиков на язык Ассемблера MPASM, можно найти список существующих директив. Наиболее важные из них будут описаны далее и в лабораторной работе № 3. Но не стоит путать директивы и команды Ассемблера. Директива – это, как правило, инструкция компилятора, а команда это инструкция МК.
Директива org
Как упоминалось ранее, память МК разделена на Память программ (ПП) и Память данных (ПД). Чтобы пояснить компилятору, куда нужно поместить вашу программу после трансляции, используют директиву – org – определяющую регион области памяти программы. Вот так можно разместить программу, начиная с 0x00 адреса:
org 0x00 ; размещение кода в начале ПП!
Обратившись к рис.2.8 следует обратить внимание, что начиная с адреса 0x00 и по 0x03 размещены векторы сброса, по адресу 0x04 находится вектор для прерываний, а с адреса 0x05 по 0x07FF память является ничем не занятой. Можно поместить программу, начиная с адреса 0x00, и она даже скомпилируется, но на практике вряд ли это приведёт к чему-то хорошему. Программу всегда нужно размещать в тех областях, которые, являются, ничем не заняты. Из вышесказанного можно сделать вывод, что предыдущий код следовало бы переписать следующим образом:
org 0x05 ; адрес начала размещения кода в ПП
Это почти корректное решение проблемы. Дело в том, что после запуска программы, МК начнёт её выполнять с 0-левого адреса, и пока доберётся до адреса 0х05, может произойти одно из двух:
1. Либо процессор наткнётся на адрес перехода по прерыванию и после этого сразу начнёт выполнять программу не с того места;
2. Либо добравшись до адреса 0х05, программа отработает, как и следовало ожидать.
Идеальным вариантом было бы начать выполнение программы с адреса 0х00, и сразу перейти на незанятую область 0х05, либо на 0х18, где, к примеру, начнёт своё расположение ваша программа. Для решения такой проблемы существует команда безусловного перехода – goto. Она относится к констант ориентированным командам. В качестве аргумента, команда goto принимает метку или адрес в ПП.
Метка – это средство организации кода программы на уровне программиста. Также меткой можно называть группировку кода, или способность структурирования кода на уровне пользователя. Компилятор использует метки при трансляции, заменяя их имена, адресами в памяти программ. На машинном уровне для перехода используются только адреса в памяти программ. Чтобы облегчить задачу программисту, в качестве точек перехода решили использовать обычные слова, которые ничего общего с программой, после компиляции иметь не будут, но на этапе написания являются основным средством навигации по коду. Метка является идентификатором, и должна иметь уникальное имя. Немного дальше мы на примере рассмотрим, как это работает, а пока взгляните, как можно организовать переход с помощью метки.
goto main ; переход на метку ‘main’
Теперь код выделения места в ПП выглядит так:
org 0x00 ; начало памяти программ (ПП)!
goto main ; произвести переход на метку 'main',
; с которой начнётся выполнение
; основной программы
org 0x05 ; адрес начала размещения кода в ПП
После компиляции и размещения команд в памяти программ – произойдёт следующее. Процессор начнёт считывание команд с адреса 0х00:
org 0x00 ; начало памяти программ (ПП)!
По этому адресу разместится команда безусловного перехода - goto на метку ‘main’, что процессор послушно выполнит:
goto main ; произвести переход на метку 'main',
; с которой начнётся выполнение
; основной программы
Т.к. выше мы указали директивой org - начать размещение программы с 0х05 адреса, то перейдя на метку ‘main’, а точнее на адрес 0х05 (ведь метки только для программиста) процессор продолжит дальнейшее считывание и выполнение команд.
Это можно считать самым корректным способом. Более тонкие моменты, а также правила, которых следует придерживаться при использовании меток, остальных директив и команд в целом, будут рассмотрены в лабораторной работе № 3.
Директива END
Последняя директива, необходимая для компиляции – END – указывает о том, что программа закончена. После того, как компилятор находит данную директиву, он прекращает процесс обработки кода.
Если вы обращали внимание на примеры, то должны были заметить, что после каждой строки кода, стоит символ - ‘;’- после которого написаны русскоязычные слова. Встречая символ точки с запятой, где-нибудь в текущей строке, компилятор пропускает всё, что за ней следует и переходит к обработке следующей. Таким образом, код можно снабжать поясняющими словами или предложениями, называемыми комментарии.
Это считается хорошей практикой написания кода, когда программист снабжает его пояснениями, в сложных местах. Комментарии можно не использовать, если давать переменным осмысленные имена. Также следует помнить, что плохо спроектированную структуру не спасёт никакое объяснение, так что следует несколько раз подумать, перед тем как браться за кодирование.
Собрав предыдущие примеры воедино, получим, работоспособную программу, в которой использованы все необходимые компоненты, которые будет иметь любая программа под МК.
; Lab_2
;--------------------------------
#include<p17С756А.inc> ; подключение заголовочного файла
; для МК 1886ВЕ2У 16F877
;--------------------------------
org 0x00 ; начало памяти программ (ПП)!
goto main ; произвести переход на метку 'main',
; с которой начнётся выполнение
; основной программы
org 0x05 ; адрес начала размещения кода в ПП
;-------------------------------
main: ; определение метки
END ; директива конца программы
Директива компилятора EQU
Хотя выше было сказано, что описание директив будет рассмотрено в лабораторной работе № 3, все же следует рассмотреть одну из них прямо сейчас, иначе вы никак не сможете выполнить задание текущей лабораторной работы.
Данные пользователя, а также регистров специального назначения размещаются в памяти данных. Директива EQU используется для ассоциации ячейки памяти, равной 1 байту, с именем, которое назначил пользователь. В качестве параметров с левой стороны она принимает имя, которое будет назначено ячейке памяти, а с правой от себя – адрес в памяти данных. Вот так можно ассоциировать ячейку с именем data_1 по адресу 0х20. Далее, ячейки памяти, которым назначены имена, будут считаться переменными:
data_1 EQU 0x20 ; ассоциирование ячейки с именем data_1
; в памяти данных!
Пока воспринимайте это так, а в лабораторной работе № 3, автор уделит больше внимания этому моменту.
Размещать переменные следует с адреса 0х20 в памяти данных, также называемой регистрами общего назначения, потому как остальная часть, впереди, отведена под регистры специального назначения. Чтобы освежить память обратитесь к рис.35 и 36.
Следует отметить, что ассоциировать для одного адреса несколько имён не составляет никакого труда и проблемы, и компилятор это пропустит, потому как всё будет выглядеть вполне корректно. Однако старайтесь этого избегать и назначать адреса с граничной проверкой, т.е. чтобы размер памяти, отведённый под одну переменную, не перешёл за границу, и не занял место, отведённое другой, иначе ошибок вам не избежать:
data_1 EQU 0x20 ; всё корректно!
data_2 EQU 0x21 ; здесь тоже!
value EQU 0x20 ; так не делайте никогда!
Ассоциировать имена с ячейками в памяти можно как в начале программы, так и после объявления директивы org. Лучше делать это, после подключения заголовочных файлов. Вроде такого:
; Lab_2
;--------------------------------
#include<p17С756А.inc> ; подключение заголовочного файла
; для МК 1886ВЕ2У 16F877
;--------------------------------
data_1 EQU 0x20
data_2 EQU 0x21
value EQU 0x22