Файл: Самоучитель по программированию PIC контроллеров для начинающих (Е.А. Корабельников,2008).pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 16.06.2025

Просмотров: 3598

Скачиваний: 3

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

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

И это должно быть понятным, так как программа исполняется последовательно (сразу две задержки формироваться не могут).

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

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

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

ВПП прерывания имеется, аналогичный описанным выше, двухразрядный счетчик на регистрах SecH_2 и SecL_2.

Пары регистров SecH_2, SecL_2 и SecH_1, Sec_L1 можно объединить в одну пару, так как на момент начала работы одного счетчика, содержимое другого счетчика очищено (не значимо). А вот регистры SecH_2, Sec_L2 и SecH, SecL объединить нельзя, так как содержимое счетчика SecH, SecL значимо.

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

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

Теперь вернемся к счетчику интервала времени сканирования.

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

Всоответствии со сформулированным ранее алгоритмом работы устройства, во время формирования интервала времени сканирования, рабочая точка программы должна (при наличии активного перепада на выводе RB0) уйти в ПП прерываний.

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

Вначале этой "зоны", нужно разрешить внешние прерывания INT.

Разрешить их до исполнения команд (или между ними) записи констант, в регистры счетчика (SecH, Sec_L), можно, но в данном случае, я "привязался" непосредственно к началу счета. Поэтому, команды записи константы, в регистр IntCon, расположены именно в том месте, где Вы их видите (см. текст программы Retr_1.asm).

В регистре IntCon, биты №4 и 7 установлены в 1 (в остальных, 0).

Это и есть разрешение прерываний INT (все остальные виды прерываний, которыми управляет регистр IntCon, запрещены нулями).

Общая особенность: при разрешении любого вида прерываний, бит глобального

разрешения прерываний должен быть установлен в 1.

Если прерывания INT разрешены (бит №4 = 1), а глобального разрешения прерываний нет (бит №7 = 0), то никаких прерываний Вы не дождетесь (в том числе и INT).

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

Запретить все прерывания также можно, установив в 0 один только 7-й бит регистра IntCon (bcf IntCon,7), но зачем, на первых порах, "напрягаться"?

Проще сбросить весь байт в 0, и дело с концом. Что и сделано. А вообще, это личный выбор каждого.

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

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

При этом, содержимое регистра Trigg можно или декрементировать, или инкрементировать. Так как речь идет о проверке на четность (используется только бит №0. Числовое значение байта может быть любым), то это "что в лоб, что по лбу".

Выбираю инкремент.

Самое главное, это ответ на вопрос: "Какое это число: четное (бит №0 = 0) или нечетное

147


(бит №0 = 1)"?

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

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

После того, как произведен инкремент (см. конец текста программы) содержимого регистра Trigg (incf Trigg,F), можно переходить на "новый", полный цикл "основного тела" программы

(goto START).

Обратите внимание на то, что применена команда incf, которая не является командой ветвления.

В данном случае, "ветвиться" не нужно. Поэтому она и применена.

Итак, мы "прошли по основному телу" программы, исходя из предположения, что активных перепадов "ухода" в прерывание (по входу RB0/INT) не поступало.

Теперь предположим, что на вывод RB0/INT, от внешнего устройства, поступил активный перепад (от 1 к 0).

Если это событие произошло во время отработки "зоны" разрешения прерываний, то произойдет условный переход ("виртуальная" команда call. Формируется аппаратно) на первую команду ПП прерывания (В PC, адрес 04h).

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

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

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

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

прерывательный вектор", хотя и с внушающим уважение названием, но как-то не слишком "комфортно ложащийся в мозги".

Cие вполне можно сформулировать и на "нормальном языке": условный переход, с помощью аппаратно формируемой команды call, в ячейку PC с фиксированным адресом 04h.

Ивсе дела. И вектор не при чём ("усоп за ненужностью"). Вернемся к нашим "разборкам".

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

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

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

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

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

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

Процедура сохранения и восстановления содержимого регистров W и Status, в обучающих целях, в тексте программы, отображена в полном объеме, хотя в данном случае, содержимое регистра W можно и не сохранять (а соответственно, и не восстанавливать).

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

Поэтому можно смело аннулировать "прописку" регистра W_Temp, а заодно и команды сохранения/восстановления содержимого регистра W.

148


Мало того, то же самое относится и к регистру Status.

И в самом деле, уходы в прерывания происходит в 0-м банке, и работа, в ПП прерывания, происходит в нулевом банке (банк не меняется).

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

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

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

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

Необходимо произвести проверку: несущая есть/нет?

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

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

Впростейшем случае, можно, после команды goto EndInt "поставить" команду goto CYCLE, "закольцевав" тем самым рабочую точку программы в "вечном кольце" из 3-х команд (сверху вниз: btfsc PortB,0, goto EndInt, goto CYCLE), но в этом случае, проверки нулевого бита регистра PortB будут производиться так быстро и так часто, что это может отразиться на качестве работы ПП устройства.

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

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

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

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

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

Впрограмме Retr_1.asm, время отработки цикла ПП CYCLE составляет 5,62 мс. (можно проверить в симуляторе).

Это мой субъективный выбор, можно установить и какое-то другое значение, соответствующим образом изменив значения констант.

Можно также упростить ПП CYCLE, заменив 2-хразрядный счетчик на 1-разрядный.

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

Втексте программы, найдите ПП CYCLE и посмотрите, как сказанное выше, реализуется на практике.

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

При выходе из ПП прерывания (см. ПП EndInt), нужно обязательно сбросить флаг прерывания INT (bcf IntCon,1), восстановить содержимое "жизненноважных" регистров и исполнить команду возврата из прерывания retfie.

Пример: если уход в прерывание произошел во время исполнения команды incfsz SecH,F, то после возврата из ПП прерывания, рабочая точка программы "встанет" на следующую (после incfsz SecH,F) команду (goto PAUSE).

После этого, работа в "основном теле" программы будет продолжена.

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

149


Пояснение: в тексте программы Retr_1.asm, Вы не найдете команд переходов в ПП TRIGGER (аналогия с ПП INT).

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

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

При работе с программой cus, сначала была выполнена отладка, а затем, отслеживание. При работе с программой Retr_1.asm, поступим наоборот, то есть "так, как положено".

Отслеживание работы программы в ее "основном теле"

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

"Врежьте" в "шапку" программы команду goto INT (об этом см. выше). Сначала работаем в "основном теле" программы.

Заблокируйте команду goto INT точкой с запятой. Команду goto START блокировать не нужно.

Сначала "прогоним" рабочую точку программы по тому сценарию ее работы, который определяют настройки MPLAB по умолчанию.

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

Так как были внесены изменения, производим ассемблирование и устанавливаем рабочую точку программы на ее начало.

Пошагово исполняем программу (F7).

Команды ПП START "проходим без осложнений" ("линейный участок").

ПП START программы Retr_1.asm построена аналогично ПП START программы cus, и поэтому останавливаться на ее отслеживании я не буду, сделайте это сами и убедитесь, что, по ходу ее исполнения, все прерывания запрещаются, вывод RB0 настраивается на работу "на вход", вывод RB2 настраивается на работу "на выход", включаются подтягивающие резисторы порта В и прерывания INT будут происходить по заднему фронту внешнего, управляющего сигнала.

Первой командой ПП TRIGGER является бит-ориентированная команда ветвления btfsc Trigg,0.

Смотрим в окно RAM.

По адресу 0Ch (адрес регистра Trigg в области оперативной памяти, "прописанный" в "шапке" программы), на момент исполнения этой команды, записано число 00h. Следовательно, 0-й бит регистра Trigg установлен в 0, и в соответствии с алгоритмом работы команды btfsc, следующей после нее, должна исполниться группа команд записи константы .251 в регистр PortB.

Что и имеет место быть (проверьте и убедитесь в этом). "Стукаем" по F7.

"Доходим" до команды goto Metka_1 и исполняем ее, осуществив безусловный переход на команду, помеченную меткой Metka_1 (movlw .197).

Далее, исполняем процедуру записи констант в регистры SecH_1 и SecL_1, команду "врезки" в ПП задержки PAUSE_D (clrwdt) и устанавливаем рабочую точку программы на команду decfsz SecL_1,F.

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

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

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

Рабочая точка "встала" на команду movlw .245.

Далее, исполняем все последующие команды и устанавливаем рабочую точку программы на

"врезку" ПП PAUSE (clrwdt).

По ходу этого исполнения убеждаемся, что в регистры SecH и SecL записались числа .245 (F5h) и .255 (FFh) соответственно, а в регистр IntCon записалось число .144 (90h/10010000). По своей конструкции, ПП PAUSE такая же, как и ПП PAUSE_D.

150