Файл: Самоучитель по программированию PIC контроллеров для начинающих (Е.А. Корабельников,2008).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 16.06.2025
Просмотров: 3635
Скачиваний: 3
Вэтом случае, полный цикл ПП задержки увеличивается с 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
Например, Metka_1 bcf PortB,2
После этого, можно осуществить безусловный переход на метку (goto Metka_1). Это конечно сделать можно, но есть более выгодный вариант - переход в ПП CYCLE.
Вэтом случае, задействуются команды обеих проверок, которые рассматривались выше. Этот вариант выгоден тем, что если выключение с передачи происходит во время формирования сигнала тонального вызова (во время 3-хсекундного интервала времени), то в момент перехода с передачи на прием, формирование сигнала тонального вызова тут же прекращается.
За счет "закольцовки" рабочей точки программы (уход в "вечное кольцо") в ПП START ("зона" кольца: от 1-й команды ПП START до команды goto START).
Вэтом случае, метку выставлять не нужно.
Вслучае перехода на команду bcf PortB,2, "помеченную" меткой, трехсекундный интервал сформируется полностью, и только после этого рабочая точка программы "уйдет в вечное кольцо" ПП START.
С практической точки зрения, вариант с переходом на метку неудобен тем, что в некоторых случаях, пьезоэлектрический излучатель будет выдавать тональный сигнал тогда, когда передатчик не работает (работа на прием), что не совсем удобно для пользователя.
Итак, осуществляем безусловный переход в ПП CYCLE (заменяем команду goto PAUSE_1 на команду goto CYCLE).
Название подпрограммы (PAUSE_1), по причине ненужности (безусловный переход осуществляется в ПП CYCLE), из текста программы убирается.
Таким образом, все команды программы, от 1-й командой ПП CYCLE и до команды
decfsz SecL,F, можно считать "врезкой" в "кольцо" циклической ПП задержки CYCLE, которая "проходится" рабочей точкой программы за время, равное одному периоду сигнала тонального вызова.
"Старую" "врезку" (clrwdt) можно удалить, так как WDT, при формировании периода, и без этого сбрасывается часто.
Теперь можно сформировать трехсекундный интервал времени. Период тонального сигнала равен 690 мкс. (см. выше).
Таким образом, необходим счетчик, считающий, как минимум, до 3000000:690=4347,826 (округляем) =4348.
"Грубая прикидка": при применении стандартной ПП задержки (полный цикл ПП = 3 м.ц.), значение константы, записываемой в назначенный, в качестве счетчика, регистр общего назначения, должно быть 4348:3= приблизительно 1450.
Максимальное значение константы, которую можно "заложить" в один регистр, равно .255 На одном регистре общего назначения, при использовании хитроумной "врезки" типа дополнительной ПП задержки, собрать такой счетчик, конечно же, можно, но это не самый лучший выход из положения (потребуется много команд).
Гораздо удобнее и проще применить двухбайтный счетчик (не путать с двумя однобайтными счетчиками!).
Такой счетчик считает до 256х256=65536 и, с его помощью, можно сформировать (применительно к нашему случаю) не только трехсекундный интервал времени, но и гораздо больший.
Если речь идет о нескольких байтах, то нужно определить порядок их старшинства. Старший байт пометим буквой H, а младший, буквой L.
Примечание: такого рода пометки - стандарт, хотя можно и придумать что-нибудь свое. Если счетчик трехбайтный, то добавляется буква M - средний байт (порядок старшинства: H, M, L), а если четырехбайтный, то добавляются буквы HH - "старший старшего" (порядок старшинства: HH, H, M, L).
Под это дело, в "шапке" программы, "прописываем" регистры общего назначения с названиями SecH (в нем "лежит" старший байт) и SecL (в нем "лежит" младший байт) и назначаем им адреса в области оперативной памяти.
Например: 0Dh и 0Eh соответственно.
Вот Вам и ответ на вопрос: откуда, в "шапке" программы, взялись регистры SecH и SecL?
Вчасти, касающейся рассматриваемой группы команд, получилось то, что Вы видите в тексте программы cus.
Давайте разберемся с 2-байтным счетчиком (что это такое и откуда что взялось?). Стандартный принцип организации работы 2-байтного вычитающего счетчика:
- сначала декрементируется содержимое регистра младшего байта,
101