Самоучитель по программированию PIC контроллеров для начинающих (Е.А. Корабельников,2008). Самоучитель по программированию PIC контроллеров для начинающих. Система команд pic16F84A 26 Что такое программа иправила ее составленияПример создания программы автоколебательного мультивибратораДирективы.
![]()
|
0,1 сек (отсюда и погрешность в 10 гц .). С учетом сказанного выше, для такой высокой частоты, вариант счета с использованием "чистого " не подходит Значит , необходимо замедлить счет TMR0 То есть, нужно сделать так, чтобы счетный вход "реагировал " не на каждый импульс, поступающий на вывода например, на каждый 10- й, 20- й, 34- й, ... и т д. (цифры "взяты с потолка "). Соответственно, враз увеличится и время одного цикла переполнения, что и требуется (проверки на переполнение не будут очень частыми. Для этого, между выводом (счетным входом ПИКа ) и счетным входом 264 необходимо включить делитель на 10, 20, 34, ... . Такой делитель в ПИКе имеется Он называется предделителем Посмотрите в распечатку регистра OPTION Для того чтобы обеспечить требуемый режим работы устройства, до " влёта " в цикл счета, нужно установить битв (выбор внешнего такта с вывода RA4/TOCKI ), бит, обычно, устанавливают в 0 (приращение по переднему фронту, бит устанавливается в 0 ( предделитель включен переда с битами №№ 0 ... 2 (коэффициент деления предделителя ) давайте разбираться Какой коэффициент деления предделителя установить Выбираем максимально возможный Кделения предделителя (256). Это соответствует заданию наивысшего, частотного "потолка ". Можно "привязаться " и к полубайту (128) и к четверти байта (64), но при этом наживаются никому ненужные проблемы, связанные с необходимостью работы либо с полубайтами , либо с четвертями байта, со всеми вытекающими, не очень- то "комфортными ", последствиями Итак , в битах №№ 0 ... 2 выставляем единицы ( К деления предделителя = 256). В этом случае, переполнение будет происходить не после подсчета "пачки ", состоящей из 256- ти импульсов, а после подсчета "пачки ", состоящей из х- ти импульсов Таким образом, за время "прохождения " 3 000 000 импульсов, произойдет 45 переполнений по принципу "недопущения перебора ", округлено в сторону уменьшения. х. Остаток 3000000-2949120=50880. Обратите внимание на то, что число .45 не выходит за "верхнюю границу " числового диапазона байта (не более .255), и оно "уместится " водном байте Таким образом, речь идет о том , что в случае организации высокоскоростного счета, можно работать (программно) с частотами более высокими, чем 30 Мгц 30 Мгц это "официальный, паспортный потолок " Если будет использован более быстродействующий ПИК , то программа может обеспечить его работу на частотах более высоких, чем 30 Мгц Вернемся к математике Имеется остаток равный 50880. На 65536 его делить нельзя, так как получится число меньше единицы, значит делим на 256. С учетом соблюдения все того же принципа "недопущения перебора ", получится следующее х. Остаток 50880-50688=.192. Еще раз обратите внимание на то, что и число .198, и число .192 не выходят за пределы числового диапазона байта, и каждое из них можно отобразить водном байте Итожим : 3 000 000=256 х 256 х 45+256 х 198+192 Вы видите математическую форму разложения десятичного числа 3 000 000. Для того чтобы убедиться в том , что между этой формой представления числа ( используемые числа - десятичные) и двоичной (бинарной) формой представления этого же числа, имеется однозначное соответствие, в программке конвертора систем исчислений , имеющейся у Вас , "настучите " число 3000000. Вы увидите, что десятичное число 3000000, в бинарном виде, выглядит так 11000110 11000000 А теперь по частям - старший байт 256 х 256 х 45= 2949120 ( 00101101 00000000 00000000 ), ( 00101101=. 45), - средний байт х ( 00000000 11000110 00000000 ), ( 11000110= .198), - младший байт 192 ( 00000000 00000000 11000000 ), ( 11000000= .192). Остается только "закрепить " - за старшим байтом (число .45) регистр, - за средним байтом (число .198) регистр, - за младшим байтом (число .192) регистр TimerL Каждое из этих трех чисел отображается водном байте- байтное , двоичное число, записанное в регистре TimerH/TimerM/TimerL , будет 265 соответствовать 7- разрядному, десятичному числу 3 000 000. Переполнение TMR0 будет происходить 3000000/65536=45,776367 разв сек (или раз засек, что соответствует числовому значению интервала времени между двумя соседними переполнениями, 2184,5 мкс В этом интервале времени можно исполнить сотни команд И это с учетом того, что речь идет об измерении достаточно высокой частоты (30 Мгц .). Этот интервал времени "прекрасно вписывается " в малое кольцо динамической индикации ( процессы счета и динамической индикации совмещены. В данном случае, время отработки одного цикла малого кольца динамической индикации не должно превышать х мкс, так как в противном случае, возникнет погрешность подсчета (2 переполнения TMR0 будут считаться заодно. Вывод в данном случае, проверки на переполнение TMR0 нужно производить чаще, чем 1 раз за 4369 мкс. Еще один вывод : для того чтобы отодвинуть верхнюю, программную границу (она определяет быстродействие программы, а не ПИКа ) полосы частот, в пределах которой производится счет, вверх по оси частот, необходимо уменьшить время полного цикла малого кольца динамической индикации В этом случае, нужно не забывать о том , что это влияет и на время отработки цикла динамической индикации, и на величину интервала времени измерения После подобного рода "катаклизма " (если он имеет место быть, нужно производить коррекцию временных характеристик программы Итак , команды 1- й проверки TMR0 на переполнение "врезаются " в малое кольцо динамической индикации, а результат этих подсчетов "оседает " в регистре TimerH Вопрос : "Каким образом происходит подсчет "? Ответ : каждый раз, при наличии факта переполнения ( флаг T0IF поднят ), содержимое регистра инкрементируется Количество таких инкрементов напрямую зависит от частоты импульсной последовательности, подаваемой на вывод (на вход предделителя ). В зависимости от нее (от частоты, переполнения TMR0 будут происходить не на каждом "витке " малого кольца динамической индикации (такое возможно только при приближении к верхней границе быстродействия программы, а например , 1 раз за 5, 65, 231, 564 и т д "витка " (цифры "взяты с потолка "). Если речь идет о 1- й проверке TMR0 на переполнение, то должна быть и вторая ? Так оно и есть Дело в том , что между группой команд 1- й проверки TMR0 на переполнение и командой окончания счета, располагается группа команд точной "доводки " интервала времени измерения и группа команд завершения измерения В интервале времени их отработки, может произойти переполнение, которое не будет подсчитано Следовательно , сразу же после окончания счета, необходимо произвести еще одну проверку на переполнение ( № 2). Если, за указанный выше промежуток времени, произошло переполнение из- за малой его величины, количество переполнений не может быть больше одного, то содержимое регистра TimerH инкрементируется , а если не произошло, то содержимое регистра TimerH не меняется Итак , с регистром старшего разряда, в основном , разобрались Для удобства, будем считать, что старший байт числа 00000000 (2949120) записан в регистр TimerH, и он "лежит в оперативных закромах " (ждет своего часа "). Итог по регистру TimerH В ходе исполнения процедур последовательных проверок переполнения проверка 1), числовое значение байта регистра TimerH будет увеличиваться Интенсивность этого увеличения зависит от значения измеряемой частоты После разрешения счета, на каждом "витке " малого кольца динамической индикации, происходит проверка переполнения 1, за счет которой и осуществляется основной "прирост " числового значения байта регистра TimerH После того как счет запрещается, осуществляется 2- я проверка переполнения, которая может либо привести, либо не привести к единственному инкременту содержимого регистра 266 После проверки переполнения 2, в регистре TimerH, будет окончательно сформировано числовое значение старшего байта 3- байтного двоичного числа результата подсчета (измерения. Ранее, для определенности, мы условились, что это число 1101 (.45). Теперь обратим внимание на регистр среднего разряда TimerM Итак , счет закончен, ив регистр TimerH записано количество переполнений, произошедших в интервале времени измерения Вопрос : что нужно записать в регистр среднего разряда Ответ : в него нужно записать содержимое TMR0 на момент окончания счета Эта операция простая содержимое, через регистр, просто копируется в регистр TimerM Таким образом, в рассматриваемом случаев средний байт 3- байтного двоичного числа) запишется число 0110 ( . 198). В "связке " с регистром TimerH , получилось это 01101101 1100 0110 00000000 Переходим к регистру младшего разряда Вопрос "на засыпку ": если количество переполнений TMR0 записалось в регистр TimerH , а содержимое TMR0 на момент окончания счета) скопировалось в регистр TimerM , то что же тогда записывать в регистр TimerL ? Ответ : если не найти то "место ", в котором "лежит хвостик " разложения значения подсчитываемого количества импульсов (в нашем случае, число .192), то записывать в регистр TimerL нечего И в самом деле, TMR0 "выжат как мочалка " и "выжимать " из него нечего, но из предделителя кое- что "выжать " можно Именно в байте предделителя и "лежит этот хвостик ". А вот здесь- то и начинается самое интересное Речь идет о такой "головоломке ", как подпрограмма досчета Из ее названия понятно, что организуется дополнительная процедура досчета Именно результат работы этой ПП и будет записываться в регистр TimerL Давайте разберемся что это такое Сначала в принципе , а затем и более детально Принцип работы подпрограммы досчета Досчет это счет с предустановкой , в пределах одного цикла счета Перед исполнением ПП досчета , содержимое регистра TimerL необходимо сбросить в ноль ( подготовка к досчету ). Так как то, что нужно подсчитать, фиксировано, то необходимо организовать "принудительный " счет Для этого нужно сформировать серию коротких, счетных импульсов Импульс формируется путем кратковременной установки единичного уровня на выводе блокировки, который электрически соединен с выводом счетного входа RA4/TOCKI То есть, счетный импульс формируется программными средствами В нашем случае ( приращение TMR0 по переднему фронту, в момент начала формирования счетного импульса, формируется активный перепад (переход от 0 к 1), поступающий на счетный вход ПИКа (то есть, на вход предделителя ), который и будет подсчитан Возникает вопрос "Ане будут ли, вовремя формирования единичных уровней счетных импульсов, паразитно подсчитываться импульсы от внешнего источника импульсов, ведь это плохо отразится на итоговом результате подсчета "? Ответ : импульсы , от внешнего источника импульсов, подсчитываться не будут, так как в интервале времени исполнения ПП досчета , блокировочный вывод RA3 настроен на работу "на выход ", что соответствует подключению, к счетному входу ПИКа , низкоомного выхода третьей защелки порта А В этом случае, на счетном входе ПИКа , амплитуда импульсов, поступающих (через гасящий резистор) от внешнего источника импульсов, за счет шунтирования счетного входа ПИКа низким выходным сопротивлением третьей защелки порта А , будет резко снижена, и она ( амплитуда ) окажется существенно ниже порога "срабатывания " счетного входа ПИКа 267 По этой причине, счетный вход ПИКа перестанет "реагировать" на импульсы от внешнего источника, но будет "реагировать" на счетные импульсы. Примечание : в процессе основного счета, который происходил до " влёта " в процедуру досчета , такое шунтирующее влияние отсутствует, так как в интервале времени основного счета, вывод RA3 настроен на работу "на вход " (выход защелки отключен от вывода. После формирования счетного импульса, может наступить 2 события - содержимое TMR0 не инкрементировалось , - содержимое TMR0 инкрементировалось Пока , просто примите это к сведению До сих поря не обращал Вашего внимания на байт, "дислоцирующийся " в предделителе Пришла пора с ним разобраться Байт предделителя , по отношению к байту TMR0 , является младшими этим все сказано И в самом деле, где, как не в байте предделителя , находиться "хвостику " результата измерения Другого не дано То есть, для получения десятичного "эквивалента" 3- байтного двоичного числа, точно равного истинному результату измерения ( подсчета ), содержимое байта предделителя нужно записать в регистр TimerL Это и есть та задача, которую нужно решить Таким образом, в байте предделителя "лежит " число .192 (условились ранее, и нужно каким- то образом "переправить " это число, из байта предделителя , в байт регистра TimerL Задача , казалось бы, простая, но это не так Так как предделитель не является регистром, отображаемым в области оперативной памяти, то при помощи стандартной процедуры записи (через регистр, "переправить " его содержимое, в регистр TimerL , нельзя Самое разумное, что можно сделать, так это инкрементировать содержимое байта предделителя до тех пор, пока число .255 сменится на число .00. В этом случае, произойдет инкремент содержимого регистра, что и будет являться критерием конца досчета Факт инкремента содержимого регистра TMR0 укажет на то, что байт предделителя инкрементирован количество раз, равное разнице между числом 256 и числом , находящимся в байте предделителя на момент окончания счета (то есть, числом, которое нужно "переправить " в регистр TimerL ). Примечание : приращение содержимого TMR0 не будет влиять на результат основного счета, так как оно происходит после того, как этот результат сохранен в регистрах TimerH и TimerM Подсчитав количество инкрементов байта предделителя (от первого инкремента и до обнаружения факта приращения содержимого регистра) и осуществив числовое преобразование, можно точно восстановить числовое значение байта предделителя на момент окончания основного счета (хвостик "). Обращаю Ваше внимание на то, что в данном случае, речь идет о досчете , а не о счете Счет производится в интервале времени измерения (основной счет, на момент окончания которого, в байте предделителя фиксируется некое число Досчет производится вне интервала времени измерения и "принудительно " (программная "симуляция " счета. Если добавить результат досчета к результату основного счета, то программная погрешность результата измерения не будет превышать 10- ти герц "Привяжемся " к рассматриваемому случаю (подсчет 3 000 000 импульсов засек. Итак, в байте предделителя "лежит " число .192. Задача : нужно "переправить " число .192, из байта предделителя , в регистр TimerL Математически это выглядит так 1. 256- 192 =.64 (значение результата досчета ). Переводим десятичное число .64 в бинарную форму Инвертируем все биты числа 01000000 Получаем : 10111111 , что соответствует числу .191. 4. инкремент Итог число .192 "переправлено ", из байта предделителя , в регистра TimerL Для того чтобы Вы убедились, что ив других случаях, происходит тоже самое, приведу еще один пример Например , считается 1 500 000 импульсов засек Делаем разложение 256 х 256 х 22+256 х 227+ 96 268 1. 256- 96 =.160 (значение результата досчета ). Переводим десятичное число .160 в бинарную форму Инвертируем все биты числа 10100000 Получаем : 01011111 , что соответствует числу .95. 4. инкремент. Пока хватит (артподготовка "). С деталями разберемся позднее Краткий , общий итог Наибольший практический интерес представляет принцип организации высокоскоростного счета. При этом, перед, включается предделитель , на вход которого ( предделителя ) , с выхода внешнего источника импульсов, подается последовательность импульсов, количество которых нужно посчитать в интервале времени счета. Организуется 3- байтный ( в рассматриваемом случае ) регистр |