Главная | |
Материал взят из книги![]() Скачать оригинал КНИГИ в хорошем качествеВ предыдущем разделе мы изучили один из способов определения системных переменных. Существует и другой способ. Этот способ при- меним в том случае, когда известно, что переменные будут храниться в пространстве обычной памяти. И в то же время не имеет значения, в какой именно ячейке, какая переменная будет храниться. Этот способ называется резервированием памяти. Резервирование памяти производится при помощи специальных операторов. В рассматриваемой версии языка Ассемблера имеются два оператора резервирования памяти: ОБ — оператор резервирования одной или нескольких ячеек ОЗУ. ОВ1Т — оператор резервирования одного или нескольких бит в битовом пространстве. Ниже приведен Фрагмент №2 управляющей программы позиционера, в котором производится резервирование памяти для всех переменных, нр ппмгянных по (Ьпягмрнте N01 ![]() ![]() Рассмотрим этот фрагмент подробнее. Как вы могли убедиться, я разделил все команды резервирования на две секции. В первой секции происходит резервирование ячеек ОЗУ, а во второй — резервирование ячеек битового пространства. Каждая секция начинается с оператора определяющего, какое из доступных пространств памяти используется. Дело в том, что процессоры, для которых предназначен описываемый Ассемблер, могут иметь до шести пространств памяти. Каждое пространство имеет свое уникальное имя: ЯБЕС Пространство регистров (РОН). ЭБЕС Пространство внутренней памяти данных. 18ЕС Пространство ячеек основной памяти с косвенной адресацией. ВБЕС Битовое пространство данных. ХБЕС Пространство внешней памяти данных. СБЕС Пространство программной памяти. Процессор АТ89С2051 использует только пять видов пространств. Внешняя память у этого процессора отсутствует. А значит, у него отсутствует пространство ХБЕС. Каждое из этих пространств имеет свой указатель текущей незанятой ячейки памяти. Посмотрите на начало фрагмента №2. Оператор ЭБЕС АТ ЗОН в начале фрагмента выбирает в качестве текущего, сегмент ОБЕв. Необязательный параметр АТ ЗОН устанавливает значение указателя этого сегмента равным ЗОН. Далее идет ряд операторов ОБ. Каждый такой оператор выделяет одну или несколько ячеек памяти для очередной переменной. Справа от оператора ставится имя переменной, для которой резервируются ячейки. Слева — обязательный параметр, равный числу выделяемых ячеек. Этот параметр может быть равен от 1 до любого разумного числа, но не больше, чем общий объем выбранного пространства. Выделение памяти начинается с ячейки, адрес которой равен текуще- му значению указателя. Затем значение указателя увеличивается на величину, равную числу выделенных ячеек. Если вернуться к фрагменту №2, то первый оператор DS в этом фрагменте выделит одну ячейку с адресом ЗОН для переменной bufli. Следующий выделит одну ячейку с адресом 3IH под переменную bull, и так далее. Под переменную patek выделяется сразу две ячейки. Их адреса будут равны 35Н и 36Н. Имена переменных используются в программе точно так же, как и в предыдущем случае. Команда mov a,bufh запишет в аккумулятор содержимое ячейки bufh. Команда mov a,#bu№ запишет в аккумулятор адрес этой ячейки. Поэтому имена зарезервированных ячеек могут использоваться как константы. Операторы DS совсем не обязательно должны следовать друг за другом. Они могут перемежаться любыми другими командами. В приведенном фрагменте, таким образом, попутно, определяются две константы: tzcle и tzdd. Пока не будет определен другой сегмент памяти, операторы DS будут последовательно выделять память в текущем сегменте. Новая ячейка всегда будет выделяться непосредственно после предыдущей. Однако, в случае необходимости, вы всегда можете принудительно поменять значение указателя. Для этой цели используется специальный оператор ORG. Этот оператор не может выбрать другой сегмент памяти, он лишь устанавливает указатель, принадлежащий текущему сегменту, в новую позицию. В рассматриваемом фрагменте программы такой оператор применяется в конце первой секции. Он устанавливает указатель в позицию 28Н. В результате последующий оператор DS резервирует для переменной strzdu одну ячейку памяти с адресом 28Н. Главным преимуществом такого способа определения переменных является то, что программисту не надо следить за правильностью выделения памяти. Компьютер сам присвоит разным переменным разные ячейки памяти. Если вы случайно некорректно применили оператор ORG и попытались установить указатель сегмента в позицию, которая уже занята, транслятор выдаст сообщение об ошибке. Несколько слов необходимо сказать о том, почему в нашей программе для размещения переменных выбраны именно эти адреса памяти. Адрес ЗОН не случайно начинает область для хранения переменных. Это первая из ячеек ОЗУ, которая не несет никаких дополнительных функций (см. рис. 42). Она не совмещена ни с РОН, ни с битовым пространством. Естественно, если ситуация не требует двойного доступа к ячейкам, то разумнее применять именно эти ячейки. Ячейки с адресами от ООН до 1FH выгоднее адресовать, как регистры общего назначения. Все операции с регистрами имеют длину всего один байт и выполняются всего за один машинный такт. Операции же с ячейками ОЗУ требуют два такта и занимают два байта программной памяти. Ячейки ОЗУ, совмещенные с битовым пространством, пригодятся для хранения однобитовых переменных. И лишь в том случае, если требуется двойной доступ к ячейке памяти, удобно использовать адреса ОЗУ с 20Н по 2ЕН. В нашей программе такой способ потребовался для счетчика принятых разрядов ДУ. Имя переменной, предназначенной для хранения значения счетчика: Для того, чтобы обеспечить возможность двойного доступа к счетчику, для него была выбрана ячейка с адресом 28Н. Команда резервирования этой ячейки приводится в конце фрагмента №2. Адрес младшего бита этой ячейки в битовом пространстве процессора равен 40Н. Вторая секция Фрагмента №2 программы, обозначенная, как «Определение системных флагов», по принципу работы аналогична первой. Различие в том, что в ней резервируются ячейки не в пространстве обычной памяти (ОБЕО), а в битовом пространстве (ВБЕО). Однобитовые ячейки выделяются для хранения так называемых флагов. Флаг — это обычная переменная, которая в процессе работы программы принимает только два значения и служит для запоминания какого-либо режима работы. Если переменная принимает только два значения, то ее разумно хранить именно в ячейке битового пространства. О том, как используются программные флаги, вы узнаете в последующих разделах книги. В данном же разделе мы рассмотрим процесс выделения ячеек в битовом пространстве процессора. Оператор ВБ ЕС выбирает в качестве текущего битовое пространство памяти процессора. Оператор 01Ю 0 устанавливает указатель этого пространства на нулевую отметку. Операторы ОВ1Т выделяют указанное количество ячеек битового пространства, каждый для своей переменной. В нашем случае для каждой переменной выделяется только один бит. В последних двух строках сегмента применен альтернативный способ определения флагов. Здесь адрес ячейки флага определен как системная константа. Причем сначала определяется адрес в пространстве обычной памяти (ОБЕО). А затем адрес флага определяется, как бит номер 1 (второй по счету) этой ячейки. Такой способ определения бита, применим для любой ячейки памяти, регистра или порта ввода/вывода, допускающего побитовый доступ. Зачем в данном случае нам понадобилось такое двойное определение ячейки для флага? Дело в том, что указанный флаг необходимо сохранять во внешней флэш-памяти для того, чтобы после включения питания позиционер восстанавливал режим своей работы, выбранный перед выключением. Однако внешняя память работает только с целыми байтами. Поэтому запоминается и затем восстанавливается сразу весь байт П^. А используется для работы лишь один его бит Яги. В заключение этого раздела необходимо отметить, что все перечисленные в этом и предыдущем разделах операторы, относятся к разряду псевдооператоров. Они получили такое название потому, что им не соответствуют никакие команды процессора. При трансляции этой части программы не происходит генерации кодов. Псевдооператоры служат исключительно для удобства составления программ и повышения эффективности программирования. Переопределение векторов прерываний Итак, мы заканчиваем описание псевдооператоров, которые существуют только в текстах программ на языке. Ассемблера, и переходим к изучению более реальных операторов, каждый из которых описывает некую команду из системы команд процессора. С некоторыми из таких операторов мы уже сталкивались в предыдущих разделах. Например, с оператором перемещения mov. На самом деле мнемокод mov применяется при описании множества разных команд процессора. Ниже приведено несколько примеров команды mov. Во втором столбце те же команды представлены в виде кодов процессора. ![]() И это далеко не все варианты употребления команды mov. Обратите внимание, что в приведенном примере три первых команды, а также самая последняя кодируются при помощи всего лишь одного байта. Оставшиеся три команды двухбайтовые. Причем первый байт — это код операции, а второй — параметр (адрес используемой ячейки памяти или константа). Для каждой команды, входящей в систему команд процессорам, в языке Ассемблера существует определенные правила ее написания. Исчерпывающая информация по этому вопросу приведена в приложении I. Теперь рассмотрим следующий фрагмент программы позиционера. В тексте книги он обозначен, как фрагмент №3. В реальной программе он непосредственно следует за фрагментом №2. Фрагмент №3 описывает именно те команды, которые и составляют самые первые ее байты, расположенные в самом начале программной памяти. Что же именно делает программа сразу после запуска? Она переопределяет векторы прерываний! И тут нам нужно подробнее остановиться на том, что же такое векторы прерываний и как их нужно переопределять. Как уже говорилось, микросхема АТ89С2051 имеет встроенную систему прерываний, рассчитанную на обработку пяти фиксированных запросов. Источники первых трех запросов — внутренние устройства самой микросхемы. Еще два запроса могут поступать от внешних устройств посредством входов INTO и INT1 (см. главу 2). Любой из таких запросов вызывает приостановку выполнения основной программы и переход к подпрограмме обработки прерывания. Встроенная система прерываний устроена таким образом, что за каждым из пяти обслуживаемых прерываний закреплен свой фиксированный адрес в программной памяти, где должно находиться начало процедуры обработки соответствующего прерывания. Получив запрос от одного из источников, встроенная система прерываний приостанавливает выполнение основной программы и передает управление на один из фиксированных адресов. Ниже перечислены все эти адреса: ![]() Фиксированные адреса обработки прерываний принято называть векторами прерываний. Некоторые процессоры допускают программное изменение этих адресов. В этом случае говорят о переопределении векторов прерываний. В микроконтроллере АТ89С2051 прямое переопределение адресов прерывания не предусмотрено. Однако существует простейший прием, позволяющий разместить процедуры обработки прерываний в любом удобном месте программы. И, конечно же, это команды безусловного перехода. Для того, чтобы переопределить какой-либо вектор прерывания, нужно по адресу стандартного начала этого прерывания записать команду безусловного перехода на новый адрес. Посмотрите еще раз на список стандартных адресов обработки прерываний. Нетрудно заметить, что расстояние между любыми двумя соседними адресами всего 9 байт. Этого абсолютно не достаточно даже для самого простейшего случая. Стандартные адреса расположены так близко потому, что разработчики микросхемы заранее предполагали, что по этим адресам будут располагаться лишь команды безусловного перехода. Адрес 0000Н — это начальный адрес для основной программы. Именно с этого адреса начинается выполнение программы сразу после включения питания. Здесь тоже придется расположить оператор безусловного перехода, так как основная программа не должна занимать фиксированные адреса, зарезервированные для системы прерываний. Теперь обратимся к фрагменту №3 программы и посмотрим, как записывается процедура переопределения векторов прерываний на языке Ассемблера. ![]() Начинается этот фрагмент с оператора инициализации программного сегмента CSEG с установкой указателя этой области в нулевое значение. Это означает, что действие всех последующих операторов отражается на программной памяти микроконтроллера. Выделение памяти для кодов команд происходит таким же способом, как и в операции резервирования памяти. Коды очередной команды размещаются в программной памяти, начиная с текущего значения указателя. Затем указатель перемещается ровно на столько байт, сколько занимает эта команда. Таким образом, коды команд располагаются в программной памяти последовательно, один за другим. При необходимости, можно принудительно передвинуть указатель при помощи оператора ORG. Именно так и устроена программа, приведенная во фрагменте. По адресу 0000Н расположен оператор безусловного перехода к новому на- Используются технологии uCoz
|