Главная

Материал взят из книги


Скачать оригинал КНИГИ в хорошем качестве

Управляющая программа

Теперь от аппаратной части позиционера перейдем к программной. Алгоритм управляющей программы микропроцессорного устройства в общих очертаниях обычно складывается в процессе разработки его схемы. Когда разработчик применяет то или иное схемное решение, то обычно он имеет в виду определенный программный алгоритм, который будет работать с такой схемой. Управляющую программу позиционера удобно разбить на три самостоятельных модуля. Первый модуль — это основная программа. Процессор начинает выполнять ее сразу после начального запуска системы, после окончания сигнала аппаратного сброса и выполняется все время, пока включено питание. Основная программа включает в себя все процессы, которые не должны быть синхронизированы во времени.

Кроме основного модуля существуют два дополнительных. Если вы еще не забыли, дополнительные модули представляют собой две процедуры обработки прерываний. Одна из дополнительных процедур реализует процесс динамической индикации. Вторая — реализует постоянный опрос фотоприемника, чтение и запись в буфер команд ДУ. Механизм прерываний позволяет одному процессору выполнять все три процедуры, как бы одновременно, и не зависимо друг от друга. Для вызова обеих дополнительных процедур используются системные таймеры.

Сразу после запуска работает только основная процедура. В самом ее начале производится настройка обоих таймеров и системы прерываний. После настройки основная программа запускает таймеры, и они начинают периодически вызывать прерывания. Каждый таймер вызывает свою процедуру прерываний. Период, с которым вызываются прерывания, для каждого таймера разный. Он определяется решаемой задачей.

Таймер ТО вызывает процедуру, реализующую процесс динамической индикации, а за одно — процесс опроса состояния клавиатуры и вывод управляющего сигнала на двигатель. Процедура вызывается с постоянным периодом, примерно равным 20 мс, что соответствует частоте 50 Гц. Алгоритм динамической индикации подробно рассматривается в разделе «Процедура динамической индикации».

Таймер Т1 вызывает процедуру приема и обработки сигналов от пульта ДУ. Период, с которым вызывается эта процедура, в разных режимах работы системы разный. Подробнее о процессе приема сигналов ДУ будет рассказано в разделе «Процедура приема сигнала ДУ».

В настоящем разделе я хотел бы остановиться на самом главном из процессов — основном программном модуле. Для того, чтобы яснее представить себе алгоритм работы любой программы, удобно представить его в виде блок-схемы. Блок-схема — это графическое изображение алгоритма, какой-либо программы. На рис. 46 приведена блок-схема основного модуля управляющей программы позиционера. В прямоугольниках описываются выполняемые действия. Стрелками показывается ход выполнения программы и все разветвления алгоритма. При помощи ромбов изображаются операторы принятия решений (условные переходы). Такие операторы оценивают факт выполнения какого-либо условия и в за-


висимости от результатов оценки выбирают один из двух путей выполнения программы. Если условие, записанное внутри ромбика, истина, то выполнение программы пойдет по ветви, помеченной словом «Да». В противном случае будет выполняться ветвь, помеченная как «Нет».

Как видно из рис. 46, основная программа состоит из модуля начального запуска и основного цикла программы. В самом начале модуля начальногьо запуска, программа выполняет команды инициализации системы. Эти команды присваивают всем основным переменным программы начальные значения, настраивают систему прерываний процессора, программируют работу системных таймеров, и поступает команда запуска таймеров. Новое для вас понятие «системные переменные» пока примите на веру. Речь о них пойдет уже в следующем разделе.

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

Большой цикл состоит из четырех процедур, которые выполняются последовательно, одна за другой. Рассмотрим каждую из них.

Процедура обработки команд с клавиатуры. Здесь имеется в виду не чтение байта состояния клавиатуры, а всего лишь обработка уже прочитанного кода. Этот код читается совсем в другом месте. В процедуре, совмещенной с процессом динамической индикации. Описываемая здесь процедура лишь читает код состояния из специальной ячейки памяти, называемой буфером клавиатуры, оценивает этот код и вызывает одну из процедур обработки нажатых клавиш. Процедуры обработки нажатых клавиш на блок-схеме отдельно не показаны. Подразумевается, что они являются частью процедуры обработки команд с клавиатуры. Полный набор команд с клавиатуры вы можете видеть на рис. 44.

Процедура обработки сигналов датчика поворота антенны. Эта процедура производит непосредственное считывание сигнала с той линии Р1.4, куда поступают сигналы датчика. Именно в этой процедуре реализуется алгоритм двухуровневой аптидребезговой обработки. Алгоритм производит фильтрацию всех лишних импульсов, обусловленных дребезгом контактов датчика. Отсеяв таким образом помехи, программа получает чистый сигнал от датчика. Затем происходит счет, то есть увеличение либо уменьшение содержимого счетчика положения антенны при каждом срабатывании датчика. Направление счета определяется косвенным образом.

Если на двигатель подана команда «прямой ход», содержимое счетчика увеличивается. Если на двигатель подана команда «реверс», то содержимое счетчика уменьшается. После каждого изменения содержимого счетчика положения антенны, оно сразу же записывается во внешнюю флэш-память. Это делается для того, чтобы при неожиданном выключении питания данные о реальном положении антенны не были утеряны.

Процедура автоматической установки антенны. Эта процедура запускает процесс автоустановки антенны на выбранную позицию. Для этого программа определяет номер выбранного канала, читает из памяти код, соответствующий записанной там позиции и сравнивает этот код с текущим значением счетчика положения антенны. Если коды не совпадают, то программа дает команду двигателю на поворот. Направление поворота определяется автоматически, в зависимости от того, какое из сравниваемых чисел больше. Данная процедура имеет опосредованное действие. Команда управления двигателем не выводится немедленно. Она просто запоминается в другой специальной ячейке ОЗУ. Ячейку, резервируемую для этих целей, называют буфером команд управления мотором. Собственно вывод команды на мотор происходит в цикле динамической индикации. Такой подход связан с тем, что для непосредственного вывода команды пришлось бы приостановить цикл динамической индикации. Однако этот цикл не может прерываться произвольным образом. Иначе свечение индикаторов будет неравномерным.

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

Завершается большой цикл процедурой проверки правильности записи во флэш-память. Дело в том, что стандартные процедуры чтения/записи флэш-памяти, которые использованы в данном случае, содержат встроенную функцию проверки. Если в процессе чтения или записи информации во флэш-память произошел сбой, то процедура устанавливает в единичное состояние специальный флаг ошибки. Флаг ошибки — это специально выделенный разряд в битовом пространстве памяти. В конце основного цикла происходит проверка этого флага. Если флаг установлен, то выполняется специальная процедура, которая кратковременно выводит на индикатор позиционера предупреждение об ошибке («Ег»). Такая индикация очень помогает в процессе поиска неисправностей.

После проверки флага ошибки программа переходит к началу основного цикла, и все повторяется сначала. В дежурном режиме ход выполнения основного цикла меняется. В этом случае выполняется другой — малый цикл. Он состоит всего из двух модулей.

Модуль подготовки дежурного режима предназначен для приостановки всех выполняемых в этот момент операций. В этом модуле выполняются команды остановки двигателя, выключения индикаторов, а также включения индикатора дежурного режима.

Модуль, обозначенный как «Остановка процессора», состоит всего лишь из одной команды. Эта команда устанавливает младший разряд регистра РССЖ в единичное состояние, чем включает режим останова процессора. В этом режиме процессор прекращает выполнение основной программы, но продолжает обрабатывать прерывания. Обе процедуры обработки прерываний в дежурном режиме работают в урезанном виде. Они выполняют только одно действие: ожидание сигнала выхода из дежурного режима. При нажатии кнопки «Вкл/Выкл» клавиатуры позиционера, либо при получении команды на включение от пульта ДУ, соответствующая процедура сбрасывает младший бит регистра РССЖ в ноль. После этого работа программы продолжается в обычном режиме.

Описание констант и переменных

Теперь рассмотрим, как вышеописанный алгоритм реализуется в виде текста программы на языке Ассемблера. И самым первым действием этой программы всегда является описание констант и переменных. Настал момент пояснить, что такое константы и переменные с точки зрения программирования.

Константа — это просто некоторое число, которое часто используется в программе, и имеет какой-либо определенный смысл. Например, длительность задержки таймера, количество бит информации в сигнале ДУ, адрес некоторой часто используемой ячейки памяти (например, адрес буфера клавиатуры, адрес буфера сигнала управления мотором и так далее). В любом языке программирования, в том числе и в языке Ассемблера, такие величины принято заменять символическими именами. Делается это при помощи специальных операторов. Если говорить об Ассемблере, то в нем существует несколько операторов, при помощи которых можно определить константу:

DATA определение константы, являющейся адресом ячейки внутренней памяти данных.

IDATA .... определение константы внутренней памяти с косвенной адресацией.

BIT  определение битовых констант.

CODE определение константы в памяти программ.

EQU  универсальный оператор определения констант.

Мы начнем с последнего из них. Оператор макроопределения EQU (сокращение от английского equivalent — эквивалентно) позволяет закрепить за любым числом, кодом регистра, названием порта символьное имя. Сразу после этого вы можете использовать это имя везде, где предполагается использовать скрытое под этим именем значение.

Рассмотрим пример использования такого оператора. В программе позиционера в нескольких местах используется коэффициент, определяющий длительность задержки динамической индикации. Значение этого коэффициента равно 0D8H. Присвоим этому коэффициенту символьное имя. Для этого в тексте программы нужно записать следующую команду:

Udind EQ’J 0Э8Н

Приведенная выше команда создает константу с именем tdind, и присваивает ей значение 0D8H. Теперь, когда имя константы определено, в любом месте программы, вместо 0D8H можно писать tdind.

Например, команды

mov A,#0D8H и mov A.ttldind

будут теперь полностью равнозначны. Обе они записывают код 0D8H в аккумулятор (регистр А).

Определение констант в принципе не обязательно, но весьма желательно. Во-первых, это улучшает читаемость программы, а во-вторых, облегчит процесс последующей модернизации. Представьте, что мы полностью отказались от определения констант и написали программу, в которой вместо имен переменных просто стоят их значения. В процессе отладки программы или при ее доработке вам обязательно придется еще и еще раз просматривать ее текст. Встретив в программе код 0D8H, вам придется долго разбираться, действительно ли это постоянная времени индикации, или это случайное совпадение значений. Встретившееся число не обязательно будет именно константой задержки. В программе вполне может встретиться и другая величина, равная 0D8H. Если же вместо константы стоит ее имя, уже при беглом взгляде на программу, сразу видно ее назначение. Имя tind в нашем примере — это просто сокращение, означающее «период индикации».

Теперь представим себе, что мы решили изменить период индикации. Вот тут-то и проявятся все преимущества механизма определения констант. Если постоянная времени индикации определена как константа tind, то для замены ее значения во всем тексте программы достаточно поменять его лишь в одной строке, в той, где она описывается. Представьте, на сколько было бы сложнее выискивать все случаи применения константы по всему тексту программы. Особенно если учесть, что полный текст описываемой здесь программы позиционера содержит более тысячи строк.

Рассмотрим подробнее особенности применения оператора EQU. Как мы видели из примера, в левой его части должно находиться имя, которое мы присваиваем этой константе. В данном случае имя не должно оканчиваться символом двоеточия. При выборе имени программист должен руководствоваться общими правилами построения имен в языке Ассемблера:

Е Для написания имени допускается использовать исключительно буквы латинского алфавита и цифры. Кроме того, допускается применение символа подчеркивания (_), который рассматривается как буква. 2. Первым символом обязательно должна быть буква. Это правило введено для того, чтобы Ассемблер всегда мог отличить имя константы или переменной от числового значения. Как известно при записи числа в шестнадцатеричной форме также могут использоваться символы латинского алфавита. Правила Ассемблера предписывают: при написании числа первым символом всегда должна быть цифра. Если число шестнадцатеричное, и первый знак — буква, то перед ним нужно поставить незначащий ноль. Например, вместо F5E4H нужно писать 0F5E4H.

В правой части оператора EQU записывается значение описываемой константы. Сюда можно поставить число, записанное в любом формате — двоичном, десятичном, шестнадцатеричном. Кроме того, там может стоять простое арифметическое или логическое выражение. В качестве членов этого выражения, кроме чисел, могут выступать любые ранее определенные константы. Например, возможно следующее определение двух констант:

konst] EQIJ 3 5

kor.st2    EQU    konstl+j

Этот фрагмент программы определяет константу konstl, имеющую значение 35 и константу konst2, имеющую значение 38 (35+3). Правильное распознавание подобных выражений обеспечивается специальной функцией программы-транслятора, которая называется «механизм препроцессора».

Кроме того, в правой части оператора EQU можно указать имя любого из внутренних регистров процессора, включая любой регистр общего назначения (РОН). Например:

1 flash    EQU    r4

rabl    EQU    DPL

rab2    EQU    асе.2

В последнем примере в качестве переменной гаЬ2, определен бит номер 2 аккумулятора. В данном случае доступ к аккумулятору происходит как к ячейке памяти. На языке Ассемблера принято в этом случае обозначать аккумулятор именем асе.

Вернемся теперь к остальным операторам Ассемблера, позволяющим определять константы в программе (DATA, IDATA, BIT, CODE). Порядок их использования точно такой же, как и порядок использования оператора EQU. Отличие их только в том, что кроме присвоения значения переменной, они одновременно определяют ее тип. Например, константа, описанная оператором DATA, по определению является ячейкой ОЗУ. Транслятор автоматически проверяет правильность применения определенных вами констант и в случае некорректного их применения сообщает об ошибке. Точно также действуют и остальные операторы определения констант.

Кроме констант, которые, согласно своему названию, в течение всего времени работы программы никогда не меняются, в программе существуют переменные. Под переменной в программе понимается имя регистра, либо адрес ячейки памяти, где в процессе выполнения программы будет временно храниться какая-либо заранее неизвестная величина, либо промежуточный результат вычислений. Существует несколько способов определения переменных. Первый возможный способ — это определение ячейки, для хранения переменной При ПОМОЩИ того же самого оператора EQU. В этом случае оператор EQU действует точно так же, как и при определении констант. Вообще понятия «константа» и «переменная» в языке Ассемблера тесно связаны. Поясню сказанное на простом примере. Допустим, нам нужно выделить одну из ячеек памяти для хранения значения счетчика неких событий. Мы решилі использовать для этого ячейку ОЗУ с адресом ЗОН. Для этой цели мг должны включить в текст программы следующую команду:

coun EQU ЗОН

Данной строкой мы создали константу с именем coun. Одновременно ; нас появилась переменная с тем же именем. Константа — это адре' ячейки памяти, а переменная — это значение, хранящееся в этой ячей ке. Пример использования константы count и переменной count иллю стрируют следующие две команды:

mov account ir.ov a .count.

Первая из команд загружает адрес данной ячейки памяти (ЗОН) в ак кумулятор. Вторая команда загружает в аккумулятор содержимое зтоі ячейки. Символ # применяется в том случае, когда нужно показать, чт< следующее за ним число — это байт данных. Если такой символ отсут ствует, то число интерпретируется как адрес ячейки ОЗУ.

Теперь рассмотрим, как определяются константы и переменные в тек сте управляющей программы позиционера. Обратимся к фрагменту №) Фрагмент представляет собой начало реального текста этой програм мы. Внимательно посмотрите на текст. Здесь вы увидите уже знакомы* вам операторы описания программных констант и несколько еще пою не знакомых операторов. Об их назначении я расскажу в конце этог< раздела. Приведенная программа снабжена подробными комментария ми, что поможет вам понять назначение каждой из создаваемых пере менных. Напомню, что признак комментария — символ «точка с запя той». Все, что написано справа от него до конца строки не являете; программой и при трансляции полностью игнорируется.

Для удобства восприятия, я условно разбил программу на секции. I каждой секции объединены операторы, определяющие близкие по на значению константы. Каждая секция снабжена заголовком, которьп тоже является комментарием. Вообще, чем больше комментариев вь вставите в текст своей программы, тем легче вам будет потом в неі разобраться. Особенно по прошествии некоторого времени.

Фрагмент №1.

; ** Программа управления позиционером спутниковой антенны $mod2051


Возможно, вы обратили внимание на то, что в тексте программы в названиях регистров и портов ввода/вывода используются строчные (маленькие) буквы, хотя ранее, я использовал прописные. Дело в том, что Ассемблер, как и многие другие языки программирования, не чувствителен к регистру. Вы можете писать команды, имена меток, названия регистров как прописными, так и строчными буквами. Для программы они равнозначны. То, какими буквами вам писать — дело вашего личного вкуса.

Рассмотрим фрагмент №1 программы подробнее. Начнем с самого первого оператора программы (не считая комментариев), то есть с команды $тоб2051. Эта команда служит для присоединения внешней библиотеки описаний. Что такое внешняя библиотека описаний, и зачем она нужна? Дело в том, что данная версия ассемблера является универсальным инструментом. С его помощью можно создавать программы для любых видов микропроцессоров, имеющих сходную систему команд. У каждого из таких процессоров свой набор внутренних регистров, портов ввода/вывода и ячеек битового пространства памяти. Общее в них — система команд и способы доступа к ячейкам ОЗУ и внутренним регистрам.

Для того, чтобы обеспечить универсальность программы транслятора, применен стандартный прием для языков подобного уровня — это механизм внешних библиотек. В основной модуль программы транслятора не заложена информация о регистрах и портах. Эта информация содержится в библиотечных файлах. Библиотечный файл — это специальный файл, содержащий фрагмент программы на языке Ассемблера, в котором описаны все внутренние регистры, порты и битовые ячейки конкретного процессора. Для каждого процессора фирма-разработчик Ассемблера создала свой библиотечный файл. В стандартный комплект поставки входит 21 библиотечный файл. Это значит, что данный транслятор поддерживает возможность создания программ для 21 вида процессоров.

Однако в стандартном пакете отсутствует файл библиотеки для процессора АТ89С2051. Причина этого проста — на момент разработки данного Ассемблера такого процессора просто еще не существовало. Поэтому мне пришлось создать такой файл самостоятельно. За основу я взял библиотечный файл для процессора iMCS-51. Этот файл имеет имя mod51 (библиотечные файлы в данном случае имеют только имя и не имеют расширения). Я подкорректировал содержимое файла mod51 и записал его под новым именем: mod2051. Команда $mod2051 просто присоединяет текст библиотечного файла к тексту основной программы в момент трансляции.

Найти полный пакет программы Ассемблера со всеми библиотечными файлами, включая файл mod2051, вы можете в Интернете, на сайте «Цифровые микросхемы и микропроцессоры» по адресу http://microprocessor.by.ru (раздел «Download»). При желании вы можете самостоятельно изучить содержание любого библиотечного файла. Для этого нужно просто открыть этот файл при помоши любого простейшего текстового редактора. Удобнее всего это сделать при помощи программы Windows Commander, используя его стандартный просмотрщик файлов, вызываемый при помощи клавиши F3. Все файлы библиотек содержат в своем тексте исчерпывающие комментарии.

Но вернемся к нашему фрагменту управляющей программы. Основная ее часть состоит из описаний различных констант и переменных. Для лучшего восприятия программы я условно разбил все описания на небольшие группы по их назначению. Каждая группа имеет заголовок. По ходу дальнейшего объяснения я буду ссылаться на эти заголовки.

Коды выбора банков РОН. Эти константы используются в программе для выбора одного из банков регистров общего назначения. Для выбора нужного банка РОН достаточно записать в регистр PSW один из четырех описываемых здесь кодов. Например, для выбора банка 0 достаточно включить в текст программы следующую команду:

~ov PSW.JfbankO

Данная команда записывает в регистр PSW код bankO (то есть 00000000В). Биты 3 и 4 регистра обнуляются, что и определяет требуемый банк. Посмотрев на текст программы фрагмента №1, можно убедиться, что биты 3 и 4 остальных констант (bankl, bank2 и ЬапкЗ) принимают значения, определяющие соответствующий банк. Остальные биты (0, 1, 2, 5, 6, 7) во всех четырех случаях обнуляются. Потеря значений всех системных флагов — это недостаток данного способа переключения банков. Однако при разработке программы позиционера эта особенность учтена и не вызывает никаких проблем.

Определения клавиш. В этой группе собраны команды, определяющие константы для подпрограммы обработки команд с клавиатуры. Как уже говорилось, специальная программа периодически считывает байт состояния клавиатуры. В этом байте каждой кнопке клавиатуры соответствует свой отдельный бит. Если кнопка нажата, соответствующий бит равен нулю, если отпущена, он равен единице. Исключение составляет лишь один разряд — разряд номер 6 (предпоследний). Связано это с тем, что разряд Р3.6 в микросхемы АТ89С2051 на внешние выводы не выводится. На него поступает сигнал от встроенного компаратора. Компаратор в схеме позиционера не используется. Его входы используются совсем для других целей. Поэтому состояние шестого бита — величина неопределенная.

Для того, чтобы исключить эту неопределенность, в программе обработки сигналов с клавиатуры этот бит специальной командой сбрасывается в ноль. И лишь затем полученный код записывается в буфер клавиатуры. В результате, для каждого из возможных состояний клавиатуры мы будем иметь в буфере свой уникальный код. Так, если нажата только кнопка «Канал —», мы получаем код состояния клавиатуры, равный 10111101В.

Если нажата только кнопка «Канал +», код будет равен 10111011В, и так далее. Для каждого такого кода мы создаем отдельную константу и присваиваем ей уникальное имя. Далее эти константы используются в программе для распознавания факта нажатия той или иной клавиши и запуска соответствующей процедуры. Применение констант в данном случае позволяет легко менять назначение кнопок на пульте, например в случае, когда нужно изменить разводку для оптимизации печатного монтажа.

В этой же секции определяются еще две величины: ЬКопоА^ и ккгев. Способ их определения отличается от только что описанного. Константа ЬКопоА определяет ту же кнопку, что и константа ккоп, но другим способом — по номеру отвечающего за нее бита. (Нумерация битов начинается с нуля). Эта константа потребовалась потому, что в одной из подпрограмм для оценки состояния этой кнопки («Вкл/Выкл») не используется байт состояния клавиатуры. Оценка производится путем прямого считывания значения соответствующего разряда порта РЗ. Константа Ьиопо1Т определяет адрес этого бита в битовом пространстве процессора.

Особым образом определяется константа ккге$. Эта константа описывает код состояния клавиатуры в тот момент, когда нажаты сразу четыре кнопки: «Канал +», «Канал —», «Поворот влево» и «Поворот вправо». Нажатие четырех кнопок одновременно применяется для запуска процедуры полного сброса и используется в процессе начальной наладки для перевода системы в исходное состояние. Для того, чтобы полный сброс не был включен случайно, применяется такой сложный способ вызова этой процедуры. Для определения константы ккгез применяется логическое выражение. Выражение представляет собой логическое умножение четырех кодов. Каждый из этих кодов соответствует одной из четырех, совместно нажимаемых клавиш. В результате выполнения операции логического умножения происходит объединение по функции «И» одноименных разрядов всех кодов, входящих в выражение. В результате мы получим число, в котором каждый разряд будет равен нулю в том случае, если хотя бы в одном из объединяемых чисел, соответствующий разряд тоже равен нулю. В исходном варианте это выглядит следующим образом:

1акои спосоо определения константы дооавляет программе гиокости. Если возникнет необходимость в смене кодов клавиатуры, то переопределять переменную ккгев уже не придется.

Далее в программе идут три группы операторов определения переменных: «Переменные основного цикла», «Переменные ввода/вывода» и «Переменные ПП обмена с 24Схх». В каждой группе описываются переменные одной из трех разных подпрограмм. Более подробно назначение всех этих переменных вы узнаете при рассмотрении соответствующих фрагментов программы. Здесь же я хотел бы остановить ваше внимание всего на нескольких моментах.

Первая строка из группы «Переменные основного цикла» определяет переменную пк и присваивает ей значение 4. Эта переменная предназначена для хранения номера текущего выбранного канала. Причем для хранения этого номера используется две соседние ячейки памяти. Доступ ко второй легко осуществить, используя выражение пк+1. Следующие две строки определяют переменные пкБ и пк1. За ними закрепляются значения, соответствующие регистрам г4 и г5, соответственно. При выборе банка 0, регистр г4 будет соответствовать ячейке памяти с адресом 4 (пк), а регистр г5 соответствовать ячейке 5 (пк+1). Это два способа доступа к одним и тем же переменным.

Почему два способа? А просто при написании программы в одном случае оказалось рациональнее использовать регистры, а в другом удобнее обращаться к ячейке памяти. По той же самой причине двумя способами определена ячейка памяти с адресом 6 (предыдущее состояние клавиатуры). Переменная klold — это доступ к ячейке, как к регистру РОН, а переменная _klold —- это доступ к той же самой ячейке напрямую.

В тексте фрагмента №1 вы можете видеть несколько еще незнакомых вам операторов. Один из них — это оператор USING. Остановимся на нем немного подробнее. Оператор USING тесно связан с выбором банка регистров. При разработке программы я определил для каждого из банков свою область применения. В основном цикле программа использует нулевой банк. Подпрограмма ввода/вывода и динамической индикации использует банк номер один. Подпрограмма обмена с внешней флэш-памятью использует банк номер два. Банк номер три остался в резерве. В связи с этим, при определении соответствующих переменных используются операторы USING О, USING I и USING 2. Эти операторы не переключают банки регистров. Каждый из них лишь сообщает транслятору, что описанные после него регистры принадлежат к тому или иному банку. Эта информация используется транслятором для поиска ошибок.

В группе операторов «Константы для ПП обмена с 24Схх» и «Константы ДУ» никаких особенностей нет. В первой из них происходит определение констант для стандартных подпрограмм обмена информацией с внешней флэш-памятью по протоколу 12С-шины. Во второй, определяются константы для подпрограммы обработки сигналов с пульта ДУ.

Следующая группа команд описывает адреса во внешней флэш-памяти. Энергонезависимая флэш-память используется для хранения не только 99 позиций антенны, но и нескольких переменных, которые не должны потеряться при выключении питания. Для этого резервируется несколько адресов. Для каждого такого адреса имеет смысл определить свою специальную константу.

И последние две маленькие группы команд фрагмента №1 присваивают символьные имена тем разрядам порта Р1, которые имеют в нашей схеме специальное назначение. В данном случае применяется оператор BIT. Думаю из текста программы все ясно.

Используются технологии uCoz