Текст
                    Белов А.В.
Самоучитель по
микропроцессорной
технике
Наука и Техника, Санкт-Петербург
2003


Белов А.В. Самоучитель по микропроцессорной технике. — 224 с: ил. СПб.: Наука и Техника, 2003. ISBN 5-94387-084-9 Серия «Радиолюбитель» В настоящее время существует огромное количество технической литературы практически по всем возможным направлениям. Однако, читая современные книги по электронике, я все время вспоминаю доперестроечные времена. Тогда, возможно, и не было такого изобилия специальной технической литературы, однако любая книга содержала в себе именно то, что и нужно. Ничего лишнего! Сегодняшняя техническая литература, к сожалению, далеко не всегда придерживается этого принципа. Современные толстые красиво иллюстрированные книжки по компьютерной и микропроцессорной тематике либо долго разжевывают очевидные вещи, и в этом легковесном потоке трудно отыскать рациональное зерно. Либо бросаются в другую крайность: начинают сыпать непонятными терминами, не объясняя их значения. В результате, большинство продаваемой в настоящее время литературы оказывается практически бесполезной. Настоящая книга задумана как четкое и конкретное руководство. Она призвана максимально понятно ответить на вопрос: что такое микроконтроллеры и как самому научиться применять их на практике. При изложении материала широко используются конкретные примеры схем и программ. Изучение вопроса начинается с самых азов: цифровой логики и теории цифрового сигнала. В книге отражены все этапы разработки микропроцессорных устройств. В качестве примера выбрано реальное микропроцессорное устройство: позиционер спутниковой антенны. ISBN 5-94387-084-9 Контактные телефоны издательства (812) 567-70-25, 567-70-26 @44M16-38-66,518-56-47 Официальный сайт: www.pubnit.com Интернет-магазин: www.nit.com.ru © Белов А.В. © Наука и Техника (оригинал-макет, обложка), 2003 ООО «Наука и Техника». Лицензия №000350 от 23 декабря 1999 года. 198097, г. Санкт-Петербург, ул. Маршала Говорова, д. 29. Подписано в печать 04.08.03. Формат 60x88 1/16. Бумага газетная. Печать офсетная. Объем 14 п. л. Тираж 5000 экз. Заказ № 285 . Отпечатано с готовых диапозитивов в ФГУП ордена Трудового Красного Знамени «Техническая книга» Министерства Российской Федерации по делам печати, телерадиовещания и средств массовых коммуникаций. 198005, Санкт-Петербург, Измайловский пр., 29.
СОДЕРЖАНИЕ Вступление 4 Глава 1. ЛИКБЕЗ ДЛЯ НАЧИНАЮЩИХ 5 Что же такое микропроцессор? 5 Считаем по-другому 10 Электронные цифры 15 Логические элементы 18 Простейший триггер 23 Хранение информации 27 Счетчики 31 Дешифраторы 37 Глава 2. ОСНОВЫ МИКРОПРОЦЕССОРНОЙ ТЕХНИКИ 43 Типовая схема микропроцессорной системы 43 Алгоритм работы микропроцессорной системы 50 Механизм прерываний 57 Прямой доступ к памяти 59 Глава 3. МИКРОКОНТРОЛЛЕР АТ89С2051 62 Структурная схема микроконтроллера 62 Назначение выводов 67 Внутренние регистры 72 Внутреннее ОЗУ контроллера 80 Специальные регистры 83 Система команд и язык Ассемблера 88 Глава 4. ПОЗИЦИОНЕР СПУТНИКОВОЙ АНТЕННЫ 94 Постановка задачи 94 Выбор процессора 98 Разработка схемы 100 Управляющая программа 107 Описание констант и переменных 112 Резервирование памяти 122 Переопределение векторов прерываний 127 Инициализация системы 130 Основной цикл программы 139 Подпрограмма обработки команде клавиатуры 141 Обработка сигналов с датчика поворота антенны 150 Процедура динамической индикации 159 Процедура приема сигнала ДУ 175 Обработка команд ДУ 190 Глава 5. ТРАНСЛЯЦИЯ И ОТЛАДКА ПРОГРАММ 195 Технология программирования 195 Транслятор с языка Ассемблер 199 Программный отладчик 206 Программатор 212 Приложение. СИСТЕМА КОМАНД МИКРОКОНТРОЛЛЕРА АТ89С2051 218
Первую свою книгу посвящаю своей маме, Беловой Вере Павловне Вступление Цель настоящей книги — научить читателя основам микропроцессорной техники. Предполагается некий начальный уровень знаний в радиотехнике. В задачи автора не входило объяснение того, что такое резисторы, конденсаторы или транзисторы. Предполагается, что читатель с этим знаком. Книга рассчитана на тех читателей, которые стремятся узнать, что такое микропроцессорные устройства и научиться самостоятельно их конструировать. Книга начинается с азов цифровой техники. Последовательно, от простого к сложному, раскрываются такие понятия, как логические элементы, цифровой сигнал, принципы хранения и обработки цифровой информации. Затем раскрываются основные принципы построения микропроцессорных систем. И, наконец, на примере реального микропроцессорного устройства, раскрываются принципы и приемы разработки схемы и управляющей программы. В качестве примера взята реальная конструкция, разработанная автором — позиционер спутниковой антенны. Позиционер — это устройство, предназначенное для автоматизации управления поворотом бытовой спутниковой антенны. Он способен запомнить до 99 позиций (направлений на спутник), а затем автоматически устанавливать антенну в любую из этих позиций. Подробное описание позиционера вы найдете в соответствующем разделе настоящей книги. Схема позиционера выполнена на основе микроконтроллера АТ89С2051 фирмы ATMEL (www.atmel.com или www.atmel.ru). В книге подробно описывается внутренняя структура и система команд этого микропроцессора, а также весь процесс разработки микропроцессорного устройства, начиная с принципиальной схемы и заканчивая подробным описанием всех важнейших элементов управляющей программы. Автор надеется, что эта книга будет полезна широкому кругу радиолюбителей и начинающих разработчиков и будет благодарен за любые замечания и комментарии по книге. Все замечания прошу высылать по адресу: Украина, г. Симферополь, ул. Русская, 194 или по E-mail: belov@gomail.com.ua, мой сайт — http://avbelov.by.ru.
для начинающих Что же такое микропроцессор? Что же такое микропроцессор? И чем он отличается от микроконтроллера? Вообще-то процессор — это одна из составных частей компьютера. До того, как изобрели микропроцессор (то есть процессор на одной микросхеме) существовали целые процессорные блоки в больших компьютерах. Для прояснения вопроса нужно сначала определиться, что же такое компьютер. Компьютер — это устройство для автоматической обработки информации. Причем информация в компьютере представляется в виде чисел. Любая компьютерная система состоит из следующих основных частей (см. рис. 1): процессор, блок памяти, порты ввода/вывода. Рассмотрим эти составляющие подробнее. ПАМЯТЬ Это набор ячеек, в каждой из которых хранится одно число. Причем это не совсем то число, с которым мы с вами привыкли иметь дело. Это упрощенное компьютерное число. Обычно каждая ячейка памяти может хранить число, принимающее значения от нуля до 255. Подробнее об этом будет рассказано ниже. ПОРТЫ ВВОДА/ВЫВОДА Это некие микросхемы, при помощи которых микропроцессорная система может общаться с внешним миром. Через порты ввода компьютерная система получает информацию извне, а через порты вывода она выдает результаты своей работы и управляет внешними устройствами. Только благодаря этим самым портам ввода/вывода к компьютеру подключаются такие устройства, как клавиатура, мышь, дисководы, CD- Ликбез
6 Самоучитель по микропроцессорной технике ROM и т.д. Те читатели, которые знакомы с компьютерами, возможно, слышали термины «параллельный порт» (LPT) и «последовательный порт» (СОМ). Так вот в данном случае речь идет совсем о другом понятии. Это просто схожие термины. Параллельный и тем более последовательный порты компьютера — это целые, достаточно сложные схемы, которые в свою очередь управляются как раз-таки при помощи портов ввода/вывода. Не нужно также думать, что клавиатура и мышь используют только порты ввода, а дисплей — порт вывода. Для управления большинством устройств компьютера используются как порты ввода, так и порты вывода микропроцессорной системы. Возможно, вас удивляет, что я называю внешними устройствами и жесткий диск и флоппи дисковод. Но когда мы начнем изучать типовую схему микропроцессорного устройства, вы убедитесь, что это именно так! Там, внутри компьютера, скрыто еще много устройств, которые по отношению к микропроцессору являются внешними, хотя находятся зачастую не только внутри компьютера, но и непосредственно на материнской плате — главной плате компьютера. ПРОЦЕССОР Процессор — это самая главная часть, сердце всей системы. Он предназначен для того, чтобы выполнять различные операции с числами. Последовательность этих операций называется программой. Программа записывается в виде чисел в ту же самую память. По сути дела, процессор — это цифровой автомат! И всего-то! Все три части вычислительной системы связаны между собой так называемыми шинами данных. По этим шинам передаются цифровые сигналы от процессора к модулю памяти, от процессора к портам ввода/вывода и обратно, от этих устройств к процессору. Модуль памяти Процессор Порты ввода/вывода Рис. 1. Основные составляющие компьютерной системы Какие же конкретно операции может выполнять процессор с числами? Да все простейшие операции, которые возможно произвести над чис-
Ликбез для начинающих лом. Он может читать число из любой ячейки памяти, складывать, вычитать, сравнивать, иногда умножать и делить прочитанные числа. Затем процессор записывает результат в ту же самую или в другую ячейку. Еще он может выполнять логические (Булевы) операции с числами (что такое логические операции, я подробно опишу ниже). Кроме того, имеется ряд специфических операций. Но обо всем по порядку. Набор операций, которые процессор способен выполнять с участием портов ввода/вывода гораздо меньше, чем операций с ячейками памяти. В них также можно записывать и считывать информацию. Однако хранение чисел, это не главное назначение. Порты ввода/вывода предназначены для связи микропроцессорного устройства с внешней средой. В общем случае можно разделить порты ввода и порты вывода. Порт ввода — это специальное электронное устройство, на которое извне поступают какие-либо электрические сигналы, предназначенные для управления микропроцессорной системой. Например, сигналы от клавиатуры, датчиков и т.п. Процессор считывает их в виде чисел и обрабатывает полученные числа. Порты вывода выполняют обратную функцию. В них процессор записывает различные числа, которые затем поступают на внешние устройства в виде электрических сигналов. Эти сигналы используются для управления. Управлять можно любым устройством, которое допускает электрическое управление: индикаторы, дисплеи, электромагнитные реле, электромоторы, электропневмоклапаны, электрические нагреватели и т.д. Нужно только усилить управляющие сигналы до требуемой мощности. На этом, по большому счету все функции процессора заканчиваются. Представьте себе, что этого вполне хватает для того, что бы делать все те чудеса, которые мы привыкли видеть от современных компьютеров. Как же это возможно? Оказывается все на свете можно описать цифрами. И текст, и изображение, и звуки, и музыку и даже целые видеофильмы. Хорошо поработали ученые — математики. Они сумели разработать математические модели всех этих процессов. Остальное — дело техники. Главное — считай побыстрее! А современные процессоры это могут! О том, как они это делают, я и собираюсь рассказать в этой книге. Книга не ставит перед собой задачи изучения современных микропроцессоров для мощных персональных компьютеров. Наша задача — небольшие специализированные микропроцессорные устройства. Такие устройства все больше и больше входят в наш быт. Вы можете встретить микропроцессорный блок управления в современной микроволновой печи, в видеомагнитофоне, в стиральной машине, электронных часах — таймере. В настоящей книге мы изучим в качестве примера так на-
8 Самоучитель по микропроцессорной технике зываемый «Позиционер спутниковой антенны». Все подобные устройства имеют одно общее название: микропроцессорные контроллеры. Что же это за такое чудесное устройство — микропроцессор. Он и читает, записывает числа и вычисляет и управляет и столько разных умных вещей делает! Видимо очень умная микросхема? На самом деле микропроцессор — это примитивный автомат, который выполняет заложенные в нем операции в соответствии с заложенной в него ПРОГРАММОЙ. Программа — это некоторая последовательность команд, разработанная программистом и записанная в том же самом блоке памяти в виде чисел. В схеме микропроцессора при его производстве заложен простой алгоритм. Сразу после включения и окончания сигнала сброса, процессор начинает читать числа из той области памяти, которая отведена для хранения программ. Чтение происходит последовательно ячейка за ячейкой, начиная с самой первой. Каждым таким числом закодирована одна из команд. Команда — это одно из элементарных действий, которое способен выполнить микропроцессор. Число, которым закодирована команда, называется кодом операции. Вся работа микропроцессора сводится к последовательному чтению и выполнению команд. Этот процесс начинается сразу после включения питания и продолжается вплоть до его выключения. Производители микропроцессоров заботятся о том, чтобы заложить в микропроцессор достаточный набор команд. Используя эти команды, разработчик конкретной микропроцессорной системы может создать свою собственную программу, заставляющую микропроцессор выполнять именно те действия, какие ему нужны. Разработанная программа в виде набора чисел записывается в ту часть памяти, которая предназначена для программ, и микропроцессорная система готова к работе. В микропроцессорных системах для хранения программ используется специальный вид микросхем памяти. Это так называемые постоянные запоминающие устройства (ПЗУ). По-английски это звучит как ROM (read only memory). Они называются постоянными потому, что после записи туда информации она там не меняется. Запись — это специальный процесс, выполняемый при помощи специальных устройств — программаторов ПЗУ. Информация в эти микросхемы записывается за счет прожигания определенных областей. Прошил раз и пользуешься этой информацией долгое время. Для хранения программы микропроцессорного контроллера это как раз очень подходит. Микропроцессор может только читать из такой памяти. Записать туда он ничего не сможет. Если же он попробует записать туда информа-
Ликбез для начинающих 9 цию, ничего страшного не произойдет. В памяти останется то, что там было до попытки записи. Кроме постоянного запоминающего устройства в системе должна быть обязательно память, выполненная на микросхемах оперативной памяти. То есть оперативное запоминающее устройство (ОЗУ). По-английски RAM. В эту память процессор может записывать информацию, а затем читать ее. Ни одна программа не обходится без некоторого количества ячеек памяти для хранения множества промежуточных результатов и вспомогательных величин. Для этих целей и служит ОЗУ. Отличительной особенностью ОЗУ является то, что при выключении питания записанная в него информация теряется. Микросхемы, позволяющие оперативно переписывать информацию, как в ОЗУ, но не теряющие ее при выключении питания тоже существуют. Они выполняются по технологии электрически стираемого ПЗУ (ЭС- ПЗУ). В иностранной литературе их принято называть flash-памятью (флэш). Такие микросхемы применяют гораздо реже, так как они имеют низкую скорость работы и пока еще очень дороги. Ну, вроде с микропроцессорами мы разобрались. А что же такое микроконтроллеры? Микроконтроллер — это дитя дальнейшей интеграции, это целая микропроцессорная система на одном кристалле! Одна микросхема содержит в себе все описанные выше составляющие: память, порты ввода/вывода и собственно процессор. Кроме того, там часто располагаются некоторые дополнительные устройства: таймеры, устройства прерывания, компараторы и др. Значения этих, возможно, пока что непонятных терминов вы узнаете из последующих глав. Вообще с понятиями «микропроцессор» и «микроконтроллер» существует некоторая путаница. То, что я сейчас назвал микроконтроллером, иногда тоже называют микропроцессором. Во-первых, это легче произносить. А во-вторых, современные микропроцессоры и микроконтроллеры так бурно развиваются, что по сложности внутреннего устройства не уступают друг другу. Но такая путаница мало существенна, так как эти два понятия почти что синонимы.
10 Самоучитель по микропроцессорной технике Считаем по-другому Если вы всерьез собрались научиться разрабатывать микропроцессорные устройства, вам просто необходимо знать, как же компьютер хранит и обрабатывает числа. К сожалению (а может и к счастью) люди не придумали способа записывать при помощи электронных сигналов числа в том виде, как мы их привыкли видеть. Поэтому математикам сначала пришлось потрудиться и придумать другой, более подходящий способ их представления. И они потрудились на славу! Придуман не один, а огромное множество способов представления чисел. Один из этих способов идеально подходит для реализации его при помощи электроники. Некоторые другие способы помогают удобнее представлять компьютерные данные на бумаге или на экране компьютера. Итак, что же это за способы? Любой грамотный человек хорошо знает, по крайней мере, два способа представления чисел. Это, широко распространенные, арабские цифры и изредка применяемые римские. Одно и тоже число можно записать как 2 или как II, как 5 или как V, как 22 или как XXII. Очевидно, что перед нами два альтернативных способа написания чисел. Числа одинаковые, а способы написания разные. Ну а если есть два способа, почему бы ни выдумать и третий, четвертый и т.д.? И математики давно нашли такие способы. И не три, четыре. Они нашли универсальный прием, позволяющий теоретически создавать бесконечное количество способов представления чисел. Эти способы назвали системами счисления. За основу взяли арабские числа. Очевидно, что этот способ представления гораздо более красивый, чем римский, так как подчиняется строгому закону. Судите сами. В привычной для нас системе счисления мы имеем 10 цифр: I, 2, 3, 4, 5, 6, 7, 8, 9 и 0. При помощи этих цифр мы легко можем представить любое число. Для представления чисел меньших десяти мы используем одну из этих десяти цифр. Для представления чисел от десяти и выше мы вводим новый разряд, который для начала приравниваем к единице. Подставляя в младший разряд по порядку те же десять базовых цифр, мы получаем следующий десяток. Как только все цифры в младшем разряде перебраны, мы увеличиваем наш старший разряд на единицу. И так, пока не переберем все цифры вплоть до 99. Когда во втором разряде будут перебраны все цифры, мы вводим третий разряд. И так далее. Внимательно изучив, как мы строим числа, мы можем сформулировать набор четких правил, как при помощи десяти знаков, означа-
Ликбез для начинающих 11 ющих десять цифр, представить любое мыслимое число! Такая система счисления называется десятичной. Так как количество цифр, используемое для представления чисел, равно десяти. Вот тут-то и кроется простое, но гениальное решение. А почему именно десять цифр? Видимо потому, что первобытные люди, которые изобретали эту систему, пользовались для счета пальцами рук. А их всего десять. А если бы природа распорядилась так, что у человека было бы, не по пять, а ло четыре пальца на каждой руке? Тогда, наверно, мы бы имели восьмеричную систему счисления! И как же такая система будет выглядеть? Ну, во-первых, она будет иметь только восемь цифр. Например: 0, 1,2, 3, 4, 5, 6 и 7. Ну а правила построения чисел, мы оставим те же. Числа от нуля до восьми мы запишем так же, как и в десятичной системе. Цифры 8 в восьмеричной системе нет. Поэтому мы поступим в строгом соответствии с правилами. Мы добавим новый разряд и запишем туда единицу. А в младшем у нас будет ноль. При этом число 8 в восьмеричной системе счисления будет выглядеть как 10. В математике придуман способ записи чисел в различных системах счисления, так, что бы было ясно в какой системе число записано. Десятичную систему еще называют системой счисления по основанию десять. А восмеричная система — это, в свою очередь, система счисления по основанию восемь. Так вот, число восемь в десятичной системе записывается так: 8]о. А то же число в восьмеричной системе записывается следующим образом: 108. Маленькая цифра в конце числа соответствует основанию системы счисления, в которой данное число записано. Продолжим записывать числа в восьмеричной системе счисления, сравнивая их с теми же числами, записанными в десятичном виде: И так далее, пока не кончится наш набор цифр. Число 15ю записывается, как 178. А вот число 16ю запишется уже как 208. То есть снова и снова выполняется одно из стандартных правил построения чисел: как только значение любого из разрядов доходит до своего максимума, значение старшего по отношению к нему разряда увеличивается на единицу, а значение текущего разряда устанавливается равным нулю.
Используя вышеописанные правила, теоретически можно построить систему счисления по любому основанию. Лишь бы хватило значков, обозначающих цифры. Реально же на практике нашли применения, кроме десятичной, восьмеричная, шестнадцатеричная и двоичная системы счисления. Причем, именно двоичная система счисления и является той самой системой представления чисел, которую инженеры без труда смогли смоделировать при помощи электронных схем. Восьмеричная и шестнадцатеричная системы счисления очень удобны для записи компьютерных данных на бумаге и на экране компьютера. Раньше, на заре развития компьютерной техники, широко использовали восьмеричную систему. Сейчас она почти забыта. Теперь вместо нее более употребима шестнадцатеричная система счисления. Разберем по подробнее две еще не описанные нами системы. В шест- надцатеричной системе счисления, как вы догадались, используется шестнадцать цифр. Обычно в качестве десяти первых цифр применяют обычные цифры из десятичной системы. А недостающие шесть цифр заменяют буквами латинского алфавита. Вот полный набор цифр шест- надцатеричной системы: О, I, 2, 3, 4, 5, 6, 7, 8, 9, А, В, С, D, Е и F. При помощи одного разряда в шестнадцатеричной системе счисления можно записать числа от нуля до пятнадцати. Число шестнадцать A610) записывается, как 10i6- Вот еще несколько примеров шестнадцатерич- ных чисел: Для того, чтобы было легче отличать число, записанное в шестнадцатеричной системе от слова, перед шестнадцатеричным числом, начинающимся с буквы, принято ставить ноль. Такое правило актуально в основном в случае написания текстов для программ, для облегчения машинного распознавания. Но к этому мы еще вернемся. А сейчас продолжим изучение нашей темы. 12 Самоучитель по микропроцессорной технике Посмотрите несколько примеров записи чисел в восьмеричной системе счисления:
Ликбез для начинающих 13 Среди всех систем счисления особое место занимает двоичная'система. Она использует для записи любого числа всего две цифры. Это цифры 0 и I. Естественно, что при помощи одного разряда, в двоичной системе можно записать только два числа: 0 и I. Число два в двоичной системе будет выглядеть как Юг- Используя уже знакомые правила, запишем другие числа: Если у вас есть компьютер, на котором установлен Windows, вы сами легко можете поэкспериментировать с переводом чисел из одной системы счисления в другую. Для этого запустите стандартный калькулятор, входящий в Windows. Обычно он запускается через меню Пуск -* Стандартные -> Калькулятор. Войдите в меню «Вид» калькулятора и выберите «Инженерный^. После этого вид калькулятора изменится. Вы увидите дополнительные буквенные клавиши для набора латинских букв. А в левой верхней части калькулятора появится переключатель систем счисления. Он имеет четыре положения: Hex (шестнадцатеричная), Dec (десятичная), Oct (восьмеричная) и Bin (двоичная). Вы можете выбрать любую из систем счисления, набрать на калькуляторе число, а затем переключить калькулятор на любую другую систему. Калькулятор тут же, автоматически, переведет набранное вами число в новую систему счисления. Советую поэкспериментировать, таким образом, стараясь лучше понять, почему так, а не иначе представляется то или иное число в разных системах счисления. В различных языках программирования применяется другие способы записи чисел в различных системах счисления. Самый распространенный способ — добавление в конце числа латинской буквы, обозначающей систему счисления. Так, для обозначения шестнадцатеричных чисел используется буква Н, для восьмеричных — буква О, для двоичной системы — буква В. Десятичные числа при этом можно записывать либо вообще без буквы, либо с буквой D. Приведем примеры записи чисел в этой форме:
14 Самоучитель по микропроцессорной технике Альтернативный способ написания чисел хорош тем, что не использует специальных эффектов типа нижнего индекса, и поэтому может быть использован при наборе текста в любом простейшем редакторе. Во всех вышеперечисленных системах счисления возможны все арифметические операции, к которым мы привыкли в десятичной системе. То есть сложение, вычитание, умножение, деление. Правда на практике, никто не занимается восьмеричной и шестнадцатеричной арифметикой. Это не имеет никакого смысла. А вот арифметика в двоичной системе была подробно проработана. Надо же было обучить этому электронные устройства. Возьмем, например, сложение. В двоичной системе счисления оно делается точно так же, как и в десятичной. Только нужно помнить, что в этой системе каждый разряд может принимать лишь два значения: либо О, либо 1. Возьмем два двоичных числа и найдем их сумму. Например, 10011001110 + 11000101110. Точно так же, как и в десятичной системе, складываем числа поразрядно, начиная с младшего разряда. Ноль плюс ноль получится, естественно, ноль. Один плюс ноль и ноль плюс один дадут в результате единицу. При сложении двух единиц мы получим ноль в этом разряде и единицу переноса в следующий разряд. Вот результат сложения вышеприведенных чисел: Умножение тоже делается аналогично умножению в десятичной системе — столбиком. При этом очевидно, что любое число, умноженное на ноль, дает в результате ноль. А число, умноженное на единицу, дает в результате то же самое число. Вот пример умножения столбиком двух двоичных чисел: Как легко убедиться из примера, умножение в двоичной системе счисления сводится к сдвигу первого числа (множимого) влево и сложению,
Ликбез для начинающих 15 полученных сдвигом чисел. Точно также легко убедиться, что деление в двоичной системе сводится к сдвигу и вычитанию. Это важно при построении вычислительных устройств. Именно поэтому многие простые микропроцессоры не имеют в составе своих команд, команд умножения и деления. Но обязательно, каждый процессор имеет команды сдвига, сложения и вычитания. Если программисту по ходу программы понадобится умножить либо поделить два числа, он всегда может составить небольшую подпрограмму, используя команды сдвига сложения и вычитания. Электронные цифры Теперь настало время узнать, каким образом в компьютерных системах представляются цифры. Во всех современных вычислительных системах это делается, как описано ниже. Представим себе некий узел вычислительной системы. Допустим, он должен передавать на последующие узлы числа в электронном виде. Для этого такой узел имеет группу выходов (обычно их количество равно или кратно восьми). Обозначим эти выходы, как это принято в вычислительных системах, D0...D7 (рис. 2). Эти выходы подключаются к соответствующим входам последующего узла, как показано на рис. 3. Для передачи числа используется вся группа выходов одновременно. Передаваемое число представляется в двоичной системе счисления. Каждый из выходов передает один разряд двоичного числа и может находиться в одном из двух состояний: состояние логического нуля — когда напряжение на выходе отсутствует, и состояние логической единицы — когда на выходе присутствует напряжение (обычно равное напряжению питания). Причем схема сделана таким образом, что исключает появление на любом из выходов промежуточных значений напряжения. Такая группа выходов называется цифровой шиной данных. Каждый разряд шины имеет свой «вес». Обычно DO обозначают разряд, который имеет самый маленький «вес» — вес, равный единице. Это значит, что когда в этом разряде установлена логическая единица, а во всех остальных разрядах логический ноль, то все число равно единице. Разряд D1 имеет «вес» равный двум A02). Это означает, что, если значение разряда D1 равно единице, а всех остальных разрядов — нулю, то все число, передаваемое шиной, будет равно двум. Вес D2 — четыре единицы A002). И так далее. Вес последнего разряда шины (D7) равен 128 (ЮОООООСЬ). Для того, чтобы узнать, какое число установлено на
16 Самоучитель по микропроцессорной технике шине данных, нужно сложить веса всех разрядов, значение которых в данный момент равно единице. Рис. 2. Узел с цифровыми выходами Рис. 3. Соединение двух цифровых узлов Очевидно, что для передачи максимально возможного числа нужно установить все разряды шины данных в единичное состояние. В этом случае число, передаваемое по нашей шине данных, будет равно 255 A + 2 + 4 + 8+16 + 32 + 64+128 = 255). Таким образом, по восьмиразрядной шине данных можно передавать числа от 0 до 255 (то есть 256 разных значений). Запомним это, так как восьмиразрядная шина является своего рода стандартом в вычислительной технике. Более подробно к описанию шин мы вернемся, когда перейдем к описанию микропроцессорной системы. А сейчас остановимся подробнее на двухуровневом сигнале, имитирующем двоичный разряд числа. Каждый из этих уровней имеет свое название. В зависимости от его значения различают сигнал логического нуля и сигнал логической единицы. Другое название — высокий логический уровень и низкий логический уровень. Эти термины в дальнейшем будут часто встречаться в нашей книге. Для получения сигналов логической единицы и логического нуля используются так называемые триггерные схемы, или схемы с двумя устойчивыми состояниями. Напряжения на выходе любого реального устройства не идеальны и имеют разброс в значениях. Например, сигнал для микросхем, выполненных по так называемой ТТЛ технологии (транзисторно-транзисторная логика), допускают следующие отклонения (при напряжении питания 5 В): ¦ Для логического нуля на выходе допускается присутствие напряжения до 0,4 В. ¦ Для логической единицы напряжение на выходе должно быть не менее 2,4 В.
Ликбез для начинающих 17 По ТТЛ технологии выполнены микросхемы таких серий, как 155, 555, 533, и др. В других типах микросхем уровни сигнала имеют другие значения. Однако существует правило, верное для любых типов цифровых микросхем: если напряжение на выходе цифровой микросхемы входит в заданный диапазон для данного типа микросхем, то другая микросхема, та, на которую приходит цифровой сигнал, надежно распознает ноль или единица у нее на входе. Это происходит благодаря тому, что у цифровых входов имеется так называемый порог срабатывания. Если входной сигнал выше порога, внутренний триггер устанавливается в состояние логической единицы. Если входное напряжение ниже порога, то триггер переходит в состояние логического нуля. Триггер — это как раз такое устройство, которое может находиться лишь в одном из двух состояний. Среднего не дано. Такой подход повышает надежность работы цифровых схем. Благодаря триггерному эффекту такие явления, как тепловые шумы, дрейф нуля и электромагнитные помехи гораздо меньше влияют на качество передачи цифрового сигнала. Вернее, они вообще не влияют, пока уровень сигнала помехи не превысит порога. Правда, если помехи все же превысят порог, то наступает полный сбой. В этом случае цифровой сигнал, передаваемый по шине данных, будет полностью потерян. Однако при цифровой передаче сигнала полностью отсутствуют такие эффекты, как постепенное ухудшение качества с увеличением дальности передачи информации и количества перезаписей с одного носителя на другой. Для обработки цифровых сигналов существует множество схем, которые позволяют хранить цифровую информацию и осуществлять ее преобразование. Например, пользуясь описанными выше правилами, над электронными цифрами можно производить любые арифметические операции, такие как сложение, вычитание, умножение, деление. Можно делать такие специфические операции, как инвертирование, поразрядный сдвиг и т.д. Данная книга ставит своей'целью подробно рассмотреть, как это делается. А основой для построения подобных схем являются так называемые логические элементы. В следующей главе мы с ними и познакомимся.
18 Самоучитель по микропроцессорной технике Логические элементы Что же это за волшебные элементы. Если вы хоть немного сталкивались с цифровыми схемами, вы наверняка знакомы с логическими элементами. Вы знаете, что на схеме логический элемент обозначается небольшим прямоугольником, имеющим несколько входов и один выход. В настоящее время цифровые микросхемы получили такое большое распространение, что логические элементы можно встретить в схемах очень далеких от микропроцессоров и вычислительной техники. Кроме того, вы наверно встречались и с другими, более сложными элементами цифровой техники: триггерами, дешифраторами, мультиплексорами, счетчиками, регистрами, и т.д. Кто-то знает и понимает, как это все работает и для чего предназначено. А кто-то еще нет. Я считаю необходимым остановиться на этом подробнее. Те, кто знаком с данной темой, могут пропустить несколько разделов. Для остальных я расскажу все с самых азов. Из всего разнообразия цифровых элементов большинство можно отнести к разряду составных. Составные эти элементы в том смысле, что их можно составить из других, более простых. А в основе всего разнообразия цифровых элементов лежат всего три простейших логических элемента. На рис. 4 изображены эти три кита цифровой техники. Элемент «И» Элемент «ИЛИ» Элемент «НЕ» Рис. 4. Простейшие логические элементы Для изображения логических элементов я придерживаюсь стандарта схемных обозначений, принятых в свое время в СССР, и теперь еще широко используемых во всех странах СНГ. По этим стандартам цифровые элементы изображаются в виде прямоугольника. Все входы рисуются слева, а выходы — справа. Именно таким образом в этом стандарте можно отличить входы элемента от его выходов. Правда, в случае более сложных элементов это правило соблюсти не всегда возможно, так как часто бывает, что один и тот же выход служит одновременно и входом. Но для простых элементов это условие всегда соблюдается.
Ликбез для начинающих 19 В западных схемах приняты другие условные обозначения. В задачи настоящей книги не входит изучение западных стандартов. Все элементы работают с цифровыми сигналами. Это значит, что сигнал на любом из входов элемента должен принимать значения либо логического нуля, либо логической единицы. На выходе каждый элемент также обеспечивает цифровой сигнал, который, в зависимости от логики работы схемы, принимает значение либо логической единицы, либо дорического нуля. На рис. 4 изображены двухвходовые варианты элемента «И» и элемента «ИЛИ». На самом деле эти элементы могут иметь любое количество входов. Теоретически количество входов может быть увеличено до бесконечности. Дело не в количестве входов, а в логике работы элемента. Рассмотрим этот вопрос подробнее. Элемент «И». На выходе этого элемента сигнал логической единицы появляется только тогда, когда на всех входах будет присутствовать логическая единица. То есть, и на первом, и на втором, и на третьем (если он есть), и на всех имеющихся входах. Если хотя бы на одном входе будет ноль, то и на выходе тоже будет ноль. Элемент «ИЛИ». На выходе этого элемента появится логическая единица тогда, когда хотя бы на одном из входов появится единица. То есть, или на первом, или на втором, или на третьем — на любом из имеющихся входов. Логический ноль на выходе будет только тогда, когда на всех входах будет сигнал логического нуля. Элемент «НЕ». Или инвертор. У этого элемента всегда один вход и один выход. И логика его работы очень проста. Когда на входе у инвертора сигнал логического нуля, на выходе — логическая единица. И наоборот, когда на входе логическая единица, на выходе логический ноль. Составляя из этих трех основных кирпичиков различные схемы, мы можем получить все разнообразие цифровых и логических элементов, применяемых в микропроцессорной технике, которые в свою очередь имеют свои схемные обозначения и выглядят на схеме как самостоятельные элементы. Для отображения логики работы того или иного элемента принято составлять так называемые таблицы истинности. Таблица истинности — это такая таблица, которая имеет столбцы для всех входов и выходов конкретного элемента. В строках таблицы отображаются все возможные состояния элемента. Каждая строка соответствует одному из возможных состояний. На рис. 5 приведены таблицы истинности для трех
20 Самоучитель по микропроцессорной технике основных логических элементов. Для наглядности в данном случае приведены трехвходовые варианты элемента «И» и элемента «ИЛИ». Рис. 5. Примеры построения таблицы истинности Теперь попробуем сами составить более сложный элемент из нескольких простых. Для примера соединим элемент «И» с инвертором так, как это показано на рис. 6. В результате у нас получится новый элемент, также широко применяемый на практике. Этот элемент имеет свое название и схемное обозначение. Называется такой элемент «И-НЕ», а его схемное обозначение приведено на рис. 7. Подчеркиваю: на рис. 6 и на рис. 7 изображен по сути дела один и тот же логический элемент. Рис. 6. Составной элемент «И-НЕ» Рис. 7. Условное обозначение элемента «И-НЕ» В реальной схеме могут применяться оба варианта: как готовая микросхема «И-НЕ», так и последовательное соединение элемента «И» и инвертора. Дело в том, что любая реальная микросхема обычно содержит несколько аналогичных логических элементов. Стандартный корпус микросхемы имеет 14 либо 16 выводов. Поэтому в одном корпусе
Ликбез для начинающих 21 обычно размещают четыре двухвходовых элемента или три трехвходо- вых. Для рационального использования всех элементов (чтобы не оставалось неиспользованных) одну и ту же схему в разных случаях собирают по-разному. Логика работы элемента «И-НЕ» очевидна. Сигнал на выходе будет равен нулю в том и только в том случае, когда на всех его входах присутствует логическая единица. Попробуем теперь синтезировать более сложный логический элемент под названием «Исключающее ИЛИ». Его тоже часто можно встретить в различных электронных схемах. Рис. 8. Элемент -Исключающее ИЛИ» Рис. 9. Одно из возможных схемных решений элемента "Исключающее ИЛИ» Схемное обозначение элемента «Исключающее ИЛИ» и его таблица истинности приведены на рис. 8. Как видно из таблицы, логика работы элемента соответствует его названию. Это тот же элемент «ИЛИ», за исключением того случая, когда на обоих входах присутствует логическая единица. В отличие от «ИЛИ», элемент «Исключающее ИЛИ» в этом случае формирует на выходе сигнал логического нуля.
22 Самоучитель по микропроцессорной технике Эквивалентная схема элемента «Исключающее ИЛИ» изображена на рис. 9. Советую самостоятельно разобрать работу этой схемы. Для этого мысленно нужно подставлять на входы XI и Х2 различные варианты логических сигналов и для каждого варианта проследить, какими будут сигналы на выходе каждого элемента и всей схемы. Рис. 10. Сумматор Если внимательно посмотреть на таблицу истинности элемента «Исключающее ИЛИ», то легко заметить, что логика работы элемента очень похожа на таблицу сложения двух одноразрядных двоичных чисел. И действительно: ноль плюс ноль равняется ноль. Один плюс ноль и ноль плюс один, равняется один. А сумма двух единиц дает ноль в этом разряде и единицу переноса в следующий разряд. Таким образом, не хватает только переноса. Элемент, который выполняет суммирование входных сигналов, называется сумматором. Его также можно составить из элементарных логических элементов. Схемное изображение и логика работы сумматора приводятся на рис. 10. Здесь XI и Х2 — это входы складываемых разрядов. Y — выход суммы. Р — выход переноса в более старший разряд. ХР — вход переноса с младшего разряда. Для суммирования многоразрядных цифровых сигналов сумматоры соединяют каскадом. При этом сигнал с выхода Р сумматора одного разряда подается на вход ХР сумматора следующего разряда. На практике отдельные микросхемы — сумматоры — почти никогда уже не применяются. Где-то внутри микропроцессора обязательно есть сумматор, который является его частью. Я привел его описание лишь, как пример сложного элемента цифровой техники. При разработке микропроцессорных систем нам чаще придется иметь дело с другими элементами, такими, как триггеры, регистры, дешифраторы, мультиплексоры, и т.д. В следующих разделах мы рассмотрим подробнее все эти устройства.
Ликбез для начинающих 23 Простейший триггер Пришло время узнать — что такое простейший триггер. Мы уже говорили, что каждый логический вход обладает триггерным эффектом. Используя более точное определение, триггер — это устройство, которое может находиться в двух (и только в двух) устойчивых состояниях. Триггер, который переходит из одного устойчивого состояния в другое в зависимости от уровня входного сигнала, называется триггером «Шмитта». В настоящем разделе мы познакомимся с представителем другого вида триггеров. Это так называемый RS-триггер. На рис. 11 изображена схема такого триггера, а на рис. 12 — его условное обозначение. Как видите, схема RS-триггера состоит из двух элементов «И-НЕ». Триггер имеет два входа, которые называются S и R. Вход S называют входом установки (от слова Set — установить). Вход R — это вход сброса (Reset). Триггер также имеет два выхода — Q и Q. Буква с чертой сверху читается, как «не кю». Черта означает, что данный выход инверсный. Выходы Q и Q — это, соответственно, прямой и инверсный выходы триггера. Логика работы триггера такова, что в то время, когда на одном из выходов присутствует логический ноль, на другом обязательно будет логическая единица. И наоборот. Рис. 11. RS-триггер Посмотрим, как работает RS-триггер. В исходном состоянии на оба входа триггера необходимо подать сигналы логической единицы. При этом триггер может находиться в одном из двух устойчивых состояний. Либо на выходе Q логическая единица, а на Q логический ноль, либо, наоборот. При первом включении триггер устанавливается в одно из этих состояний случайным образом. Рис. 12. Условное обозначение RS-триггера
24 Самоучитель по микропроцессорной технике Рассмотрим все это подробнее. Допустим, что после включения, триггер установился в положение, когда на выходе Q логический ноль. Тогда на верхнем входе нижнего по схеме элемента (см. рис. И) будет присутствовать лог. О, а на нижнем — лог. 1. В соответствии с логикой работы элемента «И-НЕ» на выходе Q установится сигнал лог. 1. Эта единица поступает на нижний вход верхнего элемента. При этом уровни сигнала на обоих входах этого элемента окажутся равными логической единице. При совпадении двух единиц на входах схемы «И-НЕ» на ее выходе появится логический ноль. Этот ноль подтверждает состояние на выходе первого элемента. Таким образом, мы убедились, что триггер находится в устойчивом состоянии. Триггер может находиться в этом состоянии достаточно долго. А точнее до тех пор, пока не изменится сигнал на одном из его входов. Представьте себе, что при включении триггер установился в противоположное состояние. То есть на входе Q — лог. I, а на Q — лог. 0. Легко убедиться, что это состояние такое же устойчивое, как и первое. Теперь посмотрим, как происходит переход триггера из одного устойчивого состояния в другое. Для того, чтобы переключить триггер, нужно кратковременно подать на один из его входов сигнал лог. 0. Допустим, триггер находится в том положении, с которого мы начали. А именно: на выходе Q лог. 1, а на Q — лог. 0. Представим, что на вход R подается сигнал логического нуля. Проследим по схеме, что же произойдет с нашим триггером. На входах нижнего по схеме элемента вместо двух логических единиц, появятся два разных сигнала. На верхнем входе пока останется лог. 1, а на нижнем появится логический ноль. В следующий момент времени, в соответствии с логикой работы элемента «И-НЕ» на его выходе сигнал сменится с низкого уровня на высокий. Этот высокий уровень поступит на нижний вход верхнего по схеме логического элемента. Теперь на обоих входах верхнего элемента присутствуют сигналы логической единицы. А это значит, что на его выходе тут же появится логический ноль. Он поступит на верхний вход нижнего по схеме элемента. Теперь, даже если уровень сигнал на входе R снова станет равен логической единице, на выходе нижнего по схеме элемента ничего не изменится. Там останется логическая единица. Таким образом, наш триггер переходит в другое устойчивое состояние. Для обратного переключения нужно подать такой же отрицательный импульс на вход S. Описанный RS-триггер можно уже считать простейшим устройством для хранения одного бита цифровой информации. Один бит — это один двоичный разряд или величина, которая может принимать только два
Ликбез для начинающих 25 значения (Да и Нет). Если одно из устойчивых состояний триггера принять за единицу, а второе за ноль, то мы получаем возможность записывать туда значение одного бита двоичного числа. Состояние бита мы всегда можем видеть на выходе Q. Если триггер хранит единицу, то на выходе Q единица. Если ноль, то там, соответственно, ноль. В свою очередь, на выходе Q мы увидим сигнал, инверсный хранимому в триггере значению. Теперь становится более понято, почему входы триггера были названы Set и Reset. Вход S (Set) устанавливает триггер в единичное состояние, а вход R (Reset) сбрасывает его в нулевое. При наличии достаточного количества таких триггеров, можно хранить любое двоичное число. На самом деле, RS-триггеры редко используются для хранения двоичных чисел. Для этого существуют другие, более сложные триггеры, о которых мы поговорим немного позже. Описываемые же RS-триггеры нашли немного другое применение в микропроцессорной технике. Чаще всего они применяются в качестве антидребезгового устройства. Такая задача, как борьба с дребезгом контактов, очень актуальна. Поэтому на этом вопросе я также хочу остановиться подробнее. Дело в том, что в цифровой и микропроцессорной технике редко удается обойтись без различных кнопок или контактов. С их помощью на микропроцессорное устройство подаются различные команды, реализуются датчики и т.д. Применение механических контактов приносит дополнительную проблему. Рис. 13. Дребезг контактов Как бы качественно ни был выполнен контакт, он никогда не замыкается и не размыкается мгновенно. В момент замыкания, когда два контакта еще только-только коснулись друг друга, и еще не плотно прижаты, происходит этот самый дребезг. То есть множественное за-
26 Самоучитель по микропроцессорной технике мыкание и размыкание цепи. В результате на вход микропроцессорного устройства поступает не единичный перепад напряжения, а целая пачка импульсов (см. рис. 13.). Цифровые микросхемы обладают настолько большим быстродействием, что для них такая пачка импульсов выглядит, как несколько нажатий клавиши. Если бы не применялись антидребезговые устройства, то мы никогда бы не смогли набрать текст на клавиатуре компьютера. При нажатии на каждую клавишу выскакивала бы не одна, а несколько одинаковых букв. Существует множество схемных и программных ухищрений, позволяющих избавиться от дребезга контактов. Один из таких способов основан на применении RS-триггера. Рис. 14. Схема антидребезга на основе RS-триггера Например, антидребезговое устройство для контакта датчика поворота антенны в схеме позиционера вполне может быть выполнено так, как показано на рис. 14. Такая схема требует применения в качестве датчика не простого контакта, работающего на замыкание, а переключающего. Как видно из схемы, на оба входа RS-триггера через токоограни- чивающие резисторы подано напряжение питания. Поэтому, если контакт датчика не замыкает соответствующий вход на общий провод, то на нем, благодаря резистору, присутствует напряжение, которое соответствует сигналу логической единицы. Если контакт замыкает вход на общий провод, то на нем напряжение падает до нуля, что соответствует логическому нулю. Во время поворота антенны кулачек, укрепленный на оси редуктора, периодически, синхронно с поворотом антенны, переключает подвижный контакт датчика из одного положения в другое. При этом контакт соединяет с общим
Ликбез для начинающих 27 проводом то один из входов RS-тригтера, то другой. При этом триггер переключается из одного устойчивого положения в другое. Контактная система должна быть устроена таким образом, чтобы в процессе переключения подвижный контакт сначала отключался от верхнего по схеме неподвижного контакта и какое-то время обязательно находился в среднем положении, не касаясь ни одного из них. И только затем он должен замкнуться с нижним по схеме неподвижным контактом. В результате в момент размыкания с верхним контактом и все время, пока подвижный контакт не касается ни одного из неподвижных, триггер не изменяет своего состояния, так как на обоих входах RS-триггера в этот момент логические единицы. В момент замыкания подвижного контакта с любым из неподвижных, происходит дребезг. Но лишь при самом первом касании происходит изменение состояния триггера. Остальные импульсы, обусловленные дребезгом, уже не изменят его состояния. В результате, на выходе схемы мы получим чистый сигнал, не «засоренный» дребезгом. На самом деле в той схеме позиционера спутниковой антенны, которую мы еще будем подробно изучать, для избавления от дребезга такой способ не применяется. Одна из причин, почему эта схема оказалась не приемлема — это то, что в стандартных поворотных устройствах (актюаторах), в качестве датчика поворота антенны всегда применяется простейший контакт на замыкание. Хранение информации В предыдущем разделе мы узнали, что для хранения информации можно использовать даже простейший RS-триггер. Но в цифровой техники имеются элементы более подходящие для этой цели. К ним можно отнести D-триггеры, Ж-триггеры и, основанные на них, различные регистры. Рассмотрим все это по порядку. Начнем с D-триггера. Схемное обозначение типичного D-триггера приведено на рис. 15. На рисунке изображен не просто D-триггер, а комбинированный элемент, в котором элементе объединены два триггера. Как видно из рисунка, у этого составного элемента имеются уже знакомые нам входы R и S. Если использовать только эти входы, то мы получим обычный RS-триггер. При работе в режиме D-триггера на входах R и S должен присутствовать сигнал лог. 1. В этом режиме переключение триггера происходит под воздействием сигналов на входах D и С.
28 Самоучитель по микропроцессорной технике Вход D — это вход данных (DATA). На него подается логический уровень, который необходимо записать в D-триггере. Рис. 15. D-триггер Вход С называется тактовым. На него поступает тактовый импульс, по которому и происходит запись. Обратите внимание, что на условном обозначении триггера тактовый вход отмечен стрелкой в виде маленького треугольника. Такой треугольник означает, что данный вход импульсный. До сих пор мы имели дело с потенциальными входами. Потенциальный вход реагирует на потенциал поступающего, на него сигнала. А импульсный вход на изменение этого сигнала. Различают импульсные входы, работающие по фронту и по спаду импульса. Фронтом импульса называют момент перехода от низкого логического уровня к высокому. А спадом — переход от высокого уровня к низкому. Иногда используют другие термины: передний фронт и задний фронт импульса. Если на вход D-триггера подать сигнал логической единицы, а на вход С импульс записи, то по спаду этого импульса триггер установится в единичное состояние. Если в момент спада импульса записи на входе D окажется логический ноль, то триггер установится в нулевое состояние. Такая логика работы D-триггера делает его очень удобным устройством для хранения одного бита цифровой информации. Для хранения двоичного числа, состоящего более чем из одного разряда, используют несколько параллельно соединенных D-триггеров. На рис. 16 показана схема, предназначенная для хранения четырехразрядного двоичного числа. Такая схема называется параллельным регистром. Для того, что бы сохранить какое-либо число в таком регистре, нужно подать это число на входы D0...D3. Затем на вход С схемы подается импульс записи. По заднему фронту этого импульса число записывается в регистр. Причем каждый разряд числа записывается в свой отдельный D-триггер. Записанное в регистр число можно считывает из него при помощи выходов Q0...Q3.
Ликбез для начинающих 29 Вход R используется для начальной установки всех разрядов регистра в нулевое состояние. Это бывает важно в том случае, когда регистр используется для управления внешними устройствами. Сигнал сброса на вход R подают обычно в момент включения питания. Обратите внимание на обозначение входа R. Мы впервые имеем дело с инверсным входом! Такое обозначение применяется не всегда. Применяя его, мы подчеркиваем, что активным значением для входа является логический ноль. Именно при подаче логического нуля происходит сброс триггера. В реальных микропроцессорных устройствах чаще используются восьмиразрядные параллельные регистры. На рис. 17 изображен такой регистр. Его внутренняя структура и назначение выводов аналогичны структуре регистра, изображенного на рис. 16. Рис. 16. Простейший параллельный регистр Рис. 17. Восьмиразрядный параллельный регистр Рис. 18. Параллельный регистр с расширенными возможностями Более сложный регистр изображен на рис. 18. Это регистр гораздо более приспособлен для работы с параллельной шиной данных. Для это- го в регистр введены два новых входа: вход выбора микросхемы (CS) и вход перевода выходов в высокоимпедансное состояние (ОЕ).
30 Самоучитель по микропроцессорной технике Разберемся подробнее с этими новыми входами и режимами. Вход выбора микросхемы CS (Chip Select) предназначен для ее включения и выключения в разные моменты времени. Такие входы можно часто встретить у микросхем, предназначенных для микропроцессорной техники. Особенно в больших, многофункциональных микросхемах. Наличие таких входов позволяет соединять несколько подобных микросхем параллельно, но работать с каждой по отдельности. В случае параллельного соединения нескольких регистров, таких, как изображены на рис. 18, можно соединить вместе одноименные входы данных (DO с DO, D1 с D1, и т.д.), а также входы синхронизации С. Поданные на входы D0...D1 данные будут записаны только в тот из регистров, на вход CS которого в момент записи будет подан низкий логический уровень. Состояние остальных регистров останется неизменным. Вход ОЕ, напротив, используется при параллельном объединении нескольких регистров по их выходам. Такое объединение возможно только в том случае, если в каждый момент времени будут работать выходы только одной из микросхем. Выходы остальных параллельно соединенных микросхем должны уметь автоматически отключаться от схемы. Для этой цели описываемый регистр имеет специальный режим. В этом режиме все выходы микросхемы отключаются и не влияют на работу остальной схемы. При этом сопротивление паразитной нагрузки, которую создает микросхема, подключенная к шине данных настолько велико, что не создает помех в работе шины. Такое состояние выходов называется высокоимпедансным. Импеданс — это полное сопротивление цепи (активное — по постоянному току, плюс реактивное — по переменному). Описываемая микросхема переводит свои выходы в высокоимпеданс- ное состояние при подаче логической единицы на вход ОЕ. Если же на вход ОЕ подать логический ноль, то выходы микросхемы перейдут в рабочее состояние. Рис. 19. JK-триггер Напоследок хочу рассказать об еще одном виде триггеров — о Ж-триг- гере. Условное обозначение такого триггера приведено на рис. 19. Как
Ликбез для начинающих 31 видно из рисунка, вместо одного D-входа такой триггер имеет два входа — J и К. Логика работы такого триггера более сложна. Если на J- вход подать сигнал логической единицы, а на К-вход — сигнал логического нуля, то по спаду тактового сигнала триггер установится в единичное состояние. Если на J подать лог. О, а на К — лог. I, то по спаду тактового импульса триггер установится в нулевое состояние. Если на обоих информационных входах лог. 1, то по каждому спаду тактового импульса триггер будет переключаться в другое, противоположное состояние. И, наконец, если на оба входа JK-триггера подать сигнал логического нуля, то триггер перестанет реагировать на тактовые импульсы, и все время будет оставаться в одном и том же состоянии. На первый взгляд логика работы триггера чересчур сложна и область применения таких триггеров не очевидна. Однако виртуозы схемотехники умудряются при помощи JK-триггеров создавать более компактные и рациональные схемы. Чаще всего Ж-триггер применяется для построения различных счетчиков и делителей. А вот что такое счетчики мы узнаем из следующего раздела. Счетчики Счетчиками в цифровой технике называются специальные элементы, позволяющие подсчитывать число поступивших на вход импульсов. Понятие «счетчик импульсов» тесно связано с понятием «делитель частоты». По сути дела это одно и то же устройство. Но рассмотрим все по порядку. Рис. 20. Деление частоты В качестве простейшего делителя частоты может выступать рассмотренный в предыдущем разделе JK-триггер. Для того, чтобы этот триггер работал как счетчик, нужно на оба входа J и К подать высокий логи-
32 Самоучитель по микропроцессорной технике ческий уровень. Теперь, если на вход С подать импульсный сигнал некоторой постоянной частоты, то по спаду каждого входного импульса триггер будет переключаться в противоположное состояние. В результате на выходе Ж-триггера мы получим другой сигнал с частотой следования импульсов в два раза меньшей, чем частота импульсов на его входе. Этот процесс наглядно показан на рисунке 20. Второй вариант делителя частоты приведен на рис. 21. Он построен на основе D-триггера. Для того, что бы перевести D-триггер в счетный режим, нужно соединить инверсный выход триггера Q с его D входом. Рис. 21. Простейший делитель частоты При этом входной сигнал подается на вход С, а с выхода Q снимается выходной сигнал делителя. Очевидно, что по спаду каждого входного импульса включенный по такой схеме D-триггер будет переключаться в противоположное состояние, так как на его D-входе в момент прихода тактового импульса всегда будет присутствовать сигнал инверсный по отношению к текущему состоянию триггера. Рис. 22. Четырехкаскадный делитель частоты Делители широко используются в цифровой технике. Цепочка последовательно соединенных D-триггеров, позволяет получить сигналы, требуемой частоты, путем деления импульсов задающего генератора. Например, соединенные последовательно два делителя, позволят полу-
Ликбез для начинающих 33 чить сигнал с частотой в четыре раза меньшей, чем входная. Три каскада делителя дадут деление на восемь. Четыре — на шестнадцать. И так далее. На рис. 22 изображен четырехкаскадный делитель частоты на D-триггерах. Импульсы тактового генератора поступают на вход первого каскада деления. Выход первого каскада подключен к входу второго и т.д. Если частота сигнала на входе равна f, то на выходах делителя мы получим сигналы со следующими частотами: Q0 - f/2 Ql - f/4 Q2 - f/8 03 - f/16 Приведенную на рис. 22 схему можно использовать не только в качестве делителя частоты, но и в качестве счетчика входных импульсов. Представьте, что выходы Q0...Q3 — это разряды некоторого двоичного числа. Q0 — младший разряд, a Q3 — самый старший. При поступлении на вход схемы счетных импульсов, D-триггера, входящие в схему, будут переключаться так, как это было показано ранее. Двоичное число, образованное выходными разрядами делителя, также будет меняться. Предположим, что перед приходом самого первого импульса на всех четырех выходах схемы были логические нули. Тогда, при поступлении входных импульсов, двоичное число будет принимать следующие значения (см. табл. 1). Логика работы делителя Таблица Десятичный эквивалент
34 Самоучитель по микропроцессорной технике Как видно из табл. 1, каждый входной импульс увеличивает значение двоичного числа на выходе счетчика на единицу. Поэтому в любой момент времени счетчик содержит число, равное количеству пришедших входных импульсов. Максимальное число импульсов, которое может посчитать счетчик, изображенный на рис. 22, это 16. После прихода шестнадцатого импульса счетчик вернется в нулевое состояние. Описанный выше счетчик относится к классу прямых счетчиков. В процессе счета его содержимое увеличивается. В цифровой технике иногда возникает потребность в счетчиках другого типа: инверсных счетчиках. На рис. 23 изображена микросхема К555ИЕ7. Это одна из микросхем 555 серии, которая широко выпускалась в свое время в СССР и сейчас ее можно свободно найти в продаже на радиорынках стран СНГ. Рис. 23. Реверсивный счетчик Микросхема 555ИЕ7 — это реверсивный четырехразрядный счетчик с возможностью предустановки. Он имеет два счетных входа, обозначенных как «+1» и «-1». По спаду каждого импульса на входе «+1» содержимое счетчика увеличивается на единицу. По спаду каждого импульса на входе «-1» содержимое счетчика уменьшается на единицу. Счетчик имеет прямые выходы всех своих разрядов: Q0...Q3. Вход сброса R служит для установки всех разрядов счетчика в нулевое состояние. Еще одно полезное свойство описываемого счетчика — это наличие режима предустановки. Используя этот режим, можно в любой момент записать во все разряды счетчика любое допустимое двоичное число. Для этого счетчик имеет несколько дополнительных входов. Во-первых, это входы D0...D3. А во-вторых, это вход предустановки РЕ. Предустановка счетчика осуществляется следующим образом. Сначала на входы D0...D3 подается код, который требуется записать в разряды счетчика. Затем на вход РЕ подается сигнал низкого логического уровня. По этому
Ликбез для начинающих 35 сигналу, код, установленный на входах D0...D3, запишется в счетчик и тут же появится на его выходах Q0...Q3. Выходы «>15» и «<0» — это выходы переполнения. Они используются при последовательном соединении нескольких таких счетчиков. В процессе счета уровень сигнала на обоих этих выходах равен единице. На выходе «>15» логический ноль появляется в том случае, если в процессе прямого счета содержимое счетчика достигнет своего максимального значения 11112, а на вход «+1» поступит очередной счетный импульс. Выход «<0» работает аналогично, но при обратном счете. Сигнал логического нуля появляется на этом выходе в тот момент, когда счетчик досчитает до своего нижнего предела — 00002, а на вход «~1» поступит очередной счетный импульс. При последовательном соединении двух счетчиков, выходы «>15» и «<0» первого счетчика соединяется, соответственно, с входами «+1» и «—1» второго. В результате, соединив последовательно два таких счетчика, мы получим восьмиразрядный реверсивный счетчик, который также будет иметь возможность предустановки. Таким способом можно соединять последовательно любое количество таких счетчиков. Одно из применений микросхемы 555ИЕ7 — построение делителей с переменным коэффициентом деления. Простой делитель частоты, такой, какой мы рассматривали в начале этого раздела, дает фиксированный набор коэффициентов деления, который к тому же можно выбирать лишь из ограниченного ряда чисел, являющихся степенью числа 2. Рис. 24. Делитель с переменным коэффициентом деления В то же время, микропроцессорной технике часто требуется делители с произвольным коэффициентом деления. При этом желательно, чтобы этот коэффициент можно было бы оперативно менять. На рис. 24
36 Самоучитель по микропроцессорной технике изображена схема делителя с программируемым коэффициентом деления на основе реверсивного счетчика К555ИЕ7. Для хранения коэффициента деления используется специальный четырехразрядный параллельный регистр, обозначенный на схеме, как D1. Коэффициент деления такого делителя может изменяться от 1 до 15. Работа счетчика начинается с установки всех его разрядов в ноль при помощи входа R. Обратите внимание на то, что в микросхеме К555ИЕ7 используется прямой, а не инверсный вход сброса. Поэтому сброс происходит при подаче на этот вход сигнала логической единицы. Затем на вход должен быть подан нулевой уровень. Входной сигнал поступает на вход «-1» счетчика. Поэтому счетчик работает в режиме вычитания. Первый же входной импульс после сброса счетчика вызовет сиг^ нал переполнения на выходе «<0». Этот импульс поступит на вход РЕ того же счетчика. В результате в него будет записано число, соответствующее выбранному коэффициенту деления. Допустим, что в регистр D1 мы записали число 10 A0102). Тогда разряды счетчика установятся в состояние, соответствующее числу десять. Каждый последующий входной импульс будет уменьшать это число на единицу. Так будет продолжаться до тех пор, пока содержимое счетчика снова не уменьшится до нуля. Для этого потребуется как раз 10 тактовых импульсов. По приходу одиннадцатого импульса на выходе «<0» снова появится сигнал переполнения, и в счетчик будет опять записано число из регистра D1. Описанный процесс будет повторяться все время, пока приходят входные импульсы. Период следования импульсов на выходе «<0», а значит и на выходе всей схемы, в нашем случае, будет в 11 раз больше периода входных сигналов. А частота выходных импульсов будет, соответственно, в И раз меньше. Записывая в регистр D1 различные значения, можно легко менять коэффициент деления описанной схемы. Если вместо регистра D1 применить один из портов вывода микропроцессорной системы, то мы получим возможность программного изменения коэффициента деления. Кроме задачи получения на выходе сигналов различных, заранее заданных частот, любой счетчик-делитель может выполнять задачу формирования заданных временных интервалов. Если на вход описанного выше счетчика с переменным коэффициентом деления подать импульсы с периодом, равным ровно 1 секунде, то задержка появления импульса на выходе такой схемы будет зависеть от выбранного коэффициента деления. В случае если регистр D1 содержит число 10, эта задержка составит 11 секунд. Схемы, предназначенные для формирования различных интервалов времени, называются таймерами. Обычно одни и те же цифровые эле-
Ликбез для начинающих 37 менты могут с успехом выступать в любой из трех описанных выше ролей: либо как делители, либо как счетчики, либо как таймеры. Среди огромного разнообразия современных цифровых микросхем существуют специальные микросхемы, выполняющие роль программируемых счетчиков-таймеров. Например, микросхема 580 серии, как К580ВИ53 — это универсальный программируемый трехканальный счетчик-таймер. Такая микросхема имеет множество режимов работы, которые должны выбираться программным путем, при помощи микропроцессора. Микроконтроллеры, или как их еще называют — однокристальные микро- ЭВМ, обычно всегда содержат в своем составе несколько встроенных таймеров-счетчиков. Например, микроконтроллер АТ89С2051 имеет два встроенных таймера/счетчика, что позволяет при создании на основе этой микросхемы различных микропроцессорных устройств, обойтись без внешних устройств для формирования временных интервалов. В позиционере используются оба встроенных таймера. Каким образом используются такие таймеры, мы разберем в соответствующей главе этой книги, в процессе изучения управляющей программы позиционера спутниковой антенны. Дешифраторы Следующий элемент, про который я хочу вам рассказать — это дешифратор цифровых сигналов. Существует много разных типов дешифраторов. В общем случае, дешифратор — это устройство, преобразующее цифровой сигнал, представленный в какой-либо одной из кодировок в другую, не закодированную форму. Нас будет интересовать классический линейный дешифратор. Схемное обозначение одного из вариантов такого дешифратора приведено на рис. 25. Описываемый дешифратор имеет три входа данных DO, D1 и D2. Вход выбора микросхемы CS. А также восемь выходов, обозначенных цифрами от 0 до 7. Логика работы микросхемы такова: на входы данных микросхемы подается цифровой код. В данном случае — это любое трехразрядное двоичное число. Если на вход CS дешифратора подан разрешающий нулевой сигнал, то выходной сигнал появится на том из выходов дешифратора, номер которого соответствует нашему входному коду. Выходным сигналом практически любого вида дешифраторов является сигнал логического нуля. Это значит, что если на входы D0...D2 мы подадим, например, число 6 A1002), и на входе CS будет логический ноль, то сигнал на выходе 6 примет значение, равное нулю, а на ос-
38 Самоучитель по микропроцессорной технике тальных выходах останутся логические единицы. Полная таблица истинности приведена на рис. 26. Обратите внимание, что в этой таблице появилось новое обозначение. Знак «X» в таблице истинности означает, что на этом входе может присутствовать любое значение, как О, так и 1. Имеется в виду, что в данном случае уровень сигнала на этом конкретном входе никакого значения не имеет. Рис. 25. Простейший дешифратор Уже знакомый нам вход выбора микросхемы CS служит для полного его отключения. Если на этот вход подать логическую единицу, все его выходы перейдут в единичное состояние. Рис. 26. Таблица истинности дешифратора Главное назначение дешифратора — выбор одного из параллельно используемых устройств. В качестве таких выбираемых устройств часто выступают различные цифровые микросхемы, также имеющие вход выбора кристалла. В качестве примера приведу схему простейшего модуля ОЗУ, состоящего всего из четырех ячеек. Эта схема изображена на рис. 27.
Ликбез для начинающих 39 Рис. 27. Простейший модуль ОЗУ
40 Самоучитель по микропроцессорной технике В качестве ячеек памяти в схеме используются параллельные регистры с возможностью перевода в высокой мпедансное состояние. Такие регистры нам уже знакомы по предыдущим разделам (см. рис. 18). Рассмотрим внимательно схему нашего ОЗУ. Линии LD0...LD7 — это восьмиразрядная шина данных. Она используется, как для записи чисел в память, так и для чтения из нее. Остальные входы используются для управления. Для правильной работы схемы на входы UPR, WRITE и READ нужно подать сигналы логической единицы. Для того, чтобы записать число в одну из ячеек такого ОЗУ, нужно сначала на лини LD0...LD7 от внешнего источника цифрового сигнала подать двоичное восьмиразрядное число, предназначенное для записи. Затем, на линии LAO, LA1 подается число, соответствующее номеру нужной ячейки памяти. Этот код называют адресом ячейки. Код выбранной ячейки поступает на дешифратор DS. В результате на одном из его выходов появляется нулевой сигнал, а на всех остальных — единичный. Нулевой сигнал появится на том выходе дешифратора, номер которого соответствует выбранному адресу. Сигналы со всех выходов дешифратора поступают на входы CS регистров. Каждый выход — на свой регистр. В результате один из регистров окажется активным, а остальные — нет. Для того, чтобы записать число в выбранную ячейку памяти, нужно подать короткий нулевой импульс на вход WRITE. Он поступит на входы С всех регистров. Однако только один регистр среагирует на этот сигнал, так как только он будет активным. Несмотря на то, что выходы всех регистров объединены между собой и с входами, они не мешают работе схемы. Благодаря высокому уровню на входах ОЕ все выходы находятся в высокоимпедансном состоянии. В режиме чтения информации лини LD0...LD7 используются как выходы. Для того, чтобы прочитать число из любой ячейки памяти, нужно сначала подать ее адрес на входы LAO, LA1. Нужный нам регистр активизируется. Теперь, для того, чтобы прочитать число из выбранной ячейки, достаточно подать на вход READ сигнал логического нуля. В результате выходы выбранного регистра перейдут в рабочее состояние. На них появится записанное в данный регистр число. Выходы всех остальных регистров останутся отключенными. В заключение хочу привести еще один пример использования дешифратора. Благодаря наличию входа CS дешифратор можно легко каскадировать. Каскадирование — это способ включения нескольких дешифраторов, имеющий своей целью создание составного дешифратора имеющего большее количество разрядов. До сих пор мы имели дело с
Ликбез для начинающих 41 двумя видами дешифраторов. Первый из них (рис. 25) имел три входа и восемь выходов. Дешифратор, который мы использовали в примере схемы ОЗУ (рис. 27), имел всего два входа и четыре выхода. Логика работы любого такого дешифратора одна и та же. Различие состоит лишь в количестве входных и выходных разрядов. Для того, чтобы в краткой форме обозначить характеристики конкретного дешифратора, иногда применяют следующее обозначение: «Дешифратор 2X4», или «Дешифратор 3X8». На рис. 28 показан способ, как при помощи каскадного соединения дешифраторов создать новый дешифратор 5X32. Рис. 28. Каскадная схема включения дешифраторов
42 Самоучитель по микропроцессорной технике Все дешифраторы, рассмотренные нами до сих пор, относятся к разряду полных дешифраторов. Поясню, что это такое. Если дешифратор имеет пять входов, то максимальное число возможных состояний этих входов равно 32. Если при этом дешифратор имеет 32 выхода, то при подаче на его входы любого возможного числа, всегда найдется выход с таким же номером. В некоторых случаях наличие всех возможных выходов не обязательно. Например, в случае с так называемыми двоично-десятичными числами. Двоично-десятичное число — это число, записанное в двоичной форме, но принимающее значение от 0 до 10. Для записи таких чисел используется четыре двоичных разряда. При этом эти разряды принимают значения от 00002 до 10102. Если подать такое число на дешифратор, то последние шесть выходов A0, 11, 12, 13, 14, 15) использоваться никогда не будут. Специально для таких случаев промышленность изготавливает микросхемы двоично-десятичного дешифратора, такие как: К555ИД1, К555ИД6, К555ИД10. На этом я заканчиваю «курс молодого бойца». Приведенные в этом разделе сведения далеко не полностью описывают все возможное разнообразие цифровых элементов. Я ставил себе задачу дать минимум сведений, необходимых для понимания последующих тем этой книги. Теперь приступим к следующему этапу — более детальному изучению основ микропроцессорной техники.
Основы микропроцессорной техники Типовая схема микропроцессорной системы Если вы внимательно прочитали предыдущую главу и поняли все, о чем в ней говорится, то теперь можно приступать к новому этапу. Рассмотрим более детально, как устроена типичная микропроцессорная система. На рис. 29 приведена ее обобщенная структурная схема. На схеме показаны все основные элементы микропроцессорного устройства. Для удобства все названия даны в русском и английском вариантах. Обнако учтите, что в реальной практике вам придется иметь дело почти исключительно с английскими обозначениями. Расшифруем все эти обозначения. Каждый термин я даю сначала в его международном английском варианте, затем расшифровку на английском языке. Далее идет дословный перевод и в конце принятые у нас название и сокращение. CPU (Central Processing Unit) — центральный процессор или центральное процессорное устройство (ЦПУ). RAM (Random Access Memory) — устройство с произвольным доступом, или оперативное запоминающее устройство (ОЗУ). ROM (Read Only Memory) — память только для чтения, или постоянное запоминающее устройство (ПЗУ). Port I/O (Port Input/Output) — порт ввода/вывода. Что такое процессор вы уже немного знаете из первой главы нашей книги. ОЗУ и ПЗУ — это два вида памяти. Их можно было бы не разделять. Процессор, например, их и не различает и работает с обоими видами памяти абсолютно одинаково. Но между двумя этими видами
44 Самоучитель по микропроцессорной технике памяти есть одно довольно существенное различие. ОЗУ хранит информацию только при наличии напряжения питания. Классический пример ячейки ОЗУ — это простейший регистр, построенный на D-триг- герах (см. рис. 27). В такой регистр можно записывать информацию и читать ее оттуда. Она там будет храниться все время, пока на схему подано питание. Но после выключения питания при последующем его включении все D-триггера регистра установятся в случайное положение. Информация будет утеряна. Рис. 29. Структурная схема типовой микропроцессорной системы В настоящее время для построения схем ОЗУ применяют совсем другие технологии. Однако и по сей день не придумано достаточно быстродействующее устройство памяти, не теряющее информации при выключении питания. Современное ОЗУ строится на основе динамически подзаряжаемых миниатюрных емкостей, выполненных интегральным способом на кристалле кремния. Это, так называемое, динамическое ОЗУ. Каждый конденсатор хранит один бит информации. Входной сигнал через внутренние схемы коммутации поступает на этот конденсатор. Если его значение равно логической единице, то конденсатор заряжается. Если логическому нулю — то разряжается. Затем внутренний ключ отключает конденсатор от всех цепей и заряженные конденсаторы какое-то время хранят свой заряд. Но эти конденсаторы имеют очень маленькую емкость. Поэтому свой заряд они держат всего лишь несколько миллисекунд. Для того, чтобы информация ни потерялась, используют схему регенерации памяти. Все ячейки памяти организуются, как набор строк. Специальная схема периодически считывает информацию из памяти строка за строкой. После считывания очередной строки, считанная информация опять записывается в те же ячейки памяти. Конденсаторы при этом подзаряжаются
Основы микропроцессорной техники 45 снова. Для нормальной работы динамического ОЗУ схема микропроцессорного устройства должна непрерывно обеспечивать такую регенерацию в течение всего времени работы системы. ОЗУ современных больших компьютеров также устроено по динамическому принципу. Однако схема регенерации встроена внутрь самих микросхем ОЗУ. Постоянное запоминающее устройство ПЗУ предназначено для долговременного хранения информации. Информация, хранящаяся в ПЗУ, не пропадает при выключении питания. Зато ее нельзя оперативно менять. Информация в ПЗУ записывается один раз либо в процессе их производства, либо непосредственно перед применением, при помощи специальных программаторов. Принцип хранения информации в микросхемах ПЗУ основан на пережигании специальных внутренних перемычек. Каждая перемычка предназначена для хранения одного бита информации. Если перемычка цела, то это значит, что в данной ячейке хранится единичный бит информации. Если прожечь перемычку, то соответствующий бит примет нулевое значение. Хотя процессор и работает с обоими видами памяти одинаково, он может только читать информацию из ПЗУ. Запись информации в ПЗУ невозможна. Если микропроцессор все же попытается произвести запись, то ничего страшного не произойдет. Просто в ячейке останется то, что там было до попытки записи. Порты ввода/вывода можно рассматривать как вместе, так и отдельно: порты ввода и порты вывода. Дело в том, что процессор работает с портами ввода/вывода практически так же, как и с ячейками памяти. У каждого порта есть свой собственный адрес. Причем адрес ячейки памяти и адрес порта ввода/вывода — это абсолютно разные адреса. Они находятся, как говорят, в разных адресных пространствах. Процессор может записать любое число в.любой порт ввода/вывода. Затем он может считать число из порта по тому же адресу. Иногда это будут одни и те же числа. Но чаще запись происходит в одно устройство (порт вывода), а читает процессор уже из другого (порта ввода). В качестве порта вывода можно применить обыкновенный параллельный регистр. Порт вывода предназначен для того, чтобы микропроцессорная система могла управлять различными внешними устройствами. При помощи порта вывода можно управлять такими устройствами, как, например, цифро-аналоговые преобразователи (ЦАП), индикаторы. К выходам порта можно подключать электронные ключи, которые позволят микропроцессорной системе управлять более мощными устройствами. Такими, как электромагнитные реле, лампочки, светодиоды, моторчики, соленоиды и т.д. При помощи портов вывода можно даже делать
46 Самоучитель по микропроцессорной технике переключения в самой схеме микропроцессорного устройства. Это делается при помощи ключей и логических элементов. Такое микропроцессорное устройство становится гибким и способным автоматически подстраиваться под выполняемую задачу. Порт ввода — это специальная схема, при помощи которой микропроцессор может принимать внешние данные. К этим входам можно подключать аналого-цифровые преобразователи (АЦП), кнопки, датчики и т.д. Главным управляющим элементом всей микропроцессорной системы является процессор. Именно он, за исключением нескольких особых случаев, управляет всеми остальными устройствами. Остальные же устройства, такие, как ОЗУ, ПЗУ и порты ввода/вывода являются ведомыми. По этой причине их еще называют «периферийными устройствами» или «периферией». Все узлы микропроцессорной системы соединены между собой при помощи трех основных шин: ШД — шина данных (DATA bus). ША — шина адреса (ADDR bus). ШУ — шина управления (CONTROL bus). Все вместе они образуют системную шину. Мы уже немного знакомы с шиной данных. Сейчас нам нужно познакомиться со всеми видами микропроцессорных шин. Начнем по порядку. Шина данных Эта шина предназначена для передачи данных от микропроцессора к периферийным устройствам, а также в обратном направлении. Разрядность шины данных определяется типом применяемого процессора. В простых микропроцессорах шина данных обычно имеет 8 разрядов. Современные процессоры могут иметь шину данных на 16, 32, 64 разряда. Количество разрядов всегда кратно восьми. Двоичное число, имеющее восемь разрядов, называется байтом. В вычислительной технике байт, по сути, стал минимальной единицей информации. Шестнадцатиразрядная шина данных может за раз передавать до двух байтов. 32-разрядная шина передает до четырех байт. 64- разрядная — до восьми. Однако во всех этих шинах обязательно предусмотрен режим передачи одного байта (по младшим его разрядам). Старшие разряды при этом не используются.
Основы микропроцессорной техники 47 Шина адреса Как и шина данных, шина адреса представляет собой набор проводников, по которым происходит передача двоичных чисел в электронной форме. Однако, в отличие от шины данных, двоичные числа, передаваемые по шине адреса, имеют другой смысл и назначение. Они представляют собой адрес ячейки памяти или порта ввода/вывода, к которому в данный момент обращается процессор. Количество разрядов адресной шины отличается большим разнообразием. Например, микропроцессор серии К580ИК80 имеет 16 разрядов адреса. Это можно считать минимальным количеством. Процессор Intel 8086, на котором собран родоначальник всех РС-со- вместимых персональных компьютеров — компьютер IBM PC-XT, имеет 20 разрядов шины адреса. Современные процессоры имеют до 32 разрядов и больше. От количества разрядов шины адреса зависит то, какое количество ячеек памяти может адресовать процессор. Процессор, имеющий шестнадцатиразрядную шину данных, может обращаться к 216 (то есть к 65536) ячейкам памяти. Это число называется объемом адресуемой памяти. Реальный объем подключенной памяти может быть меньше, но никак не больше этой величины. В вычислительной технике используется необычный способ для измерения объема памяти. Объем памяти измеряется в байтах, килобайтах, мегабайтах и т.д. Один килобайт в вычислительной технике не равен 1000 байтов, как этого можно было бы ожидать. Это связано с тем, что объем памяти, подчиняется уже знакомому нам закону. Он всегда будет равен какой-либо степени двойки. То есть он всегда равен 2П, где п — любое целое число. По этой причине один килобайт равен 1024 байтов. Такое значение с одной стороны максимально приближается к числу 1000. А с другой стороны 1024 равно 210. Для того, чтобы вы смогли окончательно разобраться в этом вопросе, приведу один небольшой пример. Для адресации 1024 ячеек памяти нужна шина адреса, имеющая ровно 10 разрядов. При этом, если мы подключим к ней именно столько ячеек памяти, шина не будет избыточна. Если бы мы захотели иметь только 1000 ячеек, то для обращения к любой из этих ячеек, нам все равно потребовалось бы 10 разрядов адреса, так как если разрядов будет девять, то мы сможем обратиться только к 512 ячейкам. Именно поэтому никто и никогда не делал запоминающего устройства с объемом не 2". Логично, что и объем памяти удобнее измерять в величинах, взятых из того же ряда. Данный принцип распространяется и на более высокие размерности. Один мегабайт равен 1024 килобайтам. Один гигабайт равен 1024 мегабайтам. Hv. и так палее.
48 Самоучитель по микропроцессорной технике Для адресации портов ввода/вывода также нужна шина адреса. В обоих случаях в этой роли выступает одна и та же шина. Но ни одной микропроцессорной системе никогда не может потребоваться такое же большое количество портов ввода/вывода, сколько обычно бывает ячеек ОЗУ. Поэтому, в процессе обмена с портами ввода/вывода процессор использует только восемь (реже 16) младших разрядов шины адреса. Шина управления Эта шина не имеет такой же четкой структуры, как шина данных или шина адреса. В шину управления условно объединяют набор линий, передающих различные управляющие сигналы от процессора на все периферийные устройства и обратно. Что же это за линии. В любой шине управления обязательно присутствуют линии, передающие следующие сигналы: RD (Read) — сигнал чтения. WR (Write) — сигнал записи. MREQ — сигнал инициализации устройств памяти (ОЗУ или ПЗУ). IORQ — сигнал инициализации портов ввода/вывода. Кроме того, к сигналам шины управления относятся: READY — сигнал готовности. RESET — сигнал сброса. И еще несколько специальных сигналов, о которых мы поговорим позже. Все, что было сказано выше, описывает общие принципы построения микропроцессорных устройств. В данной книге мы будем рассматривать гораздо более узкий вопрос. Мы будем изучать простую микропроцессорную систему, имеющую восьмиразрядную шину данных и шестнадцатиразрядную шину адреса. Рассмотрим подробнее, как работает микропроцессорная система, изображенная на рис. 29. Как уже говорилось, в основном режиме работы всей микропроцессорной системой управляет центральный процессор (CPU). При этом, по отношению к любым периферийным устройствам, процессор может выполнять в каждый момент времени одну из четырех основных операций: чтение из ячейки памяти, запись в ячейку памяти, чтение из порта и запись в порт. Для того, чтобы прочитать байт из ячейки памяти, процессор сначала устанавливает на шине данных адрес нужной ячейки. Затем он уста-
Основы микропроцессорной техники 49 навливает сигнал MREQ в активное состояние, то есть устанавливает его равным логическому нулю. Этот сигнал поступает на устройства памяти и служит разрешением для их работы. При этом сигнал IORQ остается равным лог. 1. Поэтому порты ввода/вывода микропроцессорной системы остаются не активными. Далее, процессор переводит в активное состояние сигнал RD. Этот сигнал поступает как на устройства памяти, так и на порты ввода/вывода. Однако порты не реагируют на него, так как они отключены высоким уровнем сигнала IORQ. Устройство памяти напротив, получив управляющие сигналы RD и MREQ, выдает на шину данных байт информации из той ячейки памяти, адрес которой присутствует в этот момент на шине адреса. Процесс записи данных в память происходит в следующей последовательности. Сначала центральный процессор выставляет на адресную шину адрес нужной ячейки памяти. Затем на шину данных он выставляет байт, предназначенный для записи в эту ячейку. После чего активизируется сигнал MREQ, разрешающий доступ к модулю памяти. И уже затем процессор устанавливает сигнал WR в активное состояние (лог. 0). Именно по этому сигналу происходит запись байта в ячейку памяти, адрес которой присутствует на шине адреса. Некоторые виды памяти работают очень медленно. Они могут не успеть выдать информацию или произвести ее запись так быстро, как это способен сделать центральный процессор. Для согласования работы медленных устройств памяти с быстрыми процессорами существует сигнал READY (готовность). Сразу после того, как процессор установит сигнал чтения или записи в активное состояние, устройство памяти устанавливает сигнал READY в пассивное состояние (лог. 0). Такой уровень сигнала означает, что внешнее устройство не готово, то есть еще не выполнило команду. Сигнал READY поступает на процессор, и процессор переходит в режим ожидания. Когда устройство памяти выполнит текущую команду, оно устанавливает сигнал READY в активное состояние (лог. 1). Процессор, получив этот сигнал, возобновляет работу. Сигнал READY применяется и в случае работы с медленными портами ввода/вывода. Операции чтения из порта и записи в порт происходят аналогично операциям чтения/записи ОЗУ. Различие лишь в том, что вместо сигнала MREQ в активное состояние переходит сигнал IORQ, разрешающий работу портов.
50 Самоучитель по микропроцессорной технике Алгоритм работы микропроцессорной системы В предыдущем разделе мы узнали, как микропроцессор осуществляет работу с периферийными устройствами. Мы видели, что процессор может читать числа из этих устройств и записывать в них. Кроме операций чтения и записи информации, процессор всегда производит множество операций по ее обработке. С полученными из разных источников числами процессор способен производить любые виды преобразований, которые возможны с числами. Он может их складывать, вычитать, сравнивать, производить поразрядный сдвиг. Любой процессор умеет производить поразрядные логические преобразования, такие, как логическое умножение («И»), логическое сложение («ИЛИ»), инверсия («НЕ»). Некоторые процессоры (не все) умеют даже делить и умножать числа. Нужно, правда, заметить, что базовый набор операций выполняется с простыми восьми-, реже шестнадцатиразрядными двоичными числами. То есть с одним либо с двумя байтами информации. Мы будем изучать процессоры, ограничивающиеся именно таким, базовым объемом команд. Как же заставить процессор выполнять все эти операции в нужной последовательности? Мы уже знаем, что для этого нужно создать программу. Каждая операция, которую способен выполнять конкретный микропроцессор кодируется некоторым числом. Это число называется кодом операции. Коды операций записываются последовательно, один за другим в память микропроцессорной системы (в ОЗУ, либо в ПЗУ). Процессор последовательно, байт за байтом, читает коды операций и выполняет их. Именно таким образом и происходит работа по программе. В простых процессорах коды операций обычно состоят из одного байта. Однако некоторые операции требуют дополнительных параметров. Это может быть адрес ячейки памяти, над которой нужно произвести данную операцию, некая константа, либо адрес перехода. Про переходы в программе мы поговорим немного позже. Для записи параметров используют дополнительные байты. В результате одна команда может занимать в памяти от одной до трех ячеек. В мощных современных процессорах эта цифра еще больше. Подробное описание системы команд микроконтроллера АТ89С2051 вы найдете в конце этой книги. Область памяти, предназначенная для записи программы, называется программной памятью. Некоторые процессоры имеют отдельные память программ и память данных. Другие же хранят программы и данные в
Основы микропроцессорной техники 51 одной и той же памяти. В простых микропроцессорных устройствах, таких, как позиционер спутниковой антенны, для хранения программ обычно используется ПЗУ. Теперь рассмотрим процесс выполнения программы. Для реализации этого процесса любой процессор имеет встроенный регистр адреса текущей выполняемой программы. Работа микропроцессорного устройства начинается с начального сброса. Сразу после включения питания специальный узел подает импульс сброса на вход RESET процессора. По этому сигналу все внутренние системы процессора устанавливаются в исходное состояние. В регистр адреса записывается адрес начала программной памяти. По окончании импульса сброса включается встроенный алгоритм выполнения программ. Повинуясь этому алгоритму, процессор начинает последовательно читать коды, записанные в программной области памяти, начиная с первой ячейки программной памяти. После выполнения очередной команды процессор увеличивает значение счетчика команд на единицу и переходит, таким образом, к выполнению следующей команды. Если очередная команда состоит не из одного, а из двух и более байтов, то после чтения кода операции процессор последовательно считывает эти дополнительные байты, увеличивая каждый раз значение счетчика команд. Информация о том, сколько байт читать и как выполнять каждую из команд, записана в виде микрокоманд внутри самого процессора. Режим выполнения программы продолжается все время, пока на процессор подано питающее напряжение. Закончить выполнение программы процессор может либо при поступлении нового импульса сброса, либо при выполнении специальной команды остановки. Всю совокупность команд любого микропроцессора можно разделить на три большие группы. Первая группа — это команды перемещения данных. Повинуясь этим командам, процессор копирует содержимое ячейки памяти в один из внутренних регистров, либо наоборот, копирует содержимое регистра в одну из ячеек памяти. Кроме того, данные могут копироваться из одного внутреннего регистра в другой. Нужно заметить, что в процессе всех этих перемещений содержимое источника информации остается неизменным. Специфика любой ячейки памяти такова, что невозможно стереть записанное туда число. Можно только записать туда другое. Ко второй группе относятся команды преобразования данных. А именно: команды сложения, вычитания, логических преобразований, сдвига разрядов и другие.
52 Самоучитель по микропроцессорной технике К третьей группе относятся команды передачи управления. Вот об этом классе команд я хотел бы поговорить подробнее. Сложно представить себе программу, состоящую лишь из одной последовательной цепочки команд. Подавляющее число алгоритмов требуют разветвления программы. Это значит, что программа должна уметь выполнять разные последовательности действий в зависимости от того, выполняется или нет какое-либо условие. Приведу конкретный пример. Позиционер спутниковой антенны имеет кнопки управления. При нажатии на соответствующую кнопку, можно заставить позиционер выполнять введенную таким образом команду. Так, например, при нажатии клавиши «Поворот на восток», устройство должно включить двигатель для поворота антенны в этом направлении. При нажатии клавиши «Поворот на запад», система должна включить двигатель в реверсивном направлении. И так далее. Для того, чтобы программа могла реагировать на нажатия кнопок, она, повинуясь внутреннему алгоритму, периодически считывает состояние клавиатуры. Обнаружив нажатие клавиши, программа должна прекратить опрос клавиатуры и перейти к другому алгоритму: алгоритму включения мотора. Для того, чтобы программа имела возможность менять алгоритм своей работы в зависимости от какого-либо условия, в системе команд любого процессора обязательно имеются команды передачи управления. К командам передачи управления относятся следующие виды команд: • команды условного перехода; • команды безусловного перехода; • команды перехода к подпрограмме; • команды организации цикла. Рассмотрим действие всех этих команд по порядку. КОМАНДЫ УСЛОВНОГО И БЕЗУСЛОВНОГО ПЕРЕХОДА Оба этих вида команд предназначены для того, чтобы прерывать последовательность выполнения команд и вызывать, так называемый, переход. Причем условный переход происходит только при соблюдении какого-либо условия. Безусловный переход выполняется всегда, как только программа встретит соответствующую команду. В качестве условий перехода может выступать одно из следующих логических выражений: Величина А равна величине В. Величина А не равна величине В. Величина А меньше величины В.
Основы микропроцессорной техники 53 Величина А больше величины В. Величина А меньше или равна величине В. Величина А больше или равна величине В. В качестве величин для сравнения может выступать содержимое любого внутреннего регистра процессора, содержимое любой ячейки памяти или просто константа. Рассмотрим пример применения условного и безусловного переходов. Допустим, что в зависимости от того, нажата или отпущена некая кнопка на панели управления позиционера, наша программа должна выполнить разные последовательности действий. На рис. 30 изображен ход выполнения такой программы. Квадратиками обозначены обычные команды программы. Кружечек с вопросом — это команда условного перехода. Скругленный элемент с восклицательным знаком — это безусловный переход. Стрелками показана последовательность выполнения программы. В случае нажатой клавиши должна выполниться ветвь 1, а в случае отпущенной — ветвь 2. Для того, чтобы процессор смог оценить состояние нашей клавиши, ее подключают к одному из портов ввода/вывода. В начале программы процессору дается команда прочитать число из этого порта. Полученное число будет зависеть от состояния клавиши. Рис. 30. Работа операторов условного и безусловного переходов Допустим, при нажатой клавише процессор считает число 1, а при отпущенной — число 0. Тогда действие, выполняемое условным оператором, можно записать так: если считанное число равно 2, перейти к выполнению ветви 2. Соответственно, в случае невыполнения условия, программа продолжит свою работу в обычном режиме и перейдет, таким образом, к выполнению ветви 1. В конце ветви 1 стоит оператор безусловного перехода. Он служит для того, чтобы программа не выполнила ветвь 2 после выполнения ветви 1. В данном случае никакого условия для перехода не требуется.
54 Самоучитель по микропроцессорной технике КОМАНДЫ ОРГАНИЗАЦИИ ЦИКЛА Циклическое выполнение группы команд — очень эффективное средство для сокращения программного кода. Иногда требуется выполнить одну и ту же группу команд несколько раз. Вместо того, чтобы много раз записывать одни и те же команды, можно заставить любой участок программы выполняться по несколько раз. Для этого и служат команды организации цикла. Допустим, мы хотим создать простейшую антидребезговую программу. Для избавления от дребезга мы будем считывать состояние кнопки не один, а несколько раз. Полученные числа мы сложим между собой. Из- за дребезга контактов кнопки мы не получим четкого срабатывания. Поэтому вместо сплошных единиц (кнопка нажата), либо сплошных нулей (кнопка отпущена) мы получим смесь нулей и единиц. Наша задача — определить, чего больше. Допустим, что мы будем производить подряд 20 операций чтения и сложения. Вспомним, что нажатая кнопка дает нам единицу, а не нажатая ноль. Если полученная сумма окажется больше пяти, то кнопка считается нажатой. В противном случае она считается отпущенной. Операции считывания порта и сложения полученных результатов удобно оформить в виде цикла. На рис. 31 показан ход выполнения подобной программы. Как и на предыдущем рисунке, квадратиками обозначены обычные операторы. Кружок с буквой Ц — это оператор цикла. Рис. 31. Демонстрация работы оператора цикла Важным элементом организации цикла служит регистр, куда записывается число требуемых проходов цикла. Это число называется параметром цикла. В нашем случае он равен 20. Перед началом цикла одна из команд записывает параметр цикла в один из внутренних регистров процессора, выбранный для этой цели. Затем выполняется так называемое тело цикла. Тело цикла составляют те самые команды чтения порта
Основы микропроцессорной техники 55 и сложения, которые предназначены для многократного повторения. После выполнения этих команд наступает очередь оператора цикла. Этот оператор выполняет следующие действия: 1. Уменьшает параметр цикла на единицу. 2. Проверяет, не равен ли параметр, после уменьшения, нулю? 3. Если не равен, то оператор осуществляет переход к началу цикла. 4. Если же параметр равен нулю, переход не производится и выполнение программы продолжается в обычном режиме. Благодаря этому алгоритму управление передается на начало цикла до тех пор, пока содержимое указателя цикла не достигнет нуля. После чего цикл заканчивается, и программа продолжает выполняться в обычном режиме. КОМАНДЫ ПЕРЕХОДА К ПОДПРОГРАММЕ К таким командам относятся: команда перехода к подпрограмме, команда выхода из подпрограммы и несколько команд перехода к подпрограмме по условию. Все эти команды составляют еще один механизм сокращения программного кода. Их применяют в том случае, когда необходимо многократно выполнять некие повторяющиеся действия. Например, такое действие, как вывод изображения на индикатор. По ходу выполнения программы возникает необходимость вывести какое- либо изображение в самых разных местах программы. В одном месте программы формируется номер текущего канала. В другом — возникает ошибка и программа должна вывести на индикатор надпись «Error». В третьем месте программа обнаружила нажатие клавиши перехода в р'ежим ручного управления и должна вывести на индикатор информацию о его включении. Самое простое решение такой задачи — написать в каждом подобном месте все необходимые команды, реализующие алгоритм вывода изображения на индикатор. Но дело в том, что такая процедура имеет довольно сложный алгоритм. Он состоит не из одного десятка команд. Писать все эти команды каждый раз — это не рациональное расходование программной памяти. В таких случаях подобные участки программы оформляют в виде подпрограммы. Подпрограмма — это просто часть программы, оформленная таким образом, что к ней можно обращаться из любого места остальной программы. Обращение происходит при помощи специальной команды вызова подпрограммы. При вызове подпрограммы автоматически запоминается адрес программной памяти, откуда этот вызов поступил для
56 Самоучитель по микропроцессорной технике того, чтобы можно было вернуться к нему. Ряд операторов, составляющих тело подпрограммы, заканчивается командой возврата из подпрограммы. По этой команде управление передается назад, в ту самую точку, откуда подпрограмма была вызвана. Процесс обращения к подпрограмме показан на рис. 32. Рис. 32. Демонстрация работы операторов организации подпрограммы Элемент с буквой П — это команда перехода к подпрограмме. Буквой В обозначена команда возврата из подпрограммы. Подпрограмма может находиться в значительном отдалении от места ее вызова. Главное преимущество этого подхода в том, что вызов одной и той же подпрограммы может происходить с самых разных мест программы. Например, процедура вывода на индикатор может понадобиться в нескольких десятках случаев. Если подпрограмма один раз уже написана, то во всех случаях, когда потребуется вывести что-нибудь на индикатор, достаточно поставить команду вызова соответствующей подпрограммы, и вывод готов. Использование подпрограмм также очень удобно для повышения эффективности программирования. Любая подпрограмма воспринимается, как отдельный программный блок, осуществляющий определенную функцию. Из этих блоков, как из кирпичиков, удобно строить основную программу. При построении конструкций глобального масштаба не нужно задумываться о частностях. Поэтому подпрограммы часто используют для повышения структурированности программ. Структурированная программа — это программа, четко разбитая на отдельные программные модули в соответствии с выполняемыми задачами.
Основы микропроцессорной техники 57 Механизм прерываний Вернемся теперь опять к структурной схеме типового микропроцессорного устройства (рис. 29). Для простоты изложения на ней не были показаны две очень важные системы. В любом микропроцессорном устройстве могут присутствовать: система прерываний и система прямого доступа к памяти. Эти системы не являются обязательными, но их применение может существенно увеличить гибкость и эффективность всего микропроцессорного устройства. Что же это за системы. В позиционере спутниковой антенны широко используется механизм прерываний. Прямой доступ к памяти там не применяется, но для полноты картины мы рассмотрим и ее в обших чертах. Начнем с механизма прерываний. Представим себе задачу, на вход позиционера поступают сигналы от датчика поворота антенны. Каждый поступивший сигнал требует немедленной обработки. Обработка состоит из алгоритма антидребезга и процедуры увеличения (или уменьшения в зависимости от направления поворота) содержимого счетчика положения антенны. В то же самое время позиционер должен выполнять и основные свои задачи. Такие, как опрос состояния кнопок управления и отработку команды при нажатии одной из них. А также вывод информации на индикатор. То есть подсчет импульсов от датчика поворота должен выполняться в фоновом режиме. Можно решать проблему фонового режима двумя способами. Первый способ — решать ее «в лоб». То есть разместить где-то в теле основной программы процедуру (подпрограмму) проверки датчика. При этом место размещения процедуры должно быть таково, чтобы обеспечить как можно более частое обращение к этой процедуре. При таком способе опрос датчика будет происходить лишь тогда, когда программа закончит выполнять очередную порцию основной программы. Самый большой недостаток — это нерегулярность опроса датчика. Время выполнения любой части основной программы очень зависит от конкретного режима работы программы. Операции могут так затянуться, что программа не успеет очередной раз считать состояние датчика, и он сработает вхолостую. Специально для таких ситуаций инженеры придумали систему прерываний. У любого современного микропроцессора имеется хотя бы один вход запроса на прерывание. Обычно его именуют INT (от слова Interrupt — прерывание). Описанную выше задачу удобно решить с использованием режима прерывания. Для этого мы должны подключить наш датчик к
58 Самоучитель по микропроцессорной технике входу 1NT процессора. Пока на вход INT не поступает никаких сигналов, процессор выполняет основную программу в обычном режиме. Когда антенна начнет вращаться, то в определенный момент времени срабатывает датчик поворота антенны. Сигнал от датчика поступает на вход запроса прерывания. Получив сигнал прерывания, процессор приостанавливает выполнение основной программы и выполняет переход к процедуре прерывания. Действия процессора в этом режиме очень напоминают работу процессора при переходе к подпрограмме. Различие только в том, что этот переход вызван не очередной командой программы, а внешним событием. Адрес, по которому в этом случае передается управление, называется вектором обработки прерывания. В нашем случае по этому адресу должна располагаться процедура обработки сигнала от датчика поворота антенны. Процедура обработки прерывания оканчивается командой выхода из прерывания. Действие этой команды почти полностью аналогично действию команды выхода из подпрограммы. Управление передается на ту команду программы, на которой произошло прерывание. Значение вектора прерывания в разных процессорах определяется по- разному. В одном случае используется фиксированный адрес в памяти. В другом, этот адрес определяется содержимым специального внутреннего регистра процессора и программист должен предусмотреть в своей программе команду записи в этот регистр нужного значения. Многие процессоры имеют сложный механизм определения вектора прерывания. Существуют даже специальные микросхемы — контроллеры прерываний, которые работают совместно с процессором и обеспечивают обработку не одного, а множества прерываний от разных устройств. Подведем итог. Прерывание — это специальный механизм, предусмотренный в микропроцессоре, который позволяет в любой момент, по внешнему сигналу заставить процессор приостановить выполнение основной программы, выполнить операции, связанные с вызывающим прерывание событием, а затем вернуться к выполнению основной программы. Таким образом, обеспечивается фоновый режим выполнения этой дополнительной задачи. Механизм прерываний широко применяется в компьютерной технике. Хороший пример задачи, решаемой при помощи прерывания, это работа манипулятора «мышь» персонального компьютера. Какую бы сложную программу не выполнял компьютер, но указатель свободно бегает по экрану, повинуясь движениям мыши. Часто даже на экране все остальное «зависло». Но указатель мыши живет. Мышь «зависает» только в крайнем случае. Все это происходит только благодаря тому, что мани-
Основы микропроцессорной техники 59 пулятор «мышь» работает по прерыванию. Когда вы перемещаете манипулятор по столу, внутри него вращаются специальные колесики. Связанный с ними диск с отверстиями, вращаясь, перекрывает инфракрасный луч от светодиода. Внутренний процессор, встроенный в манипулятор, подает цифровой сигнал на последовательный порт компьютера. Последовательный порт обнаруживает сигнал и вырабатывает запрос на прерывание для центрального процессора. Получив этот запрос, процессор прерывает выполнение основной программы и выполняет процедуру перемещения изображения «мышиного» курсора по экрану. Затем он возвращается к выполнению своей основной программы. Механизм прерывания в персональном компьютере используется очень широко. Кроме манипулятора «мышь» по прерыванию работают такие устройства, как клавиатура, жесткий диск, внутренние системные часы, порт принтера и некоторые другие. Прямой доступ к памяти Перед тем, как перейти к изучению конкретного процессора, рассмотрим еще одну систему, широко применяемую в больших компьютерах — систему прямого доступа к памяти. Как уже говорилось выше, в обычном режиме работы всей микропроцессорной системой управляет центральный процессор. Он отвечает за формирование адреса, на соответствующей шине, а также формирует управляющие сигналы RD, WR, MREQ и IORQ на шине управления. Режим прямого доступа к памяти — это тот случай, когда управление передается другому устройству. Этим устройством является контроллер прямого доступа к памяти. Режим прямого доступа применяется в тех случаях, когда нужно перенести большой блок информации из одной области памяти в другую. Второй случай, когда нужно с большой скоростью последовательно передать байт за байтом блок информации на один из портов ввода/вывода. Третий вариант, это когда, наоборот, требуется получить блок информации байт за байтом из порта ввода/вывода, и записать его в какую-нибудь область памяти. Под блоком информации подразумевается некоторая последовательность байтов, хранящихся в памяти в смежных ячейках. Хороший пример такой задачи — вывод текста на печать. Любой компьютер перед выво-
60 Самоучитель по микропроцессорной технике дом на печать сначала формирует специальный массив кодов, предназначенный для вывода на принтер. Этот массив содержит набор инструкций для печати нужного изображения. Затем подготовленный массив помещается в специальную область памяти, а дальше нужно просто последовательно выводить эти коды в порт принтера. Эту операцию можно прекрасно выполнить программным путем. Для этой цели можно создать программу вывода на печать, в которой для вывода кодов использовать оператор цикла. Для медленных устройств печати такой способ вполне приемлем. Однако, в том случае, если блок информации передается программным путем, нельзя достигнуть максимальной производительности, так как для вывода одного байта процессор должен выполнить 5-6 команд программы. Нужно считать из памяти очередной код, выдать его в порт, увеличить счетчик адреса на единицу, проверить, не достигнут ли конец блока. Затем повторить все для всех остальных байтов, составляющих этот блок информации. С появлением скоростных принтеров, такой способ оказался неприемлем. Для вывода информации на такой принтер применяется прямой доступ к памяти. Для передачи данных в режиме прямого доступа применяются специальные микросхемы — контроллеры прямого доступа к памяти (ПДП). На рис. 33 приведена схема подключения такого контроллера к микропроцессорной системе. Рис. 33. Подключение контроллера ПДП Микросхема контроллера ПДП — это программируемое устройство. В данном случае понятие «программируемое» означает то, что микросхема имеет внутри специальные регистры, которые подключаются к систем-
Основы микропроцессорной техники 61 ной шине, как порты ввода/вывода. Процессор может записывать в эти порты различные коды и тем самым менять режимы работы микросхемы. Так, процессор записывает в контроллер прямого доступа к памяти адреса начала и конца блока памяти, подлежащего передаче. Кроме того, таким же образом в микросхему ПДП записывается режим работы (выдать блок в порт / считать блок из порта / переместить блок в памяти). Для того, чтобы запустить процесс прямого доступа к памяти, центральный процессор должен сначала запрограммировать соответствующий контроллер. Затем процессор передает на контроллер команду запуска процесса ПДП, а сам переходит к выполнению других операций. Получив команду запуска, контроллер ПДП ждет специального сигнала с одного из специальных входов DRQ0...DRQ4 (см. рис. 33). В нашем случае сигнал запроса ПДП поступает от схемы параллельного интерфейса, который вырабатывает его при получении сигнала готовности от принтера. При получении сигнала запроса на ПДП, микросхема контроллера формирует сигнал запроса на захват (HOLD), который поступает на центральный процессор. Получив этот сигнал, процессор прерывает выполнение текущей программы и переходит в специальный режим прямого доступа к памяти. В этом режиме процессор полностью остановлен и отключен от системной шины. После того, как процессор готов к процедуре прямого доступа, он сообщает об этом контроллеру ПДП при помощи сигнала подтверждения захвата (HLDA). В режиме прямого доступа управление полностью берет на себя контроллер ПДП. Он сам вырабатывает сигналы адреса и сигналы управления (RD, WR, MREQ, IORQ). Таким образом, данные с максимальной скоростью передаются на принтер. По окончании процесса, контроллер ПДП отключается от системной шины и снимает с процессора сигнал HOLD. Процессор возобновляет свою работу в нормальном режиме. В любом персональном компьютере имеется несколько устройств, которые пользуются системой прямого доступа к памяти. В IBM совместимых компьютерах, к которым относится славное семейство «Пентиумов», существует четыре канала прямого доступа к памяти. Механизм ПДП, кроме принтеров, использует сетевые и звуковые карты, а также накопители на гибких и жестких дисках.
Микроконтроллер АТ89С2051 Структурная схема микроконтроллера В предыдущих главах мы рассмотрели общие принципы построения микропроцессорных систем. Дальнейшее обучение целесообразно проводить на примере конкретного микропроцессора. Итак, что же такое АТ89С2051. Это представитель семейства однокристальных микроконтроллеров американской фирмы ATMEL. Микросхема выполнена в стандартном DIP-корпусе и имеет 20 выводов. Напряжение питания микросхемы +5 В. Допускается разброс питающего напряжения от 2,7 до 6 В. Основное достоинство рассматриваемого микроконтроллера — это совместимость по системе команд с широко распространенной микросхемой фирмы Intel — MCS-51 (советский аналог 1816ВЕ51). Разработчики ставили задачу создать микросхему, максимально совместимую со своим аналогом, но при этом имеющую меньшие габариты и более удобную в применении. Для этого они отказались от двух из четырех портов ввода/вывода, отказались от внешнего ОЗУ данных и ПЗУ программ. В этой микросхеме вообще отказались от всех режимов, требующих внешних микросхем обвязки, встроили тактовый генератор в корпус контроллера и применили в качестве памяти команд электрически перепрограммирываемое ПЗУ, что дало возможность очень быстро и легко менять программное обеспечение. Применение системы команд популярного в свое время микропроцессора позволяет использовать для создания и отладки программ уже существующие инструментальные программные средства, такие, как программы-трансляторы и отладчики. Подробное описание инструментальных программ вы найдете в последнем разделе книги.
Микроконтроллер АТ89С2051 63 К достоинствам микросхемы АТ89С2051 относится наличие режима защиты программы пользователя от несанкционированного копирования. Если вы сами разрабатываете программу для микроконтроллера АТ89С2051, то, записав ее в программную память микросхемы, вы можете установить специальный бит защиты. После этого никто не сможет прочитать коды программы и использовать их для дублирования вашей разработки. Перечисленные выше достоинства, а также достаточно низкая стоимость A,5$) послужили причиной выбора именно этого процессора при разработке позиционера спутниковой антенны. На рис. 34 приведена структурная схема микроконтроллера АТ89С2051. Рассмотрим основные элементы схемы. Схема очень напоминает типовую схему микропроцессорной системы (см. рис. 29). Но имеются и существенные различия. Итак, по порядку. ППЗУ программ. Встроенное перепрограммируемое ПЗУ объемом 2 килобайта выполнено по технологии электрически стираемого ПЗУ (так называемая «Флэш-память»). В эту память записывается программа, которую микроконтроллер начинает выполнять сразу после включения питания и окончания сигнала сброса. Запись информации в ППЗУ программ производится при помощи специального устройства — программатора, управляемого персональным компьютером. Программатор последовательно, байт за байтом, записывает программу в ячейки ПЗУ, начиная с первой. На техническом жаргоне это называется «прошить ПЗУ». Технология флэш-памяти допускает перепрограммирование, то есть повторную запись. Для этого информацию в ППЗУ сначала стирают. Стирание производится при помощи того же самого программатора. При этом используется повышенное напряжение A2 В). Стирать можно только всю программную память целиком. Стирание отдельных частей памяти не предусмотрено. После стирания, во все ячейки программной памяти записывается число 0FFH (все биты равны единице). В стертое ППЗУ программ можно «зашивать» новую программу. Допускается 1000 циклов записи/стирания. Еще одна функция программатора — чтение записанной в ППЗУ информации. Этот режим введен для контроля правильности прошивки. Для исключения несанкционированного чтения информации, в микросхеме применена двухуровневая блокировка памяти программ. Для этого микросхема имеет два бита защиты. При помощи программатора мож-
64 Самоучитель по микропроцессорной технике но записать один или оба бита. После прошивки первого бита блокируется возможность перепрограммирования ППЗУ программ. При прошивке второго бита становится невозможным и чтение. Повторить чужую схему — дело не хитрое. А вот программу, придется создавать самому. Прочитать и затем тиражировать ее не удастся. Биты защиты очищаются в процессе полного стирания ППЗУ программ. Таймеры ОЗУ данных. Используется для хранения оперативных данных. Оно имеет 128 восьмиразрядных ячеек памяти. Как и в большинстве однокристальных микроЭВМ, в микросхеме АТ89С2051 применяется принцип совмещения ОЗУ данных с регистрами общего назначения процессора и портами ввода/вывода. Подробнее об этом мы поговорим позже. Внешняя память данных в рассматриваемой микросхеме не применяется. Порты Р1 и РЗ. Это два восьмиразрядных порта ввода/вывода. Они имеют названия Р1 и РЗ по аналогии с MCS-51. Там имелось четыре порта ввода/вывода, которые назывались РО, PI, P2 и РЗ. Поставив перед собой задачу сократить количество выводов до 20, конструкторы были вынуждены отказаться от двух портов ввода/вывода. Были исключены порты РО и Р2. Кроме того, порт РЗ теперь не полный. Линия Р3.6 не выходит ни на один из внешних выводов микросхемы и используется, как вход сигнала от встроенного аналогового компаратора. Рис. 34. Внутренняя структура микроконтроллера АТ89С2051
Микроконтроллер АТ89С2051 65 АЛУ. Арифметико-логическое устройство. Оно заменяет здесь центральный процессор. Дело в том, что АЛУ и есть центральный процессор в чистом виде. Центральный процессор, выполненный в виде отдельной микросхемы, отличается только тем, что имеет встроенные регистры для временного хранения данных. В нашем же случае регистры процессора совмещены с ячейками внутреннего ОЗУ. Таймеры. В микросхеме имеются два встроенных 16-разрядных таймера/счетчика Т1 и Т2. Они могут использоваться программистом для задания любых интервалов времени. Причем счетчик Т1 имеет режим работы, при котором он делится на два 8-разрядных таймера, каждый из которых может работать самостоятельно. Можно программно запустить и остановить любой из счетчиков. Каждый счетчик может работать в двух режимах: режиме отсчета временных интервалов (в этом случае они считают импульсы внутреннего тактового генератора), и в режиме подсчета внешних импульсов. В позиционере спутниковой антенны используются оба таймера. Один из них задает период динамической индикации, а второй используется в системе приема сигналов дистанционного управления. При этом оба счетчика работают в режиме отсчета времени. Последовательный канал. Это канал специального типа для последовательной передачи информации по одной линии (бит за битом по одному проводу). В любом компьютере всегда имеются два последовательных интерфейса (С0М1 и COM2). Один из этих интерфейсов раньше часто использовался для подключения манипулятора «мышь». А второй предназначен в основном для подключения модема. Подобный канал реализован в микросхеме АТ89С2051. В результате имеется возможность создания микропроцессорных устройств, управляемых при помощи компьютера по последовательному каналу. В позиционере спутниковой антенны данный канал не применяется. Встроенный контроллер прерываний. Способен обрабатывать шесть источников прерываний. Два источника — это внешне входы для запросов на прерывание. Следующие два источника — это прерывания от обоих счетчиков/таймеров Т1 и Т2. Запрос прерывания таймера поступает в тот момент, когда соответствующий счетчик/таймер досчитает до нуля (счетчик работает в режиме обратного счета). И, наконец, последние два источника прерывания — это прерывания от последовательного канала ввода/вывода. Один от передатчика этого канала. Он срабатывает в тот момент, когда процесс отправки очередного байта закончился. И один от приемника. Срабатывает, когда приемник принял очередной байт.
66 Самоучитель по микропроцессорной технике Аналоговый компаратор. Обычный компаратор аналоговых сигналов. На его выходе появляется сигнал лог. 1, когда напряжение на входе «+» превысит напряжение на входе «-». Внутренняя системная шина. По устройству и назначению полностью аналогична системной шине стандартной микропроцессорной системы. На схеме рис. 34 не показан еще один важный элемент микроконтроллера — встроенный тактовый генератор. На рис. 35 показана функциональная схема этого генератора. Для нормальной ее работы к выводам XTAU и XTAL2 необходимо подключить кварцевый резонатор, определяющий частоту тактового генератора и две согласующие емкости. Рис. 35. Внутренний генератор микросхемы АТ89С2051 Схема генератора построена таким образом, что допускает синхронизацию от внешнего тактового генератора. При включении микросхемы в таком режиме, кварцевый генератор и согласующие емкости не устанавливаются, а на вход XTAL1 подается тактовый сигнал от внешнего генератора. Микросхема АТ89С2051 относится к полностатическим системам. Это означает, что частота тактового генератора может выбираться в самом широком диапазоне. Максимально допустимая частота тактового генератора равна 24 МГц. Нижнего предела не существует. Частоту тактового генератора можно снижать вплоть до полной его остановки. При этом остановятся все внутренние процессы, в том числе и процесс выполнения программ. Но с первым же тактовым импульсом внутренние процессы продолжатся. Рассматриваемый микропроцессор, как и его аналог, не использует сигнал тактового генератора напрямую. Этот сигнал сначала поступает на внутренний делитель, который делит тактовую частоту на шесть (см. рис. 35). И уже этот поделенный сигнал служит для синхронизации всех
Микроконтроллер АТ89С2051 67 систем микроконтроллера. Наличие делителя — один из недостатков данной микросхемы. При максимально возможной тактовой частоте кварца в 24 МГц, микроконтроллер фактически работает на частоте 4 МГц. Такая структура обусловлена требованиями совместимости с микросхемой iMCS-51. Но, несмотря на относительно невысокое быстродействие, для многих применений микроконтроллер АТ89С2051 вполне подходит. Назначение выводов Рассмотрим теперь подробнее назначение выводов микросхемы АТ89С2051. На рис. 36 приведена цоколевка микросхемы. Некоторые пояснения к рисунку. Напряжение питания (Vcc) подается на вывод 20. Общий провод (GND) — вывод 10. Выводы XTAL1 и XTAL2 предназначены для подключения кварцевого резонатора (см. рис. 35.). Остальные выводы микросхемы — это разряды портов ввода/вывода (Р1 и РЗ). Каждая из линий порта может работать как выход или как вход без дополнительных переключений. Достигается это применением оригинальной схемы выходного каскада такой линии. Эта схема приведена на рис. 37. Рис. 36. Цоколевка микросхемы АТ89С2051 Каскад состоит из узла вывода и узла ввода, соединенных вместе и подключенных к внешнему выводу микросхемы, обозначенному на схеме «Рх.х». Узел вывода выполнен на основе каскада с общим коллектором, Нагрузкой этого каскада служит внутренний резистор RH. Если транзистор открыт, он замыкает цепь внешнего вывода на общий провод и на выходе устанавливается логический ноль. Если транзистор выходного каскада закрывается, то напряжение питания через резистор RH поступает на выход схемы, и на нем устанавливается логическая единица. Для того, чтобы перевести этот каскад в режим ввода, достаточно оставить
68 Самоучитель по микропроцессорной технике транзистор в закрытом состоянии. Соответствующий разряд порта ввода подключен в ту же самую точку. Внешнее устройство, подающее на линию порта логический сигнал, предназначенный для считывания процессором, также должно быть построено по схеме с общим коллек- тором^ На рис. 37 условно показана выходная часть такого устройства. ""Формировать выходные сигналы оно также должно, либо открывая свой выходной ключ и замыкая вывод микросхемы на общий провод (лог. 0), либо размыкая ключ (лог. 1). Рис. 37. Схема оконечного каскада линии ввода/вывода Выводы АТ89С2051, имеющие двойное назначение Таблица 2 Вывод микросхемы 2 3 6 7 8 9 12 13 Линия порта РЗ.О Р3.1 Р3.2 РЗ.З Р3.4 Р3.5 Р1.0 Р1.1 Альтернативная функция RXD (вход последовательного порта) TXD (выход последовательного порта) INTO (внешнее прерывание) FNT1 (внешнее прерывание) ТО (таймер 0, внешний ввод) Т1 (таймер 1, внешний ввод) AIN0 (прямой вход компаратора) AIN1 (инверсный вход компаратора) Мощность выходных ключей микроконтроллера АТ89С2051 допускает прямое подключение светодиодного индикатора к любому выходу портов Р0 или Р1. Многие выводы микросхемы АТ89С2051 имеют двойную функцию. Кроме своего основного назначения — служить выводами соответству-
Микроконтроллер АТ89С2051 69 ющего порта, они имеют альтернативную функцию. На рис. 36 альтернативные функции выводов обозначены в скобках. В табл. 2 перечислены все выводы, имеющие альтернативные функции. Рассмотрим подробнее перечисленные выше дополнительные функции выводов: RXD и TXD — соответственно, вход и выход последовательного канала. Как уже говорилось, последовательный канал — это канал передачи информации, где информация передается по одной линии. Вернее линий, как минимум, две. Одна — на передачу и одна — на прием. Каждый байт информации передается последовательно, бит за битом. Такой способ позволяет обойтись всего двумя проводами для приема и передачи любой информации (не считая общего провода) и уменьшить количество проводников в кабеле при подключении внешних устройств. Последовательный канал микросхемы АТ89С2051 поддерживает несколько стандартов последовательной передачи данных. Один из этих стандартов совместим с последовательным интерфейсом RS232. Любой современный персональный компьютер класса PC обязательно имеет два последовательных порта С0М1 и COM2, которые работают именно в этом стандарте. INTO и INT1 — два входа внешних прерываний. При помощи этих входов сигналы от любых внешних устройств в микропроцессорной системе (клавиш, датчиков и т.п.) могут обрабатываться контроллером в режиме прерывания. В схеме позиционера прерывания по внешним входам не применяются. ТО и Т1 — входы управления внутренними счетчиками/таймерами. Вход ТО управляет таймером ТО, а вход Т1 — таймером Т1, соответственно. В разных режимах работы таймеров эти входы действуют по-разному. В режиме отсчета времени, когда таймер считает импульсы внутреннего генератора, вход управления используется как внешний вход разрешения/запрета счета. В этом режиме высокий уровень сигнала на этом входе разрешает работу таймера, а низкий — запрещает. В режиме счетчика импульсов выводы ТО и Т1 служат входами импульсов для подсчета. AIN0 и AIN1 — входы внутреннего компаратора. Для нормальной работы компаратора в выходных каскадах двух этих выводов отсутствует резистор нагрузки R,, (см. рис. 37). Поэтому, при использовании входов по прямому назначению нужно подключать внешний резистор номиналом от 4,7 до 10 кОм. Двойное использование выводов микросхемы — очень распространенный прием в микропроцессорной технике, позволяющий иметь боль-
70 Самоучитель по микропроцессорной технике шое разнообразие выполняемых функций при минимальном количестве выводов. Как же можно использовать один вывод для двух разных целей? Для этого имеются два разных способа. Первый способ. Использовать разные режимы работы выводов в разных схемах. В одной схеме работать в основном режиме, в другой — в альтернативном. Разнообразие выполняемых функций придумано для того, чтобы обеспечить универсальность и гибкость в применении микроконтроллера. Ни одна схема никогда не использует полностью всех возможностей микросхемы. Второй способ — использовать в одной схеме оба назначения вывода, но в разные моменты времени. При этом нужно разработать схему таким образом, чтобы обеспечить при помощи внешних элементов автоматическое переключение соответствующего вывода от одной внешней цепи к другой. Управлять такими внешними переключателями можно программно, при помощи любого другого информационного вывода микросхемы. Для иллюстрации одновременного использования обоих режимов работы выводов микроконтроллера приведу фрагмент схемы реального устройства — контроллера управления газовыми котлами (см. рис. 38). Полную схему этого контроллера можно посмотреть, скачав ее из Интернета. Схему вы найдете на сайте «Цифровые микросхемы и микропроцессоры» в разделе «Простые конструкции». Адрес сайта приведен в конце книги. В этой схеме внутренний компаратор микросхемы АТ89С2051 используется для создания аналого-цифрового преобразователя (АЦП). Аналого-цифровой преобразователь служит для измерения напряжения на датчике температуры. В приводимой схеме задача решается от обратного. На основе регистра D5 собран цифро-аналоговый преобразователь (ЦАП), управляемый при помощи микроконтроллера. Передача данных на этот регистр происходит при помощи порта Р1. Одновременно, выводы 12 и 13 используются как входы встроенного компаратора. На вывод 13 (AIN1) поступает аналоговый сигнал от цифро-аналогового преобразователя. А на вывод 12 (A1N2) — измеряемый входной сигнал. Процесс измерения реализуется при помощи специальной программы. Для измерения уровня входного напряжения процессор записывает в регистр D5 последовательно возрастающие числа, начиная от нуля. В результате на инверсный вход компаратора с выхода ЦАП поступает постепенно возрастающее напряжение. После каждого шага процессор проверяет сигнал на выходе компаратора. Когда компаратор сработает, процесс преобразования останавливается, а последнее, записанное в D5, число будет соответствовать уровню входного напряжения.
Микроконтроллер АТ89С2051 71 Как видно из предыдущего повествования, выводы 12 и 13 процессора должны использоваться и как выводы порта Р1, и как входы компаратора. Для коммутации этих выводов в процессе работы применяется микросхема К561КТЗ. Она представляет собой четыре интегральных электронных коммутатора на основе полевых транзисторов с изолированным затвором. При подаче на вход Е такого ключа высокого логического уровня, ключ соединяет между собой выводы X и К. Причем направление тока через такое соединение может быть любое. Как от вывода X к выводу К, так и в обратном направлении. Рис. 38. Двойное использование выводов (фрагмент схемы) При помощи ключей D4.1 и D4.2 выводы 12 и 13 подключаются к шине данных в тот момент, когда процессор записывает какой-либо код в регистр D5, или в другие регистры системы (на схеме не показаны). При помощи ключа D4.3 к выводу 13 подключается выход ЦАП. Для коммутации измеряемого сигнала тоже используются электронные ключи, которые в данном фрагменте схемы также не показаны. Переключение ключевых элементов происходит программным путем при помощи линии РЗ.З и инвертора D8. Если процессор подает на линию РЗ.З сигнал логической единицы, то ключи D4.1 и D4.2 открываются, а ключ D4.3 закрывается. При этом, выводы 12 и 13 работают, как разряды порта. При нулевом сигнале на выходе РЗ.З, состояние ключей меняется на обратное. В этом случае, выводы 12 и 13 работают как входы компаратора.
72 Самоучитель по микропроцессорной технике Внутренние регистры Любой микропроцессор обязательно имеет в своем составе несколько внутренних регистров, которые он использует для хранения промежуточных данных. Микросхема АТ89С2051 не исключение. В связи с тем, что она является аналогом микросхемы MSC-51, то набор ее внутренних регистров полностью повторяет набор регистров MSC-51. На рис. 39 приведено схематическое изображение основных рабочих регистров микроконтроллера АТ89С2О51. Цифры в верхней части рисунка помогают понять, сколько разрядов имеет каждый из регистров, а также относительное расположение старших и младших разрядов. Из рисунка видно, что процессор имеет два шестнадцатиразрядных регистра: PC и DPTR, и четыре восьмиразрядных: А, В, PSW и SP. Шестнадцатиразрядный регистр DPTR может использоваться как два восьмиразрядных. Эти регистры имеют название DPH и DPL. Регистр DPH — это старшая половинка регистра DPTR. Она объединяет с 8 по 15 разряды своего родителя. Регистр DPL — младшая часть. Она объединяет с 7 по 0 разряды. Регистры А и В расположены рядом по той причине, что в некоторых случаях они работают совместно. Но они никогда не используются, как единый шестнадцатиразрядный регистр. Рассмотрим назначение и особенности применения каждого регистра. Рис. 39. Рабочие регистры микроконтроллера АТ89С2051 Регистр PC. Регистр — указатель адреса. В этом регистре всегда хранится адрес текущей выполняемой команды. В процессе выполнения программы микроконтроллер читает по этому адресу коды команд из памяти, выполняет их и увеличивает содержимое регистра. Команды условного и безусловного перехода, а также программы организации
Микроконтроллер АТ89С2051 73 цикла и перехода к подпрограмме записывают адрес перехода в регистр PC, осуществляя тем самым передачу управления. Регистр DPTR. Используется как регистр косвенной адресации в операциях пересылки данных из памяти программ в память данных и в специальной операции передачи управления. Что такое адресация и какие существуют виды адресации, мы рассмотрим в разделе, посвященном организации ОЗУ микроконтроллера. Регистр DPTR может также использоваться для промежуточного хранения шестнадцатиразрядных чисел. Кроме того, каждая из его половин может использоваться самостоятельно, как два обычных восьмиразрядных регистра. Регистр А (аккумулятор) и вспомогательный регистр В. Вся система регистров микроконтроллера АТ89С2051 относится к классу аккумуляторных. Это значит, что в системе регистров имеется специальный регистр, называемый аккумулятором. Особенностью этого класса регистров является то, что результаты большинства команд преобразования данных, таких, как арифметические, логические операции, операции сдвига и так далее, всегда помещаются в аккумулятор. В системах без аккумулятора, после кода операции нужно всегда указывать не только коды источников данных, но и код приемника результатов. Например, команда сложения двух чисел в такой системе обычно состоит из трех байт: КОП АДР1АДР2 Первый байт — это код операции сложения. Второй байт — адрес ячейки памяти или код регистра первого слагаемого. Третий байт — адрес ячейки или код регистра второго слагаемого. Сумма, обычно в таком случае, помещается в регистр (ячейку) АДР1. В аккумуляторной системе подобная команда будет состоять всего из двух байтов: кода операции и адреса второго слагаемого: КОПАДР1 Первое слагаемое всегда хранится в аккумуляторе. Туда же помещается и результат. Регистр аккумулятора традиционно обозначается буквой А. Он имеет восемь разрядов и именно поэтому процессор считается восьмиразрядным. При выполнении операций умножения и деления, в паре с аккумулятором участвует специальный вспомогательный регистр В. Для выполнения операции умножения один из множителей заносится в аккумулятор (А), а второй — во вспомогательный регистр (В). Результаты выполнения операции умножения заносятся в оба этих регистра. В регистр А — младшие восемь разрядов, а в регистр В — старшие.
74 Самоучитель по микропроцессорной технике Процесс деления происходит аналогично. Делимое заносится в А, делитель — в В. В результате деления в накопителе оказывается частное, а в регистре В — остаток от целочисленного деления. Большинство современных процессоров имеют систему регистров аккумуляторного типа. Регистр PSW. Регистр с таким названием вы также найдете в составе любого современного процессора. PSW — это так называемый регистр флагов. С одной стороны это обычный регистр. Процессор может, как читать из него информацию, так и записывать в него. Однако это не основное его назначение. На рисунке вы видите, что регистр разделен на отдельные биты. Каждый бит регистра PSW имеет самостоятельное значение. Каждый бит предназначен для хранения признака свершения какого-либо события. Поэтому эти биты называют системными флагами. Рассмотрим подробнее назначение каждого системного флага и те события, признаком которых они являются. Флаг CY — признак переноса. Если в процессе выполнения операции сложения (вычитания) возникает перенос из старшего разряда, то значение этого флага устанавливается в единицу. Зачем же нужен такой флаг? Дело в том, что в системе команд микроконтроллера АТ89С2051 для операций сложения и вычитания предусмотрены только такие команды, которые работают с двумя восьмиразрядными числами. Для того, чтобы сложить числа, имеющие 16, 32 и более разрядов, программист должен написать небольшую специальную программу, которая будет производить поэтапное сложение этих чисел. На первом этапе складываются младшие восемь разрядов обоих чисел. На втором — следующие восемь разрядов. Вот тут-то и учитывается бит переноса. Кроме того, флаг переноса может служить признаком отрицательного результата в операции вычитания. Флаг OV — служит для хранения признака арифметического переполнения результата. Флаг Р — хранит признак четности содержимого аккумулятора. Флаг АС — это флаг дополнительного переноса из младшей тетрады АЛУ в старшую (тетрада — это половинка байта — четыре бита). Два бита, обозначенные как RS, служат для определения текущего банка регистров общего назначения. Что такое регистры общего назначения и как они делятся на банки, мы рассмотрим чуть позже. Флаг F0 — отдан в полное распоряжение программиста. Здесь он может хранить любой признак, нужный ему по ходу выполнения программы.
Микроконтроллер АТ89С2051 75 Младший бит регистра PSW не используется. Значение любого флага можно использовать в качестве условия в операции условного перехода. Например, значение флага переноса используется для сравнения двух чисел. Для этого сначала из первого такого числа вычитают второе. В результате этой операции флаг переноса либо установится в единицу, либо сбросится в ноль. Это будет зависеть от того, какое из чисел окажется больше. Далее применяется оператор условного перехода по значению флага. Существует два таких оператора: «Перейти, если флаг установлен» и «Перейти, если флаг сброшен». Применение первого из этих операторов будет в этом случае эквивалентно переходу по условию «первое число меньше второго». Второй оператор будет означать переход по условию: «Первое число больше или равно второму». Большинство операторов условного перехода использует значения различных флагов. Размещение всех основных флагов в одном регистре позволяет легко сохранять их всех одной командой, где-нибудь во временной ячейке памяти. Например, на время действия программы обработки запроса на прерывание. К моменту поступления запроса на прерывание текущее значение флагов соответствует текущей выполняемой операции. В самом начале процедуры обработки прерывания необходимо предусмотреть команду сохранения текущего значения регистра PSW. В процессе выполнения процедуры обработки прерывания, состояние флагов непременно изменится. В конце процедуры должна быть предусмотрена команда восстановления значения PSW. Соблюдение этого условия гарантирует правильную работу условных операторов после выхода из прерывания. Регистр SP — указатель стека. На этом регистре нужно остановиться подробнее. Любой современный микропроцессор широко использует так называемую стековую память. Что же это такое? Стековая память — это особый способ организации памяти. По принципу магазина в автомате Калашникова. Сначала вы вкладываете в магазин патроны один за другим. А затем автомат извлекает их из магазина в обратном порядке. По принципу «первый вошел — последний вышел». Тот же принцип является основной идеологией стековой памяти. На рис. 40 схематично изображен процесс записи информации в стек и чтения из стека. Квадратиками обозначены ячейки памяти. Каждая из них хранит одно восьмиразрядное число. При записи информации в стек новый байт всегда помещается в самую первую ячейку стека. Одновремен-
76 Самоучитель по микропроцессорной технике но, содержимое этой ячейки, занесенное туда в предыдущем цикле записи, перемещается во вторую ячейку. Содержимое второй — в третью, и так далее. То есть, все содержимое стека сдвигается на один шаг вправо. Так можно делать до тех пор, пока все ячейки не заполнятся полезной информацией. На рис. 40 изображен стек, состоящий из шести ячеек (говорят — стек глубиной в шесть ячеек). Это значит, что в него без вреда можно записать последовательно шесть байт. При записи седьмого байта, вся информация в стеке снова сместится вглубь стека. В результате самый первый байт будет потерян. Поэтому при использовании стековой памяти всегда нужно следить, чтобы его глубина была достаточной. Процесс считывания информации из стека происходит в обратном порядке. В каждом цикле чтения, извлекается содержимое самой крайней ячейки памяти. Содержимое остальных ячеек сдвигается в обратную сторону так, что число из ячейки 2 переписывается в ячейку 1, из ячейки 3 — в ячейку 2, и т.д. В микропроцессорной технике стековая память используется очень широко. Обычно она применяется для временного хранения каких-либо данных, пока выполняется некая операция. Например, часто стоит задача — сохранить содержимое некоторых регистров процессора на время работы какой-либо подпрограммы или процедуры обработки прерывания. Для этого в начале подпрограммы помещают несколько операторов, последовательно сохраняющих содержимое всех важных Чтение из стека Рис. 40. Иллюстрация работы стековой памяти регистров в стековой памяти. После того, как регистры сохранены, подпрограмма может свободно использовать их для любых своих целей. В конце подпрограммы данные извлекаются из стека в обратном порядке и помещаются в те же самые регистры. Запись в стек
Микроконтроллер АТ89С2051 77 Типичный набор инструкций, с которых начинается любая подпрограмма, выглядит следующим образом: • занести содержимое регистра А в стек; • занести содержимое регистра В в стек; • занести содержимое регистра PSW в стек. Затем идут команды, составляющие тело подпрограммы. Заканчивается подпрограмма рядом команд восстановления регистров: • извлечь из стека число и поместить в регистр PSW; • извлечь из стека число и поместить в регистр В; • извлечь из стека число и поместить в регистр А. Еще раз обращаю внимание, что восстановление регистров идет в порядке обратном порядку их записи. Реальный механизм реализации стековой памяти любого современного микропроцессора немного отличается от схемы, изображенной на рис. 40. Стек организуется в обычной памяти данных. Для этого и применяется регистр — указатель стека (SP). В начале работы программы в этот регистр необходимо записать некий начальный адрес, называемый «вершина стека». Это тот адрес, по которому будет записываться самое первое число, посылаемое в стек. В системе команд процессора имеется две специальные команды работы со стеком. Это команда записи в стек и команда извлечения из стека. Рассмотрим подробнее, как процессор выполняет эти команды. По команде записи в стек процессор записывает информацию в ячейку, адрес которой хранится в регистре SP, а затем увеличивает содержимое SP на единицу. Если теперь снова подать команду записи в стек, то новое число запишется уже по новому адресу, а содержимое указателя стека еще раз увеличится на единицу. По команде чтения из стека процессор сначала уменьшает содержимое регистра указателя стека на 1, а затем читает байт по этому адресу. В результате такой последовательности действий, процессор читает именно тот байт, который был записан последним. Как нетрудно убедиться, добавляя всего один лишний регистр, мы получаем возможность организовать стековую память, используя обычную память процессора. Преимущество такого построения в том, что, меняя начальный адрес вершины стека (то есть содержимое регистра SP), мы можем использовать для стековой памяти любую область ОЗУ. Необходимо лишь
78 Самоучитель по микропроцессорной технике следить за тем, чтобы для стека было отведено достаточное пространство. И это пространство не использовалось бы для других целей. Кроме регистров, показанных на рис. 39, микроконтроллер АТ89С2051 имеет еше несколько видов внутренних регистров. Специальные регистры, предназначенные исключительно для хранения промежуточных данных, называются регистрами общего назначения (сокращенно РОН). На рис. 41 схематично изображены эти регистры. Рис. 41. Регистры общего назначения Описываемый микроконтроллер имеет 32 регистра общего назначения. Но они не могут использоваться все одновременно. Регистры разделены на четыре части — так называемые банки регистров. В каждый момент времени включен только один из банков. Если включен банк О, то программе доступны первые восемь регистров. Программа обращается к ним по именам RO, Rl, R2 ... R7. Регистры общего назначения могут использоваться программистом для хранения любых промежуточных значений наравне с ячейками памяти (ОЗУ). Однако любые команды, в которых участвуют регистры общего назначения, занимают места в программной памяти меньше, чем аналогичные команды с ячейками ОЗУ. Возьмем, например, команду пересылки числа из регистра в аккумулятор. Эта команда кодируется всего одним байтом. Для каждого из восьми РОН имеется свой отдельный код операции. Аналогичная команда пересылки из ячейки ОЗУ в аккумулятор кодируется двумя байтами. Первый байт — это код операции, а второй — адрес ячейки ОЗУ. Поэтому любой программист всегда старается использо-
Микроконтроллер АТ89С2051 79 вать РОН для хранения самых часто используемых данных. И лишь в том случае, когда все регистры уже заняты, используют ОЗУ. Переключение банков РОН расширяет объем доступной регистровой памяти. Специальной команды на переключение банков не существует. За выбор одного из банков отвечают два специальных бита в регистре PSW. На рис. 39 эти биты обозначены, как поле RS. Двухразрядное двоичное число, записанное в это поле, равно номеру активного банка РОН. Для того, чтобы включить тот или иной банк, нужно в регистр PSW записать такое число, у которого два средних бита соответствуют номеру выбранного банка. Как это сделать, показано в табл. 3 (символом «X» отмечены те разряды, которые могут иметь любое значение). Переключение РОН Таблица 3 Выбираемый банк БанкО Банк 1 Банк 2 БанкЗ Число в регистре PSW ХХХООХХХ ХХХ01ХХХ хххюххх ХХХ11ХХХ Если включить банк 1, то, как и прежде, процессор будет обращаться к восьми регистрам общего назначения, имеющим имена R0...R.7, используя при этом те же самые команды. Однако это будут совсем другие регистры. Значения, записанные в регистры банка 0, останутся в полной сохранности. Затем можно выбрать банк 2, и, наконец, банк 3. В результате, при неизменном количестве базовых команд, мы получаем возможность в четыре раза расширить количество применяемых регистров. На практике разные банки РОН закрепляются за разными процедурами. Например, основная программа работает с банком 0. Какая-нибудь крупная подпрограмма с большим количеством расчетов работает с банком 1. Одна из процедур обработки прерывания работает с банком 2, а вторая процедура — с банком 3. При использовании разных банков РОН нужно внимательно следить за всеми переключениями банков. Если при входе в какую-либо процедуру вы подали команду на выбор другого банка, то перед выходом из этой процедуры не забудьте восстановить старое значение выбора банка. Для этого достаточно в начале процедуры, перед тем как менять банк, сохранить значение регистра PSW в стековой памяти, а перед тем как закончить процедуру, нужно восстановить значение PSW.
80 Самоучитель по микропроцессорной технике Внутреннее ОЗУ контроллера Рассмотрим теперь структуру внутренней памяти данных (ОЗУ) микроконтроллера АТ89С2051. Для адресации любой ячейки памяти в микроконтроллере используется 1 байт адреса. Очевидно, что в этом случае ОЗУ может иметь не более 256 ячеек памяти. Используемая в позиционере версия микросхемы AT89C2051-24PI имеет всего лишь 128 ячеек. Эти ячейки занимают адресное пространство от ООН до 7FH. Выше этого диапазона ячеек памяти, в общем-то, нет. Однако адресное пространство от 80Н до FFH тоже используется. Дело в том, что в микроконтроллере АТ89С2051, как и во многих аналогичных микросхемах, реализован принцип совмещения внутренних регистров и ячеек памяти. Все внутренние регистры, являются одновременно и ячейками памяти. На рис. 42 показано адресное пространство микроконтроллера АТ89С2051. Такие рисунки часто используются для наглядной иллюстрации распределения памяти. На рис. 42 все адресное пространство представлено в виде клеточек. Каждый ряд и каждая строка этой таблицы обозначена одной шестнадцатеричной цифрой. Цифра в названии ряда — это старший разряд шестнадцатеричного адреса. Младший разряд — это название строки. Таким образом, левая верхняя клеточка на рисунке соответствует ячейке памяти с адресом ООН. Следующая по порядку ячейка имеет адрес 01Н, и так далее. Последняя ячейка в строке — это ячейка с адресом 0FH. Таким же образом определяются адреса для всех остальных строк. Серым цветом на рисунке обозначены те адреса, по которым имеется реальная память. Это либо ячейка памяти, либо один из регистров. Совмещение регистров процессора с ячейками ОЗУ имеет большие преимущества. Такой способ позволяет обращаться к любому регистру общего назначения напрямую, без переключения банков. Это увеличивает гибкость всей системы. Регистры общего назначения занимают в адресном пространстве ОЗУ ячейки с ООН по 1FH. На рис. 42 регистры нулевого банка обозначены без штриховки, регистры банка 1 обозначены с одним штрихом, банка 2-е двумя штрихами, и банка 3-е тремя. В адресном пространстве ОЗУ расположены также и все основные рабочие регистры процессора (те самые регистры, которые изображены на рис. 39). Все они располагаются во второй части этого пространства, в той его части, где отсутствуют ячейки основного ОЗУ. В этой же части вы можете видеть целый набор дополнительных регистров. Они имеют название «специальные регистры». О специальных регистрах мы поговорим в следующем разделе.
Микроконтроллер АТ89С2051 81 Рис. 42. Распределение адресного пространства памяти данных микроконтроллера АТ89С2051 Еще одна особенность микросхемы АТ89С2051 — наличие ячеек памяти с побитной адресацией. Система команд микроконтроллера имеет команды работы с битовыми ячейками памяти. Это команды типа «записать бит по адресу такому-то» и «прочитать бит по адресу такому-то». Для подобных команд контроллер имеет свое отдельное адресное пространство. Диапазон адресов битовой памяти: 00H...FFH. Однако все эти однобитовые ячейки памяти тоже совмещены с ячейками ОЗУ. Каждая ячейка однобитной памяти является одновременно одним из разрядов какой-нибудь ячейки ОЗУ. Например, ячейка однобитовой памяти с адресом ООН является одновременно младшим битом ячейки ОЗУ с адресом 20Н.
82 Самоучитель по микропроцессорной технике Посмотрите на рис. 42. В нижней части каждой ячейки памяти, которая совмещена с битовым пространством, указан диапазон адресов составляющих ее ячеек битовой памяти. Так, в нижней части ячейки, с адресом 20Н вы можете видеть следующую запись: 00-07. Эта запись означает, что с указанной ячейкой памяти совмещены восемь однобитовых ячеек с адресами от ООН до 07 Н. Под однобитовую память, выделен весь ряд, начиная с адреса 20Н, а также почти все специальные регистры. Говоря о памяти данных, хочу затронуть такой вопрос, как способы адресации памяти. В командах микропроцессора адрес ячейки памяти может задаваться четырьмя разными способами. В зависимости от метода задания адреса различают следующие виды адресации: регистровый, прямой, косвенный и непосредственный. Регистровый способ адресации. Команды, использующие этот способ адресации, обращаются только к регистрам процессора. Такие команды состоят лишь из кода операции, в который заложена информация и о виде операции и о том, какие регистры в ней участвуют. Прямой способ адресации. При этом способе адрес ячейки памяти указывается в самой команде в виде дополнительного байта. Команда состоит из двух байтов. Первый байт — это код операции, а второй байт — это адрес, участвующей в ней ячейки памяти. Косвенный способ адресации. При таком способе адресации адрес ячейки памяти сначала помещается в один из регистров. А затем можно включать в программу одну из команд, использующую этот вид адресации. В качестве регистров для косвенной адресации могут быть использованы только регистры R0 и R1. Непосредственная адресация. При таком способе адресации информация вообще не хранится ни в памяти, ни в регистрах. Байт данных в этом случае является частью самой команды. Такая команда состоит из двух или даже из трех байтов. Один из этих байтов — это данные для расчета. Пример такой команды — команда записи константы в ячейку памяти. Записывается она следующим образом: MOV ЗОН, #27Н Получив такую команду, процессор записывает в ячейку памяти с адресом ЗОН байт данных, имеющий значение 27Н. Если записать эту команду в кодах процессора, то она будет представлять собой три байта: 75Н ЗОН 27Н. Первый байт — это код данной операции. Второй байт — это адрес ячейки памяти, куда требуется записать константу. А третий байт — это и есть та самая константа. В приведенной команде используются сразу два способа адресации. Во-первых, прямая (ЗОН — прямой
Микроконтроллер АТ89С2051 83 адрес ячейки памяти). И, во-вторых, непосредственная B7Н — это константа, указанная непосредственно в самой команде). Специальные регистры Еще один вид регистров, входящих в состав микроконтроллера АТ89С2051, это специальные регистры. На эти регистры вы могли обратить внимание, когда разглядывали схему адресного пространства микроконтроллера (рис. 42). Специальные регистры, как и все остальные регистры микроконтроллера, совмещены с ячейками ОЗУ и входят в адресное пространство памяти данных. Что же такое — специальные регистры, и для чего они нужны? При помощи этих регистров происходит управление режимами работы всех встроенных системных ресурсов микроконтроллера, таких, как система прерываний, встроенные счетчики-таймеры, последовательный канал связи. К специальным регистрам также можно отнести порты ввода/вывода. На рис. 43 схематически изображены все специальные регистры микросхемы АТ89С2051. Большинство из этих регистров одновременно расположены и в битовом пространстве памяти и поэтому допускают прямой доступ к каждому своему биту. В этом случае каждый бит регистра отвечает за свою собственную функцию и имеет свое название. Исключение составляют порты ввода/вывода Р1 и РЗ. Они тоже поддерживают возможность доступа к каждому биту, но разряды портов не несут никакой дополнительной нагрузки, кроме задач ввода и вывода информации. Справа от изображения каждого регистра показано его название и адрес, который этот регистр занимает в общем адресном пространстве ОЗУ. Регистры ТО и Т1 — это шестнадцатиразрядные регистры. Каждый из них служит хранилищем текущего значения соответствующего счетчика-таймера. В адресном пространстве ОЗУ каждый из этих двух регистров занимает две ячейки памяти. Каждая такая половинка шестнадцатиразрядного регистра имеет свое название. Таким образом, мы имеем дело с регистрами THO, TLO, TH1, TL1. На рис. 43, под каждым из этих названий, указан адрес соответствующей ячейки памяти, указаны также адреса каждого бита, входящего в- битовое пространство контроллера. Эти адреса вы можете видеть в нижней части квадратика, символизирующего соответствующий бит. Следует заметить, что все названия регистров — вещь чисто теоретическая. Они предназначены для языка Ассемблера, на котором чаще всего пишутся программы для микроконтроллера. При написании программы удобнее обращаться к регистру по его имени. Однако в системе команд
84 Самоучитель по микропроцессорной технике контроллера отсутствуют специальные команды обращения к регистрам. Запись информации в любой из специальных регистров, так же как и чтение из него, происходит при помощи команд записи в ячейку памяти и чтения из ячейки памяти. Рис. 43. Схема специальных регистров микроконтроллера АТ89С2051 Рассмотрим назначение специальных регистров подробнее. Р1, РЗ — порты ввода/вывода. С точки зрения процессора любой из этих двух портов — это обычная ячейка памяти. Процессор может записать в него любое число, может также считать число из порта. Записанное в порт число, немедленно появляется на соответствующих выводах микросхемы (см. рис. 36). Чтение из порта также происходит обычным образом. Необходимо только помнить следующее условие: если вы желаете прочитать значения внешних сигналов, подаваемых на линии порта, не забудьте предварительно записать в соответствующий порт число 0FFH (то есть логические единицы во все разряды). Для чего это нужно, мы уже рассматривали ранее. Кроме того, возможны программные сброс или установка каждой отдельной линии порта при помощи битовых операций.
Микроконтроллер АТ89С2051 85 Два регистра, обслуживающие встроенный последовательный канал связи: Регистр SBUF. Это регистр данных последовательного канала. Для передачи информации из микроконтроллера на внешнее устройство, в него помещают передаваемый байт и затем запускают процесс передачи. В режиме приема в этот регистр помещается принятый байт. Регистр SCON. Предназначен для выбора режимов последовательного порта. В связи с тем, что в схеме позиционера последовательный канал не применяется, мы опустим подробности его настройки. Тех читателей, кого этот вопрос все же интересует, отсылаю к подробному описанию микроконтроллера К1816ВЕ51 (или iMCS-51), которое можно скачать, например, на сайте «Цифровые микросхемы и микропроцессоры» в разделе «Справочные материалы». В основном все сказанное относительно К1816ВЕ51 справедливо и для АТ89С2051. Там же вы найдете и другой документ, где описаны все отличия этих двух контроллеров. Адрес сайта смотрите в конце этой книги. Четыре регистра управления счетчиками-таймерами: Регистры ТО и Т1. Каждый из них предназначен для хранения текущего значения соответствующего счетчика. Собственно, эти регистры и есть те самые счетчики-таймеры. Для организации работы какого-либо из таймеров, нужно программным путем записать начальное значение в соответствующий регистр. В процессе работы счетчика происходит постепенное уменьшение значения его содержимого. Процесс счета может происходить как под воздействием импульсов от внутреннего тактового генератора (в режиме таймера), так и под воздействием внешних импульсов, подаваемых на специальные входы, которые называются ТО и Т1 — вывод 8 и 9 (см. табл. 2). Процесс счета продолжается до тех пор, пока содержимое регистра ТО (или Т1) не достигнет нулевого значения. Затем наступает переполнение счетчика. Сигнал переполнения используется в качестве сигнала запроса на прерывание. Регистр TMOD. Используется для установки режима работы обоих таймеров. Его младшие четыре бита, имеющие отдельное название T0MOD, определяют режим работы таймера ТО. Старшие четыре разряда, именуемые T1M0D, определяют режим работы таймера Т1. Каждый из счетчиков-таймеров имеет четыре основных режима работы, различающихся алгоритмами счета и количеством используемых разрядов. Эти режимы имеют названия «Режим 0», «Режим 1», «Режим 2» и «Режим 3». Режим 0, например, совместим с более ранними версиями этой линии микроконтроллеров. Он использует только 13 разрядов счетчика-таймера. Режим 1 использует все 16 разрядов. В режиме 2 соответ-
86 Самоучитель по микропроцессорной технике ствующий таймер делится на две части по 8 разрядов в каждом. Младшие восемь разрядов используются как таймер, а в старших — хранится коэффициент пересчета. В процессе счета, при достижении нулевого значения, происходит автоматическая загрузка коэффициента пересчета из старших битов в младшие. В результате таймер превращается в делитель с переменным коэффициентом деления (подобный тому, что мы рассматривали ранее, см. рис. 24). В режиме 3 счетчик-таймер ТО разделяется на два независимых восьмиразрядных счетчика. Таймер- счетчик Т1 в режиме 3 просто останавливается. Биты МО и Ml регистра TMOD используются для выбора одного из четырех режимов соответствующего счетчика-таймера. Их содержимое представляет собой двоичное число, соответствующее номеру выбранного режима. Бит С/Т служит для переключения вида входного сигнала. Если бит С/Т равен 0, то соответствующий счетчик-таймер выполняет функцию таймера. Если же С/Т равен 1, то реализуется функция счетчика. В режиме таймера в качестве тактовых импульсов используются внутренние тактовые импульсы (OSC) пропущенные через специальный делитель частоты с коэффициентом деления, равным 12. Как мы знаем, импульсы внутренней синхронизации OSC получаются в свою очередь путем деления частоты тактового генератора микросхемы на 6 (см. рис. 35). Внешние входы ТО и Т1, при этом, используются как стробирующие входы, для приостановки и последующего пуска таймеров. Если на вход ТО (Т1) подан высокий логический уровень, то счет разрешен. Если низкий, то приостановлен. Управляющий бит GATE регистра TMOD служит для программного включения и выключения режима стробирования. Регистр TCON служит для оперативного управления обоими таймерами-счетчиками, а также режимами работы входов INTO, INT1 запроса внешних прерываний (см. табл. 2). Такое управление происходит программным путем. Биты IT0 и IT1 управляют режимами работы внешних входов, соответственно, INTO, INT1. Если сбросить один из этих битов в ноль, то соответствующий внешний вход станет динамическим и будет работать по срезу входного импульса. При установке этого бита в единицу, соответствующий вход станет статическим. Биты IE0 и IE1 — это флаги прерываний по INTO, INT1. При поступлении запроса на прерывание соответствующий флаг устанавливается
Микроконтроллер АТ89С2051 87 в единицу. В тот момент, когда контроллер приступит к обслуживанию запроса, флаг автоматически сбрасывается. Флаг прерывания автоматически устанавливается в единицу при переполнении соответствующего таймера-счетчика, и дает возможность программной проверки факта появления такого запроса. Биты TR0 и TR1 служат для программного запуска/останова таймеров- счетчиков. Каждый из этих битов управляет своим таймером. И, наконец, биты TF0 и TF1 — это флаги прерывания по переполнению таймера. В момент перехода контроллера к обработке прерывания соответствующий флаг автоматически сбрасывается. Два регистра системы прерываний микроконтроллера: Регистр IE — это так называемый регистр маски прерываний. Система обработки прерываний контроллера имеет пять источников прерываний: прерывания при переполнении одного из таймеров, прерывания от одного из двух внешних входов INTO или 1NT1, а также прерывание по последовательному каналу. Каждый из этих источников может быть замаскирован (ударение на букву 'и). В данном случае «замаскирован» означает — отключен. Каждый из пяти младших битов регистра IE предназначен для маскирования своего источника прерываний. Сброс одного из этих битов в ноль отключает соответствующий источник. Установка бита в единичное состояние включает соответствующее прерывание. Самый старший бит маскирует всю систему прерываний сразу независимо от состояния остальных битов. Регистр IP — это регистр приоритетов. Что такое приоритеты и зачем они нужны? Дело в том, что все источники прерываний действуют абсолютно независимо друг от друга. Поэтому вполне возможна ситуация, когда в систему прерываний контроллера одновременно поступают два, три или все пять запросов от разных источников. Какой из них выполнять первым? Или другая ситуация: процессор еще не окончил процедуру обработки прерывания от одного источника, а тут поступает запрос от второго. Что делать? Временно прервать обработку первого запроса и перейти ко второму? Либо сначала закончить работу с текущим запросом? Все эти вопросы разрешаются путем присвоения уровня приоритета каждому из возможных источников прерываний. В описываемом микроконтроллере имеется всего два уровня приоритетов. Каждый из пяти младших битов регистра IP хранит уровень приоритета одного из источников. Если какой-либо из этих битов сбро-
88 Самоучитель по микропроцессорной технике шен в ноль, то у соответствующего источника низкий уровень приоритета. Если наоборот, он установлен в единицу, то приоритет высокий. Прерывание с высоким уровнем приоритета не может быть прервано никаким другим. Если оба прерывания имеют одинаковый приоритет, то используется схема вторичного арбитража. В соответствии с этой схемой, каждому из источников прерываний*установлен свой фиксированный уровень приоритета (см. табл. 4). Фиксированные уровни приоритетов Таблица 4 Источник прерываний Внешний вход INTO Счетчик-таймер ТО Внешний вход INT1 Счетчик-таймер Т1 Последовательный канал Приоритет 0 (высший) 1 2 3 4 (низший) Регистр PCON. Это регистр управления питанием. Установка в единичное состояние его младшего бита ADL) переводит процессор в режим ожидания. В этом режиме процессор прекращает выполнять основную программу, но может выполнять прерывания. В результате происходит частичное снижение уровня потребляемой энергии. Установка в единицу бита PD переводит процессор в режим пониженной мощности. В этом режиме все внутренние процессы прекращаются, внутренний тактовый генератор выключается. Потребление мощности практически снижается до нуля. Процессор как бы «засыпает». Выход из этого режима возможен только по сигналу общего сброса процессора. На этом я хочу пока закончить общее описание специальных регистров микроконтроллера АТ89С2051. Подробнее об использовании этих регистров мы поговорим на конкретных примерах, когда будем изучать управляющую программу позиционера спутниковой антенны. Система команд и язык Ассемблера В предыдущих разделах мы уже не раз, так или иначе, касались вопроса о системе команд микроконтроллера АТ89С2051. Системой команд называют полный набор всех команд, которые выполняет конкретный микропроцессор с их исчерпывающим описанием. Ясно, что, не зная какие команды способен выполнять контроллер, невозможно присту-
М икроконтроллер АТ89С2051 89 пать к проектированию программ. Однако в этой книге я хочу подойти к вопросу изучения системы команд микроконтроллера нестандартным образом. Из собственного опыта я знаю, что изучать систему команд проще всего на примере конкретной программы. Поэтому в данном разделе я ограничусь лишь общим описанием команд. Непосредственно же команды микроконтроллера мы будем изучать при рассмотрении управляющей программы позиционера спутниковой антенны. При этом, естественно, не все команды микроконтроллера будут рассмотрены. Однако полученного объема информации вам вполне хватит для того, чтобы разобраться с остальными командами. Полный перечень команд микропроцессора с кратким их описанием приведен в приложении в конце этой книги. Изучение команд микропроцессора тесно связано с таким понятием, как язык Ассемблера. Поясню вкратце, что это такое. Дело в том, что программисты никогда напрямую не работают с кодами команд. Человеку трудно запоминать сухие цифры. Для облегчения труда программиста и придуманы различные языки программирования. Язык Ассемблера — один из них. Именно на Ассемблере чаще всего пишутся программы для микропроцессоров. Основная идея Ассемблера — заменить коды команд некими короткими емкими словами, отражающими суть выполняемой операции так, чтобы их легче было запомнить. Эти слова еще называют «мнемокодами». Например, все команды пересылки байта из одной ячейки в другую обозначаются мнемокодом «MOV». От английского слова Move — перемещать. Команда сложения обозначается «ADD», вычитания «SUBB». Для того, чтобы создать программу для микропроцессора, программист сначала пишет текст программы, придерживаясь правил выбранного языка. Для написания этого текста он использует обыкновенный текстовый редактор. Готовый текст записывается на диск в виде текстового файла. Затем он запускает специальную программу — транслятор с языка Ассемблера. Эта программа читает текст, написанный программистом, и автоматически переводит каждую команду в ее код. В результате получается именно тот набор кодов, который и должен быть записан в программную память микроконтроллера. Результат транслирования также записывается на диск компьютера в виде файла. Теперь остается только перенести этот набор чисел в программную память -конкретной микросхемы микроконтроллера. Такая операция называется программированием или прошивкой программной памяти. Для прошивки микроконтроллеров применяются специальные устройства, называемые программаторами. Программаторы подключаются к персо-
90 Самоучитель по микропроцессорной технике нальному компьютеру и управляются при помощи специальной программы. Существуют специализированные программаторы, предназначенные для прошивки программной памяти только одного вида микроконтроллеров. Кроме того, бывают программаторы универсальные. Универсальный программатор позволяет программировать несколько видов микросхем. Для этого такие программаторы имеют несколько режимов работы. Универсальные программаторы сложнее и дороже специализированных. В главе 3 приведен пример простейшего программатора для прошивки программной памяти микроконтроллера АТ89С2051. При создании программ для микроконтроллеров и микропроцессоров, кроме Ассемблера, применяют и другие языки программирования. Например, существует специальная версия языка С («Си») для микропроцессоров. Но в этой книге мы будем учиться программировать исключительно на языке Ассемблера. Язык Ассемблера, как и любой другой язык, имеет свои правила правописания. Существует свой синтаксис и орфография. Приведем основные правила языка Ассемблера: • Каждая команда программы пишется в отдельной строке. ¦ Каждая строка разбивается на четыре поля, образующие четыре колонки. ¦ У каждого поля свое назначение: • Первое поле — поле метки (что такое метка рассмотрим позже). • Второе поле — поле команды (мнемокода). • Третье поле предназначено для параметров команды. • Четвертое поле — поле комментариев. Заполнять это поле не обязательно. Оно занимает пространство до конца страницы. Сюда, если нужно, можно поместить комментарии к команде. Для того, чтобы транслятор отличал комментарий от самой программы, в начале комментария необходимо поставить символ «точка с запятой». Этот символ называют признаком комментария. Встретив признак комментария, транслятор прекращает дальнейшую обработку строки и переходит к обработке следующей. В результате все, что стоит после точки с запятой до конца текущей строки игнорируется. Большинство из перечисленных выше правил исходят из соображений наглядности и читаемости программы. Но все же я советую их обязательно соблюдать. Рассмотрим пример написания одной строки программы на языке Ассемблер. В качестве примера возьмем комадцу, логика работы которой
Микроконтроллер АТ89С2051 91 может быть описана следующим образом: «переместить содержимое регистра R0 в аккумулятор». Строка программы, реализующая эту команду, выглядит следующим образом: MOV A.R0 ; Это команда перемещения из R0 в аккумулятор Как мы видим, первое поле в данном случае пустое. То есть, в приведенной строке отсутствует метка. Во втором поле записан мнемокод команды. Это самый распространенный оператор языка Ассемблера — MOV. В третьем поле записаны параметры команды. Команда MOV имеет два параметра. В Ассемблере параметры команд принято записывать через запятую. Для улучшения внешнего вида и придания тексту индивидуального стиля можно вставлять как до, так и после каждого из параметров любое количество пробелов. В рассматриваемой команде в качестве параметров выступают имена источника и получателя информации. По принятым в Ассемблере соглашениям во всех подобных командах параметры записываются в следующем порядке: сначала записывается имя приемника информации («куда переместить»), а затем имя источника («откуда взять»). В четвертом, последнем поле рассматриваемого примера помещен комментарий. Начинается комментарий, как уже говорилось, с символа «точка с запятой». При помощи комментариев программист дает пояснения к программе прямо в ее тексте. Комментарии — это абсолютно необходимый элемент любого языка программирования. Они нужны не только для того, чтобы пояснить назначение той или иной команды любому желающему, но и для самого программиста, чтобы он не запутался в собственной программе. Комментарий можно записать также в виде отдельной строки. В этом случае разбиение на поля не обязательно. Можно поставить точку с запятой в начале строки. Тогда комментарием будет служить вся строка. Теперь, наконец, пришло время узнать, что такое метка и как она используется. Посмотрите на следующий фрагмент программы: metli MOV A,R0 ; Это команда перемещения из R0 в накопитель SUBB А,#25 ; Увеличение содержимого накопителя на 25 ЫМР metl ; безусловный переход по метке Это довольно бессмысленный набор команд, предназначенный служить примером применения метки. Как мы видим, вначале первой строки приведенного фрагмента стоит метка metl. Метка оканчивается символом «двоеточие». Этот символ означает, что перед нами именно метка, а не какая-либо другая команда. Наличие либо отсутствие метки никак
92 Самоучитель по микропроцессорной технике не изменяет смысл команды, записанной в той же самой строке. Метка служит только для того, чтобы другие команды могли ссылаться на помеченную команду. В нашем примере первая команда вызовет пересылку числа из регистра R0 в аккумулятор. Вторая команда увеличит содержимое аккумулятора на 25. Третья команда — это команда безусловного перехода. Она передает управление в начало нашего фрагмента. В кодах процессора такая команда представляет собой три байта. Первый — это код операции безусловного перехода. Второй и третий байты — это адрес, куда будет передано управление. Адрес в программной памяти определяется 16-разрядным двоичным числом, поэтому для его записи требуется два байта. Значение этих байтов равно адресу ячейки памяти, в которой хранится код команды MOV, соответствующей первой строке рассматриваемого фрагмента. Вместо того, чтобы ставить в программе конкретный адрес перехода в языке Ассемблера, принято использовать для этого имя метки. Транслятор сам вычислит значение метки и подставит полученные коды. Такой подход позволяет не привязываться к конкретным адресам. В результате увеличивается гибкость программы. Можно легко переместить любой фрагмент программы из одного участка программной памяти в другой, ничего не изменяя в его тексте. Теперь метка будет означать совсем другой адрес. Однако это никак не повлияет на правильность трансляции программы. Имена всех меток определяется программистом произвольным образом, но с некоторыми ограничениями. Это имя должно состоять только из букв латинского алфавита и цифр. Первым символом в имени всегда должна быть буква. Пробелы, дефисы и знаки препинания не допускаются. Единственным исключением является символ подчеркивания. Этот символ применяется наравне с буквами. Допустимая длина имени метки зависит от версии программы транслятора. Команда LJMP не единственная команда безусловного перехода в системе команд АТ89С2051. Существует еще две разновидности этой команды: AJMP и SJMP. Отличаются они от своего аналога методами задания адреса. AJMP — состоит всего из двух байтов. Первый байт служит одновременно для двух целей. Пять младших его битов — это код операции, а три старших — это уже часть адреса перехода. Второй байт команды — это младшие биты адреса перехода. Такая команда может осуществлять переход только в пределах первых двух килобайт адресного пространства программной памяти. Этого вполне достаточно, так как объем памяти микросхемы 2 килобайта.
Микроконтроллер АТ89С2051 93 Команда LJMP оставлена для совместимости с прототипом — контроллером iMCS-51. Команда SJMP — это безусловный переход с относительной адресацией. Она также состоит из двух байт. Первый байт целиком представляет собой код операции. Второй байт представляет собой относительный адрес перехода. То есть число, на которое нужно изменить текущее значение счетчика адреса. Первый бит — это знак числа. Если он равен единице, то относительный адрес вычитается из текущего. Если первый бит равен нулю, то текущий адрес увеличивается на величину смешения. Описываемая в данной книге версия Ассемблера допускает применять вместо любой из вышеописанных команд безусловного перехода мнемокод JMP. Ассемблер сам выбирает оптимальный способ адресации. Вообще специфика языка Ассемблера такова, что для каждого конкретного процессора существует свой Ассемблер. Кроме того,, часто для одного и того же процессора разными фирмами разрабатывается несколько разных программ-трансляторов. При этом появляются несколько версий языка. Практически, для каждого транслятора создается своя версия. Поэтому, прежде чем изучать ассемблер, нужно определиться, какую программу-транслятор вы собираетесь применить. Все тексты программ, приводимые в настоящей книге, написаны для программы «Cross-Assembler 8051, Version 1.2h (с) Copyright 1984, 1985, 1986, 1987, 1988, 1989, 1990 by MetaLink Corporation». Полный пакет транслятора с описанием и библиотеками можно найти на сайте http://microprocessor.by.ru в разделе «Download». На этом я хочу закончить описание микроконтроллера АТ89С2051 и перейти к следующему этапу — описанию процесса разработки конкретного микропроцессорного устройства.
Позиционер спутниковой антенны Постановка задачи Итак займемся проектированием микропроцессорного устройства. Я постараюсь показать все этапы проектирования с самого начала. Мне поступил заказ на разработку позиционера спутниковой антенны. До того момента (да и после того) я никогда не занимался спутниковым приемом. Как радиоинженер я, конечно, знал основы. Но сталкиваться с этим на практике не приходилось. Поэтому я потребовал подробное техническое задание. Задача стояла следующая: Имеется стандартная спутниковая тарелка, закрепленная на стандартном поворотном устройстве. Для ее вращения используется так называемый актюатор. Актюатор — это мотор с редуктором и датчиком поворота антенны. В поворотных спутниковых антеннах обычно используется так называемая планетарная подвеска, которая позволяет обойтись только одной плоскостью вращения. Поясню вкратце, что такое планетарная подвеска. Дело в том, что все спутники, транслирующие вещательные каналы, находятся на геостационарных орбитах. То есть вращаются вокруг земли над ее экватором со скоростью, равной скорости вращения земли. В результате они как бы «зависают» каждый над своей точкой на земной поверхности. Поэтому для наведения приемной спутниковой антенны на любой из спутников, достаточно обеспечить ей возможность вращения вокруг оси, расположенной параллельно оси вращения земли. Вращаясь только в этой одной плоскости, спутниковая антенна будет последовательно наводиться на каждый из спутников, «висящих» на геостационарной орбите. Именно такую возможность и реализует планетарная подвеска. Стандартный актюатор обеспечивает вращение антенны со скоростью примерно 90 градусов в минуту. То есть, достаточно медленно. Устроен он
Позиционер спутниковой антенны 95 следующим образом: электромотор, рассчитанный на постоянное напряжение 36 В и пусковой ток 1,5 А, работает на простой редуктор, снижающий частоту вращения до 2-3 оборотов в минуту. Изменение направления вращения производится путем смены полярности питающего напряжения. На выходе первичного редуктора установлен датчик вращения. Датчик вращения представляет собой геркон, укрепленный в корпусе ак- тюатора и постоянный магнит, укрепленный на выходном валу редуктора. В данном случае применен обычный геркон средних размеров, имеющий два нормально разомкнутых контакта. Контакты геркона замыкаются один раз при каждом обороте выходного в'ала первичного редуктора. С выхода редуктора вращающий момент передается на червячный механизм, заставляющий двигаться специальную штангу. Штанга имеет достаточно большой ход. Под действием мотора, она может выходить из корпуса актюатора примерно на метр, или убираться в него полностью. Эта штанга и поворачивает спутниковую антенну. Задача, поставленная передо мной, состояла в следующем: ¦ Разработать электронное устройство (позиционер), управляющее поворотом антенны. Управление должно происходить путем подачи на двигатель актюатора питающего напряжения прямой либо обратной полярности. ¦ Постоянно, независимо от режима работы, позиционер должен следить за положением антенны при помощи датчика вращения и хранить текущее значение угла поворота во внутренней памяти. ¦ Позиционер должен иметь возможность в любой момент запомнить текущее положение антенны в одной из специальных ячеек внутренней памяти. Количество таких ячеек должно быть не менее десяти. То есть по-другому, позиционер должен иметь возможность запомнить не менее 10 позиций антенны. ¦ Вся записанная во внутреннюю память устройства информация должна храниться в нем после выключения питания. Причем схема должна гарантировать полную сохранность всей информации даже в случае непредвиденного пропадания питания. • Позиционер должен обеспечивать автоматический поворот антенны в любую из ранее запомненных позиций. Поворот должен начинаться сразу после выбора номера нужной позиции. ¦ Если поворот антенны на выбранную позицию еще не окончен, а пользователь выберет другую, то отработка предыдущей позиции должна быть немедленно прекращена, и позиционер должен перейти к отработке новой позиции. Если новая позиция находится в том же направлении, что и отмененная, то движение прекращаться не должно. Если новая позиция находится в другом направлении, то мотор должен поменять направление вращения.
96 Самоучитель по микропроцессорной технике ¦ Позиционер должен иметь цифровой индикатор. На нем должен отображаться номер текущего выбранного канала. Имеется в виду, что каждый канал хранит одну из позиций. Кроме того, на индикаторе должна отображаться информация о смене режима работы и сообщения об ошибках. ¦ Позиционер должен иметь минимум кнопок управления. ¦ Позиционер должен иметь систему дистанционного управления. Желательно при этом использовать один из стандартных пультов управления, имеющихся в свободной продаже. ¦ Позиционер должен иметь дежурный режим работы. В дежурном режиме позиционер должен переходить на пониженное потребление энергии. Должна быть предусмотрена возможность выхода из дежурного режима, как при помощи кнопок управления, так и при помощи пульта ДУ. Кроме того, было сформулировано еще одно требование к схеме: в целях повышения надежности, устройство должно иметь гальваническую развязку силовых и управляющих цепей для защиты микропроцессорной части от атмосферного электричества. Имея вышеперечисленные требования, я приступил к разработке позиционера. Первым делом я, уже сам для себя, сформулировал ряд дополнительных требований, перечисленных ниже. Для того, чтобы информация в памяти позиционера не терялась при выключении питания, я решил применить для их хранения микросхему электрически стираемого ПЗУ. Это целый класс специальных микросхем памяти, предназначенный для долговременного хранения информации в условиях отсутствия электропитания. Используя западную терминологию, такие микросхемы часто называют микросхемами флэш-памяти. Флэш- память широко применяется в наше время в радиоэлектронной аппаратуре. Современные телевизоры, автомагнитолы, мобильные телефоны используют их для хранения всех основных настроек. В нашем случае объем информации, предназначенной для хранения, был достаточно небольшим. Поэтому, в качестве микросхемы энергонезависимой памяти я решил применить самую доступную на момент разработки микросхему К558РР1. Эта микросхема применяется в блоке управления отечественных телевизоров нового поколения. В тех моделях, у которых весь процесс настройки и выбора режимов отображается непосредственно на экране, на фоне телепередачи. Микросхема К558РР1 по внешнему виду и функциональному назначению является ближайшим аналогом микросхем серии 24СХХ. Однако имеются отличия в протоколе обмена информацией. В связи с этим они не взаимозаменяемы. Микросхема К558РР1 представляет собой электрически перепрограммируемое ПЗУ, имеющее 256 ячеек, у которой для чтения и записи инфор-
Позиционер спутниковой антенны 97 мации используется последовательная двухпроводная шина, использующая протокол обмена под названием 12С. Эта шина и протокол разработаны фирмой PHILIPS. Они предназначены для систем цифрового управления в современных моделях телевизоров. Не вдаваясь в подробности, скажу лишь, что такое решение позволяет процессору обмениваться информацией с микросхемой памяти при помощи всего лишь двух проводов. Подробнее о работе 12С-шины вы можете прочитать на сайте http://digitchip.by.ru в разделе «Справочные материалы». Алгоритм работы шины довольно сложный. Однако это не вызвало у меня никаких затруднений, так как на сайте фирмы ATMEL (http://www.atmel.com), производителя микроконтроллера АТ89С2051, имеется пример готовой программы для работы с флэш-памятью по 12С-шине и схема подключения такой памяти к процессору. Вообще информационная поддержка продукции этой фирмы налажена хорошо. Следующий момент, который нужно было продумать перед тем, как начать разработку электрической схемы — это разрядность счетчика положения антенны. Показания счетчика будут храниться в памяти микроконтроллера. Поэтому под счетчик необходимо будет выделить одну или несколько ячеек. Попробуем определить, сколько ячеек памяти нам потребуется. Максимальное число, которое будет храниться в данном счетчике равно количеству срабатываний датчика при повороте антенны из одного крайнего положения в другое. В то же время, количество разрядов счетчика определяет точность, с которой мы сможем устанавливать антенну в требуемую позицию. Если для хранения показаний счетчика мы используем всего одну ячейку памяти, то счетчик переполнится уже после 256 срабатываний датчика. Такое количество срабатываний наступит при повороте антенны всего на пару градусов. Поэтому одной ячейки явно мало. Если же для счетчика выделить две ячейки, то такой счетчик переполнится только после 65536 срабатываний датчика. Подсчет количества срабатываний датчика реального актюатора на каждый градус поворота антенны показал, что этого вполне достаточно. Далее, нужно было определиться с количеством разрядов цифрового индикатора. Основное назначение индикатора — отображать номер текущего выбранного канала. Казалось бы достаточно и одного разряда. Однако я решил, что оптимальным решением будет двухразрядный семисегментный индикатор. Во-первых, на двух индикаторах легко высветить различные служебные надписи. Например «РУ» (ручное управление) или «Ег» (ошибка). Кроме того, я решил сделать не 10, а 100 ячеек для записи позиций антенны и, соответственно, 100 каналов. Объема памяти выбранной микро-
98 Самоучитель по микропроцессорной технике схемы B56 ячеек) вполне хватает. Разумеется, вряд ли вы на свою антенну сможете поймать сигналы от ста разных спутников. Но появляется возможность одну и ту же позицию записать в несколько разных каналов и согласовать номера этих каналов с номерами каналов вашего ресивера. В общем, лишний запас по количеству каналов никогда не помешает. Тем более, что это не потребует никаких дополнительных затрат. Выбор процессора Итак, мы определились с техническим заданием. Следующий этап разработки любого микропроцессорного устройства — это выбор процессора. Это очень важный выбор. Все остальные элементы схемы будут строиться, исходя из свойств выбранного процессора. Если процессор выбран удачно, схема получится рациональной и красивой. В данном случае мой выбор вам известен. Но я хочу немного поговорить о том, почему я выбрал именно этот процессор. В моем случае, я искал небольшой по размерам, не требующий для своей работы дополнительных микросхем окружения, недорогой процессор, обладающий в то же время достаточными возможностями для решения поставленной задачи. Сразу было решено использовать либо Р1С-кон- троллер, либо что-то аналогичное ему. В результате я обратил внимание на неизвестный мне ранее микроконтроллер АТ89С2051 фирмы ATMEL. Он мне сразу понравился. Во-первых, по размерам, количеству портов ввода/вывода, вычислительным возможностям, он ничем не уступает PIC-контроллерам. Во-вторых, он также, как и большинство Р1С-кон- троллеров, имеет встроенную флэш-память программ. Однако, по сравнению с PIC-ами, выбранный мной контроллер имел одно очень для меня существенное преимущество. Его внутренняя структура и система команд была максимально совместима со структурой и системой команд микроконтроллера iMCS-51 фирмы Intel. Ее советский аналог — микроконтроллер К1816ВЕ51 широко применялся в отечественной микропроцессорной технике. Мне приходилось работать с этими микросхемами, и их система команд была мне хорошо знакома. Кроме того, у меня уже имелись в наличии все основные инструментальные программы, необходимые для составления и отладки программ. А именно — транслятор с языка Ассемблера и Отладчик. Правда и то и другое предназначалось для микросхем iMCS-51, но полностью подходило для выбранной мной микросхемы. Кроме того, подкупало наличие готовых фирменных алгоритмов, специально разработан-
Позиционер спутниковой антенны 99 ной фирмой ATMEL для своего контроллера АТ89С2051 и являющихся примерами работы с различными внешними устройствами. В частности, на сайте фирмы я нашел схему подключения микросхем внешней флэш- памяти по двухпроводной шине с протоколом 12С и пример программы для обслуживания этой схемы. И в довершение всего в моем распоряжении оказалась схема простого программатора для прошивки памяти программ. Его схему и описания я привожу в конце этой книги. Но прежде, чем окончательно остановиться на выбранном процессоре, необходимо было убедиться в том, что возможностей процессора хватит для решения всех поставленных задач. Первый критический момент, по которому процессор может не подойти для данной конкретной системы — это его быстродействие. Быстродействие любого микропроцессора определяется, прежде всего, частотой его тактового генератора. По техническим условиям, максимально допустимая частота тактового генератора процессора АТ89С2051 — 24 МГц. Однако для правильной работы упомянутых выше алгоритмов поддержки флэш-памяти необходимо, чтобы тактовая частота была равна ровно 12 МГц. Оценим теперь, хватит ли такой частоты для выполнения всех предусмотренных техническим заданием функций. Сначала вспомним, что частота тактового генератора, прежде чем поступить на все схемы микроконтроллера, при помощи встроенного делителя частоты делится на шесть. В результате частота синхросигнала основной схемы в нашем случае фактически равна 1 МГц. Теперь посмотрим, хватит ли нам такой частоты. Самый быстрый процесс, который придется обрабатывать микроконтроллеру — это распознавание команд пульта дистанционного управления. Стандартный пульт ДУ от телевизора «Горизонт» (именно этот пульт было решено применить для управления позиционером), излучает управляющий сигнал в виде пачек импульсов. Частота следования импульсов в пачке — 1 кГц. Программа позиционера должна распознавать команды от пульта в режиме реального времени. Очевидно, что на каждый входной импульс от пульта ДУ придется 1000 тактов работы процессора. Учитывая, что большинство команд процессора выполняются за один, либо за два такта (см. приложение), то за время, равное периоду следования импульсов в сигнале пульта ДУ, данный процессор может выполнить программу длиной более 500 команд. Исходя из опыта построения подобных алгоритмов, можно утверждать, что такого количества команд более чем достаточно. Когда мы дойдем до описания соответствующих фрагментов реальной управляющей программы позиционера, вы сможете убедиться в том, что она состоит всего из 60 операторов.
100 Самоучитель по микропроцессорной технике Второй вопрос, который нужно продумать при выборе процессора — количество линий ввода/вывода. Наш процессор должен управлять следующими устройствами: двухразрядным светодиодным дисплеем, состоящим из двух семисегментных индикаторов, двумя ключами включения и выключения мотора поворотного устройства (прямой и инверсный ход). Кроме того, процессор должен получать и обрабатывать сигналы от следующих внешних устройств: кнопки управления G кнопок), датчик поворота антенны, фотоприемник сигналов ДУ. Для того, чтобы оценить, хватит ли существующих выводов процессора для решения всех вышеперечисленных задач, нужно иметь опыт разработки микропроцессорных устройств. Обычно разработчик в уме сразу прикидывает примерную схему будущего устройства и таким образом оценивает, насколько сложной получается схема. При этом нужно заметить, что совсем не обязательно, чтобы число выводов точно соответствовало числу обслуживаемых устройств. Существует множество приемов, позволяющих использовать одни и те же выводы для управления несколькими различными устройствами. В этом мы убедимся в следующем разделе книги. Последним аргументом, склонившим чашу весов в сторону окончательного выбора — это невысокая цена микросхемы АТ89С2051. На тот момент времени, когда разработка позиционера только начиналась, цена этой микросхемы в странах СНГ была равна приблизительно 3 у.е. В настоящее время эта цена снизилась почти вдвое. Разработка схемы Следующий этап — разработка принципиальной электрической схемы. К этому этапу нужно подходить со всей серьезностью. Удачно разработанная схема — залог качества и надежности всей конструкции. Я обычно очень долго вынашиваю основные принципы построения схемы в своей голове. Всесторонне обдумываю разные варианты схемного решения. Сравниваю их между собой, стараясь оценить недостатки и преимущества каждого из вариантов. Само собой разумеется, что для этого нужно иметь некоторый опыт в разработке микропроцессорных устройств. Поэтому я предлагаю просто посмотреть на рис. 44. Перед вами принципиальная электрическая схема позиционера спутниковой антенны. Далее будет приведено подробное описание этой схемы. Описывая каждый узел, я постараюсь объяснить, из каких соображений я применил в данном случае именно такое схемотехническое решение. Основа всего устройства — микроконтроллер DD1. Он включен по типовой схеме, приведенной в документации разработчика. Для реали-
Позиционер спутниковой антенны 101 зации типового подключения потребовалось всего пять радиоэлементов. Это кварцевый резонатор Zl с двумя согласующими конденсаторами С6, С7 и цепь начального сброса процессора, состоящая из резистора R1 и конденсатора СЗ. Мы уже частично рассматривали назначение обеих этих систем. Кварцевый резонатор служит для стабилизации частоты колебаний внутреннего тактового генератора. Цепь сброса служит для начальной установки всех внутренних систем процессора в момент включения питания. Цепь сброса работает очень просто. Сразу после появления напряжения питания конденсатор СЗ начинает заряжаться. При этом на вход RST процессора поступит положительный импульс, длительность которого определяется временем зарядки конденсатора. Показанные на схеме номиналы Rl и СЗ обеспечивают длительность импульса, соответствующую паспортным требованиям микроконтроллера. Рис. 44. Принципиальная электрическая схема позиционера спутниковой антенны
102 Самоучитель по микропроцессорной технике Все остальные узлы схемы являются периферийными устройствами микроконтроллера. Они подключены к различным выводам обоих его портов. Причем часть из этих выводов используется для управления сразу несколькими периферийными устройствами. Для этого применяется метод разделения выполняемых функций во времени. Как происходит это разделение, мы узнаем в процессе описания соответствующих узлов схемы. Однако целый ряд внешних устройств не допускает совместного их использования. Для управления каждым из них нужны свои отдельные линии. Именно с таких устройств мы и начнем. Микросхема внешней флэш-памяти DD2 (К558РР1). Для управления этой микросхемой используются линии Pl.2, P1.3 микроконтроллера. В данном случае применена типовая схема включения, которая соответствует всем требованиям 12С-шины. R6 и R7 — это развязывающие резисторы. R8, R9 — внешняя нагрузка. Наличие такой нагрузки обязательно, так как во всех устройствах, предназначенных для работы с 12С-шиной, используются выходы с открытым коллектором. Микросхема К558РР1 специально разработана для работы с 12С-шиной. Кроме входов 5 и 6, реализующих протокол этой шины, она имеет еще три входа (Al, A2 и A3). Это входы установки адреса. Дело в том, что последовательная шина стандарта 1~С допускает параллельное подключение до 128 различных устройств. Обычно одно из таких устройств выступает в качестве ведущего. Все остальные устройства — ведомые. Ведущее устройство, в качестве которого в данном случае выступает микроконтроллер, имеет возможность обращаться к любому из ведомых устройств, используя его уникальный адрес. В микросхемах флэш-памяти К558РР1 имеется возможность выставлять значение этого адреса. Адрес набирается в двоичном коде на входах Al, A2, A3. Если вход соединить с общим проводом, то это равносильно подаче на него сигнала логического нуля. Для того, чтобы подать на вход сигнал логической единицы, он соединяется с шиной питания (+5 В). Таким образом, адрес микросхемы может принимать значение от 000В до ШВ, то есть от 0 до 15. В нашей схеме используется только одна микросхема флэш-памяти, поэтому все три адресных входа соединены с общим проводом. Таким образом, микросхема имеет нулевой адрес. Микроконтроллер АТ89С2051 не имеет специальных аппаратных средств работы по 12С- шине. Алгоритм такой шины реализован программным путем. Как уже говорилось, был использован программный модуль, разработанный фирмой ATMEL, который был получен с сайта фирмы (http://www.atmel.com). Приемник сигнала от пульта дистанционного управления (ДУ). Для приема сигналов в инфракрасном диапазоне используется специальная микросхема (DD5), которая называется «фотоприемник». В данном конкретном слу-
Позиционер спутниковой антенны 103 чае применена микросхема ТК.-19. Внешний вид этой микросхемы приведен на рис. 45. Микросхема имеет всего три вывода и содержит фотодатчик, усилитель и преобразователь уровня сигнала. Назначение выводов следующее: I — общий провод, 2 — напряжение питания (+5 В), 3 — выход. На выходе микросхема формирует стандартный логический сигнал ТТЛ уровня. Если датчик микросхемы освещен, на выходе микросхемы формируется сигнал логической единицы. В противном случае на нем логический ноль. В процессе работы пульт ДУ излучает управляющий сигнал в виде пачки импульсов различной длительности. При попадании этого сигнала на чувствительный элемент фотоприемника, на его выходе появляется цифровой сигнал, полностью повторяющий сигнал с пульта. Выход фотоприемника подключен к линии Р1.5 микроконтроллера. Для считывания и распознавания принятого сигнала используется специальная подпрограмма, описание которой мы еще будем подробно рассматривать в этой книге. Рис. 45, Фотоприемник Датчик поворота антенны. Сигнал от датчика поступает на линию Р1.4. В связи с тем, что датчик поворота располагается в механизме актюато- ра, который вместе с антенной обычно находится где-то на крыше, предусмотрена система гальванической развязки между внешними цепями подключения датчика и всеми цепями управляющей схемы. Развязка обеспечивается при помощи транзисторного оптрона DAI (AOT104). Для питания светодиода оптрона используется постоянное напряжение, которое снимается с выпрямительного моста VDA2. Это напряжение предназначено для питания всех внешних цепей схемы. А именно: двигателя поворота антенны и цепей датчика поворота. Двигатель питается непосредственно от пульсирующего напряжения. Для питания светодиода такое напряжение непригодно. Импульсы 50 Гц могут быть восприняты, как импульсы от датчика поворота антенны. Поэтому в схеме применен сглаживающий фильтр R4, С8. Сглаженное напряжение подается на светодиод оптрона DAI через контакт датчика поворота антенны и токоограничивающий резистор R3. Светодиод загорается в момент замыкания контактов датчика. При этом транзистор оптрона открывается и замыкает на общий провод вывод 16 микроконтроллера (линию Р1.4). Это равносильно подаче на этот вход сигнала логического нуля. При размыкании контакта датчика светодиод гаснет, транзистор закрывается и на входе
104 Самоучитель по микропроцессорной технике PI.4 устанавливается уровень логической единицы, благодаря внутреннему резистору нагрузки выходного каскада (рис. 37). Резистор R5 служит для подачи начального смещения на базу внутреннего транзистора оптрона. В схеме подключения датчика не предусматривается никаких аппаратных антидребезговых мер. Это связано с тем, что в позиционере применен мощный антидребезговый алгоритм, заложенный в управляющую программу. Далее приведено подробное описание подпрограммы, реализующей этот алгоритм. Индикатор дежурного режима. Одно из требований, выдвинутое при разработке схемы позиционера, это наличие дежурного режима. Схема разработана таким образом, что она никогда не выключается полностью. Вместо этого схема переходит в дежурный режим. В дежурном режиме схема потребляет минимум энергии. В то же время пользователь в любой момент может включить позиционер при помощи пульта ДУ. В дежурном режиме моторы выключены, все кнопки (кроме кнопки включения) заблокированы. Все индикаторы потушены. Для индикации дежурного режима используется сегмент десятичной точки элемента HL2. Он загорается в момент перехода в дежурный режим и гаснет при выходе из этого режима. Индикатор удобен тем, что можно отличать состояние дежурного режима от состояния, когда устройство просто не подключено к сети. Для управления индикатором дежурного режима используется линия Pl.l микроконтроллера. Теперь рассмотрим более сложную часть схемы: схему подключения семисегментных индикаторов, кнопок управления и регистра управления мотором. Для подключения всех этих устройств используется порт РЗ микроконтроллера. Причем оба индикатора, кнопки клавиатуры и регистр управления мотором (DD4) подключены к этому порту параллельно. Здесь налицо совместный способ подключения устройств к одним и тем же выводам. Рассмотрим, как же устроена эта схема. Начнем с индикаторов. Индикаторы позиционера работают в режиме динамической индикации. Динамическая индикация — это очень распространенный прием в цифровой технике. Суть его состоит в том, что для сокращения количества управляющих сигналов индикаторы включают таким образом, чтобы в каждый момент времени светился только один из разрядов. В процессе работы происходит постоянное переключение индикаторов. Сначала включается первый индикатор и высвечивает старший разряд. Затем включается второй индикатор, и высвечивает младший. Затем весь цикл повторяется. Частота повторения подобрана таким образом, что человеческий глаз не видит мерцаний. Ему кажется, что каждый индикатор постоянно высвечивает свою цифру.
Позиционер спутниковой антенны 105 Схема индикации реализована на основе двух семисегментных индикаторов с общим анодом (HL1, HL2). Одноименные катоды каждого из индикаторов соединены вместе и подключены к выводам порта РЗ. Для переключения индикаторов используется дешифратор DD3 (К555ИД4). Используется только одна из двух секций дешифратора. Дешифратор управляется при помощи линий Pl.6, P1.7 микроконтроллера. Подавая на входы дешифратора двухразрядный двоичный сигнал, процессор может активизировать один из четырех выходов верхней секции дешифратора. Выходы Q2 и Q3 используются для выбора одного из двух разрядов индикатора. Для того, чтобы выбрать индикатор HL1, процессор должен подать на вход дешифратора код О IB. Для того, чтобы выбрать HL2, нужно подать код 10В. Управляющие ключи R12, VT4 и R13, VT5 предназначены для согласования выходов дешифратора с нагрузкой и повышения яркости свечения индикаторов. Резисторы R14...R20 выполняют роль токоограничивающих. Благодаря дешифратору DD3 процессор может подключать к порту РЗ не два, а четыре внешних устройства. Выход Q1 используется для активизации кнопок управления. Выход Q4 используется для записи управляющих сигналов в двухразрядный параллельный регистр, выполненный на основе микросхемы DD4 (К555ТМ2), который, в свою очередь, служит для управления двигателем поворота антенны. Для считывания информации с клавиатуры процессор подает на вход дешифратора код 00В. На выходе Q1 появляется сигнал логического нуля. В результате нижние по схеме выводы кнопок управления S1...S7 оказываются подключенными к общему проводу. Таким образом, происходит инициализация клавиатуры. Остальные устройства, управляемые дешифратором DD4, окажутся отключенными и на работу схемы влиять не будут. Теперь микроконтроллер может произвести чтение информации из порта РЗ. Перед тем как производить чтение порта, процессор обязательно должен записать туда код, устанавливающий все его разряды в единичное состояние. Данный процесс называется чтением кода состояния клавиатуры. Если ни одна кнопка не нажата, то код состояния клавиатуры будет равен 0FFH. Теперь допустим, что мы нажали кнопку S1. Тогда в процессе чтения состояния клавиатуры катод диода VD1 через контакты кнопки S1 и выход Q1 дешифратора DD4 окажется подключенным к общему проводу. Под действием логической единицы на выходе линии РЗ.О микроконтроллера диод откроется и линия РЗ.О окажется соединенной с общим проводом. Уровень сигнала в линии упадет до нуля. Это равносильно подаче на нее сигнала низкого логического уровня. В этом случае код состояния клави-
106 Самоучитель по микропроцессорной технике атуры окажется равным OFEH (IIMII10B). Нажатие остальных кнопок приведет к обнулению других разрядов. Поэтому при разных комбинациях нажатых кнопок процессор получит разные коды. Эти коды используются процессором для переключения режимов работы позиционера. Для записи сигнала в регистр управления мотором (DD4) процессор подает на вход дешифратора код 11 В. Безусловно, для управления мотором вполне можно было использовать любые два вывода процессора. Однако мы имеем только один свободный вывод. Для включения двигателя в прямом и реверсивном направлении этого не достаточно. Для того, чтобы осуществить управление мотором, необходимо, как минимум, два управляющих разряда. Судите сами, позиционер должен обеспечить три состояния мотора: состояние «мотор выключен», вращение в прямом направлении и вращение в обратном направлении (реверс). Поэтому был введен специальный регистр. Регистр выполнен на основе двух D-триггеров, входящих в состав микросхемы DD4. D-входы этого импровизированного регистра подключены к линиям РЗ.О и Р3.1 микроконтроллера. На С-входы обоих триггеров поступает сигнал с выхода Q4 дешифратора. Запись управляющих битов в регистр производится следующим образом: сначала процессор записывает в младшие разряды порта РЗ (Р3.1 и Р3.2) управляющий сигнал. Управляющий сигнал представляет собой двухбитное двоичное число. Эти два бита поступают на D-входы обоих триггеров микросхемы DD4. Затем процессор подает на входы дешифратора DD3 код 11В. На выходе Q4 устанавливается логический ноль. Перепад уровней с 1 на 0 на С-входах обоих триггеров микросхемы DD4 вызывает запись управляющего сигнала в оба триггера регистра. К прямым выходам триггеров регистра подключены управляющие ключи RIO, VT2 и R11, VT3. Ключи служат для управления электромагнитными реле Kl, K2. Применение реле обеспечило гальваническую развязку по цепям управления мотором. Реле К1 предназначено для включения мотора в прямом направлении, а при помощи реле К.2 включается реверс. Одновременно оба реле никогда не включаются. Всеми процессами, связанными с динамической индикацией, считыванием кода состояния клавиатуры и записью кодов управления мотором управляет специальная процедура в управляющей программе позиционера. Эта процедура запускается при помощи системы прерываний от внутреннего таймера микроконтроллера с частотой, равной 50 Гц. Это минимальная частота, при которой переключение разрядов в процессе динамической индикации не заметны глазу. Процедура начинается с вывода на индикацию старшего разряда. Далее отрабатывается
Позиционер спутниковой антенны 107 задержка, равная половине выбранного периода A/50 с). По окончании задержки производится цикл чтения с клавиатуры и сразу после него вывод младшего разряда индикатора. Для младшего разряда отрабатывается точно такая же задержка, как и для старшего. Это важно, так как яркость свечения обоих разрядов должна быть одинакова. По окончании этой задержки производится операция записи управляющего сигнала в регистр управления мотором. Далее все повторяется сначала. Операция чтения состояния клавиатуры и операция записи управляющего сигнала мотора занимают очень маленький промежуток времени — несколько десятков микросекунд. В связи с этим включение этих операций в цикл динамической индикации абсолютно не влияет на качество отображения символов. Транзисторный ключ R2,. VT1 служит для начальной установки триггеров микросхемы DD4 в момент включения питания. Сброс триггеров в нулевое состояние необходим для того, чтобы мотор не начал вращаться без команды от процессора. Диоды VD1...VD7 служат для того, чтобы во всех режимах, кроме режима опроса клавиатуры, нажатие нескольких кнопок одновременно не приводило к замыканию линий порта РЗ между собой. Замыкание этих линий может вызвать искажения в индикации и сбои при передаче сигналов управления мотором. В заключение нужно сказать, что схема питается от одного трансформатора, имеющего две независимые вторичные обмотки. Одна используется для питания цифровой части и обоих реле, а другая — для питания мотора поворотного устройства. Каждое напряжение поступает на свой выпрямитель. Для питания схемы позиционера используется выпрямитель VDA1, фильтр Cl, C2 и стабилизатор напряжения DAI. На выходе стабилизатора мы получаем стабилизированное напряжение +5 В. Напряжение питания мотора поступает на выпрямительный мост VDA2. Управляющая программа Теперь от аппаратной части позиционера перейдем к программной. Алгоритм управляющей программы микропроцессорного устройства в общих очертаниях обычно складывается в процессе разработки его схемы. Когда разработчик применяет то или иное схемное решение, то обычно он имеет в виду определенный программный алгоритм, который будет работать с такой схемой. Управляющую программу позиционера удобно разбить на три самостоятельных модуля. Первый модуль
108 Самоучитель по микропроцессорной технике — это основная программа. Процессор начинает выполнять ее сразу после начального запуска системы, после окончания сигнала аппаратного сброса и выполняется все время, пока включено питание. Основная программа включает в себя все процессы, которые не должны быть синхронизированы во времени. Кроме основного модуля существуют два дополнительных. Если вы еще не забыли, дополнительные модули представляют собой две процедуры обработки прерываний. Одна из дополнительных процедур реализует процесс динамической индикации. Вторая — реализует постоянный опрос фотоприемника, чтение и запись в буфер команд ДУ. Механизм прерываний позволяет одному процессору выполнять все три процедуры, как бы одновременно, и не зависимо друг от друга. Для вызова обеих дополнительных процедур используются системные таймеры. Сразу после запуска работает только основная процедура. В самом ее начале производится настройка обоих таймеров и системы прерываний. После настройки основная программа запускает таймеры, и они начинают периодически вызывать прерывания. Каждый таймер вызывает свою процедуру прерываний. Период, с которым вызываются прерывания, для каждого таймера разный. Он определяется решаемой задачей. Таймер ТО вызывает процедуру, реализующую процесс динамической индикации, а за одно — процесс опроса состояния клавиатуры и вывод управляющего сигнала на двигатель. Процедура вызывается с постоянным периодом, примерно равным 20 мс, что соответствует частоте 50 Гц. Алгоритм динамической индикации подробно рассматривается в разделе «Процедура динамической индикации». Таймер Т1 вызывает процедуру приема и обработки сигналов от пульта ДУ. Период, с которым вызывается эта процедура, в разных режимах работы системы разный. Подробнее о процессе приема сигналов ДУ будет рассказано в разделе «Процедура приема сигнала ДУ». В настоящем разделе я хотел бы остановиться на самом главном из процессов — основном программном модуле. Для того, чтобы яснее представить себе алгоритм работы любой программы, удобно представить его в виде блок-схемы. Блок-схема — это графическое изображение алгоритма, какой-либо программы. На рис. 46 приведена блок-схема основного модуля управляющей программы позиционера. В прямоугольниках описываются выполняемые действия. Стрелками показывается ход выполнения программы и все разветвления алгоритма. При помощи ромбов изображаются операторы принятия решений (условные переходы). Такие операторы оценивают факт выполнения какого-либо условия и в за-
Позиционер спутниковой антенны 109 Рис. 46. Блок-схема управляющей программы позиционера (основная программа)
110 Самоучитель по микропроцессорной технике висимости от результатов оценки выбирают один из двух путей выполнения программы. Если условие, записанное внутри ромбика, истина, то выполнение программы пойдет по ветви, помеченной словом «Да». В противном случае будет выполняться ветвь, помеченная как «Нет». Как видно из рис. 46, основная программа состоит из модуля начального запуска и основного цикла программы. В самом начале модуля начальногьо запуска, программа выполняет команды инициализации системы. Эти команды присваивают всем основным переменным программы начальные значения, настраивают систему прерываний процессора, программируют работу системных таймеров, и поступает команда запуска таймеров. Новое для вас понятие «системные переменные» пока примите на веру. Речь о них пойдет уже в следующем разделе. После выполнения модуля инициализации программа переходит к основному циклу. В этом цикле программа находится все время, вплоть до выключения питания позиционера. В зависимости от режима работы, программа выполняет либо большой, либо малый цикл. Большой цикл соответствует основному режиму работы позиционера, а малый — дежурному режиму. Большой цикл состоит из четырех процедур, которые выполняются последовательно, одна за другой. Рассмотрим каждую из них. Процедура обработки команд с клавиатуры. Здесь имеется в виду не чтение байта состояния клавиатуры, а всего лишь обработка уже прочитанного кода. Этот код читается совсем в другом месте. В процедуре, совмещенной с процессом динамической индикации. Описываемая здесь процедура лишь читает код состояния из специальной ячейки памяти, называемой буфером клавиатуры, оценивает этот код и вызывает одну из процедур обработки нажатых клавиш. Процедуры обработки нажатых клавиш на блок-схеме отдельно не показаны. Подразумевается, что они являются частью процедуры обработки команд с клавиатуры. Полный набор команд с клавиатуры вы можете видеть на рис. 44. Процедура обработки сигналов датчика поворота антенны. Эта процедура производит непосредственное считывание сигнала с той линии PI.4, куда поступают сигналы датчика. Именно в этой процедуре реализуется алгоритм двухуровневой антидребезговой обработки. Алгоритм производит фильтрацию всех лишних импульсов, обусловленных дребезгом контактов датчика. Отсеяв таким образом помехи, программа получает чистый сигнал от датчика. Затем происходит счет, то есть увеличение либо уменьшение содержимого счетчика положения антенны при каждом срабатывании датчика. Направление счета определяется косвенным образом.
Позиционер спутниковой антенны 111 Если на двигатель подана команда «прямой ход», содержимое счетчика увеличивается. Если на двигатель подана команда «реверс», то содержимое счетчика уменьшается. После каждого изменения содержимого счетчика положения антенны, оно сразу же записывается во внешнюю флэш- память. Это делается для того, чтобы при неожиданном выключении питания данные о реальном положении антенны не были утеряны. Процедура автоматической установки антенны. Эта процедура запускает процесс автоустановки антенны на выбранную позицию. Для этого программа определяет номер выбранного канала, читает из памяти код, соответствующий записанной там позиции и сравнивает этот код с текущим значением счетчика положения антенны. Если коды не совпадают, то программа дает команду двигателю на поворот. Направление поворота определяется автоматически, в зависимости от того, какое из сравниваемых чисел больше. Данная процедура имеет опосредованное действие. Команда управления двигателем не выводится немедленно. Она просто запоминается в другой специальной ячейке ОЗУ. Ячейку, резервируемую для этих целей, называют буфером команд управления мотором. Собственно вывод команды на мотор происходит в цикле динамической индикации. Такой подход связан с тем, что для непосредственного вывода команды пришлось бы приостановить цикл динамической индикации. Однако этот цикл не может прерываться произвольным образом. Иначе свечение индикаторов будет неравномерным. Процедура обработки команд ДУ. И опять мы видим процедуру опосредованного действия. Процедура сама, непосредственно, не работает с фотоприемником. Она так же, как и две предыдущие процедуры, читает уже готовый код команды ДУ из соответствующего буфера. Для этого буфера также выделена одна из ячеек. Полученный код анализируется и происходит переход к одной из подпрограмм обработки. Причем в данном случае используются те же самые процедуры, которые вызываются при нажатии клавиш. С той только разницей, что в пульте дистанционного управления используется неполный набор команд. В рассматриваемом варианте программы с пульта ДУ могут подаваться лишь следующие команды: «Увеличить номер выбранного канала», «Уменьшить номер выбранного канала», «Выключить позиционер» (перевести в дежурный режим), «Включить позиционер». Завершается большой цикл процедурой проверки правильности записи во флэш-память. Дело в том, что стандартные процедуры чтения/записи флэш-памяти, которые использованы в данном случае, содержат встроенную функцию проверки. Если в процессе чтения или записи информации во флэш-память произошел сбой, то процедура устанавливает в единичное состояние специальный флаг ошибки. Флаг ошибки — это
112 Самоучитель по микропроцессорной технике специально выделенный разряд в битовом пространстве памяти. В конце основного цикла происходит проверка этого флага. Если флаг установлен, то выполняется специальная процедура, которая кратковременно выводит на индикатор позиционера предупреждение об ошибке («Ег»). Такая индикация очень помогает в процессе поиска неисправностей. После проверки флага ошибки программа переходит к началу основного цикла, и все повторяется сначала. В дежурном режиме ход выполнения основного цикла меняется. В этом случае выполняется другой — малый цикл. Он состоит всего из двух модулей. Модуль подготовки дежурного режима предназначен для приостановки всех выполняемых в этот момент операций. В этом модуле выполняются команды остановки двигателя, выключения индикаторов, а также включения индикатора дежурного режима. Модуль, обозначенный как «Остановка процессора», состоит всего лишь из одной команды. Эта команда устанавливает младший разряд регистра PCON в единичное состояние, чем включает режим останова процессора. В этом режиме процессор прекращает выполнение основной программы, но продолжает обрабатывать прерывания. Обе процедуры обработки прерываний в дежурном режиме работают в урезанном виде. Они выполняют только одно действие: ожидание сигнала выхода из дежурного режима. При нажатии кнопки «Вкл/Выкл» клавиатуры позиционера, либо при получении команды на включение от пульта ДУ, соответствующая процедура сбрасывает младший бит регистра PCON в ноль. После этого работа программы продолжается в обычном режиме. Описание констант и переменных Теперь рассмотрим, как вышеописанный алгоритм реализуется в виде текста программы на языке Ассемблера. И самым первым действием этой программы всегда является описание констант и переменных. Настал момент пояснить, что такое константы и переменные с точки зрения программирования. Константа — это просто некоторое число, которое часто используется в программе, и имеет какой-либо определенный смысл. Например, длительность задержки таймера, количество бит информации в сигнале ДУ, адрес некоторой часто используемой ячейки памяти (например, адрес буфера клавиатуры, адрес буфера сигнала управления мотором и так далее). В любом языке программирования, в том числе и в языке Ассемблера, такие величины принято заменять символическими име-
Позиционер спутниковой антенны 113 нами. Делается это при помощи специальных операторов. Если говорить об Ассемблере, то в нем существует несколько операторов, при помощи которых можно определить константу: DATA определение константы, являющейся адресом ячейки внутренней памяти данных. I DATA .... определение константы внутренней памяти с косвенной адресацией. BIT определение битовых констант. CODE определение константы в памяти программ. EQU универсальный оператор определения констант. Мы начнем с последнего из них. Оператор макроопределения EQU (сокращение от английского equivalent — эквивалентно) позволяет закрепить за любым числом, кодом регистра, названием порта символьное имя. Сразу после этого вы можете использовать это имя везде, где предполагается использовать скрытое под этим именем значение. Рассмотрим пример использования такого оператора. В программе позиционера в нескольких местах используется коэффициент, определяющий длительность задержки динамической индикации. Значение этого коэффициента равно 0D8H. Присвоим этому коэффициенту символьное имя. Для этого в тексте программы нужно записать следующую команду: idind EQ'J 0D8H Приведенная выше команда создает константу с именем tdind, и присваивает ей значение 0D8H. Теперь, когда имя константы определено, в любом месте программы, вместо 0D8H можно писать tdind. Например, команды mov A,#0D8H и mov A.tttdind будут теперь полностью равнозначны. Обе они записывают код 0D8H в аккумулятор (регистр А). Определение констант в принципе не обязательно, но весьма желательно. Во-первых, это улучшает читаемость программы, а во-вторых, облегчит процесс последующей модернизации. Представьте, что мы полностью отказались от определения констант и написали программу, в которой вместо имен переменных просто стоят их значения. В процессе отладки программы или при ее доработке вам обязательно придется еще и еще раз просматривать ее текст. Встретив в программе код 0D8H, вам придется долго разбираться, действительно ли это постоянная вре-
114 Самоучитель по микропроцессорной технике мени индикации, или это случайное сонпадение значений. Встретившееся число не обязательно будет именно константой задержки. В программе вполне может встретиться и другая величина, равная 0D8H. Если же вместо константы стоит ее имя, уже при беглом взгляде на программу, сразу видно ее назначение. Имя tind в нашем примере — это просто сокращение, означающее «период индикации». Теперь представим себе, что мы решили изменить период индикации. Вот тут-то и проявятся все преимущества механизма определения констант. Если постоянная времени индикации определена как константа tind, то для замены ее значения во всем тексте программы достаточно поменять его лишь в одной строке, в той, где она описывается. Представьте, на сколько было бы сложнее выискивать все случаи применения константы по всему тексту программы. Особенно если учесть, что полный текст описываемой здесь программы позиционера содержит более тысячи строк. Рассмотрим подробнее особенности применения оператора EQU. Как мы видели из примера, в левой его части должно находиться имя, которое мы присваиваем этой константе. В данном случае имя не должно оканчиваться символом двоеточия. При выборе имени программист должен руководствоваться общими правилами построения имен в языке Ассемблера: 1.Для написания имени допускается использовать исключительно буквы латинского алфавита и цифры. Кроме того, допускается применение символа подчеркивания (_), который рассматривается как буква. 2. Первым символом обязательно должна быть буква. Это правило введено для того, чтобы Ассемблер всегда мог отличить имя константы или переменной от числового значения. Как известно при записи числа в шестнадцатеричной форме также могут использоваться символы латинского алфавита. Правила Ассемблера предписывают: при написании числа первым символом всегда должна быть цифра. Если число шест- надцатеричное, и первый знак — буква, то перед ним нужно поставить незначащий ноль. Например, вместо F5E4H нужно писать 0F5E4H. В правой части оператора EQU записывается значение описываемой константы. Сюда можно поставить число, записанное в любом формате — двоичном, десятичном, шестнадцатеричном. Кроме того, там может стоять простое арифметическое или логическое выражение. В качестве членов этого выражения, кроме чисел, могут выступать любые ранее определенные константы. Например, возможно следующее определение двух констант: konsU EQU 3 5
Позиционер спутниковой антенны 115 kor.st2 EQU konstl + 3 Этот фрагмент программы определяет константу konstl, имеющую значение 35 и константу konst2, имеющую значение 38 C5+3). Правильное распознавание подобных выражений обеспечивается специальной функцией программы-транслятора, которая называется «механизм препроцессора». Кроме того, в правой части оператора EQU можно указать имя любого из внутренних регистров процессора, включая любой регистр общего назначения (РОН). Например: 1 flash EQU r<l rabl EQU DPL rab2 EQO асе. 2 В последнем примере в качестве переменной гаЬ2, определен бит номер 2 аккумулятора. В данном случае доступ к аккумулятору происходит как к ячейке памяти. На языке Ассемблера принято в этом случае обозначать аккумулятор именем асе. Вернемся теперь к остальным операторам Ассемблера, позволяющим определять константы в программе (DATA, IDATA, BIT, CODE). Порядок их использования точно такой же, как и порядок использования оператора EQU. Отличие их только в том, что кроме присвоения значения переменной, они одновременно определяют ее тип. Например, константа, описанная оператором DATA, по определению является ячейкой ОЗУ. Транслятор автоматически проверяет правильность применения определенных вами констант и в случае некорректного их применения сообщает об ошибке. Точно также действуют и остальные операторы определения констант. Кроме констант, которые, согласно своему названию, в течение всего времени работы программы никогда не меняются, в программе существуют переменные. Под переменной в программе понимается имя регистра, либо адрес ячейки памяти, где в процессе выполнения программы будет временно храниться какая-либо заранее неизвестная величина, либо промежуточный результат вычислений. Существует несколько способов определения переменных. Первый возможный способ — это определение ячейки, для хранения переменной при помощи того же самого оператора EQU. В этом случае оператор EQU действует точно так же, как и при определении констант. Вообще понятия «константа» и «переменная» в языке Ассемблера тесно связаны. Поясню сказанное на простом примере. Допустим, нам нужно выделить одну из ячеек
116 Самоучитель по микропроцессорной техник памяти для хранения значения счетчика неких событий. Мы решил: использовать для этого ячейку ОЗУ с адресом ЗОН. Для этой цели mi должны включить в текст программы следующую команду: соил EQU ЗОН Данной строкой мы создали константу с именем coun. Одновременно ; нас появилась переменная с тем же именем. Константа — это адре^ ячейки памяти, а переменная — это значение, хранящееся в этой ячей ке. Пример использования константы count и переменной count иллю стрируют следующие две команды: mov a,Scount xov a,count Первая из команд загружает адрес данной ячейки памяти (ЗОН) в ак кумулятор. Вторая команда загружает в аккумулятор содержимое это) ячейки. Символ # применяется в том случае, когда нужно показать, чт< следующее за ним число — это байт данных. Если такой символ отсут ствует, то число интерпретируется как адрес ячейки ОЗУ. Теперь рассмотрим, как определяются константы и переменные в тек сте управляющей программы позиционера. Обратимся к фрагменту №1 Фрагмент представляет собой начало реального текста этой програм мы. Внимательно посмотрите на текст. Здесь вы увидите уже знакомьп вам операторы описания программных констант и несколько еще пок; не знакомых операторов. Об их назначении я расскажу в конце этоп раздела. Приведенная программа снабжена подробными комментария ми, что поможет вам понять назначение каждой из создаваемых пере менных. Напомню, что признак комментария — символ «точка с запя той». Все, что написано справа от него до конца строки не являете; программой и при трансляции полностью игнорируется. Для удобства восприятия, я условно разбил программу на секции. I каждой секции объединены операторы, определяющие близкие по на значению константы. Каждая секция снабжена заголовком, которьп тоже является комментарием. Вообще, чем больше комментариев вь вставите в текст своей программы, тем легче вам будет потом в не) разобраться. Особенно по прошествии некоторого времени. Фрагмент №1. ; ** Программа управления позиционером спутниковой антенны $mod2051
Позиционер спутниковой антенны ; Коды выбора банка РОН bankO EQU 00000000В banki EQU 00001000B bank2 EQU 00010000B ЬапкЗ EQU O0011000B I Определения клавиш kknot EQU 10111111B ; Все клавиши отпущены kkru EQU 10111110B ; Работа/Установка kkmi EQU 10111101B ; Канал- kkpl EQU 10111011B ; Канал+ kkss EQU 10110111B ; Клавиша S (запись/стирание) kkal EQU 10101111B ; Антенна влево kkar EQU 10011111B ; Антенна вправо kkon EQU 00111111В ; Вкл/Выкл bitonof EQU 7 ; Бит кнопки Вкл/Выкл ; Сброс флэш-памяти (нажато 5 клавиш) kkres EQU kkal AND kkar AND kkpl AND kkmi ; Переменные основного цикла USING 0 nk EQU 4 ; Номер канала nkh EQU r4 ; старший разряд номера канала nkl EQU r5 ; младший разряд номера канала klold EQU гб , предыдущее состояние клавиатуры _klold EQU 6 ; sger EQU г 7 ; антидребезговый накопитель tger EQU 20 ; постоянная времени антидребезга ; Переменные вывода/ввода USING 1 ibuf EQU r3 ; Указатель текущего разряда индикации iflash EQU r4 ; Счетчик мерцаний tflash EQU 40 ; Период мерцаний tdind EQU 0D8H ; Период динамической индикации ; Переменные ПП обмена с 24Схх. USING 2 index EQU r0 ; указатель буфера kount EQU li ; регистр счетчика байтов zdata EQU r1 ; регистр данных addrjo EQU r2 ; 2x байтовый регистр адреса addr_hi EQU r3 ; koupop EQU r4 ; Счетчик попыток записи ; Константы для ПП обмена с 24Схх FADDR EQU OAOh ; Фиксированный адрес для EEPROM АТ24Схх PADDR EQU 0 ; Программируемый адрес @.7) SIZE EQU 256 ; Размер памяти (в байтах) PSIZE EQU 2 ; Размер страницы (в байтах) ; Константы ДУ Kduih EQU OFEH ; Константа режима ожидания (min) Kduil EQU 0F4H Kdu2h EQU OFCH ; Константа режима приема (max) Kdu2l EQU 0DFH
118 Самоучитель по микропроцессорной технике Возможно, вы обратили внимание на то, что в тексте программы в названиях регистров и портов ввода/вывода используются строчные (маленькие) буквы, хотя ранее, я использовал прописные. Дело в том, что Ассемблер, как и многие другие языки программирования, не чувствителен к регистру. Вы можете писать команды, имена меток, названия регистров как прописными, так и строчными буквами. Для программы они равнозначны. То, какими буквами вам писать — дело вашего личного вкуса. Рассмотрим фрагмент №1 программы подробнее. Начнем с самого первого оператора программы (не считая комментариев), то есть с команды $mod2051. Эта команда служит для присоединения внешней библиотеки описаний. Что такое внешняя библиотека описаний, и зачем она нужна? Дело в том, что данная версия ассемблера является универсальным инструментом. С его помощью можно создавать программы для любых видов микропроцессоров, имеющих сходную систему команд. У каждого из таких процессоров свой набор внутренних регистров, портов ввода/вывода и ячеек битового пространства памяти. Общее в них — система команд и способы доступа к ячейкам ОЗУ и внутренним регистрам. Для того, чтобы обеспечить универсальность программы транслятора, применен стандартный прием для языков подобного уровня — это механизм внешних библиотек. В основной модуль программы транслятора не заложена информация о регистрах и портах. Эта информация содержится в библиотечных файлах. Библиотечный файл — это специальный файл, содержащий фрагмент программы на языке Ассемблера, в котором опи- t Коды кнопок на пульте ДУ sd1 EQU ООН , Кнопка «1» sdpw EQU 57H , Кнопка «Вкл/Выкл» sdpm EQU 79H , Кнопка «Р-» sdpp EQU 0В9Н , Кнопка «Р+» i Адреса во внешней флэш-памяти fnk EQU 210 , текущий номер канала fpa EQU 212 , текущее положение антенны ffl EQU 214 , Хранение регистра флагов ftdu EQU 216 , Хранение константы ДУ fkonof EQU 218 , Хранения кода ON/OFF ДУA) fkpl EQU 220 , Хранение кода К+ ДУ B) fkmi EQU 222 , Хранение кода К- Ду C) , Подключение шин микроконтроллера к последовательной шине АТ24Схх SCL BIT p1 2 , линия синхронизации SDA BIT p1 3 , линия данных Другие подключения IGER BIT p1 4 , Линия подключения геркона IDU BIT р1 5 , Линия подключения ДУ
Позиционер спутниковой антенны 119 саны все внутренние регистры, порты и битовые ячейки конкретного процессора. Для каждого процессора фирма-разработчик Ассемблера создала свой библиотечный файл. В стандартный комплект поставки входит 21 библиотечный файл. Это значит, что данный транслятор поддерживает возможность создания программ для 21 вида процессоров. Однако в стандартном пакете отсутствует файл библиотеки для процессора АТ89С2051. Причина этого проста — на момент разработки данного Ассемблера такого процессора просто еще не существовало. Поэтому мне пришлось создать такой файл самостоятельно. За основу я взял библиотечный файл для процессора iMCS-51. Этот файл имеет имя mod51 (библиотечные файлы в данном случае имеют только имя и не имеют расширения). Я подкорректировал содержимое файла mod51 и записал его под новым именем: mod2051. Команда $mod2051 просто присоединяет текст библиотечного файла к тексту основной программы в момент трансляции. Найти полный пакет программы Ассемблера со всеми библиотечными файлами, включая файл mod2051, вы можете в Интернете, на сайте «Цифровые микросхемы и микропроцессоры» по адресу http://microprocessor.by.ru (раздел «Download»). При желании вы можете самостоятельно изучить содержание любого библиотечного файла. Для этого нужно просто открыть этот файл при помощи любого простейшего текстового редактора. Удобнее всего это сделать при помощи программы Windows Commander, используя его стандартный просмотрщик файлов, вызываемый при помощи клавиши F3. Все файлы библиотек содержат в своем тексте исчерпывающие комментарии. Но вернемся к нашему фрагменту управляющей программы. Основная ее часть состоит из описаний различных констант и переменных. Для лучшего восприятия программы я условно разбил все описания на небольшие группы по их назначению. Каждая группа имеет заголовок. По ходу дальнейшего объяснения я буду ссылаться на эти заголовки. Коды выбора банков РОН. Эти константы используются в программе для выбора одного из банков регистров общего назначения. Для выбора нужного банка РОН достаточно записать в регистр PSW один из четырех описываемых здесь кодов. Например, для выбора банка 0 достаточно включить в текст программы следующую команду: ~ov PSW,ttbankO Данная команда записывает в регистр PSW код bankO (то есть 00000000В). Биты 3 и 4 регистра обнуляются, что и определяет требуемый банк. Посмотрев на текст программы фрагмента №1, можяо убедиться, что биты 3 и 4 остальных констант (bankl, bank2 и ЬапкЗ) при-
120 Самоучитель по микропроцессорной технике нимают значения, определяющие соответствующий банк. Остальные биты @, 1, 2, 5, 6, 7) во всех четырех случаях обнуляются. Потеря значений всех системных флагов — это недостаток данного способа переключения банков. Однако при разработке программы позиционера эта особенность учтена и не вызывает никаких проблем. Определения клавиш. В этой группе собраны команды, определяющие константы для подпрограммы обработки команд с клавиатуры. Как уже говорилось, специальная программа периодически считывает байт состояния клавиатуры. В этом байте каждой кнопке клавиатуры соответствует свой отдельный бит. Если кнопка нажата, соответствующий бит равен нулю, если отпущена, он равен единице. Исключение составляет лишь один разряд — разряд номер 6 (предпоследний). Связано это с тем, что разряд Р3.6 в микросхемы АТ89С2051 на внешние выводы не выводится. На него поступает сигнал от встроенного компаратора. Компаратор в схеме позиционера не используется. Его входы используются совсем для других целей. Поэтому состояние шестого бита — величина неопределенная. Для того, чтобы исключить эту неопределенность, в программе обработки сигналов с клавиатуры этот бит специальной командой сбрасывается в ноль. И лишь затем полученный код записывается в буфер клавиатуры. В результате, для каждого из возможных состояний клавиатуры мы будем иметь в буфере свой уникальный код. Так, если нажата только кнопка «Канал —», мы получаем код состояния клавиатуры, равный 10111101В. Если нажата только кнопка «Канал +», код будет равен 10111011В, и так далее. Для каждого такого кода мы создаем отдельную константу и присваиваем ей уникальное имя. Далее эти константы используются в программе для распознавания факта нажатия той или иной клавиши и запуска соответствующей процедуры. Применение констант в данном случае позволяет легко менять назначение кнопок на пульте, например в случае, когда нужно изменить разводку для оптимизации печатного монтажа. В этой же секции определяются еще две величины: bitonoff и kkres. Способ их определения отличается от только что описанного. Константа bitonoff определяет ту же кнопку, что и константа kkon, но другим способом — по номеру отвечающего за нее бита. (Нумерация битов начинается с нуля). Эта константа потребовалась потому, что в одной из подпрограмм для оценки состояния этой кнопки («Вкл/Выкл») не используется байт состояния клавиатуры. Оценка производится путем прямого считывания значения соответствующего разряда порта РЗ. Константа bitonoff определяет адрес этого бита в битовом пространстве процессора.
Позиционер спутниковой антенны 121 Особым образом определяется константа kkres. Эта константа описывает код состояния клавиатуры в тот момент, когда нажаты сразу четыре кнопки: «Канал +», «Канал —», «Поворот влево» и «Поворот вправо». Нажатие четырех кнопок одновременно применяется для запуска процедуры полного сброса и используется в процессе начальной наладки для перевода системы в исходное состояние. Для того, чтобы полный сброс не был включен случайно, применяется такой сложный способ вызова этой процедуры. Для определения константы kkres применяется логическое выражение. Выражение представляет собой логическое умножение четырех кодов. Каждый из этих кодов соответствует одной из четырех, совместно нажимаемых клавиш. В результате выполнения операции логического умножения происходит объединение по функции «И» одноименных разрядов всех кодов, входящих в выражение. В результате мы получим число, в котором каждый разряд будет равен нулю в том случае, если хотя бы в одном из объединяемых чисел, соответствующий разряд тоже равен нулю. В исходном варианте это выглядит следующим образом: kkal IClOlillB kkar 10011111В kkpl 10П101 IB kkmi 10111101B kkres 10001001B Такой способ определения константы добавляет программе гибкости. Если возникнет необходимость в смене кодов клавиатуры, то переопределять переменную kkres уже не придется. Далее в программе идут три группы операторов определения переменных: «Переменные основного цикла», «Переменные ввода/вывода» и «Переменные ПП обмена с 24Схх». В каждой группе описываются переменные одной из трех разных подпрограмм. Более подробно назначение всех этих переменных вы узнаете при рассмотрении соответствующих фрагментов программы. Здесь же я хотел бы остановить ваше внимание всего на нескольких моментах. Первая строка из группы «Переменные основного цикла» определяет переменную пк и присваивает ей значение 4. Эта переменная предназначена для хранения номера текущего выбранного канала. Причем для хранения этого номера используется две соседние ячейки памяти. Доступ ко второй легко осуществить, используя выражение nk+1. Следующие две строки определяют переменные nkh и nkl. За ними закрепляются значения, соответствующие регистрам г4 и г5, соответственно. При выборе банка 0, регистр г4 будет соответствовать ячейке памяти с адресом 4 (nk), а регистр г5 соответствовать ячейке 5 (nk+1). Это два способа доступа к одним и тем же переменным.
122 Самоучитель по микропроцессорной технике Почему два способа? А просто при написании программы в одном случае оказалось рациональнее использовать регистры, а в другом удобнее обращаться к ячейке памяти. По той же самой причине двумя способами определена ячейка памяти с адресом 6 (предыдущее состояние клавиатуры). Переменная klold — это доступ к ячейке, как к регистру РОН, а переменная _klold —- это доступ к той же самой ячейке напрямую. В тексте фрагмента №1 вы можете видеть несколько еще незнакомых вам операторов. Один из них — это оператор USING. Остановимся на нем немного подробнее. Оператор USING тесно связан с выбором банка регистров. При разработке программы я определил для каждого из банков свою область применения. В основном цикле программа использует нулевой банк. Подпрограмма ввода/вывода и динамической индикации использует банк номер один. Подпрограмма обмена с внешней флэш-памятью использует банк номер два. Банк номер три остался в резерве. В связи с этим, при определении соответствующих переменных используются операторы USING О, USING 1 и USING 2. Эти операторы не переключают банки регистров. Каждый из них лишь сообщает транслятору, что описанные после него регистры принадлежат к тому или иному банку. Эта информация используется транслятором для поиска ошибок. В группе операторов «Константы для ПП обмена с 24Схх» и «Константы ДУ» никаких особенностей нет. В первой из них происходит определение констант для стандартных подпрограмм обмена информацией с внешней флэш-памятью по протоколу 12С-шины. Во второй, определяются константы для подпрограммы обработки сигналов с пульта ДУ. Следующая группа команд описывает адреса во внешней флэш-памяти. Энергонезависимая флэш-память используется для хранения не только 99 позиций антенны, но и нескольких переменных, которые не должны потеряться при выключении питания. Для этого резервируется несколько адресов. Для каждого такого адреса имеет смысл определить свою специальную константу. И последние две маленькие группы команд фрагмента №1 присваивают символьные имена тем разрядам порта Р1, которые имеют в нашей схеме специальное назначение. В данном случае применяется оператор BIT. Думаю из текста программы все ясно. Резервирование памяти В предыдущем разделе мы изучили один из способов определения системных переменных. Существует и другой способ. Этот способ при-
Позиционер спутниковой антенны 123 меним в том случае, когда известно, что переменные будут храниться в пространстве обычной памяти. И в то же время не имеет значения, в какой именно ячейке, какая переменная будет храниться. Этот способ называется резервированием памяти. Резервирование памяти производится при помощи специальных операторов. В рассматриваемой версии языка Ассемблера имеются два оператора резервирования памяти: DS — оператор резервирования одной или нескольких ячеек ОЗУ. DBIT — оператор резервирования одного или нескольких бит в битовом пространстве. Ниже приведен Фрагмент №2 управляющей программы позиционера, в котором производится резервирование памяти для всех переменных, не описанных во фрагменте №1. Фрагмент №2 ; Резервирование ячеек памяти DSEGAT30H bufh: DS 1 ; ст. разряд буфера экрана bufl: DS 1 ; мл. разряд буфера экрана bufkl: DS 1 ; Буфер клавиатуры bufmot: DS 1 ; Буфер управления мотором dopmot: DS 1 ; Регистр направления вращения мотора patek: DS 2 ; Ячейка текущего положения антенн pakan: DS 2 ; Ячейка требуемого положения антенны coucl: DS 1 ; ячейка счетчика задержки реж. стирания tzcle EQU 150 ; константа задержки режима стирания coudd: DS 1 ; счетчик очистки дисплея от спецсимволов tzdd EQU 100 ; задержка очистки дисплея tdu: DS 2 ; Ячейка хранения константы ДУ B байта) bufdu: DS 2 ; Буфер кода ДУ (принятый код) bufdul: DS 2 ; Буфер кода ДУ (Код из флэш-памяти) ORG 28H strzdu: DS 1 ; Счетчик принятых разрядов ДУ kolrzdu EQU 28 ; Мах количество принятых разрядов ; Определение системных флагов BSEG ORG 0 flks: DBIT 1 ; Флаг "Клавиша S нажата" flsav: DBIT 1 ; Флаг "Режим записи ВКЛ" flflh. DBIT 1 ; Флаг "Мерцание ВКЛ" flifl: DBIT 1 ; Флаг "Гореть/не гореть" flmot: DBIT 1 ; Флаг разрешения автоустановки антенны flerf: DBIT 1 ; Флаг ошибки памяти flsM: DBIT 1 ; Служебный флаг 1
124 Самоучитель по микропроцессорной технике flsl2: DBIT 1 ; Служебный флаг 2 flgis: DBIT 1 ; Флаг гистерезиса для антидребезга flonoff: DBIT 1 , Флаг включено A)/ выключено @) fladu. DBIT 1 ; Флаг фазы приема ДУ flkdu: DBIT 1 ; Флаг считано/не считано ДУ flokdu. DBIT 1 ; Флаг "код ДУ готов" flondu: DBIT 1 ; Флаг задержки включения ДУ bufbit: DBIT 1 ; Буфер предыдущего бита ДУ flreg EQU 22Н ; Регистр сохраняемых флагов flru EQU flreg. 1 ; Флаг работа/установка Рассмотрим этот фрагмент подробнее. Как вы могли убедиться, я разделил все команды резервирования на две секции. В первой секции происходит резервирование ячеек ОЗУ, а во второй — резервирование ячеек битового пространства. Каждая секция начинается с оператора определяющего, какое из доступных пространств памяти используется. Дело в том, что процессоры, для которых предназначен описываемый Ассемблер, могут иметь до шести пространств памяти. Каждое пространство имеет свое уникальное имя: RSEG Пространство регистров (РОН). DSEG Пространство внутренней памяти данных. ISEG Пространство ячеек основной памяти с косвенной адресацией. BSEG Битовое пространство данных. XSEG Пространство внешней памяти данных. CSEG Пространство программной памяти. Процессор АТ89С2051 использует только пять видов пространств. Внешняя память у этого процессора отсутствует. А значит, у него отсутствует пространство XSEG. Каждое из этих пространств имеет свой указатель текущей незанятой ячейки памяти. Посмотрите на начало фрагмента №2. Оператор DSEG AT ЗОН в начале фрагмента выбирает в качестве текущего, сегмент DSEG. Необязательный параметр AT ЗОН устанавливает значение указателя этого сегмента равным ЗОН. Далее идет ряд операторов DS. Каждый такой оператор выделяет одну или несколько ячеек памяти для очередной переменной. Справа от оператора ставится имя переменной, для которой резервируются ячейки. Слева — обязательный параметр, равный числу выделяемых ячеек. Этот параметр может быть равен от 1 до любого разумного числа, но не больше, чем общий объем выбранного пространства. Выделение памяти начинается с ячейки, адрес которой равен текуще-
Позиционер спутниковой антенны 125 му значению указателя. Затем значение указателя увеличивается на величину, равную числу выделенных ячеек. Если вернуться к фрагменту №2, то первый оператор DS в этом фрагменте выделит одну ячейку с адресом ЗОН для переменной bufli. Следующий выделит одну ячейку с адресом 31Н под переменную bufl, и так далее. Под переменную patek выделяется сразу две ячейки. Их адреса будут равны 35Н и 36Н. Имена переменных используются в программе точно так же, как и в предыдущем случае. Команда mov a,bufh запишет в аккумулятор содержимое ячейки bufh. Команда mov a,#bufh запишет в аккумулятор адрес этой ячейки. Поэтому имена зарезервированных ячеек могут использоваться как константы. Операторы DS совсем не обязательно должны следовать друг за другом. Они могут перемежаться любыми другими командами. В приведенном фрагменте, таким образом, попутно, определяются две константы: tzcle и tzdd. Пока не будет определен другой сегмент памяти, операторы DS будут последовательно выделять память в текущем сегменте. Новая ячейка всегда будет выделяться непосредственно после предыдущей. Однако, в случае необходимости, вы всегда можете принудительно поменять значение указателя. Для этой цели используется специальный оператор ORG. Этот оператор не может выбрать другой сегмент памяти, он лишь устанавливает указатель, принадлежащий текущему сегменту, в новую позицию. В рассматриваемом фрагменте программы такой оператор применяется в конце первой секции. Он устанавливает указатель в позицию 28Н. В результате последующий оператор DS резервирует для переменной strzdu одну ячейку памяти с адресом 28Н. Главным преимуществом такого способа определения переменных является то, что программисту не надо следить за правильностью выделения памяти. Компьютер сам присвоит разным переменным разные ячейки памяти. Если вы случайно некорректно применили оператор ORG и попытались установить указатель сегмента в позицию, которая уже занята, транслятор выдаст сообщение об ошибке. Несколько слов необходимо сказать о том, почему в нашей программе для размещения переменных выбраны именно эти адреса памяти. Адрес ЗОН не случайно начинает область для хранения переменных. Это первая из ячеек ОЗУ, которая не несет никаких дополнительных функций (см. рис. 42). Она не совмещена ни с РОН, ни с битовым пространством. Естественно, если ситуация не требует двойного доступа к ячейкам, то разумнее применять именно эти ячейки. Ячейки с адресами от ООН до 1FH выгоднее адресовать, как регистры общего назначения. Все операции с регистрами имеют длину всего один байт и вы-
Л 26 Самоучитель по микропроцессорной технике полняются всего за один машинный такт. Операции же с ячейками ОЗУ требуют два такта и занимают два байта программной памяти. Ячейки ОЗУ, совмещенные с битовым пространством, пригодятся для хранения однобитовых переменных. И лишь в том случае, если требуется двойной доступ к ячейке памяти, удобно использовать адреса ОЗУ с 20Н по 2FH. В нашей программе такой способ потребовался для счетчика принятых разрядов ДУ. Имя переменной, предназначенной для хранения значения счетчика: strzdu. Для того, чтобы обеспечить возможность двойного доступа к счетчику, для него была выбрана ячейка с адресом 28Н. Команда резервирования этой ячейки приводится в конце фрагмента №2. Адрес младшего бита этой ячейки в битовом пространстве процессора равен 40Н. Вторая секция Фрагмента №2 программы, обозначенная, как «Определение системных флагов», по принципу работы аналогична первой. Различие в том, что в ней резервируются ячейки не в пространстве обычной памяти (DSEG), а в битовом пространстве (BSEG). Однобитовые ячейки выделяются для хранения так называемых флагов. Флаг — это обычная переменная, которая в процессе работы программы принимает только два значения и служит для запоминания какого-либо режима работы. Если переменная принимает только два значения, то ее разумно хранить именно в ячейке битового пространства. О том, как используются программные флаги, вы узнаете в последующих разделах книги. В данном же разделе мы рассмотрим процесс выделения ячеек в битовом пространстве процессора. Оператор BSEG выбирает в качестве текущего битовое пространство памяти процессора. Оператор ORG 0 устанавливает указатель этого пространства на нулевую отметку. Операторы DBIT выделяют указанное количество ячеек битового пространства, каждый для своей переменной. В нашем случае для каждой переменной выделяется только один бит. В последних двух строках сегмента применен альтернативный способ определения флагов. Здесь адрес ячейки флага определен как системная константа. Причем сначала определяется адрес в пространстве обычной памяти (DSEG). А затем адрес флага определяется, как бит номер 1 (второй по счету) этой ячейки. Такой способ определения бита, применим для любой ячейки памяти, регистра или порта ввода/вывода, допускающего побитовый доступ. Зачем в данном случае нам понадобилось такое двойное определение ячейки для флага? Дело в том, что указанный флаг необходимо сохранять во внешней флэш-памяти для того, чтобы после включения питания позиционер восстанавливал режим своей работы, выбранный перед выключением. Однако внешняя память работает только с целыми байтами. Поэтому
Позиционер спутниковой антенны 127 запоминается и затем восстанавливается сразу весь байт flreg. А используется для работы лишь один его бит flru. В заключение этого раздела необходимо отметить, что все перечисленные в этом и предыдущем разделах операторы, относятся к разряду псевдооператоров. Они получили такое название потому, что им не соответствуют никакие команды процессора. При трансляции этой части программы не происходит генерации кодов. Псевдооператоры служат исключительно для удобства составления программ и повышения эффективности программирования. Переопределение векторов прерываний Итак, мы заканчиваем описание псевдооператоров, которые существуют только в текстах программ на языке. Ассемблера, и переходим к изучению более реальных операторов, каждый из которых описывает некую команду из системы команд процессора. С некоторыми из таких операторов мы уже сталкивались в предыдущих разделах. Например, с оператором перемещения mov. На самом деле мнемокод mov применяется при описании множества разных команд процессора. Ниже приведено несколько примеров команды mov. Во втором столбце те же команды представлены в виде кодов процессора. mova.rO 0E8H Запись содержимого регистра гО в аккумулятор mova.ri 0E9H .Запись содержимого регистра г1 в аккумулятор mov a,r2 0EAH .Запись содержимого регистра г2 в аккумулятор mova.b 0E5H, OFOH Запись содержимого регистра b в аккумулятор mova,#32 74H, 20Н .Запись константы 32 в аккумулятор mov а,32 0Е5Н, 20Н .Запись содержимого ячейки с адресом ,32 в аккумулятор mova,@rO 0E6H .Запись в аккумулятор содержимого ячейки ОЗУ, .адрес которой хранится в регистре гО И это далеко не все варианты употребления команды mov. Обратите внимание, что в приведенном примере три первых команды, а также самая последняя кодируются при помощи всего лишь одного байта. Оставшиеся три команды двухбайтовые. Причем первый байт — это код операции, а второй — параметр (адрес используемой ячейки памяти или константа). Для каждой команды, входящей в систему команд процессорам, в языке Ассемблера существует определенные правила ее написания. Исчерпывающая информация по этому вопросу приведена в приложении 1. Теперь рассмотрим следующий фрагмент программы позиционера. В тексте книги он обозначен, как фрагмент №3. В реальной программе он
128 Сам оучитель по микропроцессорной технике непосредственно следует за фрагментом №2. Фрагмент №3 описывает именно те команды, которые и составляют самые первые ее байты, расположенные в самом начале программной памяти. Что же именно делает программа сразу после запуска? Она переопределяет векторы прерываний! И тут нам нужно подробнее остановиться на том, что же такое векторы прерываний и как их нужно переопределять. Как уже говорилось, микросхема АТ89С2051 имеет встроенную систему прерываний, рассчитанную на обработку пяти фиксированных запросов. Источники первых трех запросов — внутренние устройства самой микросхемы. Еше два запроса могут поступать от внешних устройств посредством входов INTO и INT1 (см. главу 2). Любой из таких запросов вызывает приостановку выполнения основной программы и переход к подпрограмме обработки прерывания. Встроенная система прерываний устроена таким образом, что за каждым из пяти обслуживаемых прерываний закреплен свой фиксированный адрес в программной памяти, где должно находиться начало процедуры обработки соответствующего прерывания. Получив запрос от одного из источников, встроенная система прерываний приостана&чива- ет выполнение основной программы и передает управление на один из фиксированных адресов. Ниже перечислены все эти адреса: Внешний запрос INTO 0003H Таймер ТО 00ОВН Внешний запрос INT1 ООПН Таймер Tl 001BH Последовательный канал ОО23Н Фиксированные адреса обработки прерываний принято называть векторами прерываний. Некоторые процессоры допускают программное изменение этих адресов. В этом случае говорят о переопределении векторов прерываний. В микроконтроллере АТ89С2051 прямое переопределение адресов прерывания не предусмотрено. Однако существует простейший прием, позволяющий разместить процедуры обработки прерываний в любом удобном месте программы. И, конечно же, это команды безусловного перехода. Для того, чтобы переопределить какой-либо вектор прерывания, нужно по адресу стандартного начала этого прерывания записать команду безусловного перехода на новый адрес. Посмотрите еще раз на список стандартных адресов обработки прерываний. Нетрудно заметить, что расстояние между любыми двумя соседними адресами всего 9 байт. Этого абсолютно не достаточно даже для самого простейшего случая. Стандартные адреса расположены так близко потому, что разработчики микросхемы заранее предполагали, что по этим адресам будут располагаться лишь команды безусловного перехода.
Позиционер спутниковой антенны 129 Адрес 0000Н — это начальный адрес для основной программы. Именно с этого адреса начинается выполнение программы сразу после включения питания. Здесь тоже придется расположить оператор безусловного перехода, так как основная программа не должна занимать фиксированные адреса, зарезервированные для системы прерываний. Теперь обратимся к фрагменту №3 программы и посмотрим, как записывается процедура переопределения векторов прерываний на языке Ассемблера. Начинается этот фрагмент с оператора инициализации программного сегмента CSEG с установкой указателя этой области в нулевое значение. Это означает, что действие всех последующих операторов отражается на программной памяти микроконтроллера. Выделение памяти для кодов команд происходит таким же способом, как и в операции резервирования памяти. Коды очередной команды размещаются в программной памяти, начиная с текущего значения указателя. Затем указатель перемещается ровно на столько байт, сколько занимает эта команда. Таким образом, коды команд располагаются в программной памяти последовательно, один за другим. При необ ходи мости, можно принудительно передвинуть указатель при помощи оператора ORG. Именно так и устроена программа, приведенная во фрагменте. По адресу 0000Н расположен оператор безусловного перехода к новому на- Фрагмент №3. ;## Начало программного кода ## CSEG AT 0000H jmp init ; после включения/сброса ; Переопределение векторов прерываний ORG 0003H ; переопределение вектора reti ; внешнего прерывания О ORG 000BH ; переопределение вектора jmp pint ; прерывания по таймеру О ORG 0013H ;переопределение вектора reti ; внешнего прерывания 1 ORG 001ВН ; переопределение вектора jmp scandu , прерывания по таймеру 1 ORG 0023H ; вектор прерывания по reti ; последовательному каналу
130 Самоучитель по микропроцессорной технике чалу основной программы. В качестве адреса перехода используется метка init. Затем, при помощи оператора ORG указатель программной области памяти поочередно устанавливается в каждую особую точку. В каждую из этих точек записываются команды переопределения вектора прерывания. В нашей программе из всех возможных источников прерываний используются только два. Это прерывание от таймера ТО и прерывание от таймера TI. Поэтому по адресам ОООВН и 001ВН находятся команды переадресации. Первая из них передает управление по адресу pint (процедура динамической индикации). А вторая запускает процедуру сканирования входа фотоприемника с адресом scandu. Во всех остальных особых точках стоит программная «заглушка» в виде команды reti. Это стандартная команда завершения процедуры обработки прерывания. Такие «заглушки» поставлены исключительно из предосторожности. При нормальном ходе выполнения программы, вызова этих прерываний не происходит. Однако, в случае какого-либо сбоя, например, в результате помехи по питанию, может произойти случайный вызов прерывания. Однако, встретив команду reti, прерывание сразу же завершится. Инициализация системы В предыдущем разделе мы увидели, как определяются начальные адреса всех трех основных модулей программы: основной программы и двух процедур обработки прерываний. Мы начнем с основного модуля. Из текста фрагмента №3 следует, что адрес начала основного модуля должен быть равен значению метки init. И первое, что должна сделать программа основного модуля — выполнить инициализацию системы. Что же такое инициализация? В понятие инициализации входит: 1. Присвоение начальных значений всем переменным программы. 2. Настройка всех внутренних систем микроконтроллера. 3. Восстановление режимов работы системы, установленных в предыдущем сеансе работы путем считывания соответствующих параметров из внешней флэш-памяти. 4. Выполнение процедур, предназначенных для установки всех периферийных устройств схемы позиционера в исходное состояние (очистка индикаторов, подтверждение команды остановки двигателя и т.д.). 5. Выполнение процедуры запуска системных счетчиков-таймеров и механизма прерываний микроконтроллера. Фрагмент №4 управляющей программы позиционера представляет собой процедуру инициализации. Рассмотрим ее подробнее.
Фрагмент №4. ; Инициализация ORG 0030H init: mov TCON,#0 ; Запрет счета таймеров clr flonoff ; Питание выключить mov bufkl,# kknot , Инициализация буфера клавиатуры mov _klold,# kknot ; и буфера предыдущего состояния iniO: mov sp, #(stack-1) ; Установка вершины стека ¦ Инициализация переменных динамической индикации mov PSW,#bank1 mov ibuf,#7FH ; Младший разряд как текущий mov iflash,#tflash ; Инициализация счетчика мерцаний ; Инициализация переменных основного цикла mov PSW,#bankO mov bufmot,#0 ; Сброс регистра управления мотором mov dopmot,#0 ; Сброс регистра управления мотором mov coucl,#tzcle ; Ини-ция счетчика задержки стирания mov coudd,#0 ; Ини-ция счетчика стирания спецсимволов ; Инициализация переменных ДУ mov strzdu,#kolrzdu ; Ини-ция счетчика принятых разрядов ДУ mov 1DH,#0 ; Обнуление г5 банк 3 ; Инициализация системных флагов clr flks ; Сброс флага "Клавиша S нажата" clr flsav ; Сброс флага записи clr flflh , Сброс флага мерцаний clr fladu ; Сброс всех флагов ДУ clr flkdu ; clr bufbit ; clr flokdu ; clr flondu ; ; Инициализация 12С-шины setb SDA ; Инициализация линии данных setb SCL ; Инициализация линии синхронизации ; Настройки из флэш-памяти mov a,#fpa ; Чтение текущего положения антенны mov b,#patek ; из флэш-памяти call rd_flh mov a,#ffl ; Чтение регистра флагов из флэш-памяти mov b,#flreg call rd_flh mov a,#fnk ; Чтение номера канала из флэш-памяти mov b,#nk call rd_flh mov a.nkh ; проверка НК на корректность clr с subb a,#10 jnc ini 1
132 Самоучитель по микропроцессорной технике Начинается этот фрагмент с оператора ORG. Он устанавливает указатель сегмента в положение ЗОН. Именно с этого адреса и начинается основной программный модуль. Метка init, поставленная перед первым оператором программного модуля, автоматически принимает значение ЗОН. Конечно, можно было бы обойтись и без метки — применить прямую адресацию. При этом во фрагменте №3 вместо команды jmp init, стояло бы jmp ЗОН. Но так не принято. Хороший стиль программирования предполагает обязательное использование метки. Это добавляет гибкости вашей программе. Если для вызова всех ваших процедур используются метки, вы можете легко перемешать уже готовую процедуру в любое другое место, вставлять новые процедуры между двумя любыми уже существующими. При этом целостность алгоритма не будет нарушена. Теперь рассмотрим по порядку назначение всех команд Фрагмента №4. Первая команда осуществляет «запрет счета таймеров». Это обычная команда mov, которая помещает в регистр специального назначения TCON байт, значение которого равно нулю. Специальный регистр TCON предназначен для управления таймерами. Установка всех его битов в нулевое состояние отключает оба встроенных таймера-счетчика микроконтроллера. Данный запрет понадобился исключительно из предосторожности. После начального сброса системы этот регистр и так содержит код ОН. Команда лишь подтверждает его. Однако в некоторых случаях приходится осуществлять программный перезапуск системы. mov a.nkl clr с subb a,#10 jc ini2 ini1. mov nkh,#O ; Установка канала 1 mov nkl,#1 ini2. call nkadr ; Установка адресов флэш-памяти call rd_flh , Чтение требуемого положения антенны setb flmot ; Включение автослежения ; Программирование таймеров — ini4: mov TMOD,#00010001B ; Выбор режима работы таймеров mov THO, #tdind , Период динамической индикации том TLO, #0 ; Период динамической индикации mov ТН1,#0 , Запись константы ДУ mov TL1, #0 mov IE, #1000Ю10В , Маска прерываний mov IP, #0000Ю00В , Установка приоритетов mov TCON,#01010000B ; Разрешение счета таймеров
Позиционер спутниковой антенны 133 Программный перезапуск может понадобиться при обнаружении сбоев в программе. Он осуществляется при помощи команды условного (или безусловного) перехода на нулевой адрес. В этом случае и пригодится команда остановки системных таймеров. Программные таймеры останавливаются только на время инициализации системы, чтобы запретить процедуры прерываний до тех пор, пока не будут закончены все настройки. Запуск прерывания при не полностью настроенной системе может привести к неправильной работе процедур обработки прерываний и, как следствие, к краху системы. Следующая команда нашей программы («питание выключить») сбрасывает флаг flonoff в ноль. Здесь используется новая для нас команда процессора clr. Эта команда используется для сброса в ноль содержимого любой ячейки битового пространства микроконтроллера. Флаг flonoff используется программой для переключения режимов «основная рабо- та»/«дежурный режим». Нулевое состояние этого флага означает, что позиционер находится в дежурном режиме. Таким образом, сразу после включения питания позиционер переходит в дежурный режим. Все процедуры, выполнение которых происходит по-разному в основном и дежурном режимах, проверяют значение этого флага и в зависимости от его состояния меняют алгоритм своей работы. Переключение флага происходит в момент нажатия кнопки «Вкл/Выкл» (S7) на передней панели позиционера. Следующие две команды производят запись начальных значений в ячейки, служащие буферами состояния клавиатуры. В качестве начального значения в обе эти ячейки записывается код, соответствующий состоянию «все клавиши отпущены» (см. Фрагмент Ml). Поясню, зачем нужны два буфера. В буфере bufkl во время работы программы всегда хранится текущее состояние клавиатуры. Во втором буфере _klold хранится состояние клавиатуры, считанное в предыдущем цикле проверки ее состояния. Значение предыдущего состояния клавиатуры используется при определении момента нажатия или момента отпускания клавиши. Команда установки вершины стека сводится к записи в регистр SP требуемого начального значения. В качестве начального значения используется константа stack, значение которой задано в модуле описаний (см. Фрагмент №1). В процессе записи в стек, содержимое регистра SP увеличивается. При извлечении из стека, содержимое SP уменьшается. Особенность работы стека такова, что возможна ситуация, когда значение стека превысит свое начальное значение на единицу. Поэтому начальное значение регистра SP принято брать на единицу меньшим адреса вершины стека.
134 Самоучитель по микропроцессорной технике Инициализация переменных динамической индикации. Эта группа команд предназначена для присвоения начальных значений группе переменных, используемых в процедуре динамической индикации. На самом деле в данной процедуре используется гораздо больше переменных, но лишь две из них требуют начальной инициализации. Для хранения обеих этих переменных использованы регистры общего назначения. Одна из них — это указатель текущего разряда индикации. Он обозначен как ibuf. Второй — это счетчик мерцаний (iflash). Процедура динамической индикации работает с банком I регистров общего назначения. Поэтому, прежде чем присваивать начальные значения переменным, нужно выбрать первый банк. Для этого в регистр PSW записывается соответствующая константа. Код 7FH, записанный в регистр ibuf соответствует младшему разряду индикатора. Подробнее об этом вы прочитаете в разделе, посвященном процедуре динамической индикации. Сейчас вам достаточно понять, что процесс индикации начнется с младшего разряда. Что такое счетчик мерцаний (iflesh), нужно пояснить особо. Дело в том, что программа вывода на индикатор кроме обычного режима индикации должна обеспечивать режим мерцания. Этот способ индикации используется в режиме записи позиции антенны в память позиционера. Для организации мерцания используется этот счетчик. Принцип работы счетчика прост. Он отсчитывает определенное количество циклов динамической индикации и гасит индикатор. Затем опять отсчитывает такое же количество и зажигает изображение. Начальное значение счетчика мерцания — это коэффициент пересчета. От значения этого коэффициента зависит частота мерцания. Инициализация переменных основного цикла. О том, что такое основной цикл подробно говорилось в главе 2. Из всех переменных основного цикла инициализации требуют всего четыре. Все четыре переменные для своего хранения используют ячейки ОЗУ. В связи с этим переключение банков не обязательно. Однако в начале этой группы команд происходит выбор банка 0. Во-первых, этот банк выбран в качестве банка по умолчанию. Это значит, что именно он применяется для всех мелких процедур, для которых переключение банков не предусмотрено. А во-вторых, переключить банк заранее никогда не помешает. Это дает гарантию, что вы не совершите случайной ошибки, решив в последствии включить в этот блок команду инициализации регистровой переменной. К переменным основного цикла отнесены: основной и дополнительный буферы команд управления мотором (bufrnot и dopmot), а также два специальных счетчика (coukl и coudd). Переменная bufmot предназначена для временного хранения команд управления мотором. Переменная
Позиционер спутниковой антенны 135 dopmot дублирует эти команды, но с учетом инерции двигателя. Все подробности вы также узнаете при описании соответствующей процедуры. В обе ячейки управления мотором записывается нулевое значение. Нулевой код — это команда остановки мотора. Переменные coukl и coudd предназначены для организации на их основе двух счетчиков, служащих для формирования двух специальных задержек. Задержки формируются путем подсчета циклов динамической индикации. Первая задержка необходима для перехода в режим стирания неверно записанной позиции из памяти позиционера. Для перехода в этот режим используется прием нажатия и удержание кнопки S4. Для того, чтобы стереть выбранную позицию, нужно удерживать кнопку в течение 2-3 секунд. Для формирования этого временного интервала и используется счетчик на основе переменной coukl. Второй счетчик понадобился для обеспечения правильного вывода спецсимволов. Спецсимволы, типа надписи «Ег» (ошибка), выводятся на экран в некоторых критических ситуациях. Они должны присутствовать на экране в течение 1-2 секунд и сами исчезать. Задержка времени для индикации спецсимволов определяется при помощи счетчика, организованного при помощи переменной coudd. В описываемом блоке команд обеим этим переменным присваиваются начальные значения. Инициализация переменных ДУ. Здесь присваиваются начальные значения переменным процедуры приема сигналов ДУ. Специфическое назначение этих переменных будет рассмотрено при описании самой процедуры. Особенностью данного блока команд является необычный способ обнуления регистра г5 из банка 3. Для сокращения количества команд обращение к этому регистру происходит как к ячейке ОЗУ. Инициализация системных флагов. Системные флаги — это ячейки в битовом пространстве памяти микроконтроллера, которые используются в качестве индикаторов того или иного режима работы различных процедур программы позиционера. Пример работы флага flonoff мы видели в начале этого раздела. Описываемая группа команд устанавливает все системные флаги в исходное состояние. В нашей программе все флаги при инициализации должны быть сброшены. Сброс флагов производится при помощи команды clr. Инициализация 12С-шины. В качестве такой шины выступают две линии порта Р1, которым в программе присвоены символьные имена SDA и SCL. Обе эти линии переводятся в единичное состояние, что позволяет использовать линии, как входные (см. раздел «Назначение выводов»).
136 Самоучитель по микропроцессорной технике Настройки из флэш-памяти. Эта группа команд служит для извлечения настроек из внешней флэш-памяти и записи их в соответствующее переменные программы. Все эти параметры записываются во флэш- память в процессе работы позиционера и хранятся там при выключении питания. При повторном включении питания все необходимые параметры должны восстанавливаться. Приведу список параметров, которые подлежат восстановлению в момент включения питания: ¦ Текущее значение счетчика положения антенны. ¦ Регистр флагов. ¦ Константа ДУ. ¦ Номер текущего выбранного канала. Кроме того, из флэш-памяти нужно извлечь число, соответствующее требуемому положению антенны. Это и есть позиция антенны, которая была записана в память позиционера. Реальное положение антенны не обязательно равно этому значению, так как антенна может находиться в процессе поворота. Реальное положение антенны и требуемое ее положение будут равны только тогда, когда позиционер закончит отработку поворота. Для чтения информации из внешней флэш-памяти разработана специальная подпрограмма. Она расположена в памяти программ по адресу rd_flh. Эта программа разработана на основе стандартной процедуры, взятой с сайта «Atmel». Мы не будем рассматривать алгоритм работы этой подпрограммы. Все желающие могут самостоятельно скачать эти примеры и разобраться в алгоритме их работы. Для того, чтобы пользоваться подпрограммой, не обязательно изучать все тонкости ее алгоритма. Достаточно представлять, для чего она предназначена, и знать правила ее использования. Правила использования подпрограммы чтения из внешней флэш-памяти: ¦ При каждом обращении подпрограмма читает два байта данных, расположенных в двух соседних ячейках флэш-памяти. ¦ Перед тем, как вызвать подпрограмму, необходимо поместить в регистр а значения адреса источника информации, а в регистр b — адрес ее приемника. Источником может служить любая пара ячеек во внешней флэш-памяти, а приемником — любая ячейка ОЗУ. Группа команд, озаглавленная как «Настройки из флэш-памяти», производит последовательное чтение каждого из перечисленных выше параметров, при помощи подпрограммы rd_flh. Рассмотрим этот процесс на примере чтения текущего положения антенны. Сначала при помощи уже знакомой нам команды mov в регистры а и b записываются соответствующие константы. Константа fpa — это адрес во внешней флэш-памяти, где хранится это значение. Константа patek — это адрес ячейки ОЗУ, исполь-
Позиционер спутниковой антенны 137 зуемой в качестве счетчика поворота антенны. После того, как параметры записаны, следует команда вызова подпрограммы (call). Подробное описание процесса перехода к подпрограмме и выхода из нее уже приводилось в главе 2. По команде call управление передается на начало подпрограммы, по адресу rd_flh. В конце подпрограммы обязательно стоит оператор ret, который осуществляет возврат из этой подпрограммы. Управление передается в то самое место, откуда она была вызвана. После окончания процедуры чтения текущего положения антенны, программа переходит к чтению регистра флагов, затем происходит чтение номера текущего выбранного канала. Все эти действия выполняются точно таким же образом, как и в первом случае. Различаются лишь адреса, записываемые в регистры а и Ь. Все эти читаемые величины занимают по два байта. Для регистра флагов два байта — это с большим запасом. Однако для того, чтобы не усложнять программу, проще оставить лишний байт. В программе заложена проверка корректности номера текущего канала. Эта проверка стала возможной, благодаря необычному формату записи этого номера в память. Это один из вариантов двоично-десятичного представления числа. Каждый из двух байтов номера канала хранит значение одного из десятичных разрядов. Вот несколько примеров: Канал №1 ООН, 03 Н Канал №2 ООН, С/Н Канал №23 02Н, ОЗН Канал №48 С.Н, 06Н Такое представление номера облегчает работу с ним. Например, для вывода номера канала на индикатор, достаточно каждый байт вывести в свой разряд индикатора. Такой способ хранения номера канала предполагает, что каждый из двух байтов будет принимать значения в диапазоне от ООН до 09Н. Остальные значения недопустимы. Если в результате случайного сбоя во внешней флэш-памяти окажется недопустимое значение, то это можно легко обнаружить программным путем. Поэтому после команд чтения номера канала непосредственно идут команды проверки. Сначала старший разряд номера канала записывается в накопитель. Следующие два оператора служат для оценки проверяемой величины. Оценка производится путем вычитания из проверяемого значения числа 10. Если результат получится отрицательный, то это значит, что проверяемое число было меньше десяти. Если результат положительный, то число либо равно, либо больше десяти. В системе команд микроконтроллера
138 Самоучитель по микропроцессорной технике существует только одна команда вычитания. Это команда subb. Команда subb a,#10 производит вычитание константы, имеющей значение, равное десяти, из содержимого аккумулятора. Причем при вычитании учитывается значение признака переноса из предыдущего разряда (флаг с). Поэтому, для правильности вычислений перед началом вычитания команда clr с сбрасывает значение признака переноса в ноль. Команда условного перехода jnc вызывает передачу управления в том случае, если признак переноса равен нулю. В нашем случае управление передается по адресу inil. По этому адресу находятся команды, выполняемые в случае ошибочного кода. Они просто принудительно устанавливают значение параметра, переключая позиционер на первый канал. Если значение первого разряда оказалось в допустимых пределах, то таким же образом проверяется второй разряд. Однако тут применяется другая команда условного перехода. Команда jc передает управление в случае единичного значения признака переноса. Переход на адрес ini2 — это обход команд принудительной установки первого канала. Он произойдет только в случае правильности обоих разрядов. В противном случае перехода не произойдет и программа все же выполнит операторы принудительной установки. В завершении группы команд чтения из флэш-памяти из нее извлекается значение, называемое «требуемое положение антенны». Для того, чтобы понять, как происходит чтение этого значения, сначала нужно понять, как производилась его запись. Для каждого из возможных каналов (от 0 до 99) существует своя специальная пара ячеек во внешней флэш-памяти, где хранится значение связанной с ним позиции антенны. В самом начале во все эти пары ячеек записан код OFFH, 0FFH. Такое содержимое ячейки индицирует тот факт, что в данном канале позиция еще не записана. Для записи позиции пользователь сначала поворачивает антенну в режиме ручного управления так, чтобы она смотрела на выбранный спутник. Затем выбирается канал и включается режим записи. В процессе записи содержимое счетчика положения антенны записывается в пару ячеек, соответствующих выбранному каналу. В режиме чтения это значение извлекается и используется в режиме автоматической установки антенны. В этом режиме происходит постоянное сравнение содержимого счетчика текущего положения антенны и содержимого ячеек, хранящих значение требуемого положения. Пока эти два значения разные, на мотор подается команда включения поворота. Для того, чтобы прочитать «требуемое положение» антенны, нужно предварительно вычислить адрес пары ячеек во внешней флэш-памяти, соответствующих выбранному каналу. Адрес вычисляется простым спосо-
Позиционер спутниковой антенны 139 бом. Сначала номер канала приводится к обычной форме записи — в виде двоичного числа. Затем номер ячейки вычисляется по формуле: AdrX = NK*2, nie:AdrN — это адрес ячейки внешней памяти, где записано искомое положение для текущего канала; NK — номер текущего канала. Описанное выше вычисление реализуется при помощи специальной подпрограммы nkadr. Эта подпрограмма вычисляет адрес во флэш-памяти и помещает его в аккумулятор. Затем она помещает в регистр b адрес буфера для хранения «требуемою положения» антенны. После завершения подпрограммы nkadr выполняется подпрограмма чтения rd_flh. Программирование таймеров. Эта группа команд производит запись управляющих кодов во все регистры специального назначения микроконтроллера, связанные с настройкой встроенных таймеров-счетчиков и системы прерываний. Код, записанный в регистр TMOD, определяет режимы работы обоих таймеров. В регистры ТНО и TL0 записывается коэффициент пересчета таймера ТО. Он определяет период динамической индикации. В регистры THl, TL1 записывается коэффициент пересчета таймера Tl. Он определяет период опроса фотоприемника. Затем загружается значение маски прерываний и значения приоритетов. В заключение записывается управляющий код в регистр TCON. Это приводит к запуску обоих таймеров-счетчиков. Именно с этого момента начинают работать оба дополнительных процесса, связанных с прерываниями: процесс динамической индикации и процесс опроса фотоприемника. Основной цикл программы После инициализации системы программа позиционера переходит к основному циклу программы. Назначение и обобщенный алгоритм работы этого цикла был описан ранее В графическом виде цикл показан на рис. 46. Фрагмент №5 программы представляет собой полный текст основного цикла. Это наверно самый короткий из всех представленных в книге фрагментов. Связано это с тем, что все функции основного цикла реализованы в виде подпрограмм. Само же тело основного цикла состоит всего лишь из нескольких команд вызова подпрограмм. В данном случае применение подпрограмм не ведет к сокращению кода. Каждая их этих подпрограмм используется только один раз. Однако подобный способ оформления программы существенно облегчает чтение и модернизацию готовой программы. Программы, написанные в таком стиле, на-
140 Самоучитель по микропроцессорной технике зываются структурированными. Создание структурированных программ считается хорошим стилем программирования. Как мы видели из рис. 46, различается большой и малый циклы. Для переключения между этими двумя режимами используется команда условного перехода jnb. Эта команда производит проверку значения ячейки битовой памяти, адрес которой указан в качестве ее параметра. Передача управления происходит в том случае, когда проверяемый бит равен нулю. В качестве проверяемого бита выступает флаг flonoff. Как уже говорилось ранее, значение флага flonoff определяется режимом работы позиционера. В рабочем режиме значение флага равно единице, а в дежурном режиме флаг равен нулю. Если значение флага равно нулю, управление передается по адресу mal. Это соответствует малому циклу. Если флаг установлен в единичное состояние, выполняется большой цикл. В большом цикле последовательно вызываются следующие процедуры: • процедура ввода команд с клавиатуры; • процедура обслуживания счетчика положения антенны; • процедура автоустановки антенны и • процедура обработки команд с пульта ДУ. В последующих разделах мы подробно рассмотрим каждую их этих процедур. Прежде, чем завершить основной цикл и перейти к его началу, программа выполняет проверку флага ошибки флэш-памяти. Многие из описанных выше процедур используют подпрограммы чтения или Фрагмент №5. ¦ Основной цикл программы main. jnb flonoff,ma1 ; Если "питание" выключено call ink) ; Обработка команд с клавиатуры call ingerk , Ввод с геркона и счет call avto ; Автоустановка call indu , Обработка команд ДУ jnb flerf.main ; индикация Error mov bufh,#16 : Символ Е mov bufl.#17 , Символ г clr flerf jmp main ma1: mov bufmot,#0 , Остановить мотор mov bufh,#10 , Очистка дисплея mov bufl,#10 clr p1 1 , Зажечь точку mov pcon,#1 ; Режим пониженного потребления jmp main
Позиционер спутниковой антенны 141 записи флэш-памяти. Если при выполнении этих процедур возникает ошибка, то процедура устанавливает значение флага flerf в единицу. В конце основного цикла происходит проверка этого флага. Если ошибок не было, то оператор условного перехода jnb выполнит переход на начало цикла основной программы и весь цикл замкнется. В случае ошибки, перехода не произойдет. Программа выполнит команды индикации Error. Для этого она запишет в ячейки буфера экрана (bufh и bufl) коды, соответствующие буквам «Е» и «г». На экране появится надпись «Ег». Затем флаг flerf сбрасывается, разрешая нормальную работу системы в случае устранения ошибки. Ошибка флэш-памяти может быть связана с отказом микросхемы, плохим контактом, замыканиями в цепи подключения и некоторыми другими. Команда безусловного перехода возвращает управление к началу цикла. В дежурном режиме выполняется малый цикл. Он начинается с адреса, соответствующего метке mal. Первая команда этого цикла записывает в буфер управления мотора (bufmot) код ООН. Это команда остановки мотора. Затем в оба буфера (для первого и второго разрядов) записывается код выключенного состояния. Оба разряда выключаются. Команда clr pl.l переводит вывод 13 микроконтроллера в нулевое состояние. Это приводит к зажиганию индикатора дежурного режима (см. рис. 44). Следующий этап — перевод процессора в режим останова. Это выполняется путем записи в управляющий регистр PCON кода 01Н. Выполнение основной программы в этом месте останавливается. Процессор переходит в режим пониженной мощности. Работают только процедуры прерываний периодически вызываемые системными таймерами. Одна из этих процедур ждет нажатия кнопки «Вкл/Выкл» на передней панели позиционера, а вторая ждет прихода от пульта ДУ команды на включение. Получив одну из этих команд, программа записывает в регистр PCON код ОН. Это выводит систему из «спящего» режима. Подпрограмма обработки команд с клавиатуры Теперь разберем по порядку все подпрограммы, входящие в основной цикл. И начнем мы с подпрограммы обработки команд с клавиатуры. Как уже говорилось, данная подпрограмма предназначена для обработки кода состояния клавиатуры, записанного в буфер клавиатуры подпрограммой, входящей в процедуру динамической индикации. Рассматриваемая же подпрограмма производит распознавание команд и запуск процедур, реализующих эти команды.
142 Самоучитель по микропроцессорной технике Рассмотрим подробнее саму задачу логической обработки команд клавиатуры. На первый взгляд никаких трудностей нет. Обнаружил нажатие кнопки — переходи к выполнению соответствующей операции. На самом деле не все так просто. Скорость работы любого микропроцессорного устройства намного больше, чем скорость, с которой человек может нажимать кнопки на клавиатуре. С точки зрения программы нажатие любой из кнопок клавиатуры — это очень длительный процесс. Пока человек совершает даже кратковременное нажатие кнопки, программа успевает пройти по основному циклу программы несколько тысяч раз. Как следует из блок-схемы на рис. 46, один раз за каждый проход основного цикла выполняется наша подпрограмма анализа команд с клавиатуры. Если каждый раз, когда программа обнаружит код, соответствующий нажатию одной из клавиш, она будет выполнять закрепленную за ней процедуру, то мы получим многократные повторы. Представьте, что вы нажали кнопку увеличения номера выбранного канала, а он вместо того, чтобы увеличиться на единицу, начнет в бешеном темпе увеличивать номер все время, пока вы держите кнопку. Очевидно, что выполнять процедуру, закрепленную за нажатой кнопкой, нужно только один раз при каждом ее нажатии. Существует два способа решения этой задачи. Можно выполнять процедуру либо в момент нажатия кнопки (по переднему фронту импульса), или сразу после отпускания (по заднему фронту). В случае позиционера большинство команд удобнее выполнять по переднему фронту. Но имеется два исключения. Первое исключение — это кнопка записи/стирания канала (S4). При кратковременном ее нажатии происходит включение режима записи текущей позиции антенны в один из каналов позиционера. При нажатии той же кнопки и удержании ее в течение 2 секунд, включается режим стирания выбранного канала. Для реализации такого двойного назначения кнопки, придется сначала определить длительность удержания кнопки в нажатом состоянии и лишь затем, выполнять одно из вышеописанных действий. В связи с этим обрабатывать команду от кнопки S4 можно только после ее отпускания. Второе исключение — это кнопки ручной установки антенны (S5 и S6). Для поворота антенны нужно нажать одну из этих кнопок и удерживать ее. Пока кнопка удерживается, двигатель поворотного устройства вращается, и антенна поворачивается в выбранном направлении. Кнопка S5 вызывает поворот на запад, а кнопка S6 — на восток (реверс). Обрабатывать нажатие этих кнопок придется как по переднему фронту, так и по заднему. По переднему фронту вызывается процедура включения двигателя поворота антенны, а по заднему — процедура остановки двигателя.
Позиционер спутниковой антенны 143 Есть еще один момент, который нужно учитывать при разработке подпрограммы обработки сигналов с клавиатуры. Порядок работы с клавиатурой предусматривает правило: каждая команда вводится при нажатии только одной соответствующей кнопки. При этом остальные кнопки не должны быть нажаты. Если на клавиатуре нажаты одновременно несколько кнопок, никакие действия не должны выполняться. Исключение составляет команда полного сброса системы. Она запускается путем одновременного нажатия четырех кнопок. Все перечисленное выше — это типичные требования, возникающие при разработке любой клавиатуры. Для решения этих задач существуют типовые приемы. Ниже приведено описание алгоритма обработки команд с клавиатуры, способного удовлетворить всем вышеперечисленным условиям. ПЕРВЫЙ ЭТАП Любые действия по обработке команд с клавиатуры должны выполняться только в момент изменения ее состояния. Для этого необходимо запоминать предыдущее состояние клавиатуры. При каждом последующем обращении к нашей подпрограмме, компьютер должен сравнивать текущий код состояния клавиатуры с кодом, считанным во время предыдущего обращения. Если код состояния не изменился, то подпрограмма на этом должна завершиться. И только в том случае, когда при очередном обращении будет обнаружена смена состояния клавиатуры, программа должна продолжить анализ и перейти ко второму этапу. ВТОРОЙ ЭТАП На втором этапе программа определяет то, к какому из трех возможных типов относится данный случай изменения состояния клавиатуры. Вариантов может быть множество, но два из них имеют особое значение. Поэтому из всех вариантов мы выделяем три: Вариант А. После того, как все кнопки отпущены, нажимается одна из кнопок. Вариант В. После того, как нажата только одна кнопка, она отпускается, и все кнопки оказываются отпущенными. Вариант С. Все остальные случаи, когда, либо до изменения состояния клавиатуры, либо после него, сразу несколько кнопок нажаты одновременно.
144 Самоучитель по микропроцессорной технике Понятно, что последний вариант мы должны исключить. При возникновении такой ситуации подпрограмма должна немедленно завершаться. В дальнейшем нас будут интересовать только варианты А и В. Проверка на этапе номер 2 производится так же, как и на первом этапе, путем оценки значений нового и старого кодов клавиатуры. Критерии оценки просты. В данном случае нам пригодится код состояния клавиатуры в момент, когда все кнопки отпущены (kknot). Если код предыдущего состояния клавиатуры оказался равен kknot, то, не зависимо от значения нового кода, мы имеем дело с вариантом Л по нашей классификации. Если, наоборот, новый код состояния равен kknot, то, не зависимо от значения старого кода, мы получим вариант В. Дальнейшая работа происходит по одному из этих вариантов. ТРЕТИЙ ЭТАП На этом этапе пррграмма представляет собой цепочку операторов сравнения. Код состояния клавиатуры должен поочередно сравниваться с кодом каждой кнопки. Причем при работе по варианту А в сравнении участвуют только те кнопки, которые должны срабатывать по переднему фронту. При работе по варианту В должны участвовать кнопки, срабатывающие по заднему фронту. В нашем случае по заднему фронту работает только одна кнопка: это кнопка S4. Проверка кодов на этом этапе происходит примерно следующим образом: ¦ Сравниваем код состояния клавиатуры с кодом кнопки SI. ¦ Если эти коды равны — выполняем процедуру переключения режимов «работа/установка» и выходим из подпрограммы оценки кодов. ¦ Если коды не равны, то проверка продолжается. Код состояния сравнивается с кодом кнопки S2. Если коды равны, выполняем процедуру уменьшения номера канала на единицу. ¦ Повторяем вышеуказанные действия для всех кнопок, участвующих в проверке. И так, пока не будут проверены все кнопки клавиатуры. Если в результате всех этих проверок окажется, что код состояния клавиатуры не равен ни одному из возможных кодов кнопок, то это значит, что в данный момент нажато одновременно несколько кнопок. В этом случае подпрограмма также не выполняет никаких действий. Примечание. В реальной программе позиционера порядок проверки кнопок немного другой. Проверка начинается вовсе не с первой кнопки. Но это не имеет принципиального значения.
Позиционер спутниковой антенны 145 Ниже приведен фрагмент №6 программы позиционера, реализующий вышеописанный алгоритм. Фрагмент №6 ,- Обработка команд с клавиатуры inki mov a.coucl cjne a,#0,ink jmp cleank , стирание содержимого канала ink mov a.bufkl , Обнуление бита 6 anl a,#10111111B cjne a,_klold,in1 , Обнаружение момента нажатия/отпускания кнопки ret in1 xch a.klold , Смена кодов старый <-> новый cjne klold,#kkres,in3 , Начальный сброс системы jmp fmi in3 cjne klold,#kknot,in4 , Последняя кнопка отпущена (случай В) mov bufmot,#0 , Сброс регистра управления мотором jbc flks,savnk , Переход к процедуре записи положения ret in4 cjne a,#kknot,m9 , Нажатие одной кнопки (случай А) cjne klold,#kkss,in5 , Кнопка записи положения нажата setb flks mov coucl,#t2cle , Инициализация счетчика задержки стирания ret in5 clr flks cjne klold,#kkmun6 , Уменьшение номера канала jmp downk in6 cjne klold,#kkpl,in7 , Увеличение номера канала jmp upnk in7 jb flsav,in9 cjne klold,#kkar,in8 , Поворот антенны вправо jmp antr in8 cjne klold#kkal,m10 , Поворот антенны влево jmp antl m10 cjne klold,#kkru,in11 .Работа/установки jmp swreg in11 cjne klold,#kkon,in9 , Вкл/выкл "питания" jmp onoff in9 ret
146 Самоучитель по микропроцессорной технике Если вы просмотрите предлагаемый фрагмент до конца, то вы увидите, что он заканчивается командой ret. Как мы уже знаем, ret — это команда выхода из подпрограммы. Это говорит о том, что Фрагмент №6 представляет собой подпрограмму. При обнаружении моментов нажатия клавиш выполняется переход к одной из процедур обработки этого события. Переход к этим процедурам производится при помощи команды jmp, то есть команды безусловного перехода. Поэтому каждая из таких процедур является продолжением приведенной здесь подпрограммы. В конце каждой из этих процедур также стоит оператор ret. В результате подпрограмма обработки команд с клавиатуры превращается в некое подобие спрута. Одна подпрограмма имеет несколько окончаний. Каждое из «щупалец» этого спрута может служить в определенный момент выходом из подпрограммы. Первые три строки Фрагмента №6 предназначены для запуска процедуры стирания текущего канала. Как уже упоминалось, процедура стирания запускается при нажатии и удержании в течение нескольких секунд кнопки S4 (запись/стирание канала). Для отработки этого временного интервала организован программный счетчик. Мы уже упоминали об этом счетчике. Программный счетчик — это просто ячейка памяти, содержимое которой периодически уменьшается (или увеличивается) программным путем. В данном случае используется ячейка памяти coucl. Для того, чтобы счетчик считал, в процедуру динамической индикации включена команда, уменьшающая каждый раз при вызове этой процедуры содержимое ячейки coucl на единицу. Процедура динамической индикации вызывается с постоянным периодом (примерно 50 Гц). Этим достигается синхронизация счетчика во времени. В той же процедуре динамической индикации организован программный запуск и остановка этого счетчика. Запускается счетчик при нажатии кнопки S4 и считает все время, пока эта кнопка нажата. Если кнопка будет отпущена раньше, чем счетчик досчитает до нуля, то счет остановится. При новом нажатии кнопки счетчик иерезапус- тится, и счет начнется сначала. Подробное описание всей программы динамической индикации будет приведено далее. Сейчас же вернемся к фрагменту № 6. Три первые команды этого фрагмента, выполняют последний этап обработки — проверку содержимого счетчика на равенство нулю. Если в ячейке счетчика ноль, то это значит, что клавиша S4 удерживалась в нажатом состоянии уже достаточно долго. Временной лимит истек и пора включать процедуру стирания информации из текущей ячейки памяти. Рассмотрим, как это происходит. Первая команда (mov) копирует содержимое ячейки coucl (значение счетчика) в аккумулятор. Далее идет новая для нас команда
Позиционер спутниковой антенны 147 cjne. Это команда сравнения двух чисел. Она относится к командам условного перехода. Команда сравнивает содержимое аккумулятора и числовой константы, выступающей в качестве ее второго параметра. В нашем случае константа равна нулю. Если содержимое аккумулятора не равно нулю, команда передает управление по адресу ink. Адрес — это продолжение текущей подпрограммы. Если же содержимое аккумулятора равно нулю (счетчик досчитал до конца), то условного перехода не происходит и выполняется очередная команда, а именно команда безусловного перехода к процедуре стирания информации выбранного канала, начало которой находится по адресу cleank. Мы опустим подробное описание всех подобных процедур. Детальное описание всего текста программы заняло бы слишком много места. Продолжим изучение подпрограммы, приведенной во фрагменте №6. Следующие две команды (начиная с метки ink) служат для обнуления бита номер 6 в коде состояния клавиатуры. Немного ранее я уже писал, зачем это нужно. Шестой бит содержит случайную информацию, поэтому для устранения влияния этого бита на результаты дальнейшего анализа бит нужно обнулить. Рассмотрим и это действие подробно. Сначала код состояния клавиатуры, из буфера bufld помещается в аккумулятор (команда то\). Затем применяется оператор an). Этот оператор выполняет поразрядное логическое умножение (операцию «И») с константой. В данном случае значение константы равно 10111111B. Действие команды anl подобно наложению маски. Маской являются разряды нашей константы. Если бит маски равен нулю, то и в аккумуляторе этот бит обнуляется. В тех же разрядах, которые в маске равны единице, содержимое аккумулятора остается без изменений. Если вы еще не поняли как это происходит, посмотрите еще раз на таблицу истинности элемента «И» (рис. 5). Получив однозначный код, определяющий состояние клавиатуры, приступим к следующему этапу — обнаружению момента изменения состояния клавиатуры. Уже знакомый нам оператор cjne выполняет сравнение последнего считанного кода состояния клавиатуры, который после выполнения операции anl находится в аккумуляторе, с содержимым ячейки _klold, где хранится предыдущее значение этого кода. Если коды не равны, то выполняется переход по адресу inl, и процедура обработки команд с клавиатуры продолжается. В противном случае (если коды оказались одинаковы) выполняется команда ret. В том случае, если изменение состояния клавиатуры обнаружено, начинается следующий этап. В начале этого этапа старый и новый коды меняются местами. Обмен байтами выполняется при помощи команды хсп.
148 Самоучитель по микропроцессорной технике Зачем нужен этот обмен? Это сделано для оптимизации последующих операций. Дело в том, что дальше выполнение программы пойдет по одному из нескольких возможных путей. Это зависит от того, какая из кнопок оказалась нажата. Однако, для правильной работы программы необходимо, чтобы после выхода из подпрограммы в буфере klold оказался тот код состояния клавиатуры, который был считан в текущей сессии. При последующем вызове подпрограммы он будет выступать в роли предыдущего кода. Но и тот код, который до сих пор хранился в буфере klold, нам еще нужен. Ведь мы еще не определили, какой из вариантов изменений наступил (А, В или С). Может показаться, что мы рано делаем этот обмен. Но нет, в самый раз! Далее произойдет разветвление программы. Именно из этого места у нашего «спрута» растут его «щупальца». Так как выходов из этой подпрограммы несколько, нам пришлось бы поместить команду записи нового кода в ячейку klold в конце каждого такого ответвления. С точки зрения оптимальности программного кода разумнее поместить его в начале, перед самым первым ответвлением. Обратите внимание на то, как в разных местах программы происходит обращение к буферу klold. В команде xch используется ссылка «klold», а в команде cjne — «_klold». Если вы обратитесь к модулю описания переменных (фрагмент М/), вы обнаружите, что эти две разные переменные, описывающие одну и ту же ячейку памяти. Только в первом случае она описывается, как регистр, а во втором — как ячейка ОЗУ. Связано это с тем, что оператор cjne не работает с регистрами. Второй параметр этого оператора может быть только адресом ячейки ОЗУ. Переменная _klold была специально создана для этого случая и имена этих двух переменных не случайно похожи друг на друга. Но вернемся к описанию нашей подпрограммы. Следующая команда проверяет, не нажаты ли четыре клавиши для вызова процедуры начального сброса системы. Если вы еще не забыли, код клавиатуры в этом случае должен быть равен константе kkres. При обнаружении такого кода выполняется безусловный переход к процедуре начального сброса fini. В противном случае анализ кода продолжается. Я думаю, подробно разбирать конкретные команды в данном случае не требуется. Далее (начиная с метки in3) программа приступает к определению того, к какому из вариантов (А, В или С) относится наш случай. Сначала новый код состояния клавиатуры, который теперь находится в буфере klold, сравнивается с кодом kknot. Напоминаю, что kknot — это код состояния клавиатуры, когда все кнопки отпущены. Если новый код равен kknot, то мы имеем дело с вариантом В. Вариант b означает, что все кнопки только что оказались отпущены. Поэтому программа
Позиционер спутниковой антенны 149 выполняет действия, связанные с моментом отпускания кнопок. Сначала программа останавливает мотор. Для этого в буфер команд управления мотором (bufmot) записывается команда остановки. Код этой команды равен нулю. Остановка мотора нужна для того случая, если до этого была нажата одна из кнопок ручного управления (S5 или S6). Если нажаты были не эти кнопки, то команда остановки двигателя тоже не помешает. Затем программа производит проверку флага flks. Значение этого флага зависит от длительности нажатия кнопки S4. Если эта кнопка была нажата, но не настолько долго, чтобы сработала процедура стирания канала, то флаг flks имеет значение I. В противном случае его значение равно нулю. Изменение значения флага происходит в соответствующем месте процедуры динамической индикации. Проверка флага происходит при помощи оператора jbc. Это еще один вид операторов условного перехода — переход по значение бита. Если бит (в данном случае flks) равен единице, то выполняется переход к процедуре записи канала, начало которой расположено по адресу savnk. Кроме того, оператор jbc делает еще одно действие. Он, в отличие от аналогичного оператора jb, сбрасывает проверяемый бит в ноль. В результате флаг очищается, что предотвращает повторное срабатывание процедуры записи. Если флаг flks окажется сброшенным в ноль, то условный переход не произойдет и команда ret завершит подпрограмму. Следующий раз процедура стирания будет вызвана только после очередного нажатия клавиши S4 (если условия по длительности нажатия будут соблюдены). Теперь рассмотрим ход выполнения программы, если вариант В не подтвердился. В этом случае выполнение программы продолжается с метки in4. В этом месте уже не новый, а старый код состояния клавиатуры сравнивается с константой kknot. Если код равен константе, то это значит, мы имеем дело с вариантом А. Если же коды не равны, то это вариант С. Вариант С ведет к немедленному завершению программы. Для сравнения кодов используется уже известный нам оператор djne. В случае неравенства кодов происходит переход по адресу in9, где расположена команда ret. В противном случае анализ кода продолжается. Этот случай соответствует варианту А. Посмотрим, что же делает программа при обработке варианта А. Дальнейшая программа представляет собой цепочку операторов сравнения. Причем в сравнении участвуют коды тех клавиш, которые должны срабатывать по переднему фронту. И первая операция сравнения, вопреки упрощенному примеру в начале этого раздела, выполняется для кнопки S4. Снова кнопка S4! Что же поделаешь! Слишком много функций нагружено на эту кнопку. Факт нажатия именно этой кнопки определяется путем сравнения кода состояния клавиатуры с константой kkss. На этот раз программа выполняет операции, связанные с моментом нажатия этой кнопки. А именно: сначала
150 Самоучитель по микропроцессорной технике флаг flks устанавливается в единичное состояние и индицирует тот факт, что кнопка была нажата. Затем программа перезапускает счетчик coucl. Для этого в ячейку счетчика coucl записывается начальное значение. Начальное значение описано как константа tzcle (см. фрагмент №1). На этом действия, закрепленные за передним фронтом нажатия клавиши S4, заканчиваются. Поэтому команда ret завершает подпрограмму. Если клавиша S4 оказалась не нажата, то прежде, чем выполнить остальные сравнения, сбрасывается флаг flks. Одно из назначений флага flks — запускать и останавливать процесс счета программного таймера coucl. Поэтому, если клавиша S4 оказалась отпущена, таймер нужно остановить. Он должен отсчитывать время, пока нажата клавиша S4. Следующая проверка — это проверка нажатия клавиши S2 (метка in5). Код клавиши S2 описан константой kkmi. В случае совпадения кодов выполняется процедура уменьшения на единицу номера текущего канала (downk). Точно так же происходит проверка нажатия клавиши S3 (метка in6). Код клавиши kkpl. В случае совпадения выполняется процедура — увеличение номера канала (upnk). Перед тем как выполнять последние четыре проверки, программа проверяет значение флага flsav (метка in7). Если значение флага равно единице, то последние четыре проверки не выполняются. Флаг flsav равен единице в режиме записи положения антенны. Позиционер переходит в режим записи при первом нажатии кнопки S4. В этом режиме индикатор мигает и ждет, пока пользователь выберет номер канала, а затем вторично нажмет кнопку S4. Пока идет процесс записи, все кнопки, кроме тех, что участвуют в этом режиме, должны быть отключены во избежание неопределенности результата. При завершении процесса записи флаг flsav будет сброшен, и четыре последние проверки будут разблокированы. Все эти проверки выполняются уже известным нам способом. Предлагаю разобраться со всеми оставшимися командами фрагмента №6 самостоятельно. Обработка сигналов с датчика поворота антенны Как уже говорилось, датчик поворота антенны представляет собой гер- кон — пара герметичных контактов с магнитным управлением, который установлен в поворотном механизме антенны (актюаторе) на выходе первичного редуктора. На оси редуктора закреплен постоянный магнит, который вращается вместе с осью и при каждом обороте вы-
Позиционер спутниковой антенны 151 зывает замыкание контактов датчика. Сигнал с датчика через схему гальванической развязки поступает на линию iger (P1.4) микроконтроллера. Используя этот сигнал, процессор должен постоянно отслеживать положение антенны. Главная проблема, с которой мы сталкиваемся при разработке подобной программы — это дребезг контактов датчика. О том, что такое дребезг, мы уже подробно говорили в главе 1. Так как датчик поворота антенны состоит всего из одной пары контактов, то единственный способ борьбы с дребезгом контактов — это фильтрация паразитных импульсов при помощи интегрирующих цепочек. Однако в схеме позиционера интегрирующих цепочек не предусмотрено. Та же задача решается на программном уровне. Поэтому, первое, что делает рассматриваемая в настоящем разделе подпрограмма, реализует алгоритм программной интеграции входных импульсов. Для надежности применен двухэтапный антидребезговый алгоритм. Прежде, чем рассматривать его подробнее, я хотел бы остановиться на некоторых теоретических моментах. Срабатывание датчика поворота — это достаточно медленный процесс. Он лишь немного быстрее, чем процесс нажатия кнопок клавиатуры. Поэтому управляющая программа за время между двумя срабатываниями датчика также успевает пройти по основному циклу несколько тысяч раз. Столько же раз будет вызвана рассматриваемая подпрограмма igerk. Поэтому процесс интеграции придется сделать распределенным. Это значит, что обработка одного импульса с датчика положения будет происходить не за один, а за несколько циклов обращения к подпрограмме igerk. Причем распределенным является лишь второй этап алгоритма. Первый этап антидребезговой обработки — это десятикратное чтение сигнала с датчика. Такое чтение происходит в каждом цикле обращения к подпрограмме igerk, в самом ее начале. Просто производится десять последовательных считываний сигнала с линии iger. Весь процесс десятикратного считывания выполняется всего за 20 микросекунд при длительности сигнала с датчика порядка 50... 100 мс. При считывании реального сигнала, часть считанных значений будут отличаться от действительного состояния датчика. Различия вызваны влиянием дребезга контактов и сигналами помехи. Затем происходит усреднение считанного результата. Все десять полученных значений складываются, а затем производится оценка того, каких значений было больше — нулей или единиц. Если полученная сумма окажется больше либо равна пяти, то программа считает, что реальное состояние геркона в момент считывания соответствует единичному сигналу (геркон разомкнут). Если сумма меньше пяти, то это означает, что состояние геркона соответствует нулю (геркон замкнут). Первый этап позволяет избавиться лишь
152 Самоучитель по микропроцессорной технике от высокочастотных помех. Для фильтрации всех остальных помех и повышения надежности распознавания сигналов с датчика положения антенны введен второй этап программной интеграции. Второй этап имитирует работу накопительного конденсатора. Роль этого конденсатора выполняет специально отведенный для этой цели регистр процессора. В программе этот регистр обозначен меткой sreg. Работает программный имитатор накопительного конденсатора следующим образом. При каждом обращении к подпрограмме обработки сигнала с геркона, происходит либо увеличение, либо уменьшение содержимого регистра sreg, в зависимости от того, какое значение входного сигнала было получено после первого этапа антидребезгового алгоритма. Если после первого этапа получена единица, то содержимое ячейки увеличивается. Если ноль, то уменьшается. Изменение значения регистра sreg ограничено, как сверху, так и снизу. Если значение регистра достигнет нуля, то операция по уменьшению содержимого ячейки блокируется. При нулевом значении sreg возможно только увеличение его значения. Второе ограничение наступает при достижении верхнего предела. Значение верхнего предела равно tger. Если в процессе интеграции значение регистра sreg достигнет величины tger, операция увеличения блокируется. В этом случае возможно только уменьшение. Описанный выше алгоритм приводит к тому, что наш программный «конденсатор» от каждого единичного импульса «подзаряжается», а от каждого нулевого в такой же мере «разряжается». Однако это еще не все. После программного конденсатора стоит программный триггер Шмитта. В этом месте мне придется сделать небольшое отступление и рассказать, что такое триггер Шмитта. Описание этого устройства как-то не вписалось в раздел, посвященный азам цифровой техники. Придется восполнить этот пробел сейчас. Вообще-то, триггер Шмитта — это пороговое устройство, имеющее аналоговый вход и цифровой выход. В зависимости от значения сигнала на входе, на выходе триггера устанавливается либо сигнал логической единицы (включение), либо сигнал логического нуля (выключение). Триггер Шмитта обладает таким свойством, как гистерезис. Гистерезис — это разница между уровнем включения триггера и уровнем выключения. На рис. 47 показана передаточная характеристика триггера Шмитта. Рис. 47 отражает весь процесс работы триггера. Вначале входное напряжение триггера равно нулю. На выходе низкий логический уровень (левая нижняя точка графика). Входное напряжение повышается. Выходное напряжение, при этом, остается без изменений. Такая ситуация сохраняется до тех пор, пока уровень входного напряжения не достиг-
Позиционер спутниковой антенны 153 нет верхнего порога срабатывания (U,l2). При достижении порога, триггер моментально переключается, и на его выходе устанавливается высокий логический уровень. При дальнейшем росте входного напряжения, выходной уровень уже не меняется. Весь описанный процесс обозначен на рис. 47 стрелками и помечен буквой Ь. Рис. 47. Передаточная характеристика триггера Шмитта При уменьшении входного напряжения на выходе сохраняется высокий логический уровень. Переключение триггера в нулевое положение произойдет только при достижении нижнего порога срабатывания (Ur,i). Этот процесс отражает часть характеристики, обозначенная буквой а. Применение триггера Шмитта позволяет значительно повысить помехозащищенность любой системы. Слабый сигнал помехи не сможет переключить триггер. К тому же триггер Шмитта повышает крутизну фронта поступающих на него импульсов. Но вернемся к нашей программе. Программный триггер Шмитта служит для той же цели, что и его физический аналог. Для реализации алгоритма триггера Шмитта в программу введен флаг гистерезиса flgis. Состояние этого флага имитирует выходной сигнал триггера. Входным «сигналом» является текущее значение накопительного регистра sreg. Верхний и нижний пороги срабатывания триггера — это те же самые пороги, которые ограничивают диапазон значений регистра sreg. Для реализации триггерного режима используется специальная программа, алгоритм работы которой сводится к следующему: ¦ Флаг flgis устанавливается в единицу только в том случае, когда значение накопительного регистра sreg достигнет верхнего порога. ¦ Сброс флага flgis в нулевое состояние происходит лишь в тот момент, когда значение регистра sreg станет равно нулю. ¦ В промежутке же между двумя этими событиями, когда наш «конденсатор» «заряжается» или «разряжается», состояние флага гистерезиса остается неизменным.
На этом антидребезговая процедура заканчивается. В результате ее работы переключения флага flgis можно считать импульсами от датчика поворота антенны свободными от помех. Состояние флага будет повторять состояние датчика поворота с небольшой задержкой по фазе, вызванной процессом интеграции. Далее программа приступает к выполнению основного действия: изменяет значение счетчика поворота антенны. Это изменение происходит по переднему фронту сигнала, то есть в момент установки флага flgis в единичное состояние. В зависимости от направления вращения двигателя содержимое счетчика либо увеличивается, либо уменьшается. Для этого производится оценка содержимого буфера управления мотором. Если на мотор подана команда .«прямой ход», то содержимое счетчика положения антенны увеличивается на единицу. Если на мотор подана команда «реверс», то показания счетчика уменьшаются на единицу. Ниже приведен фрагмент №7 управляющей программы позиционера. Он представляет собой полный текст подпрограммы обработки сигнала с геркона. Фрагмент №7. ; Ввод и обработка сигналов^: геркона ingerk: setb iger ; Первый этап антидребезга mov r0,#10 ; инициализация счетчика принятых бит mov a,#0 ; обнуление аккумулятора ingO: mov c.iger ; десятикратный ввод addc a,#0 ; суммирование всех введенных битов djnz rO.ingO subb a,#5 ; сумма больше или меньше пяти? ; Второй этап антидребезга jnc ing2 cjne sger,#0,ing1 ; если значение уже достигло нуля clr flgis ; сбросить флаг гистерезиса ret ing1: dec sger ; уменьшение значения интегратора ret ing2: mov a,#tger ; сравнить с верхним пределом subb a.sger jc ing3 inc sger ; увеличение значения интегратора ret ing3: mov cflgis ; Проверка фл&га гистерезиса setb flgis jc ing 10
Позиционер спутниковой антенны 155 Первая команда подпрограммы — это команда установки линии подключения геркона (iger) в единичное состояние. Вместо имени Р1.4 используется Команда введена для перестраховки, чтобы гарантировать работу этой линии в режиме ввода. Для установка разряда используется оператор setb. Далее идет группа команд первого этапа антидребезга (десятикратного считывания). Регистр гО используется в качестве счетчика циклов считывания. Поэтому в этот регистр помещается число 10. Именно столько циклов считывания нам нужно произвести. Обратите внимание на то, что в данном случае число 10 записано в десятичном формате. Регистр а (аккумулятор) используется в данном случае для подсчета суммы всех принятых битов. Поэтому, перед началом цикла программа записывает туда ноль. Цикл десятикратного чтения организуется при помощи команды djnz. В теле цикла всего две команды. Первая производит чтение разряда iger и запись его значения в ячейку признака переноса. Вторая команда в теле цикла (addc) — это команда сложения содержимого аккумулятора с константой с учетом признака переноса. Так как в качестве константы применяется ноль, то в каждом цикле считывания к текущему значению аккумулятора прибавляется лишь значение признака переноса. После окончания всех десяти циклов считывания там окажется число, равное сумме всех считанных разрядов. ; Обработка полученного сигнала mov a.dopmot ; прочитать направление вращения мотора cjne a,#01H,ing4 mov a,#0 ; Уменьшение значения счетчика (поворот влево) cjne a,patek+1,ing5 cjne a,patek,ing6 ret ing5: dec patek+1 , младший байт счетчика jmp ing9 ing6: dec patek ; старший байт счетчика mov patek+1,#0FFH jmp ing9 ing4: cjne a,#2,ing10 , Увеличение значения счетчика (поворот вправо) mov a,#0FFH cjne a, patek+1, ing7 cjne a,patek,mg8 ret ing7: inc patek+1 , младший байт счетчика jmp ing9 ing8: inc patek ; старший байт счетчика mov patek+1,#0 ing9: mov a,#fpa ; Запись текущего положения антенны mov b,#patek ; во флэш-память call wr_flh ing 10: ret
156 Самоучитель по микропроцессорной технике Остановимся подробнее на операторе djnz. Это оператор организации цикла. Он имеет два параметра. Первый параметр (в нашем случае это гО) всегда указывает на один из регистров общего назначения. Этот регистр используется в качестве счетчика цикла. Второй параметр — это адрес перехода. Оператор djnz действует следующим образом: ¦ Сначала программа выполняет команды, входящие в тело цикла. Сразу после тела располагается оператор djnz. ¦ Этот оператор уменьшает содержимое регистра счетчика цикла на единицу и затем проверяет его на равенство нулю. ¦ Если значение счетчика не равно нулю, то выполняется переход на начало цикла и цикл повторяется снова. ¦ Когда содержимое счетчика цикла достигнет нуля, перехода на начало цикла не произойдет, цикл закончится, и программа продолжит свое выполнение с оператора, непосредственно следующего за djnz. После окончания цикла происходит проверка полученной суммы, которая к этому моменту находится в аккумуляторе. Для проверки при помощи команды subb производится вычитание из содержимого накопителя числа 5. В результате вычитания признак переноса будет содержать нужную нам информацию. Если число в накопителе меньше пяти, то в результате вычитания получится отрицательное число, а значит, признак переноса с установится в единицу. Если число в накопителе больше или равно пяти, то результат будет положительный, либо ноль. В этом случае признак переноса окажется сброшенным в ноль. Второй этап антидребезговой программы начинается с оператора безусловного перехода jnc. Этот оператор выполняет переход в том случае, когда признак переноса равен нулю. Таким образом, реализуется разделение алгоритма на две ветви. Одна ветвь выполняет уменьшение значения интегрирующего регистра sreg (если результат первого этапа равен нулю). Вторая ветвь выполняет увеличение значения того же регистра (если результат первого этапа равен единице). Ветвь уменьшения (метка ingl) начинается с проверки регистра sreg на равенство нулю. Проверка производится при помощи оператора cjne. Если sreg оказался равен нулю, то это значит, что мы имеем дело с нижним порогом программного «конденсатора». А по сему, никакого уменьшения не происходит, флаг гистерезиса сбрасывается в ноль, и затем происходит выход из подпрограммы. В том случае, если содержимое sreg не равно нулю, происходит переход к метке ingl, где и происходит уменьшение значения sreg. Уменьшение выполняется при помощи команды dec. Команда получила название от слова «декремент», которое и означает «уменьшение». В нашем случае команда dec умень-
Позиционер спутниковой антенны 157 шает значение интегрирующего регистра sreg. На этом данная ветвь заканчивается. Так как достижение нижнего предела не должно вызывать дальнейших действий, в конце этой ветви программы стоит команда ret, которая осуществляет выход из подпрограммы. Ветвь увеличения интегрирующего регистра sreg выполняет те же действия, что и ветвь уменьшения, но с точностью до наоборот. Переход к этой ветви программы происходит в том случае, если после первого этапа антидребезга сумма битов оказалась больше 5. Начинается эта ветвь с метки ing2. И первое, что делает программа в этом случае — проверяет текущее значение интегрирующего регистра sreg. Для этого, сначала в аккумулятор загружается константа, равная максимальному его значению (treg). Значение этой константы определяет постоянную времени интегрирования. Далее происходит сравнение текущего значения sreg с константой. Сравнение происходит по уже знакомой схеме. Оператор subb вычитает из значения константы текущее значение интегрирующего регистра. В результате признак переноса установится в единицу в том случае, если заданный предел еще не достигнут и останется равным нулю в противном случае. Далее, в зависимости от результата сравнения, принимается решение: увеличивать интегрирующий регистр или нет. Если верхний предел не достигнут, программа увеличивает содержимое sreg и заканчивает на этом свою работу. Увеличение значения регистра выполняется при помощи оператора inc (инкремент). Его действие обратно действию оператора dec. В случае достижения верхнего предела увеличение содержимого sreg не происходит, зато происходит несколько дополнительных действий. Это установка флага гистерезиса в единичное состояние и обнаружение переднего фронта. Для обнаружения переднего фронта проверяется предыдущее значение флага гистерезиса. Если предыдущее значение флага равно единице, то это значит, что значение флага не изменилось. Это не передний фронт, а середина импульса. В том случае, если предыдущее значение флага равно нулю, то это значит, что мы имеем дело с передним фронтом сигнала. Именно в этом случае программа выполняет изменение содержимого счетчика положения антенны. Проверка флага гистерезиса начинается с адреса ing3. Сначала значение флага гистерезиса (flgis) сохраняется в ячейке признака переноса с. Следующая команда (setb) устанавливает бит flgis в единицу. Затем происходит проверка старого значения флага (jc). Если старое значение флага, находящееся в с, равно единице, выполняется переход в конец подпрограммы (inglO) и выход из нее. Если старое значение флага равно нулю, то программа переходит к процедуре обработки полученного сигнала.
158 Самоучитель по микропроцессорной технике Обработка полученного сигнала начинается с проверки направления вращения двигателя. Для этого в аккумулятор загружается содержимое ячейки dopmot. Как уже говорилось ранее, ячейка dopmot — это дублирующая ячейка для команд управления мотором. Когда в основную ячейку bufmot записываются команды «вращение вперед» @1Н) или «вращение назад» (ЮН), то они же помещаются в ячейку dopmot. Когда же в ячейку bufmot помещают команду «стоп» (ООН), то в dopmot она не дублируется. В результате во время действия команды «стоп», в ячейке dopmot находится информация о направлении движения двигателя до его остановки. Это позволяет правильно определять направление вращения в том случае, если после поступления команды остановки антенна продолжает вращаться по инерции. Следующий оператор (djne) производит сравнение значения управляющего кода с числом 0IH. Если управляющий код равен 0IH, выполняется переход к процедуре увеличения значения счетчика положения антенны (по адресу ing4). В противном случае выполняется процедура уменьшения значения этого счетчика. Счетчик положения антенны имеет 16 разрядов и хранится в двух ячейках памяти. Старшие разряды счетчика хранятся в ячейке с адресом patek, а младшие — в ячейке patek+1. Поэтому, как увеличение, так и уменьшение его значения проходят в два этапа. Рассмотрим сначала процедуру уменьшения значения счетчика. Начинается процедура с проверки младшего-и старшего байтов счетчика на равенство нулю. Для осуществления проверки в аккумулятор записывается ноль. Затем, при помощи оператора djne содержимое аккумулятора сравнивается с содержимым ячеек памяти, в которых хранится код счетчика положения антенны. Сначала младший байт счетчика проверяется на равенство нулю. Если он не равен нулю, то программа выполняет переход по адресу ing5, где происходит уменьшение значения младшего байта на единицу и выход из подпрограммы. Если младший байт равен нулю, то проверяется старший байт. Если и он равен нулю, то это значит, что счетчик уже досчитал до своего нижнего предела и уменьшать его значения нельзя. Поэтому подпрограмма завершается немедленно. Если старший байт еще не ноль, то его значение уменьшается на единицу, а младшему разряду присваивается значение, равное 0FFH. Такой алгоритм имитирует работу обычного шестнадцатиразрядного счетчика. Процедура увеличения значения счетчика поворота антенны построена аналогично процедуре уменьшения. Отличие в том, что байты счетчи-
Позиционер спутниковой антенны 159 ка сравниваются не с нулем, а с максимально возможным для них значением — 0FFH, а при уиеличении значения старшего байта, младший приравнивается к нулю. И, наконец,'последняя группа команд. Она начинается с метки ing9. Управление в эту точку программы передается только в том случае, если и результате всех предыдущих преобразований значение счетчика положения антенны было изменено. В этом случае производится запись нового положения антенны во внешнюю флэш-память. Запись производится при помощи подпрограммы wr_fl. Эта подпрограмма работает в паре с подпрограммой rd_fl, описанной ранее. Запись производится сразу по два байта. Для правильной работы подпрограммы в регистр а (аккумулятор) процессора помещается адрес пары ячеек флэш-памяти, где должна храниться записываемая величина. В регистр b помещается адрес ячеек ОЗУ, служащих источником информации. В нашем случае источником служат ячейки счетчика положения антенны. Таким образом, запись положения антенны во флэш-память происходит сразу после любого его изменения. Это дает гарантию, что при непредвиденном отключении питания не произойдет потеря информации и рассинхронизация системы. Процедура динамической индикации Как уже много раз говорилось, процедура динамической индикации, по сути дела, является процедурой обработки прерывания от счетчика/таймера ТО. Счетчик/таймер настраивается таким образом, что прерывание вызывается с постоянным периодом, равным 20 мс. В результате частота смены изображения на индикаторах равняется 50 Гц. Это самая минимальная частота, при которой человеческий глаз еще не видит мельканий. Блок-схема алгоритма процедуры динамической индикации приведена на рис. 48. Рассмотрим подробнее этот алгоритм. Описываемая процедура, как и любая процедура обработки прерывания, начинается с сохранения содержимого рабочих регистров в стековой памяти. Причем сохраняются только те регистры, которые текущая процедура будет использовать для своих целей. В конце процедуры содержимое всех сохраненных регистров восстанавливаются. Основная часть процедуры начинается с проверки условия. То есть прямо с самого начала алгоритм разветвляется. Дальнейший ход выполнения программы зависит от того, в каком из двух режимов работы находится позиционер в данный момент:
160 Самоучитель по микропроцессорной технике в рабочем или в дежурном. В рабочем режиме программа выполняет все свои функции в полном объеме, а в дежурном у процедуры только одна задача — ожидание нажатия кнопки «Вкл/Выкл» (S7). Начнем рассмотрение основной части алгоритма с рабочего режима. Как видно из блок-схемы на рис. 48, в основном режиме работы процедура также разветвляется и образует две параллельных ветви. Каждая из ветвей соответствует своей фазе работы программы. Основное назначение этих фаз следующее: первая фаза служит для вывода старшего разряда индикатора, а вторая — для вывода младшего. Программа выполняет только одну из этих ветвей. Ту, которая соответствует текущей фазе. При каждом последующем вызове процедуры динамической индикации, то есть при каждом запросе на прерывание от таймера ТО, фаза меняется на новую. В результате две фазы вывода чередуются. Рис. 48. Блок-схема процедуры динамической индикации
Позиционер спутниковой антенны 161 В каждой фазе, кроме основных команд, связанных с выводом информации на индикатор, выполняются дополнительные действия. В первой фазе дополнительно выполняется блок команд, осуществляющий опрос клавиатуры. В ходе этого опроса считывается код состояния клавиатуры и помещается в буфер клавиатуры. Сразу после опроса клавиатуры, происходит вывод символа в старший разряд индикатора. Код, соответствующий этому символу, помещается в порт РЗ и находится там все время, пока таймер ТО не отсчитает положенную задержку и не вызовет процедуру динамической индикации очередной раз. При этом, благодаря дешифратору DD3 и ключу VT4, изображение высвечивается на индикаторе HL1. Во второй фазе в качестве дополнительной операции включены ряд команд, которые производят вывод управляющего сигнала на двигатель. К этому времени код управляющего сигнала уже хранится в буфере управления мотором. Программа лишь извлекает его оттуда и записывает во внешний регистр DD4. Затем программа выполняет свое основное действие. Она выполняет вывод в младший разряд индикатора. В этом случае код, соответствующий выводимому символу, также хранится в регистре РЗ. Однако высвечивается он на индикаторе HL2. Старший разряд будет высвечиваться также все время, пока таймер ТО отсчитывает очередную задержку. Теперь остановимся немного на дежурном режиме. В дежурном режиме выполнение процедуры пойдет по-другому, гораздо более короткому пути. Вывод символов на экран и управление мотором в этом режиме не производятся. Мотор будет остановлен, а индикаторы потушены. Посмотрите на рис. 48. Ветвь дежурного режима начинается с ответа «нет» в самом первом модуле принятия решений. Она содержит всего два элемента. Первый из них осуществляет проверку нажатия клавиши S7. Если клавиша не нажата, то вся процедура сразу переходит к своему завершению. Если клавиша оказалась нажатой, то моментального перехода к выполнению команд основного режима не происходит. Программа лишь устанавливает флаг, управляющий режимами работы в положение, соответствующее основному режиму, и на этом завершается. И лишь при следующем вызове процедуры динамической индикации ее выполнение пойдет по основной ветви алгоритма. Рассмотренный выше алгоритм описывает работу программы лишь в общих чертах. На самом же деле алгоритм намного сложнее. Прежде, чем перейти к рассмотрению текста программы этой процедуры, я хотел бы уточнить некоторые подробности. Начнем с механизма вызова прерывания. Счетчик/таймер в выбранном режиме работы считает поступающие на его вход импульсы от внутреннего генератора. Каждый такой импульс увеличивает значение регист-
162 Самоучитель по микропроцессорной технике ра ТО. После того, как значение этого регистра достигнет максимально возможного @FFFFH), следующий счетный импульс вызовет переполнение. Переполнение счетчика/таймера послужит запросом на соответствующее прерывание. В нашем случае будет вызвана процедура динамической индикации. Первое, что должна сделать вызванная процедура, это заново записать в регистр ТО значение коэффициента пересчета. Это нужно для того, чтобы следующий вызов прерывания произошел через такой же промежуток времени, что и предыдущий. Еще один момент, о котором нужно рассказать подробнее, это метод вывода символов на индикатор. Индикатор позиционера, кроме цифр, обозначающих номер текущего выбранного канала, должен отображать различные служебные символы. Это могут быть некоторые буквы и специальные знаки. В общем случае желательно предусмотреть вывод любых знаков, которые способен отобразить семисегментный индикатор. Весь набор символов для вывода на экран продумывается заранее. Каждому символу присваивается свой рабочий код. Удобно, чтобы рабочие коды символов, отображающих цифры, соответствовали самим отображаемым цифрам. То есть символ, отображающий единицу, должен иметь рабочий код 1. Символ двойки — код 2, и так далее. Остальным символам присваиваются все оставшиеся коды, от 10 и выше. Рабочие коды для символов мы присваивали из соображений удобства обработки. Однако для каждого символа существует еще один код — код вывода. Это тот самый код, который нужно вывести в порт РЗ для того, чтобы на индикаторе высветился соответствующий символ. Код этот определяется очень просто. Каждый разряд порта РЗ подключен к своему сегменту индикатора. Как видно из схемы (рис. 44) ноль в соответствующем разряде кода вывода вызовет зажигание соответствующего сегмента индикатора, а единица потушит соответствующий сегмент. Основная программа работает с рабочими кодами. Именно их она записывает в буфер экрана. Такой способ кодировки позволяет легко вычислять требуемый код. Однако при выводе на индикатор необходима перекодировка. Вместо рабочего кода символа на индикатор нужно вывести соответствующий код вывода. Для перекодировки кода символа в код вывода применяется кодировочная таблица. Таблица хранится в программной памяти микроконтроллера вместе с управляющей программой. Таблица представляет собой часть программной памяти, куда помещены коды вывода всех символов. Причем коды помешены в таблицу таким образом, что соответствующие им символы располагаются в порядке возрастания их рабочих кодов.
Позиционер спутниковой антенны 163 Фрагмент №8 текста программы позиционера представляет собой то самое место этой программы, где описывается таблица перекодировки символов. Для описания кодов таблицы применяется оператор описания данных DB. Суть этого оператора в том, что он помещает в текущий сегмент памяти процессора один или несколько кодов. Коды, которые нужно поместить в выбранное место памяти, указываются в правой части оператора в качестве его параметров. Оператор может содержать любое число параметров. Их количество ограничено лишь разумной длиной строки. Слишком много параметров указывать просто неудобно. Проще в новой строке поставить еще один оператор DB и продолжить нужную последовательность. Все параметры должны разделяться запятой. Каждый из параметров представляет код, который нужно поместить в очередную ячейку памяти. Код может быть задан в любой допустимой форме: десятичной, шестнадцатеричной, двоичной. Вот пример применения оператора DB для записи в память пяти различных кодов: DB 10, 12, 0F3H, 001101В, 105Н Кроме того, коды могут задаваться в символьном виде. В этом случае в память помещаются ASCII-коды соответствующих символов. При таком способе задания кодов символьные строки заключаются в кавычки: DB "Proba", "Test" Однако в программе позиционера символы в ASCII-кодировке не применяются и описываемый метод определения констант не используется. Но вернемся к нашей таблице символов. Посмотрите внимательно на фрагмент №8. Описание таблицы начинается с оператора ORG. Оператор ORG помещает указатель текущего сегмента в адрес 0700Н. Текущим сегментом является программная память микроконтроллера. Это приводит к тому, что первый из операторов DB поместит свой код в программной памяти по адресу 700Н. Таким образом, таблица символов всегда будет находиться по фиксированному адресу. Фрагмент №8 , Таблица символов ORG 0700H tbchr DB 11000000B 0 Символ 0 DB 11111001B , 1 Символ 1 DB 01100100B ,2 Символ 2 DB 01110000B ,3 Символ 3 DB 01011001B ,4 Символ 4 DB 01010010B .5 Символ 5 DB 01000010B 6 Символ 6 DB 11111000B ,7 Символ 7 DB 01000000B , 8 Символ 8
164 Самоучитель по микропроцессорной технике В начале таблицы стоит метка tbchr. Эта метка будет использоваться для доступа к таблице в процедуре перекодировки. Коды из таблицы извлекаются по их порядковому номеру. Например, для того, чтобы вывести на индикатор символ «Р» с рабочим кодом, равным 18, нужно извлечь код из восемнадцатой ячейки от начала таблицы и поместить его в порт РЗ. Очевидно, адрес ячейки, в которой находится код вывода указанного символа, вычисляется как tbchr+18. Все коды вывода для удобства восприятия заданы в двоичной форме. Такая форма записи дает возможность сразу увидеть состояние каждого бита. В конце таблицы символов имеется еще один оператор, который описывает константу попе. Эта константа имеет прямое отношение к.таблице символов. Константа попе записывается в порт РЗ тогда, когда требуется выключить индикатор. В процедуру динамической индикации включено еще несколько вспомогательных операций. Это специальные операции, служащие для организации трех программных счетчиков. Мы уже частично упоминали о некоторых из них. Первый из счетчиков служит для формирования периода мерцаний в режиме записи. Второй служит для формирования времени индикации спецсимволов. А тритий задает время удержания кнопки «Запись/стирание», необходимое для включения режима стирания. Все вышеперечисленные виды задержки относятся к разряду сверхдлинных (по сравнению с задержками, формируемыми при помощи системных таймеров). Такие задержки сформировать при помощи таймеров невозможно. Шестнадцать разрядов для этого слишком мало. Поэтому, для формирования таких интервалов удобнее использовать DB 01010000В ; 9 Символ 9 OB 11111111B ; 10 Символ пробела DB 01001111B ; 11 Символ |- DB 01111001В ;12Символ-| DB 11110111B ; 13 Символ _ (подчеркивание) DB 11000110B ; 14 Символ [ (открывающая квадратная скобка) DB 11110000B ; 15 Символ] (закрывающая квадратная скобка) DB 01000110B ; 16 Символе DB 01101111В ; 17 Символ г DB 01001100В ; 18 Символ Р DB 01010001B ; 19 Символ У DB 01001001В ; 20 Символ Н DB 01111111В ; 21 Символ- DB 01001000В ; 22 Символ А DB 01000011В ;23 Символb DB 11000110В , 24 Символ С DB 01100001B ,25 Символ d DB 01000110B ; 26 Символе DB 01001110B ; 27 Символ F none EQU 11111111В ; Индикатор потушен
Позиционер спутниковой антенны 165 программные счетчики, с управлением от процедуры динамической индикации. Процедура динамической индикации вызывается с постоянным периодом, примерно равным 50 Гц. Поэтому, если при каждом вызове процедуры будет производиться итерация (увеличение или уменьшение на единицу) содержимого регистра счетчика, то работа такого счетчика будет строго синхронизирована во времени. И последняя тонкость, о которой хотелось бы упомянуть перед тем, как перейти к рассмотрению текста программы. В реальной программе алгоритм дежурного режима немного отличается от алгоритма, изображенного на рис. 48. Основные операции в этом режиме полностью не прекращаются. Просто они идут в немного измененном виде. Программа опрашивает состояние клавиатуры, производит вывод управляющего сигнала на мотор. Работает даже вывод символов на индикатор. Правда в этом случае в оба разряда индикатора выводится символ с рабочим кодом 10Н. Это так называемый символ пробела. При выводе этого символа все сегменты индикатора гаснут. В качестве управляющего сигнала мотора выводится сигнал «Стоп» (ООН). А программа опроса клавиатуры используется только для того, чтобы проверить состояние всего лишь одной кнопки. Кнопки S7. Теперь обратимся к тексту процедуры динамической индикации. Этот текст приведен ниже (см. фрагмент №9). Фрагмент №9 ; Обработка прерывания динамической индикации pint: push PSW ; Сохранение регистров в стеке push ACC push DPH push DPL mov PSW,#bank1 ; Включение банка 1 mov TH0,#tdind ; Загрузка в регистр таймера коэффициента пересчета oudisp: jb flonoff,ou5 ; Ветвь дежурного режима mov a.bufkl ; Ожидание, пока будет отпущена кнопка «Вкл/выкл» jnb acc.bitonof.ou5 mov p1 ,#3FH ; Перевод схемы в режим чтения с клавиатуры mov p3,#0FFH mov a,p3 ; Чтение байта состояния клавиатуры jb acc.bitonof,ou5 ; Если кнопка S7 не нажата, то переход ; Выход из дежурного режима mov bufkl.a ; Запись прочитанного байта в буфера клавиатуры
166 Самоучитель по микропроцессорной технике jnb acc.bitonof,ou5 mov p1 ,#3FH ; Перевод схемы в режим чтения с клавиатуры mov p3,#0FFH mov а.рЗ ; Чтение байта состояния клавиатуры jb acc.bitonof,ou5 ; Если кнопка S7 не нажата, то переход ; Выход из дежурного режима mov bufkl.a ; Запись прочитанного байта в буфера клавиатуры mov _klold,a ; . ив буфер предыдущего состояния setb flonoff ; Включение "питания" ; Включение дисплея jnb flrujnidi ; Проверка режима (работа или установка) mov bufh.nk ; вывод номера канала (старший разряд) mov bufl,nk+1 ; (младший разряд) jmp ou7 inidi: mov bufh,#19 ; Вывод надписи «УС» mov bufl,#24 ou7: mov pcon,#0 ; Выход из режима пониженного потребления ;— Конец ветви дежурного режима ou5' djnz iffash,ou6 ; Счетчик мерцаний mov iflash,#tflash ; Проверка условий мерцания оиб: setb flifl ; включить индикатор (подтвердить включение) jnb flflh,ou2 ; если мерцание выключено, то обойти mov ajflash ; определение фазы (гореть/не гореть) clr с subb a,#tflash/2 jc ou2 ; если содержимое счетчика больше половины периода clr flifl ; потушить индикатор ; Подготовка к разветвлению: вывод старшего / младшего разрядов ou2: mov DPTR,#tbchr ; Загружаем в DPTR начало таблицы символов, cjne ibuf,#7FH,ou1 ; Проверка значения номера разряда ; ВЕТВЬ ВЫВОДА СТАРШЕГО РАЗРЯДА ; Ввод состояния клавиатуры mov p1,#3FH ; Перевод схемы в режим чтения с клавиатуры mov p3,#0FFH mov а.рЗ ; Чтение из порта байта состояния клавиатуры mov bufkl.a ; Запись в буфер клавиатуры ; Вывод старшего разряда буфера на дисплей mov a.bufh ; Чтение кода символа move a,@A+DPTR ; Вычисление адреса в таблице знакогенератора mov p3,#none ; Вывод сигнала гашения индикатора mov pl.ibuf ; Переключение дешифратора jnb flifl,ou3 ; Если флаг «гореть/не гореть» ноль обойти mov рЗ,а , Вывести символ ou3: mov ibuf,#OBFH ; Поменять значение номера разряда jmp flh2 ; Закончить ветвь
Позиционер спутниковой антенны 167 ; ВЕТВЬ ВЫВОДА МЛАДШЕГО РАЗРЯДА ; Вывод сигнала управления мотором ou1: mov a.bufmot ; Прочитать команду из буфера orl а,#11111100В ; Отбросить неиспользуемые разряды mov рЗ,а ; Вывести код управления в порт mov p1,#OFFH ; Включить режим записи в регистр mov p1,#3FH ; Отключить режим записи ; Вывод младшего разряда буфера на дисплей mov a.bufl ; Чтение кода символа move a,@A+DPTR ; Вычисление адреса в таблице знакогенератора mov p3,#none ; Вывод сигнала гашения индикатора mov pl.ibuf ; Переключение дешифратора jnb flifl,ou4 ; Если флаг «гореть/не гореть» ноль обойти mov рЗ,а ; Вывести символ ои4: mov ibuf,#7FH ; Поменять значение номера разряда ; Конец обоих ветвей ; Итерация счетчика очистки от спецсимволов flh1: mov a.nk ; Сравнить старшие разряды номера каналов и буфера cjne a,bufh,zdd1 mov a,nk+1 ; Сравнить младшие разряды номера каналов и буфера cjne a,bufl,zdd1 zdd4: mov coudd,#0 ; Если нет различий, обнулить счетчик очистки jmp ¦ flh2 ; и пропустить всю процедуру счета ; Если есть различия, zdd1: mov a.bufh ; проверить не записано ли в буфере «РУ» cjne a,#18,zdd3 mov a.bufl cjne a,#19,zdd3 jmp zdd4 ; Если в буфере «РУ», тоже обнулить счетчик zdd3: mov a.coudd cjne a,#0,zdd2 ; Если счетчик обнулен (не запущен) mov coudd,#tzdd ; запустить его (записав туда коэффициент пересчета) jmp flh2 zdd2: dec a ; уменьшение значения счетчика на 1 mov coudd.a ; запись в ячейку счетчика cjne a,#0,flh2 ; He достиг ли счетчик нуля? mov bufl,nk+i ; Если достиг, переносим номер канала mov bufh.nk ; в буфер экрана ; Итерация счетчика задержки включения режима стирания flh2: jnb flks,flh3 ; Если флаг нажатия кнопки S равен 0, не считать mov a.bufkl cjne a,#kkss,flh3 ; Если кнопка S не нажата, не считать dec coucl ; Уменьшить значение счетчика на 1 (счет) ; Конец прерывания flh3: pop DPL ; Восстановление регистров pop DPH pop ACC pop PSW reti ; Выход из прерывания
168 Самоучитель по микропроцессорной технике Процедура начинается с сохранения содержимого регистров в стековой памяти. Для этого используются оператор push. Каждый такой оператор помещает в стек содержимое одного из регистров контроллера. Команда push PSW сохраняет в стеке содержимое регистра флагов. Команда push АСС сохраняет в стеке содержимое аккумулятора. АСС — это второе название регистра аккумулятора. Это название применяется в том случае, когда к аккумулятору обращаются, как к ячейке памяти. Две последующие команды сохраняют по очереди каждую из двух половинок шестнадцатиразрядного регистра DPTR. Регистры общего назначения не могут быть сохранены в стековой памяти. Таких команд в описываемом микроконтроллере не предусмотрено. Поэтому сразу после сохранения регистров программа выполняет переключение банков РОН. Переключение делается очень просто. При помощи команды mov PSW,#bankl в регистр флагов записывается константа, значение которой соответствует нужному банку. Еще на этапе предварительной разработки банки РОН были распределены между основными процедурами. Для процедуры динамической индикации было решено использовать банк номер I. За командой выбора банка следует команда перезапуска таймера. Для этого в старшую половину регистра таймера ТО записывается старший байт коэффициента пересчета, соответствующего задержке в 20 мс. Так как в данном случае не требуется высокой точности в отработке задержки, младший байт коэффициента пересчета не загружается. Далее идет команда проверки флага flonoff. Этот флаг служит для переключения позиционера из основного режима в дежурный. В зависимости от значения этого флага программа либо выполняет ветвь дежурного режима, либо обходит ее. В том случае, если значение флага равно нулю, перехода не происходит и программа начинает переходить к обработке дежурного режима. Ветвь дежурного режима. Эта часть программы начинается с проверки значения буфера клавиатуры. Причем программу интересует только бит 7 записанного там числа. Если этот бит равен нулю, то это означает, что кнопка S7 еще не отпущена после того, как она была нажата для включения дежурного режима. Пока это так, программа будет обходить остальные команды дежурного режима. То есть дежурный режим включится только после отпускания кнопки S7. Вся операция оценки состояния кнопки S7 выполняется в две команды. Сначала значение кода состояния клавиш помещается в аккумулятор. Затем применяется команда условного перехода (jnb). Такая команда вызывает передачу управления в том случае, если проверяемый бит равен нулю. Выражение acc.bitonof
Позиционер спутниковой антенны 169 позволяет обратиться к биту номер bitonof аккумулятора. Как мы уже говорили ранее, константа bitonof равна 7 и специально введена для того, чтобы описать номер бита, связанного с кнопкой «Вкл/Выкл». Основная часть ветви обработки дежурного режима занимается ожиданием нажатия кнопки «Вкл/Выкл». Для этого в эту часть программы включена своя собственная процедура чтения состояния клавиатуры. Процедура чтения начинается с команд подготовки схемы позиционера к этому режиму. В порт pi записывается код 3FH. Два старших разряда такого числа равны нулю. Эти два нуля поступают на дешифратор DD3 (см. рис. 44) и переключат его в режим выбора клавиатуры. Затем в порт рЗ записывается код 0FFH. В результате все выходы порта установятся в единичное состояние, и порт подготавливается к работе в режиме ввода. Следующая команда читает состояние клавиатуры из порта рЗ и записывает его в аккумулятор. На этом процедура чтения состояния клавиатуры заканчивается. После чтения состояния клавиатуры производится оценка бита, соответствующего кнопке «Вкл/Выкл». Обращение к соответствующему биту происходит точно так же, как и в начале ветви дежурного режима. Но теперь вместо jnb используется оператор jb. Этот оператор наоборот выполняет переход только в случае, когда проверяемый бит равен единице. Если кнопка «Вкл/Выкл» оказалась не нажата, значение бита будет равно единице и программа выполнит переход но адресу ои5. А это означает, что операторы, переводящие систему в основной режим, не будут выполнены. Как только кнопка вновь окажется нажатой, очередная процедура динамической индикации, дойдя до этого места, перейдет к выполнению команд перехода в основной режим работы. Эти команды объединены в два блока, озаглавленные в тексте программы как: «Выход из дежурного режима» и «Включение дисплея». Выход из дежурного режима. Эта группа команд производит запись только что считанного кода состояния клавиатуры в основной и дополнительный буферы клавиатуры. Затем флаг flonoff устанавливается в единичное состояние. Включение дисплея. При переходе в основной режим работы необходимо возобновить вывод изображения на дисплей. Конечно, для этого достаточно вывести на дисплей номер текущего выбранного канала. Однако в программе позиционера заложено небольшое усложнение, вызванное соображениями удобства пользования. Дело в том, что для позиционера различают еще два режима работы: «Работа» и «Установка». Эти два режима отличаются тем, что в режиме установки включены все возможности по записи и корректировке каналов, а в рабочем режиме все эти
170 Самоучитель по микропроцессорной технике возможности заблокированы. Все это нужно для того, чтобы обезопасить позиционер от случайной порчи настроек. Для переключения режимов «Работа/Установка» применяется флаг flru. Если позиционер находится в режиме «Установка», то в момент включения на дисплей выводится предупреждающая надпись «УС». Проверкой флага flru занимается оператор jnb. Если флаг имеет единичное значение, это значит, что позиционер находится в режиме установки. Управление передается по адресу inidl, где в буфер дисплея записываются коды букв «У» A9) и «С» B4). В противном случае в буфер дисплея записываются старший и младший разряды номера канала из той ячейки памяти, где хранится его исходное значение. То есть из ячейки nk и ячейки nk+1. Завершается ветвь обработки дежурного режима командой вывода процессора из режима пониженного потребления, которая записывает нулевой байт в регистр peon. Счетчик мерцаний. Для организации счетчика мерцаний выделена специальная ячейка памяти iflash. Сам счетчик мерцаний работает постоянно, независимо от того, отключено мерцание в данный момент или нет. Для итерации счетчика применена уже знакомая нам программа организации цикла djnz. В данном случае она применяется нестандартным образом. Каждый раз, когда выполнение программы дойдет до этого места, команда djnz уменьшает содержимое ячейки iflash на единицу. Если после этого содержимое ячейки еще не равно нулю, тот же самый оператор передает управление по адресу оиб и таким образом продолжает выполнение программы. Если в результате уменьшения содержимое ячейки iflash оказалось равно нулю, то перехода не происходит и команда mov производит загрузку в ячейку счетчика его начального значения (tflash). Таким образом, счетчик мерцаний работает на протяжении всего времени, пока включено питание позиционера и считает по кругу, от максимального значения до нуля и опять сначала. Константа tflash определяет период мерцания. Для осуществления самого процесса мерцания служит процедура проверки условий мерцания. Задача этой процедуры — отслеживать значение счетчика мерцания, и в случае, когда его значение меньше tflash/2, устанаапивать флаг flifl в единицу. А при значениях счетчика больших tflash/2, устанавливать флаг flifl в ноль. Флаг flifl называется «гореть/не гореть». Его значение используется затем в программе вывода символа. Если значение флага равно нулю, изображение на индикатор не выводится, и он остается погашенным. Для включения и отключения мерцания служит флаг flflh. Если значение этого флага равно единице — мерцание включено. Если нулю — выключено. Процесс проверки условий мерцания начинается с установ-
Позиционер спутниковой антенны 171 ки флага «гореть/не гореть» в положение «гореть». Затем происходит проверка флага разрешения мерцания (flflh). Если его значение оказалось равно нулю (мерцание выключено), то управление передается по адресу ои2. Дальнейшая проверка условий мерцания прекращается и флаг «гореть/не гореть» остается в положении «гореть». Если мерцание включено, то выполняется процедура сравнения. Сравнение производится путем вычитания из текущего значения счетчика мерцаний константы, значение которой равно tflash/2. Здесь опять используются возможности препроцессора. Транслятор вычислит выражение и подставит вместо него число, равное целой части результата деления константы tflash на два. Далее, оператор jc производит проверку признака переноса. В случае, если результат вычитания отрицательный произойдет переход по адресу ои2. В случае положительного результата перехода не будет и оператор с!г выполняет сброс флага flifl в ноль. После программного счетчика мерцаний начинается разветвление процедур на два пути, соответствующих двум фазам процедуры динамической индикации. При первом вызове, программа пойдет по пути индикации старшего разряда, при последующем вызове, она пойдет по-другому пути, и будет выполнять операции по индикации младшего разряда. Так как в обоих случаях будет применяться перекодировка по таблице символов, в регистр DPTR заранее загружается адрес начала этой таблицы. Далее производится проверка содержимого буфера указателя текущего разряда индикатора (ibuf). В этом буфере хранится код, который нужно выдать в порт pi для того, что бы дешифратор DD3 переключился в режим индикации соответствующего разряда индикатора. При индикации старшего разряда в буфере хранится число 7FH, а при индикации младшего — 0BFH. Оператор cjne проверяет содержимое этого буфера и передает управление либо на процедуру обработки первой фазы индикации, либо на процедуру обработки второй фазы. Если содержимое буфера ibuf не равно 7FH, то программа переходит к обработке первой фазы (вывод младшего разряда). В противном случае выполняется вывод старшего разряда. Ветвь вывода старшего разряда начинается с процедуры ввода состояния клавиатуры. Данная процедура аналогична подобной процедуре, которую мы уже рассматривали в составе команд ветви дежурного режима. Отличие этой новой процедуры лишь в том, что код состояния клавиатуры записывается только в основной буфер (bufkl). В дополнительном буфере остается код предыдущего состояния клавиатуры. Сразу после команд опроса клавиатуры начинается процедура вывода символа. Сначала код символа из старшего разряда буфера экрана по-
172 Самоучитель по микропроцессорной технике мешается в аккумулятор. Далее происходит перекодировка. Для перекодировки применяется оператор чтения константы из программной памяти move. Этот оператор устроен таким образом, что читает код из программного сегмента памяти CSEG по адресу, который вычисляется как сумма шестнадцатиразрядного числа в регистре DPTR и содержимого аккумулятора. Прочитанный код также помещается в аккумулятор. В регистре DPTR у нас находится адрес начала таблицы символов. Это значит, что команда move извлечет из памяти код, порядковый номер которого в таблице символов соответствует содержимому аккумулятора. А оно, в свою очередь, равно рабочему коду символа, поступившему из буфера экрана. Извлеченный код временно сохраняется в аккумуляторе. А программа приступает к процедуре вывода на индикатор. Сначала в порт рЗ засылается константа попе. При выводе этой константы все сегменты индикатора окажутся погашенными. Это делается для того, чтобы в момент переключения на индикатор не попал случайный код. Далее в порт pi записывается сигнал из буфера ibuf. Два его старших разряда поступают на дешифратор DD3 и переключают в режим индикации старшего разряда. Далее идет оценка флага flifl («гореть/не гореть»). Если значение флага равно нулю, то вывод кода не производится и индикатор так и остается не включенным. Если гореть разрешено, то код вывода из аккумулятора помещается в порт pi, где он находится вплоть до следующего вызова процедуры динамической индикации. В заключение программа меняет содержимое буфера ibuf на 0BFH для того, чтобы при следующем вызове процедура пошла по-другому пути и выполнила ветвь вывода младшего разряда. Безусловный переход передает управление по адресу flh2, где заканчиваются обе ветви динамической индикации. Ветвь вывода младшего разряда построена аналогично ветви вывода старшего. Однако вместо процедуры опроса клавиатуры ветвь начинается процедурой вывода управляющего сигнала на мотор. Для этого команда управления мотором считывается из буфера мотора в аккумулятор. Затем команда логического сложения orl выполняет операцию побитного «ИЛИ» кода команды с константой 11111100В. Такая операция установит в единицу все разряды, кроме двух младших. Именно два младших разряда будут записаны в регистр DD4, и будут влиять на работу двигателя. Неиспользуемые разряды порта всегда правильнее держать в единичном состоянии. Далее, полученный код помещается в порт рЗ. Следующая команда записывает в порт pi код 0FFH. Оба старших разряда в числе 0FFH равны единице, поэтому дешифратор DD3
Позиционер спутниковой антенны 173 перейдет в режим записи кода в регистр DD4. На выходе 12 дешифратора появится низкий логический уровень, который поступит на входы С обоих триггеров регистра DD4. В следующий момент в порт pi записывается код 3FH. Уровень сигнала на обоих входах С микросхемы DD4 становится равным единице. По переднему фронту происходит запись двух младших разрядов порта рЗ в этот микрорегистр. Закончив процедуру вывода сигнала управления мотором, программа приступает непосредственно к процедуре вывода старшего разряда. Эта процедура полностью аналогична процедуре вывода младшего разряда и повторять описание нет смысла. Итерация счетчика очистки от спецсимволов. После завершения обоих ветвей динамической индикации, программа переходит к процедуре организации счетчика задержки вывода спецсимволов. Дело в том, что в обычном режиме программа высвечивает на своем дисплее номер текущего выбранного канала в диапазоне от 00 до 99. Но для индикации различных дополнительных режимов работы на индикатор могут выводиться специальные не цифровые надписи (спецсимволы). Ниже приведен весь список спецсимволов, заложенных в программе: PS Работа. УС Установка. РУ Ручное управление. МУ Начальная установка. f j Конец процесса начальной установки. ?г Ошибка процедуры чтения(записи) флэш-памяти. Каждый из спецсимволов, выведенный на дисплей, должен оставаться там несколько секунд и исчезать, уступая место номеру выбранного канала. Для этой цели разработана универсальная процедура, убирающая спецсимволы с дисплея. Она постоянно сравнивает содержимое буфера экрана (bufh, bufl) и содержимое регистра указателя номера текущего выбранного канала (nk). Если их содержимое не совпадает, то запускается специальный счетчик. Счетчик отсчитывает определенный период времени. По истечении этого периода программа переписывает содержимое указателя номера канала (nk) в буфер экрана. Спецсимвол «РУ» является исключением. Он высвечивается при нажатии на любую из кнопок ручного поворота антенны (S5 или S6) и должен присутствовать на дисплее все время, пока нажата кнопка поворота. А поворот антенны на нужное направление может длиться дос-
174 Самоучитель по микропроцессорной технике таточно долго. Поэтому в программе делается специальная проверка. Если в буфере экрана находятся коды надписи «РУ», то запуск счетчика очистки спецсимволов не производится. Начинается процедура счетчика очистки от спецсимволов сравнением старших разрядов буфера экрана и указателя номера канала. Старший разряд номера канала помещается в аккумулятор. Затем, при помощи команды cjne он сравнивается со старшим разрядом буфера экрана. Если коды не равны, управление передается по адресу zddl к процедуре запуска счетчика. Если старшие разряды оказались одинаковые, то таким же образом сравниваются младшие разряды. В случае различия младших разрядов управление также передается по адресу zddl. Если же и эти коды оказались равными, то на этом обработка счетчика удаления спецсимволов завершается. Значение счетчика сбрасывается в ноль. Нулевое значение счетчика означает для дальнейшей программы, что он еще не был запущен. Команда безусловного перехода jmp flh2 обходит все остальные операции, связанные с данным счетчиком, и переходят к последующим операциям. Если программа обнаружила спецсимвол и запустила счетчик, программа продолжается с адреса zddl. По этому адресу расположены команды проверки: не содержит ли буфер экрана надпись «РУ». Процедура эта полностью аналогична сравнению буфера экрана и указателя номера канала. Если в результате сравнения окажется, что в буфере экрана находится «РУ», то программа обходит дальнейшие операторы сравнения. Если в буфере экрана другой спецсимвол, то программа переходит непосредственно к процедуре итерации счетчика. Сначала производится проверка содержимого регистра счетчика (coudd) на равенство нулю. Если содержимое счетчика оказалось равно нулю, значит счетчик еще не запушен. Программа запускает счетчик, записывая в регистр coudd коэффициент пересчета tzdd, и заканчивает на этом процедуру обработки счетчика. Если содержимое счетчика не равно нулю, то это означает, что счетчик находится в режиме счета. Поэтому программа выполняет уменьшение его содержимого на единицу (команда dec). Новое значение содержимого счетчика записывается в coudd. Сразу после этого производится проверка на ноль. Если после очередного уменьшения содержимое счетчика стало равно нулю, то происходит завершение периода индикации спецсимвола. На индикатор выводится номер канала. Итерации счетчика задержки режима стирания гораздо проще. Все операции по запуску, сбросу и оценке окончания счета выполняет основная программа. На процедуру динамической индикации вохчожена лишь функция счета. Кроме того, в процедуру счета добавлена проверка двух дополнительных условий. При невыполнении любого из них счет приостанавливается.
Позиционер спутниковой антенны 175 Первое условие: флаг flks должен быть равен единице. Если вы еще не забыли, флаг устанавливается в единицу сразу после нажатия кнопки «запись/стирание» (S4), а сбрасывается в том случае, если процедура стирания памяти уже произошла, даже если кнопка S4 еще не отпущена. Это условие останавливает счет, если режим стирания уже включился, а кнопка еще не отпущена. Второе условие — сама кнопка S4 должна быть нажата. Если она не нажата, счет тоже будет остановлен. Проверка этого условия производится путем сравнения содержимого буфера клавиатуры bufkl с кодом клавиши S4 (kkss). На этом процедура обработки прерывания заканчивается. В заключение процедуры происходит восстановление всех регистров, сохраненных в ее начале. Восстановление регистров производится при помощи команды pop. Команда pop служит для извлечения информации из стека. Восстановление регистров происходит в порядке, обратном тому, в каком производилось их сохранение. При восстановлении регистра PSW одновременно восстанавливается тот банк РОН, который был включен до начала процедуры обработки прерывания. И, наконец, выход из процедуры обработки прерывания происходит по команде reti. Команда reti по своему действию равнозначна команде ret. Она извлекает из стека адрес, на котором было прервано выполнение основной программы, и передает управление по этому адресу. Однако процедуры обработки прерывания всегда должны заканчиваться именно командой reti. Команда reti вызывает правильное срабатывание системы приоритетов. Процессор должен всегда точно знать, обработка каких прерываний в данный момент еще не закончилась. Процедура приема сигнала ДУ Отдельная крупная задача, которую мне пришлось решить при разработке позиционера — это заставить его подчиняться командам от пульта дистанционного управления. Задачу создания программы, принимающей команды ДУ, пришлось решать, не имея никакой справочной литературы на эту тему. Решено было просто приспособить для этой цели один из стандартных пультов ДУ от телевизора. Единственным критерием при выборе пульта была его достаточная распространенность. Исходя из этих соображений, был выбран пульт RC-500 от телевизора «Горизонт». Это стандартный пульт для целой серии отечественных телевизоров с так называемой «скрин-индикацией». Скрин-индикаии-
176 Самоучитель по микропроцессорной технике ей (от слова screen — экран) называют вывод информации о режимах работы телевизора непосредственно на его экран. Выбранный пульт имеет довольно широко распространенную систему команд. Цел?1й ряд пультов импортного производства можно без каких-либо доработок использовать вместо пульта RC-500. Как уже говорилось, метод кодирования команд пульта мне заранее не был неизвестен. В связи с этим пришлось провести небольшие исследовательские работы. Для изучения сигнала, передаваемого с пульта ДУ, решено было использовать осциллограф. Причем осциллограф подключался не к пульту, а к выходу фотоприемника на самом позиционере (выход 3 фотоприемника DD5 на рис. 44). Излучающий диод пульта ДУ направлялся на фотоприемник и на пульте, поочередно, нажималась каждая кнопка. При этом на экране осциллографа появлялись пакеты импульсов, соответствующих различным командам ДУ. Несмотря на то, что длина каждого пакета оказалась намного меньше периода их следования, все же удалось засинхрони- зировать развертку осциллографа и рассмотреть форму сигнала внутри самого пакета. В результате этих исследований выяснилось следующее: ¦ Каждая команда передается пакетами импульсов, по 26 или 28 импульсов в пакете (в разных командах по-разному). Период следования импульсов в пакете равен одной миллисекунде. ¦ Каждый пакет построен таким образом, что промежутков между соседними импульсами нет, так что идущие подряд два единичных импульса сливаются в один импульс двойной ширины. ¦ Таким же образом сливаются идущие подряд два нулевых импульса. ¦ Для передачи команд используются специальный вид кодировки, обеспечивающий минимизацию полосы передаваемого сигнала. Для этого импульсы в каждом управляющем пакете подчиняются следующему правилу: не допускается, присутствия в одном пакете подряд более двух единиц или более двух нулей. ¦ При нажатии каждой кнопки передается свой уникальный пакет импульсов, закрепленный именно за этой кнопкой. ¦ Первые 12 импульсов пакета для всех кнопок одинаковые. Эти импульсы несут общую информацию о виде используемой системы команд. Эта информация используется для того, чтобы приемное устройство отличало сигналы своего пульта от чужих сигналов. ¦ Описанные выше пакеты передаются один за другим с периодом примерно равным 100 мс все время, пока нажата кнопка на пульте. Передача пакетов прекращается сразу после отпускания кнопки. По результатам всех этих исследований было принято решение создать свой нестандартный алгоритм, основная задача которого — уверенно распозна-
Позиционер спутниковой антенны 177 вать любую из команд указанного пульта ДУ. При этом не ставилась задача использования всех возможностей, заложенных в указанную систему кодировки. Для создания такого алгоритма было применено несколько приемов, упрощающих поставленную задачу. Однако рассмотрим все по порядку. В данном случае мы имеем дело с последовательным методом передачи управляющих кодов. Для организации процесса приема сохранения и расшифровки такого кода не обойтись без сдвигового регистра. Количество разрядов такого регистра должно быть равно максимальному количеству битов в принимаемом коде. Упрощенно, процесс приема сигнала можно представить следующим образом. Каждый принятый бит записывается в младший разряд этого регистра. При этом остальное содержимое регистра сдвигается на один разряд вверх. Указанный процесс записи повторяется для каждого принимаемого бита. Таким образом, принимаемый код постепенно заполняет регистр. После записи последнего бита пакета необходимо приостановить процесс записи и приступить к распознаванию кода и выполнению команды. Таким образом, если решать поставленную задачу напрямую, «в лоб», то нужно иметь регистр с числом разрядов, равным 28. Для организации такого регистра программным путем придется выделить под него 4 ячейки памяти. Это существенно затрудняет обработку принятого кода. Однако несколько нехитрых приемов позволяет существенно сократить размеры сдвигового регистра. Рассмотрим эти приемы подробнее. Первый прием связан с особенностями используемого метода кодирования. Данный метод широко известен в системах последовательной передачи данных. Его преимущество в том, что сформированный по такому принципу аналоговый сигнал имеет минимальную полосу частот, что снижает требования к каналам передачи данных. В то же время, передаваемый код обладает довольно большой избыточностью. В результате его можно легко сократить, без какой-либо потери информации. Порядок преобразования следующий: ¦ Каждые два рядом стоящих разряда преобразовываются в один. ¦ Для преобразования применяется следующее правило: • Если оба разряда в исходном коде равны между собой, то есть это 00 или II, то в результирующем коде мы получим разряд, значение которого равно нулю. • Если исходные разряды отличаются друг от друга, то есть это 01 или 10, то соответствующий разряд в результирующем коде будет равен единице. Такой метод позволяет вдвое сократить длину принимаемого кода. Причем потери информации не произойдет. Каждой комбинации исходного
178 Самоучитель по микропроцессорной технике кода будет соответствовать своя уникальная результирующая комбинация. А значит, всегда можно отличить одну команду от другой. Еще один резерв сокращения разрядности сдвигового регистра кроется в том, что для всех команд пульта начало кода всегда одно и то же. Для упрощения программы можно просто не учитывать первую половину кодовой посылки. Это несколько снижает защищенность системы от ложных срабатываний, но зато позволяет снизить количество принимаемых бит до восьми. В результате применения этих двух приемов принятый код занимает всего один байт в памяти компьютера, что значительно упрощает процедуру его обработки. Для реализации процесса приема кода было решено использовать синхронный метод приема. Синхронный метод состоит в следующем. На первом этапе реализован алгоритм обнаружения начала первого импульса. Этот момент служит точкой отсчета для остального процесса. Основной процесс приема организован в виде цикла, в котором оценка входного сигнала производится путем считывания его значения через фиксированные промежутки времени, равные периоду входного сигнала. Для считывания всего пакета программа производит 28 циклов чтения. В процессе чтения происходит попарное объединение соседних разрядов и отбрасывание лишних. Весь этот процесс организован в виде процедуры обработки прерывания, которая запускается при помощи внутреннего таймера/счетчика Т1. Интервал времени между отдельными циклами считывания определяется путем программирования периода таймера/счетчика. На рис. 49 показана временная диаграмма всего процесса приема кода. Рис. 49. Процесс приема сигналов ДУ Весь процесс разбит на три фазы: «Фазу ожидания кода», «Фазу приема» и «Фазу ожидания отпускания кнопки». Периоды следования циклов чтения в различных фазах разные. Единицей отсчета для всех временных интервалов описываемой процедуры служит период следования импульсов в передаваемом сигнале. На рис. 49 этот период обозначен, как Тсигн.
Позиционер спутниковой антенны 179 В фазе ожидания кода циклы считывания повторяются с периодом равным 1/3 Тсигн. В этой фазе единственным действием, которое выполняет программа, является проверка наличия входного сигнала. Если в момент считывания на выходе фотоприемника окажется нулевой логический уровень, то программа считает, что сигнал с пульта отсутствует. Поэтому фаза ожидания продолжается. Если в очередном цикле чтения уровень сигнала окажется равным единице, то программа переходит в фазу приема. В фазе приема период следования циклов чтения точно равен Тсигн. Исключение составляет только самый первый временной интервал: интервал между последним чтением фазы ожидания и первым чтением фазы приема. Этот переходный интервал равен 1/3 Тсигн. Из рис. 49 хорошо видно, что такой способ выбора интервалов позволяет с большой точностью «попасть» в центр первого импульса принимаемого пакета. В фазе приема программа производит ровно 28 циклов чтения. Для реализации описанных выше методов сокращения разрядности, четный и нечетный биты принятого кода обрабатываются по-разному. Четный бит просто запоминается в специальном буфере. После чтения нечетного бита, программа производит операцию исключающего ИЛИ между обоими прочитанными битами. Полученный таким образом результирующий бит заносится в младший разряд регистра приема. Остальное содержимое этого регистра сдвигается на один разряд влево. Таким образом, за все время, пока длится фаза приема, в указанный регистр будет записано 14 бит данных. Так как размер регистра приема равен 8 битам, в результате всех этих операций, самые первые записанные туда биты будут утеряны. Однако полученный таким образом код, как уже указывалось выше, все равно будет уникальным для каждой команды. В конце фазы приема, считанный код помещается в буфер команд ДУ, где он становится доступным для специальной подпрограммы основного цикла, осуществляющей его дальнейшую обработку. Затем программа автоматически переходит в фазу ожидания отпускания кнопки. Фаза ожидания отпускания кнопки на рис. 49 не показана. В этой фазе считывание входного сигнала происходит с периодом 1/3 Тсигн. Задача программы в этом режиме — дождаться отпускания кнопки на пульте ДУ. Этот режим нужен для предотвращения повторного срабатывания команды. Как уже говорилось, все время, пока нажата кнопка пульта, происходит многократная передача управляющих пакетов. В фазе ожидания отпускания кнопки программа проверяет наличие сигнала на выходе фотоприемника. Эта фаза продолжается до тех пор, пока на выходе фотоприемника присутствует сигнал ДУ. Для надежности введен защитный интервал. Если сигнал с пульта пропадет, то мгновенного выхода их последней фазы не последует.
180 Самоучитель по микропроцессорной технике Программа продолжит проверку входного сигнала. Если в течение защитного интервала времени поступит хотя бы один входной импульс, то программа остается в фазе ожидания отпускания кнопки, а отсчет защитного интервала времени начинается заново. И только в том случае, если в течение всего защитного интервала не будет обнаружено ни одного входного импульса, программа перейдет в начальную фазу своей работы — фазу ожидания кода. На рис. 50 изображен алгоритм работы процедуры приема сигнала динамической индикации. Рис. 50. Блок-схема алгоритма приема кода ДУ
Позиционер спутниковой антенны 181 После подробного описания всей процедуры распознавания кодов ДУ, я надеюсь, вы самостоятельно легко разберетесь во всех тонкостях представленного алгоритма. Одно учтите, что для лучшего восприятия приведенный алгоритм немного упрощен. Из него исключены элементы дежурного режима. Полное представление о процедуре приема сигнала ДУ вы получите после детального изучения текста этой процедуры, который представлен в виде фрагмента №10. Фрагмент N910 Обработка прерывания ДУ scandu: push PSW ; Сохранение регистров push ACC mov PSW,#bank3 ; Выбор банка 3 ; Задержка при включении jb flondu,sdu10 inc r5 cjne r5,#15,sdu2 setb flondu ; Прием сигнала sdu10: call inpfp ; Чтение из фотоприемника ДУ jnb flokdu.sdul ; Если код не готов - продолжаем принимать • Режим ожидания отпускания кнопки пульта ДУ jc sdu9 ; Есть сигнал? mov r6,#0 ; Если есть сигнал, обнуляем счетчик jmp sdu7 ; Остаемся в режиме приема , Если нет сигнала sdu9: inc пЗ ; Счетчик задержки включения режима приема cjne r6,#255,sdu7 ; Если счетчик досчитал до 255 clr fladu ; Переход в режим ожидания clr flokdu; jmp sdu7 ; ¦ Режим ожидания сигнала sdul: jb fladu,sdu6 ; Проверка флага «прием пакета» jc sdu7 ; Если нет сигнала - ожидать setb fladu ; Если есть, установить флаг «режим приема» mov strzdu,#kolrzdu ; Загрузить счетчик принятых разрядов sdu7: mov TH1,#Kdu1h ; Запись константы режима ожидания mov TL1,#Kdu1l jmp sdu2 ; Режим приема пакета sdu6: jb strzdu.0,sdu3 ; Проверка младшего бита счетчика принятых разрядов i Первый такт (четный разряд) mov bufbit.c ; Запись принятого разряда в буфер бита jmp sdu8
182 Самоучитель по микропроцессорной технике Приведенный фрагмент состоит из собственно процедуры обработки прерывания (scandu) и подпрограммы чтения сигнала с фотоприемника (inpfp). Подпрограмма inpfp является простейшей антидребезговой процедурой. Удобнее начать рассмотрение фрагмента именно с нее. Подоб- sdu3 jnb bufbit,sdu4 , Операция старый бит XOR новый бит cpl с i Запись бита со сдвигом всего кода sdu4 mov a.bufdu , Старший разряд rrc a mov bufdu,a mov a,bufdu+1 , Младший разряд rrc a mov bufdu+1,a sdu8 djnz strzdu,sdu5 , Итерация счетчика битов и переход, если еще не все , Обработка после приема пакета mov г6,#0 , Обнуление счетчика задержки setb flokdu , Установка флага «код принят» jb flonoff,sdu7 , Проверка флага дежурного режима , Проверка условий выхода из дежурного режима mov a.bufdu cjne a,#sdpw,sduON , Если на пульте нажата кнопка «Вкл/выкл» cjne a,#sd1,sduON , Если на пульте нажата кнопка «1» jmp sdu7 , Выход из дежурного режима sduON setb flonoff mov pcon,#0 , Сброс режима пониженного потребления mov bufh.nk , Засылка в буфер экрана номера канала mov bufl,nk+1 mov bufdu,#O , Сброс буфера ДУ mov bufdu+1,#0 jmp sdu7 , Окончание для всех фаз режима приема sdu5 mov TH1,#Kdu2h , Запись константы режима приема mov TL1 #Kdu2l sdu2 pop ACC , Восстановление регистров pop PSW red , Выход из процедуры обработки прерывания % Подпрограмма чтения сигнала с фотоприемника ДУ inpfp setb IDU , Установка соответствующей линии в единицу mov rO,#12 , Параметр цикла mov a,#0 , Обнуление накопителя infpi mov с,IDU , Двенадцатикратное считывание addc a,#0 djnz rO.infpi clr с subb a,#6 , Если больше 6 cpl с , Инвертирование результата ret
Позиционер спутниковой антенны 183 ную процедуру мы уже рассматривали в разделе, посвященном обработке сигнала с датчика поворота антенны. Сигналы ДУ не подвержены эффекту дребезга. Однако во избежание влияния различных помех введена простейшая накопительная подпрограмма. В данном случае подпрограмма inpfp осуществляет двенадцатикратное чтение входного сигнала и подсчет суммы всех принятых битов. Затем производится оценка полученной суммы. Если сумма больше или равна шести, то текущее мгновенное значение сигнала фотоприемника считается равным единице. Если сумма меньше шести, то считается, что мгновенное значение сигнала равно нулю. Я предлагаю вам самостоятельно разобраться в работе этой подпрограммы и ограничусь только несколькими общими пояснениями. Именем IDU обозначена линия порта PI, к которой подключен выход фотоприемника. Регистр гО используется в качестве параметра цикла считывания. В начале подпрограммы в этот регистр записывается начальное значение 12, которое равно количеству циклов считывания. Аккумулятор микроконтроллера в начале подпрограммы обнуляется и служит для вычисления суммы считанных битов. Бит считывается в ячейку признака переноса. Затем производится сложение содержимого накопителя с константой, равной нулю с учетом признака переноса. Операции чтения и сложения повторяются 12 раз. Оценка результата производится путем вычитания из полученной суммы битов числа шесть. По результатам вычитания устанавливается признак переноса. Однако его значение оказывается обратным относительно того, что должна возвращать подпрограмма. При преобладании единиц в считанном сигнале, мы получим ноль. И, наоборот, при преобладании нулей — единицу. Поэтому производится инверсия признака переноса (команда cpl). На этом подпрограмма inpfp завершается. Результат ее работы передается в вызывающую программу через признак переноса. Теперь перейдем к рассмотрению основной части фрагмента №10. И начнем мы ее с описания системы флагов. Для обеспечения всех необходимых режимов работы, связанных с процедурой приема команд ДУ, в программу введено несколько специальных флагов. Ниже перечислены названия всех этих флагов и их назначение. flondu — флаг задержки включения ДУ. Сбрасывается в процессе начальной инициализации системы. Вызывает отключение всей процедуры считывания сигнала ДУ на некоторое время после включения питания. Используется для предотвращения ложных срабатываний от воздействия переходных процессов, вызванных
184 Самоучитель по микропроцессорной технике включением питания. Устанавливается в единицу по окончании задержки, после чего больше не влияет на работу программы. flokdu — флаг готовности кода. Устанавливается в единицу сразу после того, как код очередной команды полностью принят и записан в буфер ДУ. Для основной программы позиционера служит индикатором того, что в буфере находится принятый код команды ДУ. Служит разрешением для начала процесса обработки принятого кода. Сбрасывается при переходе в режим ожидания новой команды. fladu — флаг включения режима приема. Устанавливается в единицу при обнаружении первого импульса кодовой посылки от пульта ДУ. Остается в этом состоянии все время, пока пульт излучает сигнал (пока кнопка на пульте нажата). Сбрасывается при пропадании сигнала от пульта (кнопка отпускается). Кроме этих трех флагов, специально введенных для процедуры приема команд ДУ, в программе используется уже знакомый нам флаг дежурного режима (flonoff). Как любая процедура обработки прерывания, процедура приема сигнала ДУ начинается с сохранения всех используемых ею регистров. В данном случае сохраняемых регистров всего два. Сразу после сохранения регистров происходит выбор нового банка РОН. Для процедуры обработки прерываний ДУ выделен банка регистров номер три. После этих подготовительных действий начинается собственно сама процедура. Для удобства весь текст процедуры разделен на отдельные блоки, в соответствии с выполняемыми функциями. Каждый блок имеет свой заголовок. При рассмотрении программы мы будем ссылаться на эти заголовки. Итак, начинается наша процедура с модуля, обеспечивающего задержку при включении. Такую задержку пришлось ввести после первых испытаний программы дистанционного управления. Оказалось, что в момент включения возникали ложные срабатывания. Специально для режима задержки был введен флаг flondu. Этот флаг сбрасывается в процессе инициализации системы (см. раздел «Инициализация системы»). Там же происходит обнуление регистра г5 банка 3. Этот регистр используется в качестве счетчика задержки. В модуле задержки включения происходит проверка флага flondu. Если флаг сброшен, то приема команд ДУ не происходит. Вместо этого происходит увеличение содержимого регистра г5 на единицу при каждом прерывании.
Позиционер спутниковой антенны 185 Затем происходит оценка содержимого этого регистра (djne). Пока оно не равно 15, ситуация не меняется. Управление передается на конец процедуры по адресу sdu2. Основная часть процедуры при этом не выполняется. Когда содержимое регистра г5 достигнет 15, программа установит флаг flondu в единичное состояние. После этого модуль задержки больше никогда выполняться не будет. Сразу после начала процедуры управление будет передаваться по адресу sdulO, откуда начинается основной процесс приема команд. Прием сигнала. Прием сигнала начинается с вызова подпрограммы inpfp, с описания которой мы начали рассмотрение текста процедуры. После выхода из подпрограммы признак переноса содержит текущее значение сигнала на выходе фотоприемника. Это значение необходимо программе в любом из трех режимов ее работы. Дальнейший алгоритм зависит от состояния специальных флагов. Сразу после выхода из подпрограммы начинается цепочка команд по проверке флагов. В зависимости от их значения программа выполняет ту или иную ветвь алгоритма, соответствующую одному из трех основных режимов работы. Сначала проверяется значение флага flokdu (код готов/не готов). Если код готов, то программа переходит к обработке «режима ожидания отпускания кнопки». В противном случае проверяется значение флага fladu. Если этот флаг установлен в единицу, программа выполняет обработку «режима приема кода». Если же значение флага fladu равно нулю, то программа переходит в «режим ожидания сигнала». Рассмотрим работу процедуры приема сигнала ДУ в каждом из этих трех режимов. Изучать процедуры удобно не в той последовательности, как они записаны в тексте программы, а в порядке их чередования в процессе реальной работы. Режим ожидания сигнала (sdul). Начинается с проверки значения признака переноса. Этот признак, как мы уже знаем, содержит текущее значение входного сигнала. Если признак переноса равен нулю (сигнал отсутствует), то вся процедура завершается (переход по адресу sdu7). Перед завершением выполняются команды перезапуска таймера Т1. Для этого в старшую и младшую части его регистра (ТН1 и TL1) записывается константа, определяющая промежуток времени, через который процедура будет вызвана следующий раз. Для режима ожидания константы, записываемые в регистр таймера, будут равны Kdulh и Kdull. Они обеспечивают задержку в 1/3 Тсшн. Затем управление передается в самый конец процедуры (метка sdu2), где происходит восстановление
186 Самоучитель по микропроцессорной технике регистров и завершение прерывания. Все это, напоминаю, происходит при отсутствии сигнала на входе. В том случае, если в результате проверки обнаружится, что сигнал на входе есть, то программа выполняет несколько подготовительных команд для перехода во второй режим — режим приема. Подготовительные действия сводятся к установке флага fladu в единичное состояние и инициализации счетчика принятых разрядов (strzdu). В счетчик принятых разрядов программа записывает начальное значение (kolrzdu), которое в нашем случае равно 28. В процессе приема разрядов значение этого счетчика будет уменьшаться, и в тот момент, когда оно станет равно нулю, прием прекращается. После выполнения команд подготовки режима приема, управление передается по адресу sdu7. В результате первая задержка перед переходом в режим приема будет равна 1/3 Тсигн. Процедура на этом завершается, однако, благодаря тому, что флаг fladu установлен в единичное значение, при следующем вызове процедуры она будет работать в режиме приема. Режим приема (sdu6). В режиме приема процедура работает ровно 28 раз. При каждом вызове процедуры происходит считывание и обработка очередного бита кода ДУ. Причем четные и нечетные принятые биты обрабатываются по-разному. Поэтому обработка режима приема начинается с проверки младшего разряда счетчика принятых битов strzdu.0. Если этот разряд равен нулю, выполняются команды обработки четного разряда. Если он равен единице, то выполняются команды обработки нечетного разряда. Обработка четного разряда — это самая короткая из всех операций. Значение этого разряда просто записывается в специальный буфер bufbit. После этого вся процедура заканчивается. Однако перед тем как выйти из этой процедуры программа передает управление по адресу sdu8, где происходит уменьшение значения счетчика принятых разрядов, и затем, если это не последний разряд, управление передается по адресу sdu5, где происходит загрузка регистров таймера, но уже другой константой (Kdu2h, Kdu21). Эта константа заставляет таймер сформировать задержку, равную Тсигн. При очередном запросе значение младшего бита счетчика разрядов (strzdu.0) изменится на противоположное. Поэтому программа выполнит переход по адресу sdu3 и будет выполнять обработку нечетного разряда. Первым делом она выполнит операцию «исключающее ИЛИ» (XOR) между предыдущим принятым битом, хранящимся в bufbit, и новым его значением, хранящимся в ячейке признака переноса. К сожалению, операция XOR в системе команд микроконтроллера
Позиционер спутниковой антенны 187 АТ89С2051 не предусмотрена. Поэтому она заменяется эквивалентной операцией, состоящей из двух команд. Первая команда проверяет значение буфера bufbit. Если оно равно нулю, то значение признака переноса инвертируется. Если же в буфере bufbit окажется единица, то значение признака переноса останется без изменений. В результате выполнения этих операций ячейка признака переноса будет содержать искомую величину. То есть, ячейка признака переноса будет содержать результат операции XOR между четным и нечетным битами команды ДУ. Но на этом обработка нечетного бита не заканчивается. Полученный таким образом результирующий бит записывается в сдвиговый регистр принятого кода. В программе применен 16-разрядный регистр принятого кода, в качестве которого выступают две зарезервированные ячейки в ОЗУ с начальным адресом bufdu. Запись бита в такой регистр с одновременным сдвигом всего его содержимого происходит в два этапа. Сначала производится сдвиг старшего байта этого регистра с адресом bufdu, a затем сдвиг младшего байта. Его адрес равен bufdu+1. Система команд микроконтроллера содержит несколько команд кольцевого сдвига разрядов. Однако все они применимы только к содержимому аккумулятора. Поэтому, каждый из двух байтов регистра bufdu сначала переносится в аккумулятор. Там разряды числа сдвигаются при помощи команды ггс, а затем результат сдвига возвращается обратно, в соответствующую ячейку памяти. Сдвиг производится от старших разрядов к младшим. После сдвига первого байта буфера bufdu самый младший его бит должен перейти во второй байт буфера, то есть в ячейку bufdu+1. Для того, чтобы это стало возможным и была использована именно эта команда сдвига (ггс). На рис. 51 изображена схема работы команды ггс. Рис. 51. Действие команды ггс Как видно из рисунка, сдвиг происходит по кольцу, от старшего разряда к младшему с использованием ячейки признака переноса с. Теперь представьте, что на первом этапе перед началом сдвига в ячейке признака переноса находится наш только что сформированный бит, предназначенный для записи в регистр приема. В аккумуляторе содер-
188 Самоучитель по микропроцессорной технике жимое первой ячейки регистра приема. На втором этапе в ячейке признака переноса находится содержимое последнего разряда, оставшееся от первого этапа, а в аккумуляторе второй байт регистра приема. После 28 циклов приема мы получим 16-разрядный код команды. При желании можно использовать все 16 разрядов. Однако программа позиционера использует только 8 из них. Шестнадцать разрядов заложено для будущих расширений. При разработке программы в нее сознательно закладывались некоторые элементы избыточности для облегчения работ по расширению ее возможностей. В частности, предполагалось дополнить ее режимом обучения, позволяющим применять любой пульт. После операции сдвига программа завершает обработку нечетного разряда и плавно переходит к тем же самым операциям, которые выполнялись по окончании процесса обработки четного разряда, то есть по адресу sdu8. Программа уменьшает содержимое счетчика принятых разрядов, записывает константы в регистры таймера и завершает процедуру обработки прерывания ДУ. Режим ожидания отпускания кнопки. Когда значение счетчика принятых битов достигнет нуля, команда djnz по адресу sdu8, осуществляющая его уменьшение, не вызовет перехода по адресу sdu5 и процессор перейдет к подготовке заключительного режима работы. То есть «режима ожидания отпускания кнопки пульта ДУ». Сначала обнуляется регистр гб, используемый в качестве счетчика задержки в этом режиме. Затем флаг готовности кода flokdu устанавливается в единицу. На этом подготовка к новому режиму завершается. Однако пока не завершается сама процедура. Дело в том, что в этом самом месте удобнее всего расположить процедуру обработки дежурного режима. Как уже упоминалось, в дежурном режиме основная программа не работает. Однако позиционер должен выходить из дежурного режима не только при помощи кнопки «Вкл/выкл», но и при помощи пульта ДУ. Именно в этом месте программы, после того, как код от пульта ДУ принят, можно проверить, не равен ли он коду команды на включение позиционера. Обработка дежурного режима начинается с оценки значения флага flonoff. Если значение этого флага равно нулю, то это не дежурный режим, управление передается по адресу sdu7, и дальнейшие операции по обработке дежурного режима не выполняются. Если флаг равен нулю, то это значит, что позиционер в дежурном режиме. В этом случае программа производит проверку принятого кода. Выход из дежурного режима должен происходить при нажатии на пульте ДУ одной из двух кнопок: кнопки «Вкл/выкл» или
Позиционер спутниковой антенны 189 кнопки «I» (включения первого канала). Для осуществления проверки только что принятый код ДУ копируется в аккумулятор. Затем последовательно производятся две операции сравнения. Содержимое аккумулятора сравнивается сначала с кодом кнопки «Вкл/выкл» пульта (sdpw), а затем с кодом кнопки «I» (sdl). Если код ДУ не совпал ни с одним из вариантов, то выполнение программы продолжается в прежнем режиме. Если хотя бы одно из условий выполнилось, то выполняется переход по адресу sduON, где производятся операции, обеспечивающие выход позиционера из дежурного режима. Эти операции полностью повторяют аналогичные операции, выполняемые при первом способе выхода из дежурного режима. То есть при нажатии на кнопку «Вкл/Выкл» на клавиатуре. Как бы ни закончилась обработка дежурного режима, управление во всех случаях передается в одно и то же место — по адресу sdu7. В результате, перед выходом из процедуры таймер настраивается на формирование задержки в режиме ожидания в 1/3 Тсигн. Благодаря новому значению флага flokdu при последующем вызове процедуры прерывания ДУ, она будет работать в режиме «ожидания отпускания кнопки пульта». Режим ожидания отпускания кнопки пульта ДУ. Программа обработки этого режима предельно проста. Первая команда проверяет значение признака переноса. Там в этот момент хранится значение входного сигнала. Если сигнал отсутствует, то процессор переходит по адресу sdu9, где находится начало программного счетчика задержки. При каждом таком обращении содержимое счетчика увеличивается на единицу. Если при очередном обращении входной сигнал окажется равным единице, то счетчик обнуляется (команда mov г6,#0) и счет начинается сначала. При этом процедура завершается переходом по адресу sdu6. При этом таймер будет запрограммирован на длительность задержки 1/3 Тсигн. И только в том случае, если сигнал на входе долгое время отсутствует (кнопка отпущена и выдача команд прекратилась), то счетчик досчитывает до своего максимального значения B55). Как только это произойдет, программа не совершит переход по адресу sdu7, а перейдет к выполнению команд подготовки к начальному режиму (режиму ожидания сигнала). Подготовка состоит из двух команд, выполняющих сброс флагов fladu и flokdu. Затем программа выполняет переход по адресу sdu7, программирует таймер и заканчивает свою работу. При следующем вызове процедура будет работать в режиме ожидания. Теперь позиционер готов к приему следующей команды ДУ.
190 Самоучитель по микропроцессорной технике Обработка команд ДУ В предыдущем разделе была описана процедура приема сигналов ДУ. Процедура оканчивалась тем, что принятые коды команд ДУ записывались в буфер bufdu. Там же было сказано, что дальнейшая обработка команд возлагается на основную программу позиционера. В этом разделе мы рассмотрим подпрограмму, которая занимается окончательной обработкой команд дистанционного управления. Подпрограмма обработки кодов ДУ включена в основной цикл программы (см. начало главы). Если вы вернетесь к фрагменту программы №5, то обнаружите, что основной цикл содержит обращение к подпрограмме обработки команд ДУ (indu). Ниже приведен текст этой самой подпрограммы indu (фрагмент №11). Алгоритм работы данной подпрограммы очень похож на алгоритм аналогичной процедуры (inkl), которая занимается обработкой команд с клавиатуры. Однако существуют и отличия. Например, для правильной работы процедуры indu введен дополнительный системный флаг flkdu — флаг «код обработан». Его назначение — исключить повторную обработку одной и той же команды. Фрагмент №11 ; Обработка команд ДУ indu: jnb flokdu.indi ; Если код не голов, перейти в конец jb flkdu,ind2 ; Проверка флага «код обработан» mov a,bufdu ; Чтение принятого кода из буфера setb flkdu ; Установка флага «код обработан» ; Вставлено для отладки ; call prnhex ; Переход к подпрограмме вывода кода ДУ на индикаторы ; ret , в шестнадцатеричном виде , Конец вставки ind5: cjne a,#057H,md3 jmp onoff ; Вкл/выкл "питания" ind3' cjne a,# 079H,md4 jmp upnk , Уменьшение номера канала ind4: cjne a,# 0B9H,ind2 jmp downk ; Увеличение номера канала , Если неизвестная команда ind1: clr flkdu ; Сброс флага «код обработан» ind2: ret ; Выход из подпрограммы
Позиционер спутниковой антенны 191 Начинается процедура обработки команд ДУ с проверки флага готовности кода (flokdu). Пока код не готов управление будет передаваться в конец подпрограммы (по адресу indl), где сначала происходит сброс флага flkdu, а затем выход из подпрограммы. Когда при очередном обращении к подпрограмме окажется, что код уже готов (флаг flokdu установлен в единицу), то выполняется проверка флага flkdu. При первой попытке обработать принятый код этот флаг, естественно, будет сброшен. Поэтому команда проверки не вызовет передачи управления и выполнение программы продолжится. Дальнейшая программа очень похожа на аналогичную процедуру проверки кода клавиатуры. Принятый код помещается в аккумулятор, где он будет находиться до конца проверки. Последующие команды проверки будут сравнивать его с различными константами. Каждая константа соответствует одной из используемых команд. Но прежде чем начинать сравнение, программа устанавливает флаг flkdu. Теперь, пока флаг установлен, повторной обработки этой команды не произойдет. После команды установки флага в тексте подпрограммы вы видите закомментированный фрагмент, озаглавленный «Вставлено для отладки». Назначение этого фрагмента мы рассмотрим немного позже. Фрагмент используется исключительно в режиме отладки программы. В рабочей версии эти команды отсутствуют. Мы же закончим описание подпрограммы. Сразу за отключенным пока фрагментом следуют три оператора сравнения. Они последовательно сравнивают код ДУ, находящийся в аккумуляторе с тремя разными константами. Каждая из констант — это код одной из трех команд ДУ. Используемый в системе пульт способен выдавать 23 различные команды. Из всех этих команд, используются только три. Их описание приведено в табл. 5. При совпадении принятого кода с одной из констант выполняется переход к соответствующей подпрограмме. Например, при нажатии на пульте ДУ кнопки «Power», программа получит код, равный 057 Н. Это вызовет переход к процедуре onoff, которая предназначена для перевода позиционера из дежурного режима в рабочий и обратно. Если окажется, что принятый код не соответствует ни одной из вышеперечисленных констант, то это значит, что на пульте ДУ нажата кнопка, которая не используется для управления позиционером. Это равносильно отсутствию команд. Поэтому программа, прежде чем завершиться, сбрасывает флаг flkdu. Сброс флага необходим потому, что в этом случае становится бессмысленным блокирование повторной обработки команды. Теперь вернемся к закомментированной процедуре. Как уже говорилось, этот модуль используется в режиме отладки. Признаки комментария (точки с за-
192 Самоучитель по микропроцессорной технике пятой) в начале двух команд этого модуля, удаляются. И мы получаем программу с новыми свойствами. Для чего же нужен этот отладочный режим? Список команд дистанционного управления Таблица 5 Кнопка Power + - Константа 057Н 0В9Н 079Н Назначение в программе позиционера Переключение режимов «Рабочий/Дежурный» Увеличение номера выбранного канала на 1 Уменьшение номера выбранного канала на 1 Дело в том, что по осциллографу очень трудно разглядеть форму каждого конкретного сигнала. Как же узнать коды каждой из команд? Самый лучший способ — сделать это программным путем. Для определения кодов команд ДУ я применил следующий метод: ¦ Создал вышеописанную программу для приема сигналов ДУ. ¦ Создал специальную подпрограмму, способную выводить любой восьмиразрядный двоичный код на индикатор позиционера в шестнадца- теричном виде. ¦ Записал эту программу в программную память микроконтроллера позиционера. Адрес начала этой подпрограммы: prnhex. ¦ Временно вставил в подпрограмму обработки команд ДУ описанный выше отладочный модуль. Этот модуль сразу после того, как принятый код готов к обработке, вызывает подпрограмму prnhex. ¦ Включил позиционер, направил на него пульт и, нажимая по очереди все кнопки на пульте, увидел на индикаторе все коды команд. Именно таким образом я узнал коды команд, приведенные в табл. 5. ¦ Закомментировал в тексте программы отладочный модуль. ¦ Подставил коды трех нужных команд в соответствующее место программы. ¦ Проверил работу пульта и убедился, что все команды работают нормально. В заключении я хочу рассмотреть принцип работы программы prnhex. Сначала рассмотрим общие принципы ее работы. Для вывода шестнад- цатеричного кода на семисегментный индикатор программа использует следующие знаки (рис. 52). Рис. 52. Изображение символов шестнадцатеричного кода
Позиционер спутниковой антенны 193 Буквы d и b пришлось сделать маленькими. На семисегментном индикаторе иначе не получается. Однако при таком способе индикации шестнадцатеричных цифр числа прекрасно читаются. Специально для этой программы в конце таблицы символов были добавлены все недостающие знаки (см. фрагмент №8). Для упрощения процесса перевода из двоичной системы в шестнадцатеричную, дополнительные знаки в таблице символов были расположены по алфавиту. В результате получился следующий алгоритм вычисления кодов букв: ¦ Для того, чтобы вывести код любого байта на индикатор, сначала нужно разделить его на две тетрады. Тетрадой называется двоичное число, состоящее из четырех разрядов. ¦ Затем нужно получить код символа для каждой тетрады. ¦ Символ старшей тетрады нужно вывести в старший разряд индикатора, а символ младшей тетрады — в младший разряд. При вычислении кодов символа для каждой из тетрад применяется следующее правило: ¦ Если значение кода, записанного в тетраду, лежит в диапазоне от 0 до 9, то его не нужно преобразовывать. Сам этот код и является рабочим кодом выводимого символа. ¦ Если значение кода в тетраде лежит в диапазоне от 10 до 15, то это значит, что на индикатор нужно вынести одну из цифр. Для этого код нужно преобразовать. Преобразование кода сводится к прибавлению константы смешения. Эта константа равна 22. В результате число 10 превратится в рабочий код 32. Л это код символа «А» и так далее. Фрагмент №12 представляет собой полный текст подпрограммы, реализующей описанный выше алгоритм. Фрагмент №12 Вывод байта в 16-ричном виде (а - содержит выводимый байт) prnhex push асе , Сохранение аккумулятора в стеке call phx2 , Получение кода младшей тетрады mov bufl.a , Поместить код в буфер экрана pop асе , Восстановление содержимого аккумулятора swap a , Обмен тетрад call phx2 , Получение кода старшей тетрады mov bufh.a , Поместить код в буфер экрана ret
Приведенная подпрограмма получает код, предназначенный для вывода на индикатор через аккумулятор. Она разделяет код на тетрады, затем получает код символа для каждой из них. Для получения кода символа используется специальная вспомогательная подпрограмма phx2. Затем коды обоих символов помещаются в буфер экрана, после чего их изображение появляется на индикаторе. Я предлагаю самостоятельно разобраться с текстом подпрограммы. Почти все команды, применяемые в описываемой подпрограмме, нам уже известны. Новой командой для нас является команда swap. Команда swap меняет местами младшую и старшую тетрады аккумулятора. На этом заканчивается описание управляющей программы позиционера. В книге дано описание далеко не всех процедур и подпрограмм. Однако книга не является описанием конструкции позиционера. Книга предназначена для того, чтобы дать читателю основные понятия о принципах и приемах построения микропроцессорных устройств и написания управляющих программ. Если вы желаете просто повторить позиционер, обращайтесь за полным текстом программы к ее автору на сайт http://avbelov.by.ru или по электронной почте: belov@gomail.com.ua. А мы перейдем к последнему этапу в проектировании микропроцессорных устройств: этапу трансляции и отладки программ. 194 Самоучитель по микропроцессорной технике , Получение кода символа phx2 anl a,#OFH , Отделение младшей тетрады mov Ь,а , временно запомнить код в Ь clr с subb a,#10 , Сравнение кода с 10 jc phx1 , Если код больше 10 (буквы) add a,#22 , Добавить 22 ret phx1 mov a.b , Если нет, восстановить код из b ret
Трансляция и отладка программ Технология программирования И так мы приступаем к рассмотрению еще одного важного вопроса, который неизбежно задает себе каждый начинающий конструктор микропроцессорной техники. Как же практически происходит процесс создания программы для микропроцессорного устройства. Технология написания программ включает в себя следующие этапы: ¦ Написание текста программы. ¦ Трансляция. ¦ Отладка. ¦ Прошивка программного кода в программную память микроконтроллера. ¦ Опробование работоспособности программы на реальной схеме. ¦ Анализ выявленных ошибок. ¦ Корректировка программы по результатам опробования и повторная отладка. Рассмотрим эти этапы подробнее. Текст программы пишется на компьютере при помощи обычного текстового редактора. Однако не каждый редактор подойдет для этой цели. Используемый вами редактор должен иметь возможность создавать текстовые файлы именно в том формате, который совместим с выбранным вами транслятором. В следующем разделе мы подробно коснемся этого вопроса. Написанная вами программа будет содержать ошибки. Этого не стоит пугаться. Даже опытный программист при написании программы практически всегда допускает ошибки. В среде программистов даже ходит такая шутка: «Если
вы написали программу и при первой трансляции, в ней не было обнаружено ошибок, проверьте — все ли нормально с транслятором!». Ошибки могут быть двух типов. Первый вид — это ошибки синтаксиса. То есть неправильное написание команд, ошибки в количестве параметров и т.д. Второй вид ошибок — это ошибки алгоритма. В этом случае текст с точки зрения синтаксиса написан правильно, но программа в результате делает не то, что вы от нее ожидаете. Первый тип ошибок транслятор обнаруживает автоматически в процессе трансляции и сообщает о них программисту. Второй тип ошибок транслятор обнаружить не может. Откуда ему знать, чего вы хотите от программы? Такие ошибки выявляются в процессе отладки программы. Отладкой называют поэтапное выполнение написанной вами программы под управлением специальной программы — отладчика. Различают два вида отладчиков: программный и программно-аппаратный. Самый эффективный — это программно-аппаратный отладчик. Он представляет собой некую специальную схему, которая имитирует работу микроконтроллера. Эта схема управляется при помощи компьютера и специальной управляющей программы. Такая схема может выполнять программу точно так же, как и имитируемый ею микроконтроллер. Кроме этого, схема имеет ряд дополнительных возможностей, связанных с отладкой программ, таких как: ¦ Возможность выполнения отлаживаемой программы в пошаговом режиме. ¦ Возможность оперативного просмотра всех регистров микроконтроллера на экране компьютера. ¦ Возможность установки точек перехвата. Пошаговый режим — это такой режим, когда ход выполнения программы берется под полный контроль управляющей программы. Программист дает команду «Сделать очередной шаг» и микроконтроллер выполняет одну очередную команду отлаживаемой программы. Это дает возможность шаг за шагом прогонять отлаживаемую программу, наблюдая при этом на экране компьютера ход ее выполнения и содержимое всех регистров процессора. Одновременно можно проверять по осциллографу или другими способами правильность формирования сигналов на всех выводах микроконтроллера. Если отлаживаемая программа имеет достаточно большой размер, то для ее отладки пошаговый режим не всегда подходит. Если действовать только пошаговым способом, то пришлось бы слишком долго «шагать» до нужного места. В этом случае применяется прием постановки точек перехвата. Точка перехвата — это некий адрес в программной памяти, в котором выполнение программы должно приостановиться. Любой отладчик способен запомнить несколько таких точек останова. После оп-
ределения точки останова программа под управлением отладчика запускается на выполнение в автоматическом режиме. Если в ходе выполнения программы она дойдет до одного из адресов, отмеченных как точка останова, выполнение отлаживаемой программы приостановится. Отладчик покажет текущее содержимое регистров. Дальнейшая отладка возможна как в пошаговом режиме, так и повторный запуск программы в автоматическом режиме до следующей точки перехвата. Общий смысл всех этих действий — выявить те места программы, где ход ее выполнения не соответствует задуманному алгоритму. Программно-аппаратный отладчик — это сложное и дорогое устройство. Его целесообразно применять на промышленных предприятиях и в научно-исследовательских учреждениях. Для индивидуальной и мелкосерийной разработки вполне можно обойтись программным отладчиком. Он представляет собой программу, имитирующую работу процессора. Действует он аналогично программно-аппаратному варианту. Однако никаких сигналов не формируется. При отладке на таком отладчике можно проверить лишь ход выполнения программы. Оценить формируемые внешние сигналы можно только теоретически, косвенным путем. Управляющая программа описываемого здесь позиционера была отлажена именно на таком отладчике. После отладки программы нужно записать ее в программную память микроконтроллера и опробовать ее работу в реальной схеме. На техническом жаргоне это называется «прошить» микросхему. Для прошивки микроконтроллера применяется специальное устройство называемое программатором. Программатор подключается к компьютеру и работает под управлением специальной управляющей программы. Программируемая микросхема вставляется в специальную панельку программатора. Затем, при помощи управляющей программы, вы запускаете процесс программирования. Существуют программаторы разной степени сложности. Полнофункциональный программатор умеет выполнять следующие операции: ¦ Записывать коды программы в программную память микроконтроллера. ¦ Считывать коды из этой памяти. ¦ Читать код производителя микросхемы. ¦ Прошивать защитные биты, запрещающие чтение программы из памяти микросхемы. ¦ Стирать программную память (одновременная очистка защитных битов). Защитные биты предохраняют вашу программу от несанкционированного копирования. Если ваши конкуренты захотят повторить вашу конструкцию, то программу им придется писать заново.
198 Самоучитель по микропроцессорной технике Более простые программаторы не поддерживают полный набор вышеперечисленных функций. Они обычно имеют только самые необходимые из них. Программатор, который использовался при разработке и изготовлении позиционера, производит лишь одну комбинированную операцию. За один запуск он сначала стирает программную память, а затем зашивает туда указанный вами программный код. В процессе отладки программы приходится «перешивать» программную память процессора множество раз. Для разработки программ различных микропроцессорных устройств у меня сложилась определенная устоявшаяся методика, которую я рекомендую и вам. Я не стараюсь создать сразу весь текст программы. Разработку программы удобнее делать по частям. Удобнее всего начать с программы вывода на индикатор. Создайте простейшую программу, выводящую на индикаторы любую подходящую надпись. Это будет лишь заготовка вашей будущей программы. Однако она должна иметь законченный вид и выводить на индикатор задуманную вами надпись. Отладьте эту программу в отладчике. Запишите в микросхему и попробуйте на реальной, схеме. Добейтесь, чтобы на индикаторе появилась задуманная вами надпись. Далее, когда программа вывода на индикатор будет готова, можно дополнить ее программой ввода с клавиатуры. Программу добавьте таким образом, чтобы при нажатии разных кнопок клавиатуры на индикатор выводились бы их номера. Снова отладьте получившийся кусок программы в отладчике. Прошейте эту усовершенствованную программу в программную память микроконтроллера. Теперь вы можете проверять работу программы ввода с клавиатуры, нажимая кнопки и наблюдая за индикаторами. Таким же образом постепенно добавляйте к программе все новые и новые модули, но в такой последовательности, в какой это удобнее для проверки каждой вновь добавляемой части. Старайтесь при добавлении нового модуля программы не затрагивать уже отлаженные части. Тогда, если после очередного изменения ваша программа откажется работать, вы будете знать в каком месте программы искать ошибку. Добавляя в программу новый модуль, не закладывайте сразу все возможности, которые он должен выполнять. Создайте сначала упрошенный вариант. Отладьте, проверьте его в работе. А затем усовершенствуйте его, но тоже не сразу, а поэтапно, постепенно приближаясь к окончательному варианту. Это очень интересный и занимательный процесс! Достаточно втянуться в него один раз и вы на всю жизнь останетесь фанатиком микропроцессорной техники! Ну а теперь от общих рассуждений пора переходить к изучению конкретных инструментальных программ, которые использовались при разработке позиционера.
Трансляция и отладка программ 199 Транслятор с языка Ассемблер Для трансляции программ я использовал кроссассемблер фирмы «MetaLink», версии 1.2h. Эта программа предназначена для работы под управлением операционной системы DOS. Она написана в старом стиле. Имя файла для трансляции передается как параметр при запуске транслятора. Все сообщения выводятся в окно DOS. Поэтому запускать программу удобнее при помощи DOS-ориентированного файлового менеджера. Файловый менеджер — это целый класс программ, начало которому положил легендарный Norton Commander. В настоящее время существует множество программ, являющихся его клонами. Это такие программы, как Windows Commander, VoJkov Commander, FAR, Dos Navigator и т.д. Все перечисленные программы очень похожи друг на друга. Однако, лично я из всех перечисленных программ больше всего предпочитаю программу Dos Navigator (ДОС-навигатор) нашего советского производства. На рис. 53 показан внешний вид программы ДОС-навигатор. Теперь поговорим о текстовом редакторе. Текст программы нужно писать в классическом текстовом формате. Такой формат широко использовался в старых компьютерах. Его поддерживают практически все текстовые редакторы, написанные под DOS. Большинство программ для Windows, используют более сложные форматы. Но и тут можно найти подходящую программу. Однако, в связи с тем, что описываемый транслятор предназначен для работы под управлением DOS, логичнее и редактор текстов выбирать также ДОСовский. Для этой цели не нужна «навороченная» программа. На мой вкус, самый лучший вариант — это встроенный текстовый редактор программы ДОС-навигатор (Dos Navigator). Тот самый редактор, который вызывается при нажатии клавиши F4. Рис. 53. Файловый менеджер «ДОС-навигатор»
200 Самоучитель по микропроцессорной технике Все клоны Norton Commander-a имеют простейший встроенный редактор текстов, вызываемый по F4. Но только в Dos Navigator-e этот редактор представляет собой удобный многофункциональный инструмент. В нем есть все, необходимое для работы. Поиск и замена текстовых фрагментов, автоотступ, копирование и перенос при помощи выделенных блоков. Причем редактор поддерживает как прямоугольные, так и строчные блоки. Редактор даже умеет рисовать при помощи псевдографических символов! Если рисование, это такое свойство, которое мало пригодно для задачи написания программ, то следующее его свойство очень полезно именно в нашем случае. Описываемый редактор имеет режим запоминания текущего состояния редактирования. Если включен этот режим, то при повторном открывании текста вашей программы вы автоматически попадаете в то же самое место, на котором окончили редактирование в прошлый раз. Еще одна очень приятная особенность этого редактора — он имеет настраиваемую контекстную подсветку редактируемого текста. Это означает, что при написании текстов на Ассемблере можно, как в современных специализированных редакторах, наслаждаться внешним видом вашей программы. Ключевые слова будут выделены одним цветом, числовые значения — другим, а комментарии — третьим! Редактор является неотъемлемой частью «ДОС-навигатора» и поэтому обладает всеми достоинствами последнего. ДОС-навигатор выполнен с применением Windows-подобного оконного интерфейса. Это означает, что вы можете открыть не одно, а несколько окон редактора, менять их размеры, положение, копировать любые блоки из одного окна в другое и это далеко не все удобства и возможности. Я в свое время был горячим сторонником программы Dos Navigator. На моей личной страничке вы можете найти множество вспомогательных файлов для него. Это и специально подобранные файлы раскраски для Ассемблера, и программы-заставки, и многое другое. ДОС-навигатор и сейчас установлен на обоих моих компьютерах — на работе и дома. В некоторых случаях он по-прежнему незаменим. Итак, мой совет — при написании текста программы для микроконтроллера пользуйтесь ДОС-навигатором. Однако, принимая решение пользоваться программой, работающей под управлением DOS, необходимо знать, что в этой операционной системе применялась кодировка символов, которая отличается от кодировки, принятой в настоящее время. Поэтому, если вы напишете текст вашей программы, пользуясь редактором ДОС-навигатора, а затем захотите просмотреть его под Windows, то вместо русских букв вы увидите бессмысленный набор экзотических символов. То же самое произойдет, если вы примените любой другой текстовый редактор, рассчитанный для работы под DOS. Однако это не должно вызывать у вас больших затруднений.
Трансляция и отладка программ 201 Дело в том, что все надписи в тексте программы, которые выполнены на русском языке — это всего лишь комментарии. Все команды, составляющие собственно текст программы, всегда пишутся с применением исключительно латинских символов. Латинские символы во всех известных кодировках имеют одни и те же коды. Все команды, написанные в DOS, будут выглядеть точно так же при просмотре их под Windows. Если учитывать, что в процессе трансляции программы все комментарии игнорируются, то проблемы кодировки не вызывают особых затруднений. Просто читать вашу программу вам придется в той среде, в которой она была написана. Поэтому вы можете свободно выбирать — в какой операционной системе вам работать удобнее: в DOS или в Windows. В том случае, если вы не желаете путаться в кодировках и выбираете Windows, я рекомендую, для запуска программ транслятора, отладчика и программатора использовать файловый менеджер Windows Commander. A для написания программ воспользоваться либо встроенным редактором Windows Commander, вызываемым при нажатии клавиши F4, либо программой «Блокнот» (Note Pad), входящей в состав Windows. На рис. 54 вы можете увидеть, как выглядит Windows Commander. Каким бы редактором вы не пользовались, при записи вашей программы на диск необходимо позаботиться о том, чтобы полученный файл имел расширение asm. Например, файл с текстом управляющей программы позиционера я назвал pozi.asm. Рис. 54. Файловый менеджер Windows Commander
202 Самоучитель по микропроцессорной технике После того, как текст программы написан, приступаем к процессу трансляции. Для запуска транслятора пользуйтесь тем же самым файловым менеджером. Рекомендую для всех ваших будущих программ создать в корневом каталоге вашего жесткого диска специальную директорию. Назвать ее, например, Prog. Внутри этой директории создайте еще одну, назовите ее asm51 и поместите туда все файлы программы транслятора. Затем директорию prog откройте в левой панели вашего файлового менеджера, а директорию asm51 — в правой его панели. На рис. 53 и 54 показано, как это будет выглядеть для ДОС-навигатора и Windows Commander-a. Постепенно в директории prog у вас накопится множество разных программ. Это будут пробные программы, различные варианты рабочей программы, а затем и новые проекты. Для того, чтобы оттранслировать какую-либо из этих программ, нужно переместить ее в директорию asm51. Это легко делается средствами вашего файлового менеджера путем нажатия клавиши F6. Затем нужно сделать правую панель активной, то есть переместить в нее указатель выбранного файла. Переключение между правой и левой панелями в любом менеджере производится при помощи клавиши TAB. Можно также воспользоваться мышью. Теперь все готово для трансляции. Для запуска транслятора наберите в командной строке, находящейся сразу под файловыми панелями, следующую команду: asm51 pozi Затем нажмите клавишу Enter. Если вы все сделали правильно, запустится процесс трансляции. Обратите внимание, что команда состоит из двух слов, разделенных пробелом. Первое слово — это имя программы-транслятора (asm51.exe). Второе слово — это имя файла вашей программы на ассемблере (pozi.asm). Причем оба имени допускается писать как с расширением, так и без. Если вы запишите asm51.exe pozi.asm, то результат будет точно такой же. Процесс трансляции на современных компьютерах происходит почти мгновенно. Вы не успеете ничего понять, как процесс закончится. Если в вашей программе не было никаких ошибок, по завершении работы транслятора на экране появится следующая надпись: C\PROG\ASM51>asm51 pozi 8051 Cross-Assembler, Version 1 2h (с) Copyright 1984, 1985, 1986, 1987, 1988, 1989, 1990 by Metaljnk Corporation First pass Second pass ASSEMBLY COMPLETE, 0 ERRORS FOUND
Трансляция и отладка программ 203 В том случае, если вы работаете в Windows Commander, эта надпись появится в отдельно открывшемся окне и останется на экране, пока вы не закроете это окно вручную. Если вы работаете в ДОС-навигаторе, то надпись, промелькнув на экране, будет закрыта открывшимися файловыми панелями. Но вы легко можете посмотреть ее. Для этого достаточно нажать клавишу Esc и панели уберутся, открыв вам черное окно, находящееся под ними. В этом окне и остаются все надписи, выводимые ДОС-овскими программами. Для того, чтобы вернуть панели обратно, повторно нажмите Esc. Режим отключения панелей по нажатию клавиши Esc по умолчанию выключен. Если вы не хотите или не умеете его включить, воспользуйтесь альтернативным способом отключения панелей: Ctrl+O. В случае отсутствия ошибок процесс трансляции можно считать законченным и переходить к отладке. При успешной трансляции в той же директории появятся два новых файла, с тем же именем, что и транслируемая программа, но с другими расширениями. pozi.lst — листинг программы pozi.hex — оттранслированная программа в НЕХ-формате. Но такого результата вы сможете достигнуть, скорее всего, не сразу. Если в процессе трансляции транслятор обнаружит в вашей программе какие- либо ошибки, то он покажет их общее количество в последней строке своего сообщения. При этом файл с расширением hex сформирован не будет. Более подробное описание ошибок транслятор помещает в листинг трансляции (файл с расширением 1st). Прежде, чем продолжить нашу тему, необходимо понять, что такое листинг программы. Листинг программы — это специальный файл, где в наглядном виде показан весь процесс трансляции. Файл листинга тоже имеет текстовый формат. Вы можете просмотреть его при помощи встроенного просмот- рщика вашего файлового менеджера. Для этого вы должны выбрать этот файл в файловой панели менеджера и нажать клавишу F3. В результате вы увидите приблизительно следующее: Листинг программы 173 .################################################## 174 ## Начало программного кода ## 17 5 #ЖМЖ#Ш№######№№1Ш1ЖЖШ#Ш#1Ш1и11ШШ№Ш 176 — 177 CSEG 178 0000 179 ORG 0000H к процедуре инициализации 0000 020030 180 jmp init после включения/сброса 181
204 Самоучитель по микропроцессорной технике Приведенный фрагмент представляет собой листинг трансляции управляющей программы позиционера. Для наглядности я привел фрагмент из середины программы. Как видите, листинг — это тот же текст программы, дополненный с левой стороны еще тремя столбцами. Первый столбец — это адрес в памяти, куда помещаются коды конкретной команды, записанной далее в этой же строке. Второй столбец — это сами коды команды. И адрес и коды записываются в шестнадцатеричном виде. Еще один новый столбец — это просто номер строки. Номер строки используется для быстрого поиска ошибки. Коды ошибок и номера строк, где они были обнаружены, приводятся в самом конце листинга. 0003 182 ORG 0003H ; переопределение вектора 0003 32 183 reti ; внешнего прерывания 0 184 000В 185 ORG 000BH ; переопределение вектора OOOB0203DC 186 jmp pint ; прерывания по таймеру 0 187 0013 188 ORG 0013H ; переопределение вектора 0013 32 189 reti ; внешнего прерывания 1 190 001В 191 ORG 001BH ; переопределение вектора 001В 020346 192 jmp scandu ; прерывания по таймеру 1 193 0023 194 ORG 0023H ; вектор прерывания по 0023 32 195 reti ; последовательному каналу 196 0030 197 ORG 0030H 198 USING 0 ; выбор нулевого банка регистров 199 200 201 202 ; Инициализация 203 0030 758800 204 init: mov TCON,#0 ; Запрет счета таймеров 0033 С209 205 clr flonoff ; Питание выключить 0035 7532BF 206 mov bufkl,#OBFH ; Инициализация буфера клавиатуры 0038 7506BF 207 mov _klold,#0BFH ; и буфера предыдущего состояния 003B75815F 208 iniO: mov sp, #(stack-1) ; Установка вершины стека 209 003E75D008 210 mov PSW,#bank1 0041 7B7F 211 mov ibuf,#7FH ; Младший разряд как текущий 0043 7С28 212 mov iflash,#tflash ; Инициализация счетчика мерцаний 0045 75D000 213 mov PSW,#bank0 0048 753300 214 mov bufmot,#0 ; Сброс регистра управления мотором 004В 753400 215 mov dopmot,#0 ; Сброс регистра управления мотором 004Е753996 216 mov coucl,#tzcle ; Ини-ция счетчика задержки стирания 0051 753А00 217 mov coudd,#0 ; Ини-ция счетчика стирания спецсимволов 0054 75281С 218 mov strzdu,#kolrzdu ; Ини-ция счетчика принятых раз-дов ДУ 219 0057 С200 220 clr flks ; Сброс флага "Клавиша S нажата" 0059 С201 221 clr flsav ; Сброс флага записи 0058 С202 222 clr flflh ; Сброс флага мерцаний 005DC20A 223 clr fladu ; Сброс всех флагов ДУ 005FC20B 224 clr flkdu ; 0061С20Е 225 clr bufbit 0063 C20C 226 clr flokdu ; 0065 C20D 227 clr flondu ;
Трансляция и отладка программ 205 Каждая обнаруженная ошибка дополнительно помечается непосредственно в той строке, где она обнаружена. Это сообщение выглядит следующим образом: 0000 12bank0EQU00000000B 0008 13 banki EQU 00001000В 0010 14 bank2 EQU 00010000B 15 bank3FQU 00011000В ""ERROR #23: Illegal or missing directive Импровизированная стрелка показывает место, где в тексте найдена ошибка. В приведенном примере программа обнаружила незнакомый оператор. На самом деле это просто опечатка. Вместо буквы Е случайно была набрана буква F. В результате транслятор обнаружил эту ошибку. По классификации транслятора этот вид ошибки имеет номер 23. Краткое описание ошибки: «Illegal or missing directive». Что в переводе означает «Недопустимый или неверно записанный оператор». В конце листинга кроме полного списка ошибок приводится также список всех констант и переменных вашей программы с указанием их значений, а также полный список меток, также со значениями. Используя листинг, программист может обнаружить и исправить все ошибки синтаксиса. Если процесс трансляции прошел нормально, то его результат помещается в специальный файл, имеющий расширение hex. Файл в НЕХ- формате — это тот самый машинный код, который мы и должны получить в результате трансляции, предназначенный для записи в память микроконтроллера. НЕХ-формат — это специальный формат для записи машинных кодов, принятый во всех подобных трансляторах. Это тоже, по сути, текстовый файл, где каждый байт полученного кода записывается специальным образом в шестнадцатеричном виде. Там же содержится информация об адресах, куда эти коды должны быть помещены. Вот фрагмент такого файла: :04О000О002О0303298 :03000B000203DCll :0100130032ВА :03001ВО002034697 :0100230032АА :10003000758800C2097b32BF7506BF75815K7bI}0BH :10C04000087B7F7C287 5D0007b3300753400753 9C6 :1000SC00967 53A007 52 81CC200C201C202C20AC2CB Я не буду вдаваться в подробности кодирования. Для составления программ это знать не обязательно. Нужно просто понимать, что именно здесь хранится оттранслированная программа. Именно файл в НЕХ- формате прямым или косвенным способом используется программатором для прошивки микросхем. Ниже будут описаны две разные про-
206 Самоучитель по микропроцессорной технике граммы для управления программатором. Для одной из них входным является НЕХ-файл, а для второй в качестве входного нужен файл в BIN-формате. BlN-формат, это еще один способ хранения оттранслированных данных. Он представляет собой просто набор тех самых кодов, которые и составляют программу для процессора. Для получения BIN-формата существуют программы-перекодировщики. На сайте «Цифровые микросхемы и микропроцессоры» вы можете найти две программы: программу hex2bin.exe и программу bin2hex.exe. Одна из них предназначена для перекодировки файла, записанного в НЕХ-формате, в BIN-формат. А другая — для обратной перекодировки. Программный отладчик После того, как текст программы написан и оттранслирован без ошибок, можно приступать к проверке правильности ее функционирования. Как уже говорилось, для такой проверки применяется специальная программа — отладчик. Я применяю программу ACS5I «Advanced Micro Controller High Speed Simulator» Version 1.02 by Intelligent Designer Tools Moscow, 1989. Процесс отладки происходит следующим образом. Сначала запускается отладчик. Затем в него загружается наша оттранслированная программа. Все дальнейшие операции производятся под управлением отладчика. В качестве входного файла для отладчика используется выходной файл транслятора в НЕХ-формате. Теперь рассмотрим подробнее последовательность работы с программой отладчика. Для отладки программы удобно внутри директории prog создать специальную директорию для отладчика. Назовем ее acs51. В эту директорию помещается программа-отладчик (файл fd51.exe). Туда же, перед началом отладки нужно поместить отлаживаемый файл в НЕХ- формате. Для запуска отладчика сначала, при помощи файлового менеджера, откройте директорию asc51. Установите указатель выбора файлов на файл fd51.exe и нажмите Enter. Отладчик запустится, и вы увидите на экране его рабочее поле (см. рис. 55). На рабочем поле наглядно отображается полная информация о текущем состоянии имитируемого контроллера. Рабочее поле программы разделено на восемь отдельных окон. Каждое окно имеет свое назначение. Самое большое окно в верхней части экрана называется «Special Function Registers». Оно постоянно отражает содержимое всех внутренних регистров процессора, как регистров общего назначения, так и специальных регистров. Текущий банк регистров общего назначения выделяет-
Трансляция и отладка программ 207 ся более ярким, цветом. Если выполнять программу пошагово, то на каждом шаге вы сможете визуально наблюдать, как меняется содержимое регистров. В левом нижнем окне (без названия) всегда отображается фрагмент программы, записанный в виде команд Ассемблера. Запись очень похожа на листинг программы. Этот текст получен из кодов программы путем так называемого «дизассемблирования». Дизассемблирование — это процесс обратный трансляции. Мнемокоды программ определяются по их машинным кодам. Однако здесь вы не увидите ни меток, ни имен переменных и констант, ни комментариев. Все это осталось в тексте программы. Вместо этого вы увидите конкретные адреса и числа в шестнадцатеричном коде. Вторая сверху строка этого окна выделена голубым цветом. В процессе выполнения команд весь текст в окне смещается вверх таким образом, что в этой строке всегда находится текущая выполняемая команда. В самой верхней строке находится только что выполненная команда. Следующее окно называется INT RAM. Оно отображает текущее состояние ОЗУ контроллера. Левый столбец четырехразрядных шестнадца- теричных чисел, выделенный голубым цветом, отображает адреса ячеек памяти. Остальные двухразрядные числа зеленого цвета — это содержимое этих ячеек. Такой способ отображения называется дампом памяти. Адрес в начале каждой строки относится только к первой ячейке Рис. 55. Программа-отладчик ACS51 в рабочем режиме
208 Самоучитель по микропроцессорной технике этой самой строки. Каждая последующая ячейка имеет; адрес на единицу больший, чем у предыдущей. В окне видна лишь часть ячеек памяти. Но при помощи команд управления можно выбрать другой начальный адрес просмотра и увидеть любую другую часть ОЗУ. Естественно, в этом окне можно увидеть также те ячейки, которые одновременно являются регистрами. Их содержимое будет одинаковым. Маленькое окно PSW, как вы уже догадались, отображает текущее состояние всех флагов регистра PSW. В верхнем, самом большом окне мы также можем видеть регистр PSW. Но там его содержимое отображается в виде одного шестнадцатеричного числа. А в специальном окне все флаги отображаются по отдельности. Окно PGM ROM отображает в виде дампа программную память контроллера. Мы уже рассматривали окно, в котором та же самая информация отображается в виде текста на Ассемблере. Данное же окно дублирует предыдущее, но уже в другой форме. Окно предназначено в основном для того, чтобы наблюдать те ячейки программной памяти, в которых хранятся данные. Например, в нем удобно наблюдать таблицу символов программы позиционера. В окне PGM ROM также отображается только часть всей программной памяти. Но при помощи команд навигации можно посмотреть любую ее область. Окно «Stack» отображает текущее состояние стека. Столбец слева, окрашенный в голубой цвет — это номер ячейки стековой памяти, начиная с его вершины. В столбце справа показано текущее содержимое каждой ячейки. Следующее окно — это окно ввода команд. В нем вы увидите надпись CMD (сокращение от Command) и мигающий курсор. В это окно вы можете вводить различные команды, при помощи которых происходит управления всеми режимами отладки. Каждая такая команда состоит из одной буквы. За этой буквой записывается один или нескольких параметров. Полный набор команд описан в краткой справке, которая вызывается но команде «Н» (без параметров). Наберите Н на клавиатуре и нажмите Enter. Появится окно справки, где в кратком виде на английском языке будут даны описания команд и некоторая другая информация. В пакет программы отладчика, который вы можете скачать на сайте «Цифровые микросхемы и микропроцессоры», входит текстовый файл на русском языке с описанием всех команд. Этот файл является переводом текста встроенной помощи. И последнее маленькое окошко служит для оценки реального времени выполнения программы. Время считается в секундах, миллисекундах и микросекундах, о чем свидетельствуют надписи «s», «ms» и «mcs» в заголовке этого окна.
Трансляция и отладка программ 209 Кроме команд, которые должны вводиться в командной строке, существует ряд команд, которые вводятся при нажатии одной из функциональных клавиш (F1...F10). Эти клавиши часто называют «Горячими клавишами», так как нажатие любой из них вызывает немедленное выполнение закрепленной за клавишей функции. Для удобства работы в нижней части окна отладчика помещена строка подсказки, где в краткой форме поясняются команды, закрепленные за каждой из этих клавиш. Более развернутое описание для всех этих команд приведено в табл. 6. «Горячие клавиши" отладчика FD5 / Таблица 6 Кроме того, в отладчике имеется режим прямого ввода адреса или содержимого регистра. Для этого нужно сделать пустой ввод (нажать клавишу Enter, когда в окне команд ничего не написано). Сразу после этого включится режим прямого ввода. О том, что режим включился, будет свидетельствовать изменение формы курсора. Курсор превратится в квадратик. Теперь можно при помощи стрелок переместить курсор в любое место окна отладчика и ввести туда новое значение. Например, можно подвести курсор к адресу ячейки ОЗУ в окне INT RAM и набрать новый адрес для отображения. Можно поменять значение любой ячейки ОЗУ, значение любого регистра и т.д. Некоторые элементы
210 Самоучитель по микропроцессорной технике изображения не допускают изменения. В этом случае попытка изменить недоступный элемент не вызовет никакой реакции. Если вы изменили любой элемент в любом окне отладчика и такой ввод допустим, то он сразу повлияет на содержимое других окон. Например, если поменять адрес в верхней строке окна INT ROM, то цифры, отображающие содержимое ячеек, тут же поменяются в соответствии с новыми адресами. Адрес других строк этого окна менять недопустимо. Выход из режима прямого ввода происходит также при помощи пустого ввода. Теперь немного о самом процессе отладки. В качестве примера будем отлаживать управляющую программу позиционера. Сначала нужно загрузить отлаживаемую программу в отладчик. Для этого в окне ввода команд наберите следующую команду: I, POZI.HEX Можно набирать это все как прописными буквами, так и строчными. Главное, не забудьте между командой L и именем загружаемого файла поставить пробел. Имя файла нужно обязательно набирать целиком, с расширением. Иначе команда будет считаться ошибочной, и программа не загрузится. После набора текста команды нажмите Enter. Если все выполнено правильно, то в левом нижнем окне появится текст первых строк загруженной программы. Рис. 56. Программа-отладчик ACS51 в режиме установки точек перехвата
Трансляция и отладка программ 211 Далее мы начинаем отлаживать загруженную программу. Сначала можно прогнать ее в пошаговом режиме. Для этого нажимайте клавишу F1. При каждом нажатии будет выполняться одна очередная команда. После выполнения очередного шага посмотрите на состояние всех регистров и ячеек памяти. Их содержимое должно изменяться в сбответствии с задуманным алгоритмом. Если при выполнении программы встретится команда передачи управления, то это сразу отразится на содержимом окна в левой нижней части отладчика, где показан фрагмент текста программы. Одновременно изменится содержимое регистра PC (регистра текущего адреса). Если программа слишком большая и «прошагать» ее до нужного места — «утомительное» занятие, воспользуйтесь механизмом постановки точек перехвата. Для этого нажмите клавишу F5. Рабочее поле программы приобретет вид, показанный на рис. 56. В верхней части экрана появится окно красного цвета, предназначенное для установки точек перехвата. Всего можно установить восемь таких точек. Точки устанавливаются методом прямого ввода. Причем в данном случае программа переходит в режим прямого ввода автоматически. Перемешайте курсор непосредственно в нужную позицию и вводите новое значение. Как вы видите на рис. 56, для каждой точки перехвата в таблице имеется четыре параметра. BRN — это номер точки перехвата. PC — это адрес, при достижении которого программа должна остановиться. Следующие два столбца служат для еще более тонкой настройки режимов останова. Столбец Counter — это счетчик проходов. В этом столбце вы обязательно должны заменить ноль на какое-либо другое число. Иначе останова не будет. Если вы параметру Counter присвоите значение 001, то программа будет останавливаться каждый раз, когда адрес текущей исполняемой команды будет равен значению параметра PC. Если вы поставите туда число большее единицы, например 10, то останов программы произойдет не при первом проходе через этот адрес, а при десятом. Параметр Occur устанавливать не надо. Его значение увеличивается автоматически каждый раз, когда программа проходит через указанный адрес. При совпадении Counter и Occur происходит остановка программы и сброс параметра Occur. После того, как программа остановится, вы можете продолжить ее отладку в пошаговом режиме. Можно также запустить программу снова в автоматическом режиме. В этом случае она будет работать, пока не встретит следующую точку останова. Если вы часто используете одни и те же точки перехвата, то их настройки можно записать на диск, а затем, при следующей загрузке программы, восстановить настройки. Для записи точек перехвата используется клавиша F2, а для восстановления — клавиша F1. Выйти из режима
212 Самоучитель по микропроцессорной технике установки точек перехвата можно, нажав повторно клавишу F5. Всего на диске можно запомнить десять наборов точек перехвата. Особое затруднение может вызвать выход из программы-отладчика. Для выхода в окне ввода команд нужно набрать команду quit и нажать Enter. Как видите, рассмотренный отладчик довольно примитивная программа с современной точки зрения. Но нужно учитывать, что программа эта писалась очень давно. В те времена это был, чуть ли не верх совершенства! Итак, с процессом отладки мы разобрались. Теперь можно приступать к прошивке программной памяти микроконтроллера. А для этого нам понадобится программатор. Программатор Как вам уже известно, микросхема АТ89С2051 имеет встроенную электрически стираемую память программ объемом 2 килобайта. В исходном состоянии (сразу после изготовления микросхемы) во всех ячейках этой памяти записан код 0FFH. В процессе прошивки памяти программ в ячейки записываются коды управляющей программы. Затем эти прошитые коды можно прочитать для проверки. Для того, чтобы изменить прошивку (записать другую программу) память программ необходимо стереть. После стирания во всех ячейках снова пояшшется код 0FFH. Для защиты программы от считывания и несанкционированного копирования предусмотрены специальные биты защиты LB1 и LB2. Если прошить бит LB1, блокируется возможность дозаписи в программную память. При прошивке обоих битов защиты, блокируется как возможность дозаписи, так и возможность считывания информации из программной памяти. Очистить защитные биты можно только в режиме стирания программной памяти. При этом записанная туда программа также стирается. Для осуществления всех описанных выше функций, в микросхеме предусмотрен специальный режим программирования. Для перехода в этот режим используется вход RST (вывод I) микросхемы. В рабочем режиме этот вход используется как вход начального сброса. Сброс производится путем кратковременной подачи сигнала логической единицы. Затем вплоть до выключения питания на входе поддерживается низкий логический уровень. Для перевода микросхемы в режим программирования, на вход RST постоянно подается сигнал логической единицы. Кроме того, непосредственно в момент программирования на этот же вход подается программирующее напряжение +12 В.
Трансляция и отладка программ 213 В режиме программирования, функции всех выводов микросхемы изменяются. Линии порта Р1 выполняют функции шины данных для записи кодов программы в память микросхемы и для чтения данных из нее. Линии РЗ.З, Р3.4, Р3.5, Р3.7 используются для выбора одного из подрежимов программирования. В табл. 7 приведен полный список этих подрежимов с описанием сигналов на управляющих входах, необходимых для включения каждого подрежима. Подрежимы программирования АТ89С2051 Таблица 7 Линия Р3.2 в режиме программирования используется как вход PROG. То есть вход, куда подается импульс программирования. Линия Р3.1 используется, как выход сигнала готовности (READY). Кварцевый резонатор в режиме программирования не используется. Вывод XTAL1 используется, как вход внутреннего счетчика адреса. Приведу примерный алгоритм, по которому должен работать любой программатор в режиме программирования: Режим записи кода 1. Подать на входы порта Р1 первый байт программного кода. 2. Подать на входы РЗ.З...Р3.7 код выбранного режима @111), согласно табл. 7. 3. Подать на вход RST напряжение +12 В. 4. Подать на вход PROG короткий импульс программирования (длительностью от 1 до 110 мкс). 5. Дождаться сигнала готовности на выходе READY. 6. Если это не последний байт кода, перейти к прошивке следующего байта. Для этого: • Подать короткий положительный импульс на вход XTAL1. Этот импульс увеличит на единицу содержимое внутреннего счетчика адреса.
214 Самоучитель по микропроцессорной технике • Подать на входы порта Р1 следующий байт программного кода. • Повторить все, начиная с пункта 4. 7. Если это последний байт, закончить программирование. Для этого: • Снять напряжение +12 В с входа RST. Режимы записи битов защиты и очистки памяти 1. Подать на входы РЗ.З...Р3.7 код выбранного режима, согласно табл. 7. 2. Подать на вход RST напряжение +12 В. 3. Подать на вход PROG импульс программирования (для записи бита его длительность должна быть от 1 до 110 мкс, для стирания памяти — 10 мс). 4. Дождаться сигнала готовности на выходе READY. 5. Снять напряжение +12 В с входа RST. В режимах чтения программирующее напряжение +12 В на вход RST и сигнал PROG на вход Р3.2 не подаются. Вход XTAL1 в режиме чтения программного кода так же, как и при его записи, используется для последовательного перебора адресов. Байт сигнатуры — это специальный код, записываемый в микросхему при ее изготовлении. По значению этого байта можно определить фирму-изготовителя конкретной микросхемы. Если вас интересует полное описание всех режимов программирования, вы можете скачать описание микросхемы АТ89С2051 на сайте http://microprocessor.by.ru в разделе «Справочные материалы». Однако на практике все эти подробности знать не обязательно. В настоящее время разработано множество конструкций программаторов. Их описание можно найти и в специальной литературе и в Интернете. Я рекомендую использовать простейшую схему Blowlt2051 Copyright (С) 1996 Silicon Studio. Схема приведена на рис. 57. Она состоит из двух транзисторов КТ315, пяти резисторов и одного конденсатора. Подключается схема к параллельному порту компьютера (LPT). Схема имеет свой внутренний источник питания. Это малогабаритный трансформатор с двумя вторичными обмотками. Два выпрямительных мостика и два стабилизатора напряжения (КРЕН5Б и К.РЕН8Б). Блок питания выдает два стабилизированных напряжения: +5 В и +12 В. Для приведенной схемы существует два варианта управляющей программы. Первый вариант разрабатывался одновременно со схемой. Он называется Bi2O51. Объем файла программы всего 6 килобайт. Но эта программа имеет один недостаток. Она написана на языке Паскаль. В стандартной библиотеке используемой версии Паскаля имеется скрытая ошибка. На медленных компьютерах (с тактовой частотой до
Трансляция и отладка программ 215 100 МГц) она не проявляется. На более быстродействующих компьютерах в программе возникает ошибка деления на ноль. Для преодоления этого недостатка существует специальная программа — заплатка. Она называется unzero.com. Такую программу нужно запускать каждый раз перед началом работы программатора. Рис. 57. Схема программатора Blowit для микроконтроллера АТ89С2051 Второй вариант управляющей программы был разработан в 2001 году под ту же самую схему, что и первый вариант. Называется он py2051.exe. Программа рассчитана для работы не только в среде DOS, но и под Windows 9x и даже под Windows NT. В выходных данных программы сказано следующее: py2051.py AT89C2051 Programmer 10.06.2001 Dincer Aydin dinceraydin@altavista.net http://www.geocities.com/dinceraydin/ Объем этой программы гораздо больше. Весь пакет занимает 576 килобайт в архивированном виде. Порядок работы с обоими вариантами программы практически один и тот же. Он похож на порядок работы с транслятором и отладчиком. Все
216 Самоучитель по микропроцессорной технике действия необходимо выполнять при помоши выбранного вами файлового менеджера. Отличие состоит в том, что для первого варианта программы требуется файл в BIN-формате, а для второй в качестве входного используется НЕХ-формат. Как уже упоминалось раньше, для перекодировки из одного формата в другой существует специальная программа hex2bin.exe. Ее можно скачать как с сайта «Atmel», так и получить в пакете с первой версией программатора на сайте http://microproccssor.by.ru. Для того, чтобы осуществить перекодировку нужно поместить НЕХ-файл в одну директорию с программой hex2bin.exe, сделать эту директорию текущей и ввести в командной строке файлового менеджера следующую команду: hex2bin pozj .hex После нажатия клавиши Enter программа запустится и, если вы все сделали правильно, в той же директории появится файл pozi.bin. Это и есть ваша программа в BIN-формате. Ее нужно поместить в директорию, где находится программа программатора (первый вариант) и использовать для программирования. Для того, чтобы запрограммировать микроконтроллер, нужно: ¦ Подключить программатор к компьютеру (питание компьютера выключено). ¦ Вставить в него микросхему, предназначенную для программирования. ¦ Включить компьютер. ¦ Включить питание программатора. ¦ Затем в компьютере необходимо последовательно подать две команды: unzero М2051 pozi.bin Команды подаются путем их ввода в окно команд файлового менеджера. Если все сделано правильно и, если микросхема исправна, начнется процесс программирования. Ход выполнения этого процесса будет отображаться на экране компьютера в виде растущей строки из точек. По завершении процесса программа выведет сообщение: «We are finished». Если вместо этой надписи вы увидите «Error, never ready?» или «Error, no device?», то это значит, что микросхема неисправна, либо вы допустили ошибку при сборке схемы. Программатор может отказаться работать и в том случае, если в вашем компьютере используется нестандартный параллельный порт. По умолчанию программа настроена
Трансляция и отладка программ 217 на LPT1. Если в вашем компьютере два параллельных порта, и вы подключили программатор к порту LPT2, то для запуска программатора нужно применять следующую команду: Ы2051 pozi.bin 2 После окончания процесса программирования нужно выключить питание программатора, извлечь микросхему из панельки и вставить в проверяемую схему. Порядок работы со вторым вариантом управляющей программы программатора гораздо проще. Никакой перекодировки форматов не требуется. Помещаете ваш НЕХ-файл в одну директорию с программатором и вводите в командном окне файлового менеджера следующую команду: ру2051 pozi.hex После нажатия клавиши Enter начнется процесс программирования. Ход процесса программирования никак не индицируется. На экран только выводится количество байтов, подлежащих записи в микросхему. Все сообщения программы в случае возникновения ошибки аналогичны первому варианту программы. При завершении программы она выдает сообщение: «We are finished!». Второй вариант программы так же поддерживает возможность переопределения номера LPT-порта. Все операции по подключению программатора к компьютеру, установке микросхемы в программатор и извлечения ее оттуда полностью аналогичны первому случаю. Помните, что все операции по установке и извлечению микросхемы, как в программаторе, так и в отлаживаемой схеме, можно производить только при выключенном питании. В противном случае можно вывести микросхему из строя.
АТ89С2051 Система команд микроконтроллера АТ89С2051 насчитывает 107 команд, из них 45 однобайтовых, 45 двухбайтовых и 17 трехбайтовых. Все команды выполняются за один или два машинных цикла A2 тактов ALE) за исключением команд MUL и DIV, которые требуют четыре цикла. Большинство двухбайтовых команд одноцикловые, а все трехбайтовые команды — двухцикловые. Это объясняется тем, что за один машинный цикл может считываться до двух байтов, программного кода. Все множество команд удобно разбить на пять групп: ¦ Команды пересылки B5). ¦ Команды логической обработки B5). ¦ Арифметические команды B4). ¦ Команды передачи управления A7). ¦ Битовые команды A7). В процессе исполнения, команды влияют на ряд флажков-признаков результата, входящих в состав PSW (табл. nl). Признак Р устанавливается всякий раз, когда приемником результата служит аккумулятор, включая операции пересылки. Группа команд пересылки (табл. п2) содержит команды MOV (пересылки данных между DSEG и RSEG), MOVC (между CSEG и А), команды обращения к стеку PUSH и POP, а также две команды обмена ХСН и XCHD. Наиболее емкой инструкцией является команда MOV, которая использует четыре способа адресации: регистровый (A, Rn, DPTR), прямой (direct), косвенный (@Ri) и непосредственный (#data, #datal6). Для указания приемника служат три способа адресации (кроме непосредственного), для указания источника — все четыре. Трехбайтовая команда MOV direct, direct обеспечивает пересылку между двумя любыми ячейками памяти, включая регистры микроконтроллера. Тем не менее, для обмена с регистрами предусмотрены специальные двух- и однобайтовый форматы: mov Rn, direct MOV direct, Rn MOV A, Rn MOV Rn, A Система команд микроконтроллера
Приложение 219 Влияние команд на флаги регистра PSW Таблица п 1 Их использование позволяет существенно сократить длину программного кода. Специальная команда MOV DPTR, #datal6 позволяет загрузить 16- разрядный указатель DPTR значением datal6. При выполнении команды MOVC считывания данных из программной памяти могут быть применены два способа адресации: по базе DPTR и относительный. В обоих случаях целое без знака смещение (индекс) хранится в ак- Таблица п2
220 Приложение кумуляторе. Приемником результата также служит аккумулятор. Команда дает возможность выполнять быструю перекодировку по таблицам, осуществлять доступ к массивам памяти. Операции PUSH и POP используют только прямой способ адресации, что не мешает им манипулировать содержимым регистров, которые рассматриваются как ячейки памяти. Две типовые операции обмена ХСН и XCHD дополняют одностороннюю пересылку двусторонней. При выполнении операции ХСН обмену подлежат байты, при XCHD — младшие тетрады байтовых операндов. Приведенная в табл. пЗ группа команд логических операций, содержит три типовые двухместные операции: ANL — логическое И, ORL — логическое ИЛИ и XRL — логическое исключающее ИЛИ. Источником первого операнда и одновременно приемником результата служит либо аккумулятор А, либо прямо адресуемая ячейка памяти. Второй операнд задается одним из четырех основных методов адресации. В состав группы входит также ряд одноместных операций: CLR — очистки, CPL — Команды логических операций Таблица пЗ
Приложение 221 Арифметические операторы Таблица п4 логического дополнения (инверсия), а также RL, RLC, RR и RRC — операции циклического и расширенного сдвигов вправо и влево. Все операции манипулируют содержимым только аккумулятора А. Сюда же включена операция обмена тетрад в аккумуляторе SWAP, которая может интерпретироваться как циклический сдвиг байта на четыре разряда. В состав группы команд арифметической обработки (табл. п4) входят: операция сложения ADD, сложения с учетом переноса ADDC, вычитания с учетом займа SUBB, увеличения и уменьшения на единицу INC и DEC, десятичная коррекция сложения в 2/Ю-коде упакованного формата DA, умножение MUL и деление DIU. Операции выполняются над беззнаковыми целыми числами. В операциях сложения и вычитания первым операндом и приемником результата служит аккумулятор. В качестве второго операнда выступает либо рабочий регистр Rn, n = 0...7, выбранного регистрового банка, либо ячейка памяти данных, адресуемая прямо direct или косвенно @Ri, i = 0-1, либо непосредственные данные #data. Операции INC и DEC применимы к ак-
222 Приложение кумулятору, одному из рабочих регистров или к ячейке памяти, адресуемой как прямо, так и косвенно. Кроме этого операция увеличения на единицу может быть применена к содержимому регистра указателя DPTR. В операциях целочисленного умножения и деления без знака участвуют аккумулятор и регистр В. При умножении 8-разрядное значение А умножается на 8-разрядное значение В, а 16-разрядный результат записывается в пару ВА. При этом регистр В хранит старшую часть произведения. Флажок переполнения OV устанавливается, если произведение больше 255. При делении 8-разрядного значения А на 8-разрядное значение В частное записывается в А, а остаток в В. При попытке деления на 0 устанавливается флажок переполнения. Операция десятичной коррекции для сложения DA осуществляется стандартным способом. В составе группы команд передачи управления (табл. п5) находятся команды перехода AJMP, LJMP, SJMP, JMP, условного перехода JZ, JNZ, CJNE, вызова ACALL, LCALL, возврата RET, RET1 и модификации с условным переходом DJNZ. Сюда же включена пустая команда NOP. В командах передачи управления широко применяется относительная адресация, которая поддерживает перемещаемые программные модули. В качестве относительного адреса выступает 8-разрядное смещение rel со знаком, обеспечивающее ветвление от текущего положения PC в обе стороны на +127 байт. Для перехода в любую другую точку 64К-байто- вого адресного пространства может быть использован либо прямой addrl6, либо косвенный @A+DPTR адрес. В последнем случае содержимое А интерпретируется как целое без знака. Вариант короткой прямой адресации addrll внутри 2К-байтовой текущей страницы введен для совместимости с более старыми процессорами. Все эти типы адресации могут быть применены только к операции перехода, а для операции вызова допустимы только прямой addrl6 и внутристраничный addrll способы адресации. Во всех условных операциях может использоваться только относительная адресация. Когда микроконтроллер АТ89С2051 опознает запрос на прерывание, он генерирует одну из команд типа LCALL addrl6, что автоматически обеспечивает запоминание адреса возврата в стеке. При этом логика прерываний перестает срабатывать на запросы того уровня, который был принят к обслуживанию. Для понижения уровня прерывания служит команда возврата из прерывания RET1, которая кроме операции, эквивалентной RET, включает операцию разрешения прерывания данного уровня. К условным операциям относятся также операторы JZ и JNZ, JC и JNC. Две последние включены в группу булевых. Кроме того, в системе команд
Приложение 223 Операторы передачи управления Таблица п5 имеется операция «Сравнить и перейти» CJNE. По данной команде операнд сначала сравнивается по правилам вычитания целых чисел с константой и в соответствии с результатом сравнения выставляется флажок CY. Затем в случае несовпадения с константой выполняется ветвление. Сравнивая аккумулятор, регистр или ячейку памяти с последовательностью констант, получаем удобный способ проверки на совпадения, например, с целью выявления особых случаев. По сути дела команда CJNE может рассматриваться, как элемент языка высокого уровня типа CASE. Команда DJNZ — это команда организации программного цикла. В качестве счетчика может использоваться один из рабочих регистров Rn, п=0...7, а так же любая ячейка памяти данных DSEG. Ряд команд, предназначенных для выполнения операций пересылки, проверки условий и логической обработки булевых (одноразрядных) переменных, образует отдельную группу (табл. пб). В качестве одного из операндов они применяют флажок переноса CY, в качестве другого служит прямо
224 Приложение адресуемый элемент пространства BSEG. Флажок CY при выполнении операций И и ИЛИ может рассматриваться как булевый аккумулятор. В группу входят также операции безусловного и условного переходов с относительным 8-разрядным смещением rel. Условный переход может быть осуществлен как при установленном JB, так и при сброшенном JNB бите. Особо следует отметить операцию JBC, которая реализует ветвление при установленном бите и одновременно с этим сбрасывает его в 0. Такая операция полезна в системах, решающих много задач, при организации семафоров, которые вводятся для защиты коллективно используемых ресурсов микропроцессора. Семафор представляет собой расположенный в памяти флажок, информирующий о состоянии связанного с ним ресурса: 1 — свободно; 0 — занято. Захват ресурса допускается только в случае, если он свободен, затем семафор должен быть переведен в состояние «Занято». Захват ресурса с помощью команды JBC осуществляется следующим образом: WAIT: JBC bit, ОК ;Проверка семафора bit SJMP WAIT .Ресурс занят, ожидание ОК: — ;Ресурс захвачен Битовые операции Таблица пб