Файл: Самоучитель по программированию 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