Файл: Самоучитель по программированию PIC контроллеров для начинающих (Е.А. Корабельников,2008).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 16.06.2025
Просмотров: 3628
Скачиваний: 3
;Присвоение буквенного обозначения операции направления результата выполнения
;команды в регистр, с содержимым которого производится действие (для удобства
;восприятия текста программы).
;================================================================================
F equ 1 ; Результат направить в регистр, с содержимым ; которого производится действие.
;================================================================================
;Присвоение биту выбора банка регистра STATUS (пятому) его стандартного названия
;для удобства восприятия текста программы).
;================================================================================
RP0 |
equ |
5 |
; |
Присвоение 5-му биту регистра STATUS |
; |
названия RP0. |
;================================================================================
; Определение точки входа в программу.
;================================================================================
org |
0 |
; Установка нулевого адреса в счетчике |
|
; |
команд PC. |
||
goto |
START |
; |
Безусловный переход на подпрограмму START. |
;********************************************************************************
;******************************************************************************** ;---------------------------- РАБОЧАЯ ЧАСТЬ ПРОГРАММЫ -------------------------
;******************************************************************************** ; Подготовительные операции.
;-------------------------------------------------------------------------------- |
|||||
START |
clrf |
IntCon |
; Сброс в ноль всех битов регистра IntCon. |
||
clrwdt |
; Установка |
начала отсчета сторожевого |
|||
; таймера WDT. |
|||||
bsf |
Status,RP0 |
; Установка |
5-го бита регистра Status |
||
; в единицу. |
|||||
movlw |
.65 |
; Запись в регистр W |
константы .65 |
||
; (.65 = 0100 0001) |
|||||
movwf |
TrisB |
; Установка |
нулевого |
и 6-го бита регистра |
|
; TrisB в единицу, а |
остальных - в ноль. |
||||
movlw |
.143 |
; Запись в регистр W |
константы .143 |
||
; (.143 = 1000 1111) |
|||||
movwf |
OptionR |
; Установка |
4,5,6-го |
битов регистра OptionR |
|
; в ноль, а |
остальных - в единицу. |
||||
bcf |
Status,RP0 |
; Установка |
5-го бита регистра Status в ноль. |
||
;--------------------------------------------------------------------------------
; Запись констант времени работы таймера.
;--------------------------------------------------------------------------------
movlw |
.15 |
; Запись в регистр W константы .15 |
|
movwf |
SecH |
; Копирование константы .15 из регистра W |
|
; в регистр SecH. |
|||
movlw |
.255 |
; Запись в регистр W константы .255 |
|
movwf |
SecL |
; Копирование константы .255 из регистра W |
|
; в регистр SecL. |
|||
;-------------------------------------------------------------------------------- |
|||
; Проверка наличия включения на передачу (опрос клавиатуры). |
|||
;-------------------------------------------------------------------------------- |
|||
CYCLE |
btfsc |
PortB,0 |
; Если нулевой бит регистра PortB равен 1, то |
; выполняется следующая команда (goto START), |
|||
; а если равен 0, то следующая команда не |
|||
; выполняется (вместо нее - nop) и следующей |
|||
; активной командой будет btfss PortB,6 |
|||
goto |
START |
; Безусловный переход на подпрограмму START. |
|
;-------------------------------------------------------------------------------- |
|||
; Проверка: режим тонального вызова включен или выключен ? |
|||
;-------------------------------------------------------------------------------- |
|||
btfss |
PortB,6 |
; Если 6-й бит регистра |
PortB равен 0, то |
; выполняется следующая |
команда (goto PRD), а |
||
; если равен 1, то следующая команда не |
|||
; выполняется (вместо нее - nop) и следующей |
|||
; активной командой будет bcf PortB,2 |
|||
83
goto |
PRD |
; Безусловный переход на подпрограмму PRD. |
||
;-------------------------------------------------------------------------------- |
||||
; Формирование времени |
отрицательного полупериода сигнала тонального вызова. |
|||
;-------------------------------------------------------------------------------- |
||||
bcf |
PortB,2 |
; Установить 2-й бит регистра PortB в 0. |
||
nop |
; Пустые машинные циклы. |
|||
nop |
; ---------- |
"----------- |
||
nop |
; ---------- |
"----------- |
||
movlw |
.85 |
; Запись в регистр W константы .85 |
||
movwf |
Sec |
; Копирование константы .85 из регистра W |
||
; в регистр Sec. |
||||
PAUSE_1 |
clrwdt |
; Установка начала отсчета сторожевого |
||
; таймера WDT. |
||||
decfsz |
Sec,F |
; Декремент (-1) содержимого регистра Sec с |
||
; сохранением результата декремента в нем же. |
||||
; Если этот результат не=0, то выполняется |
||||
; следующая команда (goto PAUSE_1), а если =0, |
||||
; то следующая команда не выполняется (вместо |
||||
; нее - nop) и следующей активной командой |
||||
; будет bsf PortB,2 |
||||
goto |
PAUSE_1 |
; Безусловный переход на подпрограмму PAUSE_1. |
||
;-------------------------------------------------------------------------------- |
||||
; Формирование времени |
положительного полупериода сигнала тонального вызова. |
|||
;-------------------------------------------------------------------------------- |
||||
bsf |
PortB,2 |
; То же самое, что и при формировании |
||
nop |
; отрицательного полупериода, только |
|||
nop |
; 2-й бит регистра PortB |
|||
nop |
; устанавливается в 1. |
|||
movlw |
.83 |
; То же самое, что и при формировании |
||
movwf |
Sec |
; отрицательного полупериода, только в регистр |
||
; Sec записывается константа .83 |
||||
PAUSE_2 |
clrwdt |
; Установка начала отсчета сторожевого |
||
; таймера WDT. |
||||
decfsz |
Sec,F |
; То же самое, что и при формировании |
||
goto |
PAUSE_2 |
; отрицательного полупериода, только |
||
; безусловный переход осуществляется на |
||||
; подпрограмму PAUSE_2. |
||||
;-------------------------------------------------------------------------------- |
||||
; "Очистка" (декремент) таймера. |
||||
;-------------------------------------------------------------------------------- |
||||
decfsz |
SecL,F |
; Декремент (-1) содержимого регистра SecL с |
||
goto |
CYCLE |
; сохранением результата в нем же. |
||
; Если этот результат не=0, то выполняется |
||||
; следующая команда (goto CYCLE), а если =0, |
||||
; то следующая команда не выполняется (вместо |
||||
; нее - nop) и следующей активной командой |
||||
; будет decfsz SecH,F |
||||
decfsz |
SecH,F |
; То же самое, что и при декременте |
||
goto |
CYCLE |
; содержимого регистра SecL, только |
||
; применительно к регистру SecH. |
||||
bcf |
PortB,2 |
; Установить 2-й бит регистра PortB в 0. |
||
;-------------------------------------------------------------------------------- |
||||
;Уход рабочей точки программы в "вечное" кольцо и выход из него после
;переключения р/станции с передачи на прием.
;-------------------------------------------------------------------------------- |
|||
PRD |
clrwdt |
; Установка начала отсчета сторожевого |
|
; таймера WDT. |
|||
btfss |
PortB,0 |
; Если нулевой бит регистра PortB равен 0, то |
|
; выполняется следующая команда (goto PRD), а |
|||
; если равен 1, то следующая команда не |
|||
; выполняется (вместо нее - nop) и следующей |
|||
; активной командой будет btfss PortB,0 |
|||
goto |
PRD |
; Безусловный переход на подпрограмму PRD. |
84
;Еще одна проверка.
btfss |
PortB,0 |
; То же |
самое, что и при |
первой проверке, |
||
; только, при |
равенстве нулевого бита |
регистра |
||||
; PortB |
единице, следующей активной командой |
|||||
; будет |
goto START. |
|||||
goto |
PRD |
; Безусловный |
переход на |
подпрограмму |
PRD. |
|
goto |
START |
; Безусловный |
переход на |
подпрограмму |
START. |
|
;================================================================================ end ; Директива конца текста программы.
Для того чтобы далее работать с текстами этих программ, создайте проекты cus_1 и cus_2, а затем скопируйте в них файлы cus_1.asm и cus_2.asm соответственно.
О том, как это делается, рассказано в 5-м разделе.
Можете проассемблировать их и убедиться в отсутствии ошибок.
Итак, перед Вами текст программы cus (так я буду называть любую из них), оформленный по всем правилам составления текста программы.
Ранее я упоминал про "правило 12-ти пробелов".
В тексте программы cus, это правило использовано на практике. Давайте разбираться.
Текст программы содержит комментарии, из которых можно многое узнать. Такого рода комментарии - достаточно большая редкость.
По совокупности причин, разработчики программ редко себя этим утруждают. Отчасти этим и объясняется то, что при наличии большого количества разнообразных текстов программ, большая их часть так и остается "тайной за семью печатями".
Для опытных программистов, владеющих приемами программно-аппаратного анализа, отсутствие комментариев не является непреодолимой преградой, но с начинающими сложнее: c непривычки, можно "заполучить множество фингалов".
Чтобы уменьшить их количество, давайте потрудимся.
Напоминаю Вам снова и снова: движение рабочей точки программы, по тексту программы, никогда не останавливается (за исключением "уходов" в спящий режим
SLEEP).
Это означает то, что если необходимо задержать исполнение последующих команд, то рабочую точку программы обязательно нужно "закольцевать" (задержать) в какой-то подпрограмме, образно выражаясь, "поставленной на счетчик".
Выход рабочей точки программы, из этой подпрограммы, возможен либо после завершения, программно организованным счетчиком, своего счета, либо после поступления внешнего, управляющего сигнала.
Любая программа это постоянная "вереница" такого рода колец, и без глубокого понимания смысла и "технологии" этих "закольцовок", в программировании делать нечего. Программа cus не является исключением.
Если Вы поймете ее работу, то найдете ответы на многие вопросы.
"Шапка" программы.
Напоминаю: все что находится правее точек с запятой, MPLAB "не видит", и к программе, в буквальном смысле этого слова, это не имеет отношения, так как программа, опять же, в буквальном смысле этого слова, это то, что не заблокировано точками с запятыми. Вверху "шапки" программы, обычно, помещается общая, пояснительная информация о программе, об устройстве, которое она обслуживает и т.п. ("правило хорошего тона". Не обязательно, но желательно).
Эта информация может быть изложена в произвольной форме. То же самое относится и к комментариям.
"Активная" часть "шапки" начинается с директив LIST и __CONFIG.
Первая "подсказывает" MPLAB, какой именно файл, из весьма обширной библиотеки файлов, нужно извлечь из ее "недр" для того, чтобы "привязаться" к конкретному типу ПИКа (в нашем случае, к PIC16F84A), а при помощи второй директивы устанавливаются значения битов конфигурации.
В PIC16F84A, битов конфигурации всего 5 и поэтому, из пяти двоичных разрядов 16-ричного
85
числа (в данном случае, 03FF5h), активными (в которых можно что-то менять) являются только 2 последних разряда, а первые три всегда "прописываются" как 03F. 16-ричному числу F5h соответствует бинарное число 1111 0101.
Сверяемся с распечаткой битов конфигурации.
Получается: переводим тактовый генератор ПИКа в режим стандартного, кварцевого генератора (XT), включаем сторожевой таймер WDT, разрешаем работу таймера включения питания PWRT, отключаем бит защиты памяти программ и EEPROM памяти данных.
Что касается PWRT, то на него, пока, можно не обращать внимания. Он не представляет собой нечто совершенно необходимое.
Его можно включить, а можно и выключить.
PWRT, за счет формирования задержки, "нейтрализует" негативные последствия медленного нарастания питающего напряжения.
Практически всегда, эта скорость настолько высока, что "услуг" PWRT не требуется. Далее необходимо определиться с регистрами специального и общего назначения.
Порядок этого "определения" не имеет значения: можно, сначала определиться с регистрами общего, а затем, специального назначения или "перетасовать их как карты".
Так как "бардак", в тексте программы, совсем не нужен, то советую Вам придерживаться того "порядка", который "наведен" в "шапке" программы cus.
При "прописке" регистров специального (и общего) назначения, нужно "прописывать" только те регистры, которые задействованы при выполнении программы (к содержимому которых происходят обращения).
"Прописывать" те регистры, которые не задействуются при выполнении программы, можно, но не нужно.
Если возникают сомнения типа: "А вдруг потребуется?", можно "прописать" все (или часть) регистры специального назначения, а потом, когда программа будет отработана, убрать лишние.
Лично я, в подобных обстоятельствах, поступаю именно так.
В программе cus, Вы видите только те регистры специального назначения, которые задействуются при выполнении программы. Лишних нет.
"Прописка" происходит при помощи директивы equ с указанием адресов регистров специального назначения в области оперативной памяти.
Обратите внимание на то, что адрес регистра TrisB (1-й банк) дублирует адрес регистра PortB (нулевой банк).
Это то, о чем говорилось ранее (кто забыл, вернитесь назад).
Регистры общего назначения прописываются по адресам области оперативной памяти, не относящимся к регистрам специального назначения.
Можно выбрать любые из этих адресов. Это личное дело программиста. Регистрам общего назначения нужно присвоить какие-нибудь названия. Это тоже личное дело программиста.
Ну и соответственно, "прописать" эти названия в "шапке" программы.
Я назвал их Sec, SecH и SecL.
Какие они выполняют функции - понятно из комментариев.
Возникает законный вопрос: "Откуда они взялись и вообще, что это такое"? А взялись они из программы.
Становится еще непонятней: "А если, например, программа еще не написана, то какие регистры общего назначения прописывать"?
Ответ: никакие.
Вопрос: а откуда взялись Sec, SecH и SecL? Ответ: из программы.
Похоже на испорченную пластинку. Даже матом хочется заругаться. Давайте выходить из этого "замкнутого круга".
Срегистрами специального назначения все понятно: у них фиксированные названия и их, изначально, можно "прописать всем скопом", а потом "избавиться" от лишних.
Срегистрами общего назначения сложнее.
Пока они не будут "фигурировать" в рабочей части программы, эти регистры находятся как бы в состоянии "бревна/болванки" и представляют собой форму без содержания (толка – никакого).
А вот когда команды программы начинают к ним обращаться и что-то с ними "вытворять" (наполнение формы содержанием), то совсем другое дело.
86
В этом случае, "прописка" обязательна.
Вашему вниманию предоставлена готовая программа, и по этой причине, вполне понятно, какие именно регистры общего назначения нужно прописывать, а анализируя текст программы, становится понятным и то, зачем они нужны и какие функции выполняют.
А если программист сидит перед "чистым листом бумаги" и только приступает к составлению программы???
Вчасти, касающейся регистров специального и общего назначения, это делается так:
В"шапке" программы, "оптом прописываются" регистры специального назначения. После окончания составления программы, лишние можно удалить.
Регистры общего назначения не "прописываются", так как пока не ясно, что "прописывать". Им можно назначить какие-нибудь названия, которые, по ходу составления программы, можно в любой момент изменить (у любого более-менее "набившего руку" программиста, имеется такой "набор" привычных названий), после чего эти регистры "прописываются". Но это не обязательно. Можно начать и с "пустого места".
Например, по ходу создания текста программы, возникла необходимость в однобайтном счетчике.
Ему тут же придумывается название, например, ABC, присваивается адрес (в области оперативной памяти), например, 0Eh и после этого, в "шапку" программы добавляется строка:
ABC equ 0Eh
Всё. Этот регистр "прописан" ("введен в эксплуатацию") и с ним можно работать. Таким же образом "рождаются и вводятся в эксплуатацию" другие регистры общего
назначения, необходимость в "рождении" которых возникает по ходу составления текста программы.
В конечном итоге, к концу процесса написания текста программы, в "шапке" программы "накапливается/оседает" какое-то количество регистров общего назначения, к содержимому которых, по ходу исполнения программы, с помощью команд, происходят обращения.
Втексте программы cus, таких регистров "накопилось" три.
Вдругих программах, их может быть другое количество. Зависит от замысла. Пошли дальше.
В "шапке" программы, Вы видите строку F equ 1. Смысл этой строки заключается в следующем.
Откройте список команд и обратите внимание на байт-ориентированные команды, и в частности, на букву d, которая является составной частью команды.
В зависимости от значения этого параметра (0 или 1), результат исполнения команды может сохраниться либо в аккумуляторе (W), либо в том же регистре, с содержимым которого производится действие (F).
Для комфортного восприятия текста программы, удобнее, если в качестве параметра d будет указываться не 0 или 1, а W или F соответственно.
Примечание: с регистром W все понятно, это его название воспринимается однозначно, а вот регистр F физически не существует.
Буква F, в символьном (или в символическом, или в обобщенном) виде, обозначает тот регистр, с содержимым которого производится действие и поэтому, за этой буквой может "скрываться" любой из задействованных в программе регистров.
Например, команду декремента содержимого регистра ABC, с сохранением результата декремента в нем же, можно "изобразить" так:
decf ABC,1
но гораздо удобнее она будет восприниматься как: decf ABC,F
Для того чтобы перейти к этому более комфортному восприятию места сохранения результата выполнения команды, в "шапке" программы и "прописывается" строка F equ 1. Директива equ дает указание MPLAB: если в тексте программы имеется буква F, то ее нужно "воспринять" как 1.
Такого же рода манипуляцию можно произвести и с нулем, поставив ему в соответствие букву W.
В этом случае, в "шапку" программы нужно добавить W equ 0.
При написании программы "с чистого листа", в "шапку" программы, "не мудрствуя лукаво", можно поместить обе этих строки.
По окончании работы над программой, текст программы просматривается на предмет наличия/отсутствия, например, команд, результат выполнения которых помещается в регистр
87