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

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

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

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

Добавлен: 16.06.2025

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

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

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

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

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

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

Сверьтесь с "раскладкой" секторов 7-сегментного индикатора (A,B,C,D,E,F,H), и Вы без особого труда заметите, что например, после исполнения команды 1-го сценария, в регистр W скопируется число, отображающее в 7-сегментном индикаторе символ 0, 2-го сценария – символ 1, 3-го сценария – символ 2 и т.д.

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

То же самое относится и ко всем остальным двоичным числам до 9 включительно. Первые 10 команд retlw осуществляют кодовое преобразование двоичных чисел в коды символов 0 … 9 .

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

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

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

То есть, вывести символ на индикацию.

Каким образом должны формироваться значения чисел, копируемых в регистр W, перед началом отработки подпрограммы табличного, вычисляемого перехода TABLE?

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

Единственное ограничение: "граница" между блоками памяти программ (один блок это

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

Внашем случае, команда call TABLE находится выше (по тексту программы, а значит и в PC)

ПП TABLE.

Вслучае 15-тисценарной работы, с учетом того, что команды начала исполнения сценариев программы расположены компактно, максимальное значение числа, предварительно записываемого в регистр W, должно быть 15-1=14.

То есть, в регистр W, предварительно, должны записываться числа, находящиеся в числовом диапазоне от .0 до .14.

Для первых 10-ти сценариев, значения этих чисел дублируются в символьной форме

(0 0, 1 1, 2 2, ... 9 9).

Вданном случае, к значениям чисел, предварительно записываемым в регистр W для исполнения сценариев с №11 по 15 (числа с .10 по .14), должны быть "жестко привязаны" результаты выполнения операций установки признаков режимов, которые, в свою очередь, "жестко привязаны" к результату опроса состояния клавиатуры (режимы работы устройства переключаются при помощи клавиатуры).

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

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

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

165


Для краткости, назову эти регистры LEDами. От LED0 (самый младший), до LED7 (самый старший).

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

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

Что касается последнего, то "технология" вывода на индикацию проста: результат кодового преобразования, из регистра W, копируется в регистр того порта, к выводам которого подключены выводы секторов 7-сегментного индикатора.

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

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

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

И так далее. До конца линейки.

После этого, все опять повторяется снова и снова.

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

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

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

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

Абез него, такая индикация и даром не нужна.

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

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

Все повторяется снова. Ну и так далее. Много раз.

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

Это и является причиной так называемых "мерцаний", являющихся недостатком динамической индикации.

"Заход на второй круг".

Вотдельно взятом, 7-сегментном индикаторе, символ индицируется ("высвечивается") в течение интервала времени формирования одного "витка" малого кольца индикации.

Вэтом интервале времени, он активен.

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

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

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

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

166


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

Получается 8 выводов, которые и подключаются к выводам порта, который задействован для управления линейкой.

Сказанное относится к тому случаю, если линейка создается из отдельных, 7-сегментных индикаторов.

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

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

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

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

Но не всегда выводов портов хватает.

Например, PIC16F84A.

Все 8 выводов порта В задействованы (через них осуществляется вывод символов на индикацию).

Остается 5 выводов порта А.

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

Поэтому ничего другого не остается, как применить внешний (по отношению к ПИКу) дешифратор на 3 адресных входа и 8 выходов.

Это уже вполне приемлемо, так как 3 это не 8. "Извернуться" можно.

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

Ниже Вы видите практическую иллюстрацию сказанного.

Это принципиальная схема частотомера-цифровой шкалы.

На ней Вы видите то, о чем говорилось выше: выводы порта В подключены к выводам секторов 7-сегментных индикаторов (одноименные секторы "запараллелены" внутри АЛС318), 8 общих выводов 7-сегментных индикаторов подключены к выходам дешифратора

167

(555ИД7), а адресные входы дешифратора подключены к первым трем выводам порта А. Резисторы R16...R23 - гасящие.

Они нужны для предотвращения токовых перегрузок оконечных каскадов защелок порта В. Пояснение.

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

Посмотрите на схему.

Кнопки клавиатуры подключены к выводам RA0 и RA1.

Значит, эти выводы должны быть настроены на работу "на вход".

Но к этим же выводам подключены и первые два адресных входа дешифратора 555ИД7. Значит, эти выводы должны быть настроены на работу "на выход".

Вопрос: "Как же тогда все это "мирно сосуществует" и работает в комплексе"?

Ответ: бОльшую часть полного цикла программы, выводы RA0 и RA1 работают "на выход", то есть, управляют дешифратором (обеспечивают процесс динамической индикации).

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

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

Эти "перенастройки" происходят очень быстро.

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

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

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

Работа с EEPROM памятью данных.

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

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

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

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

Это только отдельный пример.

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

168


И не по той причине, что я "враг народа". Просто интересно.

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

Из нее можно только или считать данные, или записать их в нее.

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

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

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

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

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

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

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

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

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

После этого, они могут быть видоизменены, и в этом виде, снова записаны в EEPROM память данных.

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

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

Можно еще перечислить множество различных случаев задействования EEPROM памяти данных.

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

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

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

Для начала, нужно понять, "что это вообще такое и с какого бока к этому подойти". Объем EEPROM памяти данных не велик.

Для PIC16F84A, это 64 ячейки. В других типах ПИКов, может быть и больше.

Вкаждую из этих ячеек может быть записан один байт (число от .00 до .255).

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

Каждая из этих 64-х ячеек, в диапазоне адресов от .00 до .63 (00h .. 3Fh), имеет свой адрес,

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

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

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

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

То есть, речь идет о замене одного числа другим.

Во время "прошивки" ПИКа, в EEPROM память данных может быть произведена предварительная запись данных.

169


Этим "рулит" директива (или несколько таких директив) DE (см. ниже), которая, в "шапке" программы, должна располагаться до директивы org 0.

Поставим перед собой достаточно простую и конкретную задачу (что-то типа задания на разработку).

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

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

Например, увеличим его содержимое на единицу (.101), с сохранением результата операции в этом же регистре Registr.

Затем, запишем число .101 в ту же ячейку EEPROM памяти данных.

По ходу этих "разборок", я буду объяснять общие положения работы с EEPROM памятью данных.

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

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

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

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

Это хорошо, но не "шустро".

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

Идаже не за 5, а поболее. Это и есть специфика.

Файл с примером работы с EEPROM памятью данных eeprom.asm находится в папке

"Тексты программ".

Это выглядит так:

;******************************************************************************** ; РАБОТА С EEPROM ПАМЯТЬЮ ДАННЫХ

;******************************************************************************** ; "ШАПКА ПРОГРАММЫ"

;================================================================================ ;.............................................................

;.............................................................

;================================================================================

; Определение положения регистров специального назначения.

;================================================================================

Intcon

equ

0Bh

; Регистр Intcon.

Status

equ

03h

; Регистр Status.

EEData

equ

08h

; EEPROM - данные

EECon1

equ

08h

; EECON1 - банк1.

EEAdr

equ

09h

; EEPROM - адрес

EECon2

equ

09h

; EECON2 - банк1.

;.............................................................

;.............................................................

;================================================================================

; Определение названия и положения регистров общего назначения.

;================================================================================

Registr equ 0Ch ; Регистр оперативной памяти, используемый

170