Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Samouchitel

.pdf
Скачиваний:
16
Добавлен:
13.02.2015
Размер:
3.65 Mб
Скачать

Это "дело вкуса" программиста.

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

Запись, в регистр TrisB, числа .65 происходит в 2 приема, так как за один прием записать в него константу нельзя.

Сначала константа .65 записывается в аккумулятор (регистр W): movlw .65 (запись константы

.65 в регистр W), а затем копируется (после копирования, число .65 из регистра W не удаляется, а остается в нем), из регистра W, в регистр TrisB (movwf TrisB).

Итак, задействованные, в принципиальной схеме, выводы порта В, работают в соответствии с ранее сформулированным требованием.

Переходим к содержимому регистра OptionR. Сразу "выбраковываем" то, что не нужно.

Так как внешние тактовые сигналы в работе устройства не используются (внешние сигналы управления не являются тактовыми) и уходов в прерывания нет, то значения 4-го, 5-го и 6-го битов регистра OptionR могут быть любыми.

То есть, они не влияют на работу устройства и поэтому установим их, например, в 0 (а можно и в 1 или в любой комбинации).

Теперь работаем с битами, которые на что-то влияют.

Сначала нужно определиться: задействовать или нет предварительный делитель? Предделитель может быть включен либо перед таймером TMR0, либо после сторожевого таймера WDT.

Внешних тактовых сигналов у нас нет, значит и незачем включать предделитель перед TMR0. Остается WDT.

Давайте поподробнее с ним разберемся.

WDT (сторожевой таймер) сбрасывается командой clrwdt.

Строго говоря, вместо слова "сбрасывается", нужно применять слово "перезапускается", но так как по отношению к WDT, слово "сбрасывается" является стандартным, то его и буду применять.

Имейте это ввиду.

После инициализации ПИКа, по умолчанию (аппаратно), начинается формирование импульса

WDT.

Такой аппаратный запуск происходит только один раз (за одно включение питания), а далее, по ходу отработки программы, WDT (если он включен) нужно программно перезапускать. При каждом перезапуске, к сформированному ранее импульсу, проще говоря, добавляется "довесок/хвостик" продолжительностью 18 мс., и поэтому формирование импульса продолжается (не завершается).

"Примерно" потому, что стабильность временных характеристик управляемого RC-одновибратора с перезапуском (это основа WDT) оставляет желать лучшего. Разработчики ПИКов предлагают ориентироваться на 18 мс.

Если WDT работает без предделителя, то сбрасывать (перезапускать) его необходимо через промежутки времени менее чем 18 мс., то есть, достаточно часто.

Это не всегда бывает удобным из-за необходимости применения относительно большого количество команд clrwdt.

Если после WDT включить предделитель, то максимальный интервал времени перезапуска увеличится. Он будет кратен коэффициенту деления предделителя.

Например, если предделитель с максимальным коэффициентом деления (128) подключен к WDT, то команды clrwdt нужно располагать в тексте программы через промежутки времени меньшие чем 18х128=2304 мс. (2,3 сек.).

То есть, потребуется меньшее количество команд clrwdt, нежели в случае, когда предделитель не подключен к WDT.

Если программа "зависнет" (перезапуски WDT прекращаются), то в данном случае, примерно через 2,3 сек. после начала "зависания", произойдет аппаратный сброс программы на ее начало (исполнение программа начнется с ПП START).

"Не мудрствуя лукаво", применяю это на практике (можно задать и меньший Кдел. предделителя).

Итак, определились: подключаем предделитель, с коэффициентом деления 128, к WDT.

Для этого необходимо установить в 1 первые 4 бита (начиная с младшего) регистра

OptionR.

Остался один 7 бит: включение/выключение подтягивающих резисторов порта В.

91

Если подтягивающие резисторы порта В программно включены, то они автоматически (аппаратно) отключаются от тех выводов порта В, которые работают "на выход" и остаются подключенными к тем выводам порта В, которые работают "на вход".

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

Авот для внешних устройств, подключенных к выводам порта В, работающим "на вход", это важно.

Если оконечные каскады этих внешних устройств имеют "свою" нагрузку (например, в цепи коллектора или в цепи стока), то подключение подтягивающих резисторов может изменить их режим работы по постоянному току.

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

Если эти "бяки" возможны, то подтягивающие резисторы порта В включать не нужно.

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

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

То же самое относится и к внешним, механическим, коммутационным устройствам типа кнопок/тумблеров.

В нашем случае, подтягивающие резисторы порта В включать не нужно, так как выходы внешних устройств, подключенных к выводам RB0 и RB6, имеют "свои" нагрузки. Следовательно, 7-й бит регистра OptionR нужно установить в 1.

То есть, в регистр OptionR нужно записать константу .143 (1000 1111). Можно использовать также и число 8Fh (см. таблицу перевода).

Так как это число является константой, то запись производится через аккумулятор (W). Получается то, что Вы видите в тексте программы: подтягивающие резисторы порта В выключены, и предделитель, с коэффициентом деления 128, включен после WDT.

В 1-м банке "все дела сделаны" и делать в нем больше нечего.

Теперь нужно перейти в основной (нулевой) банк: bcf Status,RP0 (выбор нулевого банка). Идем дальше.

Теперь необходимо определиться с числовыми значениями тех констант, которые определяют величину интервала времени "выхода" сигнала тонального вызова в эфир. Реально, при составлении программы "с чистого листа", ПП START так и заканчивается командой bcf Status,RP0.

И это естественно, так как пока неизвестно, что из себя будет представлять таймер. Только после того, как "конструкция" и принцип работы таймера будут определены и задействованные в нем регистры общего назначения, будут "прописаны", можно рассуждать о записи, в эти регистры, каких-то констант.

Забегая вперед, скажу, что таймер "собран" на регистрах общего назначения SecH и SecL. После их "прописки", а также и "конструирования", на их основе, таймера, группа команд записи констант (4 команды) просто-напросто "врезается" в концовку ПП START (см. текст программы).

Давайте сделаем так: не будем "ставить телегу впереди лошади", а предположим, что программа пишется "с чистого листа" и принцип работы таймера пока не известен.

В этом случае, сразу же после команды bcf Status,RP0, минуя команды операций с константами таймера и расcчитывая на то, что впоследствии, эти команды будут "вставлены" в концовку ПП START (так и происходит при реальном составлении текста программы), переходим к составлению подпрограммы CYCLE,.

Итак, в левом столбце текста программы, "настукиваем" название подпрограммы (CYCLE). Смотрим в блок - схему программы.

Сначала необходимо проверить, управляющий сигнал включения на передачу есть, или его нет?

Ранее мы определились, что сигналу включения на передачу соответствует 0, а выключения1. Этот сигнал присутствует на выводе RB0, который настроен на работу "на вход". Следовательно, нужно опросить состояние этого вывода, и в зависимости от результата

92

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

Для этого нужно предельно четко и ясно сформулировать алгоритм производимой логической операции.

Он формулируется следующим образом:

1.Если нулевой бит регистра PortB (он соответствует выводу RB0) равен 1 (передача выключена), то тональный сигнал формироваться не должен, и рабочая точка программы должна где-то "закольцеваться" (напоминаю, что выполнение программы не должно останавливаться), до момента появления, на выводе RB0, нулевого уровня.

2.Если нулевой бит регистра PortB равен 0 (передача включена), то должно начаться

формирование тонального сигнала (программа должна исполняться далее). Эта формулировка достаточно конкретна, но не совсем.

Лирическое отступление: любой микроконтроллер, также как и любая микро-ЭВМ, это всеголишь "бездушная железяка".

И эта "железяка абсолютно не терпит" неопределенности.

Для того чтобы она заработала, необходимо избавиться от любой неопределенности.

Вконечном итоге, задача любого программиста сводится к "борьбе" с неопределенностями и к умению четко формулировать алгоритмы работы всех составных частей программы.

Это присутствует всегда, но особенно ярко это проявляется при работе с командами ветвления.

Итак, устраняем неопределенность, которая заключается в том, что пока, не понятно, каким образом и куда именно необходимо перейти рабочей точке программы, для того чтобы там "закольцеваться"?

Если речь идет о том, что нужно куда-то перейти, то сама собой возникает мысль о том, что этот переход можно осуществить, используя команду перехода.

Вопрос: какую именно команду перехода использовать? Анализируем.

"Закольцовывать" рабочую точку программы в командах, расположенных ниже (по тексту программы) нельзя, так как ниже будут располагаться команды, формирующие сигнал тонального вызова, а в соответствии со сформулированным выше алгоритмом, при наличии, на выводе RB0, единицы, сигнал тонального вызова формироваться не должен.

Остается только одно "место" подпрограмма START. Следовательно, нужно перейти в нее.

Вэтом случае, рабочая точка программы будет "крутиться по кольцу", "границы" которого: от первой команды ПП START и до команды перехода в ПП START.

Теперь остается только выяснить, какой из двух видов переходов применить (безусловный или условный)?

Условный переход, то есть, переход с использованием стека, применять нет смысла хотя бы потому, что для возврата по стеку требуется лишняя команда (команда возврата), да и вообще, смысла задействовать, для выполнения элементарной "закольцовки", стек, нет. Вполне достаточно команды безусловного перехода goto.

Вданном случае (на выводе RB0 1), команда goto, на каждом "витке", просто будет

"отфутболивать" рабочую точку программы на первую команду ПП START. До тех пор, пока, на выводе RB0, 1 не сменится на 0.

Итак, устраняем последнюю неопределенность: при наличии, на выводе RB0, единицы, должен быть осуществлен безусловный переход в ПП START.

В конечном виде, алгоритм проверки формулируется так:

-если бит №0 регистра PortB (вывод RB0) равен 1 (передача выключена), то должен

быть осуществлен безусловный переход в ПП START,

-а если бит №0 регистра PortB равен 0 (передача включена), то программа должна

исполняться далее.

Всё... Полная определенность.

Теперь нужно просто подобрать нужную команду ветвления.

Естественно, что эта команда должна быть бит-ориентированной (происходит обращение к отдельному биту).

Смотрим в список команд. Таких команд две: btfsc и btfss.

Команда btfss не подходит, так как сразу же после команды ветвления, необходимо будет

93

устанавливать две команды переходов, устанавливать метку и вообще, неэффективно "ломать голову по поводу выхода из вилки". Зачем нужен этот "геморрой"?

А вот btfsc - в самый раз.

Втексте программы cus, посмотрите на первые две команды ПП CYCLE. Прочитайте комментарии. Мне к ним добавить просто нечего.

Не правда ли, как просто.

Единственное, что можно добавить: словосочетание "программа исполняется далее" означает то, что следующей будет исполняться команда btfss PortB,6

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

Если одним из этих сценариев является сценарий типа "программа исполняется далее", то вторым сценарием, в большинстве случаев (но не всегда), является сценарий типа "переход куда-то" (в подпрограмму, на метку), причем, команда, на которую переходит рабочая точка программы по сценарию "программа исполняется далее", должна быть второй снизу (по тексту программы), от команды ветвления, так как только в этом случае программа может "исполняться далее".

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

Вэтом случае, осуществляется либо первый, либо второй переход.

Таким образом, сценарий типа "программа исполняется далее" связан с исполнением второй, после команды ветвления, команды.

Идем дальше.

Смотрим в блок-схему программы.

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

Разница заключается в следующем.

Работа происходит с битом № 6 регистра PortB.

Уровни управляющего сигнала "привязаны" к другому органу управления. Переход, с целью "закольцовки" рабочей точки программы в "вечном кольце", осуществляется в подпрограмму PRD.

Для реализации алгоритма проверки, использована команда btfss. А теперь - потренируйтесь.

Постарайтесь самостоятельно понять, "где здесь собака порылась" и почему нужно организовывать эту проверку в том виде, в котором она организована в тексте программы (почему не используется команда btfsc?).

Указанные выше, 2 проверки, идущие подряд одна за другой, выполняют роль своеобразного "сита".

Результат их совместной работы таков, что для того чтобы началось формирование сигнала тонального вызова, необходимо одновременное выполнение 2-х условий:

-режим тонального вызова должен быть включен,

-и р/станция должна быть включена на передачу.

Подобного рода "сита", при составлении программ, применяются сплошь и рядом. Если нужно обеспечить одновременное выполнение, например, 3-х или 4-х условий, то применяются 3 или 4 проверки.

В большинстве случаев, такие проверки "идут друг за другом", но они могут быть и разнесены.

О подпрограмме PRD.

Загляните в блок-схему программы.

ПП PRD нужна для того, чтобы, после 3-хсекундной "выдачи" в эфир сигнала тонального вызова, рабочая точка программы либо "закольцевалась" в этой подпрограмме (если передача включена), либо "ушла" на новый "виток" полного цикла программы (если передача выключена).

Если текст программы составляется "с чистого листа" и программист находится на теперешней стадии ее составления, то при проверке включения или выключения режима тонального вызова, в команде безусловного перехода goto, просто указывается название подпрограммы (PRD), а саму эту подпрограмму можно составить позднее.

94

То есть, тогда, когда "до нее дойдет дело" (что и будет сделано в дальнейшем).

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

При этом, можно пропускать команды, групп команд и даже целые подпрограммы, работающие с содержимым регистров, которые еще не "введены в бой" (но будут "введены" в будущем), в том числе и с переходами в подпрограммы, которые еще не созданы (но будут созданы в будущем).

Можно пропускать даже несколько подпрограмм, с расчетом на их создание/проработку в будущем (приходит с опытом).

В любом случае, нужно быть уверенным в том, что "стратегических ляпов" не допущено (блок-схема программы капитально продумана).

"Самоучитель по программированию PIC контроллеров для начинающих" http://ikarab.narod.ru E-mail: karabea@lipetsk.ru

95

8. Пример создания программы (продолжение)

Итак, мы остановились на том, что, в ходе описанных выше проверок, состояния выводов RB0 и RB6 анализируются, и в зависимости от соотношения уровней сигналов на этих выводах, рабочая точка программы либо "закольцовывается" в ПП START, либо "закольцовывается" в ПП PRD (в обеих случаях "уход в вечное кольцо", с выходом из него по внешнему воздействию), либо она "движется далее" по тексту программы (сценарий типа "программа исполняется далее").

Первый случай был описан выше. Это самая простая "закольцовка".

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

После выключения с передачи, рабочая точка программы должна "прыгнуть" в ПП START, в которой должна "уйти в еще одно вечное кольцо", выход из которого происходит в момент переключения с приема на передачу.

Втретьем случае, рабочая точка программы должна продолжить свое "движение" вниз по тексту программы.

Смотрим в блок - схему программы.

Теперь необходимо сформировать один период сигнала тонального вызова, соответствующий частоте 1450 Гц.

То есть, сначала нужно сформировать первую половину периода (полупериод), а затем, вторую (форма сигнала – "меандр").

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

Вывод RB2 работает "на выход" (см. подготовительные операции), а это означает то, что к этому выводу подключен выход защелки, которая управляется вторым битом регистра PortB. Таким образом, устанавливая бит №2 регистра PortB в 0 или 1 и задерживая момент следующей смены состояний этого бита, можно сформировать нужный период. Зависимость простая: если бит №2 регистра PortB установить в 0, то на выходе соответствующей защелки, а следовательно и на выводе RB2, установится 0, а если 1, то установится 1.

Напоминаю, что защелка это триггер, и если он установлен управляющим импульсом (командой, которая его формирует) в какое-то одно из двух своих состояний, то он будет находиться в этом состоянии вплоть до поступления следующего управляющего импульса (формируется другой командой).

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

Из этого следует то, что после установки, на выводе RB2, например, того же нулевого уровня, рабочая точка программы может "скакать" по каким-то другим командам, производя при этом действия, не связанные с управлением защелками порта В.

Следовательно, после смены уровней на выводе RB2, можно, на определенное время, "закольцевать" рабочую точку программы в подпрограммах задержки, и за счет этого, сформировать интервалы времени полупериодов. А значит и период.

Этим сейчас и займемся.

Сначала нужно определиться, с какого уровня начинать формирование полупериода: с нулевого или с единичного?

Вданном случае, ничего синхронизировать не нужно.

Значит, формирование периода можно начать с любого уровня. Начнем, например, с нулевого.

Для того чтобы начать формирование нулевого уровня на выводе RB2, необходимо установить в ноль бит №2 регистра PortB.

Делаем это при помощи бит-ориентированной команды bcf (bcf PortB,2). Далее Вы видите три NOPа.

При составлении программы с "чистого листа", изначально, их нет.

Это "элементы" точной установки ("подгонки") интервала времени отрицательного полупериода под заданное значение.

Они "врезаются" в текст программы после "прогонки" подпрограммы задержки через секундомер MPLABа (об этом, позднее).

Теперь нужно "закольцевать" рабочую точку программы в подпрограмме задержки, которая

96

ранее названа PAUSE_1.

Ее "конструкция" должна быть Вам понятна.

Эта подпрограмма задержки построена "по образу и подобию", рассмотренной ранее, подпрограммы задержки программы Multi.asm.

Следовательно, необходимо, в качестве счетчика, назначить регистр (регистры) общего назначения.

Количество этих регистров зависит от величины времени задержки.

Чем большее время задержки нужно обеспечить, тем большее количество регистров требуется.

Расчет их количества и "грубое" определение величины константы/констант: Период сигнала с частотой 1450 Гц. = 689,6 мкс., а полупериод 344,8 мкс.

Так как в данном случае, время отработки одного машинного цикла равно 1 мкс., то округляем величину интервала времени полупериода до 345 мкс.

Именно такую величину задержки и нужно сформировать.

Полный цикл рассматриваемой подпрограммы задержки составляет 3 м.ц. (3 мкс.), плюс 2 м.ц. (2 мкс.) на последнем "витке".

Если применить конструкцию ПП задержки программы Multi.asm, то одним регистром можно обеспечить задержку до 256х3-1=767 мкс.

Полупериод равен 345 мкс., следовательно, достаточно одного регистра общего назначения.

Если речь идет о задержках, то уместно вспомнить о том, что не мешало бы сбросить WDT (вспомните, по ходу выполнения программы, его нужно периодически сбрасывать). Команду clrwdt можно поставить следующей, после команды bcf PortB,2 c сохранением 3-хмикросекундного, полного цикла ПП задержки, а можно и "врезать" команду clrwdt в полный цикл ПП задержки, увеличив тем самым полный цикл ПП задержки c 3 мкс. до 4 мкс. (команда clrwdt выполняется за 1 м.ц.).

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

По большому счету, выгоднее "врЕзать" команду clrwdt в цикл ПП задержки, чем размещать ее после команды bcf PortB,2.

Вэтом случае, сброс WDT будет происходить чаще (1 раз за 4 мкс., вместо 1 раза за 690 мкс.).

Втексте программы cus, Вы видите именно такой вариант построения ПП задержки (с

"врезкой"), который я применил не столько по причине необходимости столь частого сброса WDT (такой необходимости нет), сколько в обучающих целях.

Дело в том, что "врезая" в нее другие команды ("по образу и подобию" указанной выше "врезки"), время отработки цикла ПП задержки можно сделать гораздо бОльшим, чем 3 м.ц.

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

А ведь вместо одной команды можно "врезать" и несколько.

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

И чем "массивнее врезка", тем бОльшим будет это увеличение.

Если в интервале времени отработки ПП задержки, не нужно производить никаких действий (нужно просто увеличить время отработки ПП задержки), то "врезается" NOP (NOPы). Таким же образом, в подпрограмму задержки, можно "врезать" группу команд, производящих действия, подпрограмму (в том числе и циклическую), группу подпрограмм, а также и все это в комплексе и в любой комбинации (оценИте открывшуюся перспективу …).

Вкачестве примера, можно привести любую программу частотомера.

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

Всё, что касается такого рода "врезок", очень важно, и на это обязательно нужно обратить самое пристальное внимание.

Для того чтобы "закрыть" эту тему, приведу практический пример:

Предположим, что используется классическая конструкция ПП задержки (как в программе Multi.asm), обеспечивающая максимальное время задержки 767 мкс., а нужно сформировать задержку в 1000 мкс.

Можно задействовать второй регистр общего назначения, а можно обойтись и одним, "встроив" в ПП задержки всего один NOP.

97

Вэтом случае, полный цикл ПП задержки увеличивается с 3-х до 4-х м.ц., и при помощи такой ПП задержки можно сформировать задержки до 256х4-1=1023 м.ц. (1023 мкс.)

Задержка в 1000 мкс. попадает в этот интервал, следовательно, можно обойтись одним регистром общего назначения.

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

Ранее было выяснено, что для того чтобы обеспечить задержку в 345 мкс., достаточно одного регистра общего назначения (даже без "врезки").

Если, при 4-х машинных циклах полного цикла ПП PAUSE_1 (с "врезкой" clrwdt), обеспечивается максимальная задержка в 1023 мкс. (что соответствует максимальному значению константы .255), то значению времени задержки 345 мкс. будет соответствовать значение константы 345х255:1023=85,99...

Округляем до 86-ти.

При написании программы "с чистого листа", значение этой константы (.86) и нужно "прописать" в тексте программы.

Втексте программы cus, Вы видите другое значение константы (.85) и три NOPа.

Такого рода числовая коррекция произойдет позднее, при отладке временных характеристик программы в симуляторе (я расскажу об этом подробно), а пока используем результат "грубой прикидки" (.86).

Теперь остается только придумать название этого регистра (назовем его Sec) и "прописать" его в "шапке" программы ("прописываем"его по адресу 0Ch, но можно назначить и другой). Вот вам и ответ на вопрос: "Откуда, в "шапке" программы, взялся регистр Sec и каков механизм его возникновения".

После этого, константа .86, обычным образом (за 2 приема, через регистр W), записывается в "новорожденный" регистр Sec.

Эту запись нужно произвести до первой команды подпрограммы (PAUSE_1 или PAUSE_2), в которой используется этот регистр.

Далее располагаются 3 команды ПП PAUSE_1, комментарии к которым Вы найдете в тексте программы и к которым мне добавить нечего.

Идем дальше.

Теперь необходимо сформировать положительный полупериод.

По своей конструкции, ПП PAUSE_2 такая же, как и ПП PAUSE_1, только, перед ее началом, в бит 2 регистра PortB, записывается 1, и безусловный переход осуществляется на начало ПП PAUSE_2.

Регистр Sec уже имеется в наличии, так что ничего "назначать и прописывать" не нужно.

На момент перехода рабочей точки программы на команду bsf PortB,2 , в регистре Sec будет "лежать" ноль (конечный результат декремента содержимого регистра Sec в ПП PAUSE_1). Поэтому, перед "влётом" в ПП PAUSE_2, в регистр Sec, нужно записать "новую" константу. Она будет определять продолжительность положительного полупериода.

При написании программы "с чистого листа", в качестве этой константы, с расчетом на осуществление дальнейшей коррекции числового значения константы, можно использовать всё то же число .86.

Изначально, NOPов также нет. Все это оставляется "на потом". Почему, в тексте программы cus, Вы видите число .83, узнаете позже.

Примечание: классическая подпрограмма задержки (такая, как в программе Multi.asm), и она же, но с "врезкой" (такая, как в программе cus), по своей сути, есть вычитающий счетчик импульсов, то есть, абсолютно необходимое, в цифровой технике, устройство.

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

Но на самом деле, импульсы есть, и считаются именно они, так как результатом исполнения команды (например, такой как decfsz) является активный перепад (строб), аппаратно формируемый внутри микроконтроллера (его прохождение нельзя проконтролировать с помощью приборов), который и уменьшает (или увеличивает, если применяется команда incfsz) на единицу содержимое регистра-счетчика (в данном случае, Sec).

Также следует иметь ввиду, что в части касающейся м/контроллеров, счетчик реализуется не одними только аппаратными средствами (например, как в 555ИЕ2), но и программными средствами (в комплексе).

98

И в самом деле, для того чтобы создать счетчик, необходимо не только задействовать (назначить), в качестве счетчика, регистр/регистры общего назначения (все регистры области оперативной памяти реализованы аппаратно), но и "встроить" его/их в циклическую ПП задержки, в состав которой должны входить байт-ориентированные команды ветвления incfsz и/или decfsz (они управляют регистром/регистрами).

Впервом случае, получается суммирующий, а во втором случае, вычитающий счетчик. Практический вывод из этого следующий.

Для создания однобайтного счетчика, необходимо назначить, в качестве счетчика, регистр общего назначения, определить его начальную установку, предварительно (до входа в цикл счета) записав в этот регистр константу, и программно организовать циклическую подпрограмму задержки, с использованием команд incfsz

(суммирующий счетчик) или decfsz (вычитающий счетчик).

Если речь идет о многобайтном счетчике, то все то же самое, только во множественном числе.

Примите к сведению: если счетчик, например, двухбайтный (используются 2 регистра общего назначения), то он не обязательно должен быть только суммирующим или только вычитающим. Он может быть еще и комбинированным: один его разряд может работать на суммирование, а другой, на вычитание (или наоборот). Такие счетчики используются редко. Пример реализации двухразрядного, вычитающего счетчика будет рассмотрен ниже.

ПП задержки не должна отрабатываться все время.

Если такое произойдет, то рабочая точка программы просто "зависнет" в этой подпрограмме. Счетчик должен считать, от предварительно записанного в него числа (так называемая предустановка), до момента установки в нем нуля ("очищение"), после чего рабочая точка программы должна выйти из ПП задержки по сценарию "программа исполняется далее". Даже в случае "ухода" рабочей точки программы в "вечное кольцо" (специфическая разновидность счетчика без предустановки. "Ловушка рабочей точки"), она все-равно рано или поздно из него выходит. По внешнему воздействию (например, после нажатия кнопки). Понятия "счетчик" и "задержка" - два "сиамских близнеца" и их нельзя отделить друг от друга. И в самом деле, счетчик, при условии, что он когда-то "остановится", всегда обеспечивает какую-то задержку, а задержка какого-то процесса на время, кратное машинному циклу, предполагает их подсчет, то есть, применение счетчика.

Таким образом, ПП PAUSE_1 или PAUSE_2 можно описать так: циклическая подпрограмма

задержки с "врезкой" из одной команды, на основе однобайтного, вычитающего счетчика, с предустановкой и выходом из полного цикла подпрограммы после его очистки (после окончания счета).

Если "привязаться к понятию "закольцовка", то в части касающейся стандартных ПП задержек, можно сказать так: "закольцовка" рабочей точки программы в ПП задержки,

создает задержку выполнения следующей, после ПП задержки, команды. Суть "закольцовки" - многократная отработка цикла ПП задержки, вплоть до очищения регистра общего назначения, выполняющего функцию счетчика.

Вэтом случае, речь идет о калиброванном времени задержки.

Пример: ПП PAUSE_1 и PAUSE_2.

Если речь идет о "вечном кольце", то такие "закольцовки" есть в ПП START и PRD. Если кто-то из Вас не до конца понял правила функционирования этих "механизмов", то вернитесь назад.

В идеале (пусть не сейчас, а в будущем), у Вас должно сложиться свое индивидуальное, образное восприятие подобного рода процессов, которое очень помогает при составлении текстов программ.

Обращаю Ваше внимание на следующее: такого рода общие рассуждения следует рассматривать не как мешающее отвлечение от "разборок" с текстом программы, а как насущную необходимость, связанную с капитальным осознанием смысла того, о чем идет речь.

Без этого осознания, работа конструктора напоминает езду на машине в условиях густого тумана.

Прошу отнестись к этим общим рассуждениям/выводам со всей серьезностью.

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

99

А вот теперь, со спокойной совестью, можно перейти к дальнейшим "разборкам" с программой cus.

Мы остановились на том, что сформировали оба полупериода (то есть, один период) тонального сигнала вызова.

Естественно, что этого маловато.

Нужно последовательно сформировать несколько тысяч таких периодов, и причем так, чтобы обеспечить заданную скважность ("меандр". Полупериоды равны друг другу).

Так как интервал времени "выдачи" сигнала тонального вызова в эфир вовсе не обязательно в точности делать равным 3 секундам, то задачу можно сформулировать так: сигнал тонального вызова должен "выдаваться" в эфир в течение приблизительно 3-х секунд.

Не трудно догадаться, что после окончания формирования одного периода, нужно сразу же начать формирование следующего периода, и т.д.

До тех пор, пока не сформируется трехсекундный интервал времени "выдачи" сигнала тонального вызова в эфир.

Теперь переходим к устранению всех неопределенностей, а иначе ПИК "не поймет, что он должен сделать и будет с Вами конфликтовать".

Предположим, что мы работаем "с чистого листа".

На данный момент составления текста программы, известно, что при переходе с приема на передачу (на выводе RB0 1 меняется на 0), должен быть запущен некий счетчик времени (таймер), который отмеряет приблизительно 3 секунды.

По окончании формирования этого интервала времени, должно быть выполнено следующее:

-если р/станция включена на передачу, то рабочая точка программы должна "уйти в вечное кольцо" подпрограммы PRD (ее еще нет. Не "родилась" еще. Мы просто дали ей название, а что в ней "тайна покрытая мраком") и выйти из него при переключении с передачи на прием (переход на "новый", полный цикл программы),

-если р/станция включена на прием, то рабочая точка программы сразу же должна уйти в "вечное кольцо" подпрограммы START и выйти из него при переключении с приема на

передачу (см. блок-схему программы). Детализируем.

Так как сначала нужно сформировать трехсекундный интервал времени "выдачи" сигнала тонального вызова в эфир, а только после этого производить "уход в вечное кольцо", то группа команд, производящих операции с таймером, должна быть расположена в тексте программы сразу же после последней команды ПП PAUSE_2, а группа команд ПП PRD должна следовать сразу же после последней команды группы команд, производящих операции с таймером.

Теперь порядок следования ясен и можно перейти к конструированию таймера.

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

Так как необходимо сформировать фиксированный интервал времени и после этого "уйти" в сценарий "программа исполняется далее" (перейти в ПП PRD), то очевидно, что счетчик можно построить "по образу и подобию" рассмотренного выше счетчика (см. ПП PAUSE_1 и PAUSE_2).

В этом случае, все очень просто: все 3 команды подпрограммы, например, PAUSE_1 (вместе с названием ПП) просто вставляются (копируются) в текст программы сразу же после команды goto PAUSE_2.

Теперь нужно "навести порядок".

Название ПП (PAUSE_1) необходимо либо заменить (текст программы не должен содержать две ПП с одинаковым названием), либо удалить из текста программы.

Кроме того, нужно определиться, на какую ПП (или метку) необходимо осуществить безусловный переход (goto)?

Считать необходимо количество периодов, следовательно, для организации "закольцовки" счетчика, формально, нужно перейти на ту команду, с которой начинается формирование периода. То есть, на команду bcf PortB,2

Посмотрите в текст программы cus.

Эта команда не является первой командой подпрограммы, и она ничем не помечена (метка не установлена).

Для того чтобы на нее перейти, необходимо придумать какое-нибудь название для метки и "пометить" ей данную команду.

100

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]