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

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

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

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

Добавлен: 16.06.2025

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

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

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

Значит, назначаем точку остановки на команде clrf IntCon, включаем "автомат" и дожидаемся конца процесса.

Исполняем команду clrf IntCon и убеждаемся, что содержимое регистра IntCon изменилось с

.144 на .00.

Запоминаем значение числа, записанного в регистр Trigg (в окне RAM, адрес 0Ch), исполняем команду incf Trigg,F и оцениваем изменение, произошедшее с содержимым регистра Trigg.

Значение записанного в регистр Trigg числа, должно увеличиться на 1. Исполняем команду goto START.

Рабочая точка программы "встанет" на первую команду ПП START.

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

Один сценарий работы отслежен. Отслеживаем следующий сценарий. Ищем первую, после команды clrf IntCon, команду ветвления.

Это команда btfsc Trigg,0.

Один сценарий ветвления этой команды мы уже отследили. Отслеживаем второй. Вспоминаем про "уловки".

Заменяем команду btfsc Trigg,0 на команду btfss Trigg,0.

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

По этому сценарию, должен произойти безусловный переход на метку Metka148. Поэтому назначаем точкой остановки команду movlw .255.

Запускаем "автомат" и ждем окончания процесса. Рабочая точка программы "встала" на команду movlw .255.

Исполняем эту команду и следующую за ней команду movlw PortB. Убеждаемся, что во все биты регистра PortB записались единицы (число .255). Далее, этот сценарий отслеживается точно так же, как и первый сценарий.

А раз это так, то зачем "бестолковкой заниматься"?

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

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

Ранее говорилось о том, что количество сценариев работы программы зависит от количества команд ветвления.

Вобщем виде, это верно, но теперь следует уточнить, каких именно команд ветвления?

Вгруппе команд "основного тела" программы, кроме команды ветвления btfsc Trigg,0, Вы увидите еще 4 команды ветвления (decfsz, incfsz).

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

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

Это можно назвать "глобальным сценарием" (или еще как-то).

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

Отслеживание работы программы в пределах ПП прерывания.

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

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

Исполняем эту команду.

Рабочая точка программы "встанет" на первую команду ПП прерывания (movwf W_Temp) и далее будет "скакать" по командам ПП прерывания (она будет исполняться).

После исполнения первых 3-х команд, содержимое регистров Status и W должно скопироваться в регистры Stat_Temp и W_Temp соответственно.

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

151


В регистре W, по умолчанию, установлено число 00h.

Так как в регистре W_Temp, по умолчанию, также установлено число 00h, то, при сохранении содержимого регистра W, в регистре W_Temp, в окне RAM, никаких изменений не произойдет (кроме PC).

В регистре Status, по умолчанию, установлено число 18h.

Проследите (в окнах Watch и RAM), как это число, сначала, запишется в регистр W (movf Status,W), а затем, скопируется из регистра W в регистр Stat_Temp.

Пошли дальше.

Перед исполнением команды ветвления btfsc PortB,0, необходимо посмотреть на состояние нулевого бита регистра PortB.

По умолчанию, он установлен в 0, следовательно, в соответствии с алгоритмом работы команды btfsc, рабочая точка программы "уйдет" сценарий "программа исполняется далее", То есть, "встанет" на команду movlw .250.

Так оно и есть.

Далее, исполняем все команды записи констант в регистры SecH_2 и SecL_2. Убеждаемся, что в регистры SecH_2 и SecL_2, из регистра W, скопировались числа .250 и

.120 соответственно.

Переходим на "врезку" в ПП задержки PAUSE_2 (clrwdt).

Далее, отслеживание работы программы происходит аналогично отслеживанию работы ПП

PAUSE или PAUSE_D.

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

Так и делаем.

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

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

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

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

Один сценарий отслежен. Отслеживаем следующий. "Встаем" все на ту же команду btfsc PortB,0.

Применяем "уловку", заменив эту команду на команду btfss PortB,0. Производим ассемблирование и устанавливаем программу на начало.

Так как должен произойти безусловный переход на первую команду ПП EndInt, то устанавливаем точку остановки на команде bcf IntCon,1.

Запускаем "автомат" и ждем окончания его отработки. Рабочая точка программы "встала" на команду bcf IntCon,1.

Исполняем ее и убеждаемся, что 1-й бит регистра IntCon установился в 0 (флаг прерывания INT программно сброшен).

Далее, исполняем, рекомендованный разработчиками, стандартный "набор" из 4-х команд восстановления содержимого регистров Status и W (результат можно проконтролировать). Рабочая точка программы "встала" на команду retfie.

Исполняем команду retfie и получаем предупреждение (MPLAB "в панике") о том, что стек пуст и соответственно, извлекать из него нечего. Хоть "шаром покати".

Но паниковать не нужно. В конце-концов, мы кто? Гомо сапиенсы или мартышки? Щелкнув по ОК, спокойно закрываем окно предупреждения, после чего рабочая точка программы устанавливается на начало (в данном случае, на команде goto INT в "шапке" программы).

Поза мыслителя.

Вопрос: "В чем дело? Почему стек пустой"?

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

152


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

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

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

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

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

Но это вовсе не означает, что "уход" в ПП прерывания происходит по какому-то "таинственному указанию святого духа".

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

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

Таким образом, чтобы проверить/сымитировать уход в прерывание из "зоны" разрешения прерываний "основного тела" программы, необходимо просто-напросто "врезать" в нее команду call INT.

Для того чтобы быстро "добраться" до этой команды (не ждать окончания отработки счетчика), ее лучше "врезать" между командами clrwdt и decfsz SecL,F.

Для работы в "основном теле" программы, также необходимо заблокировать команду goto INT и разблокировать команду goto START.

Делаем это.

Производим ассемблирование, и после получения сообщения о безошибочном ассемблировании, устанавливаем программу на начало (goto START), назначаем точку остановки на команде call INT и запускаем "автомат".

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

Атеперь разбираемся со стеком.

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

Это делается так: в главном меню MPLAB, щелкаем по слову Window и в выпадающем списке, щелкаем по строке Stack.

Откроется окно Stack Window.

В нем пока ничего нет (т.к. команд условных переходов не было).

Расположите это окно в любом удобном для Вас месте обычным, для "Виндов", способом. Исполняем команду call INT.

Рабочая точка программы "уйдет" в ПП прерывания и "встанет" на первую ее команду

(movwf W_Temp).

А теперь посмотрите в окно стека.

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

Этот адрес - 003Bh.

Откройте окно ROM и убедитесь в том, что команда с этим адресом (decfsz SecL,F) является следующей, после команды call INT.

При переходе в ПП прерывания по активному перепаду на входе RB0/INT, по сути, происходит то же самое.

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

Напоминаю Вам, что ранее мы отслеживали исполнение 2-го сценария работы ПП прерываний.

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

153


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

После его отработки, рабочая точка программы "встала" на команду retfie. Исполняем ее.

Вершина стека очистится (стек станет опять пустым), рабочая точка программы "вернется" в "основное тело" программы и установится на команде decfsz SecL,F, в чем и требовалось убедиться.

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

Программа отслежена.

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

Отладка программы

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

При этом, внимания на ее временнЫе характеристики не обращалось.

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

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

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

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

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

Только после этого имеется гарантия того, что он поставит точки остановок точно и без ошибок.

Разбираемся с задержками программы Retr_1.asm.

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

Определяемся с "границами" защитного интервала времени.

Он начинает формироваться после исполнения команды movwf PortB (таких команд две), как для 1-го, так и для 2-го сценария работы программы в "основном теле" программы.

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

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

По вполне понятным причинам, общие команды этих 2-х сценариев в расчет не берутся. Остаются те части этих сценариев, которые не являются общими.

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

Соответственно, интервалы времени их отработки тоже могут быть разными. Вот Вам и разница во времени.

Давайте разбираться.

После команды btfsc Trigg,0, происходит "разветвление" сценариев, а "слияние" сценариев происходит на команде movlw .197 (на это намекалось выше).

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

Если при этом выявятся различия, то необходимо произвести их выравнивание калибровочными NOPами.

Вданном случае, практической необходимости в "выравнивании" сценариев нет, но

154


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

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

Итак, "расхождение сценариев из одной точки" происходит от команды btfsc Trigg,0. "Схождение сценариев в одну точку" происходит на команде movlw .197. Выставляем точку остановки на команде btfsc Trigg,0.

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

Выставляем точку остановки на команде movlw .197.

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

Секундомер показал 6 м.ц.

Чтобы отработать 2-й сценарий, нужно применить "уловку", в виде замены команды btfsc Trigg,0 на команду btfss Trigg,0.

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

"Разнобой" в 1 м.ц.

Для его устранения, нужно "врезать" один nop после команды movwf PortB (той, которая следует за командой movlw .255).

Выравнивание сценариев произведено (оба будут исполняться за 6 м.ц.).

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

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

Этот пример простейшего выравнивания времени исполнения сценариев приведен для того, чтобы было понятно, о чем идет речь.

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

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

После того, как мы убедились, что оба сценария будут исполняться за одно и то же время (если имеется такая необходимость), можно заняться калибровкой (но не наоборот). Сбросьте программу Retr_1.asm на начало (на goto START) и, в пошаговом режиме (а можно и в "автомате"), "встаньте" на команду movwf PortB (на ту, которая находится после команды movlw .251).

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

Назначьте точку остановки на команде movlw .245 (конец формирования защитного интервала времени) и запустите "автомат".

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

Естественно, что в этом случае, числовые значения констант защитного интервала времени уже подобраны (.197 и .121).

Можете, для тренировки, поизменять их и посмотреть (по секундомеру), что из этого получится.

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

Замечание: фактически, формирование защитного интервала времени заканчивается не после выхода рабочей точки программы из ПП PAUSE_D, а после исполнения команды movwf IntCon, то есть, величина защитного интервала времени окажется на 6 мкс. (6 команд по одному м.ц.) больше (60 006 мкс.), что с учетом допуска в "плюс-минус 2 лаптя", вполне приемлемо.

Отладка остальных ПП задержек - аналогична.

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

1. "Ширина зоны" разрешения прерываний: 11,28 мс. ("границы": верхняя - movwf IntCon,

нижняя - clrf IntCon).

155