Вы находитесь на странице: 1из 12

Задержки.

Задержки задерживают (звучит как-то неблагозвучно, но это так) исполнение последующих


действий, с учётом того, что предыдущие действия произведены.
Мотивации необходимости введения, в программу, задержек могут быть различными.
Следует учесть, что любая команда исполняется не мгновенно, а за какое-то время
(в основном за 1 машинный цикл, но может и за 2. Это зависит от конкретной команды) , что, по сути, есть
маленькая задержка.
То есть, любая программа, вне зависимости от того, есть ли в ней
"специализированные" задержки или их нет, представляет собой некий "набор
маленьких задержек", просто часть из них считается (ведь нужна же какая-то классификация)
"специализированными", а другая часть ими не считается.
Начну с самых простых задержек.
Самые простые задержки.
Это одна или несколько таких команд, которые, образно выражаясь, "не наносят
вреда".
В основном, применяются NOPы, но можно и clrwdt (если WDT работает, то лишний раз его
сбросить не помешает, а если не работает, то и сбрасывать нечего. Просто задержка на 1 м.ц.) .
Например, задержка на 5 м.ц. это 5 "подряд идущих" NOPов.
Можно использовать goto $+1. Это задержка на 2 м.ц. (заменяет два NOPа).
Например, 5 "подряд идущих" goto $+1 это задержка на 10 м.ц.
А если нужна задержка, например, в 1 000 000 м.ц. ?
То-то и оно…
Соответственно, имеются более "программнокомпактные", фиксированные задержки.
Фиксированные задержки.
Любая из ПП стандартных, фиксированных задержек состоит из 2-х частей:
подготовительной и исполнительной.
В подготовительной части, в N регистров счётчика записываются времязадающие
константы, числовые значения которых задают время задержки (это называется предустановкой).
Исполнительная часть представляет собой N-байтный счётчик, в котором рабочая
точка программы "мотает витки" внутренних циклов.
Каждый "виток" внутреннего цикла "отматывается" не за 0 секунд, а поболее.
Если таких "витков" более одного, то по мере их "отматывания" происходит
постепенное наращивание суммарной задержки до заданной величины.
По факту окончания задержки, рабочая точка программы выходит из группы команд
фиксированной задержки.
Критерий выхода из нее - обнуление содержимого всех N регистров счётчика.
Такое событие может наступить как по факту инкрементного (+1) счёта, так и по факту
декрементного (-1) счёта.
Наиболее распространено последнее.
Соответственно, ориентируюсь на декрементный счёт.
Программные "конструкции" стандартных ПП фиксированных задержек достаточно
просты, но их калибровка довольно-таки трудоёмка.
В том смысле, что в условиях отсутствия "сервисных инструментов", которые
комфортно/быстро производят расчёт предустановочных, числовых значений
времязадающих констант, эти значения приходится довольно-таки трудоёмко и
времязатратно подбирать (если необходима точная калибровка).
Эта проблема решена усилиями Николая Марова и Петра Высочанского, путём
создания ими виндопрограмм расчёта стандартных, декрементных задержек.
В конечном итоге, эти виндопрограммы "выдают" готовый текст ПП задержки, который
можно скопировать (через буфер обмена) в соответствующее "место" текста программы.
Наличие подобного рода виндопрограмм позволяет создать, в интервале времени не
более одной минуты, точно откалиброванную (в соответствии с заданными параметрами расчёта) ПП
задержки.
Обе эти виндопрограммы имеются у всех участников сообщества (см. CD).
Также их можно скачать с моего сайта (плюс, "инструкции по их эксплуатации"):
1
http://ikarab.narod.ru/pause.htm - программа расчёта задержек Николая Марова.

http://ikarab.narod.ru/Delay.html - программа расчёта задержек Петра Высочанского.

Программа Николая Марова хороша, но имеет недостаток: она создана под


соотношение 1 м.ц. = 1 мкс. (кварц 4 Мгц.).
Программа Петра Высочанского свободна от этого недостатка, гораздо более
функциональна/универсальна и работает без ошибок, поэтому рекомендую пользоваться
ей.
Так как можно задать великое множество значений задержек, а также и с учётом того,
что можно задать различные значения тактовой частоты (от этого зависит время отработки
машинного цикла), количество вариантов ПП задержек огромно.
В зависимости от требуемой величины задержки и от времени отработки машинного
цикла, в ПП задержек могут быть задействованы 1-байт, 2-байта, 3-байта и более.
Приведу пример программной реализации 1-секундной (3 байта) задержки, рассчитанной в
виндопрограмме Петра Высочанского (для ПИКов базового и среднего семейства):
; Задержка 1 000 000 машинных циклов
; Длительность задержки 1 секунд
; Частота задающего генератора 4 МГц

movlw .173
movwf Reg_1
movlw .19
movwf Reg_2
movlw .6
movwf Reg_3
decfsz Reg_1,F
goto $-1
decfsz Reg_2,F
goto $-3
decfsz Reg_3,F
goto $-5
nop
nop

А это то же самое, но с комментариями/оформлением:


;=========================================================================
; Задержка на 1000000 м.ц., что соответствует 1000000 мкс. (кварц 4 Мгц.).
;=========================================================================
; Подготовительная часть.
;------------------------------------
movlw .173 ;
movwf Reg_1 ; Предустановка
movlw .19 ; времязадающих
movwf Reg_2 ; констант.
movlw .6 ;
movwf Reg_3 ;
;------------------------------------
; Исполнительная часть.
;------------------------------------
decfsz Reg_1,F ; Стандартный,
goto $-1 ; 3-байтный,
decfsz Reg_2,F ; декрементный
goto $-3 ; счётчик.
decfsz Reg_3,F ;
goto $-5 ;
nop ; Калибровочные
nop ; NOPы.
;=========================================================================

Ещё один вариант (то же самое, но без использования $):


;=========================================================================
; Задержка на 1000000 м.ц., что соответствует 1000000 мкс. (кварц 4 Мгц.).
;=========================================================================
; Подготовительная часть.
;------------------------------------
movlw .173 ;
movwf Reg_1 ; Предустановка
movlw .19 ; времязадающих
2
movwf Reg_2 ; констант.
movlw .6 ;
movwf Reg_3 ;
;------------------------------------
; Исполнительная часть.
;------------------------------------
SNOVA decfsz Reg_1,F ; Стандартный,
goto SNOVA ; 3-байтный,
decfsz Reg_2,F ; декрементный
goto SNOVA ; счётчик.
decfsz Reg_3,F ;
goto SNOVA ;
nop ; Калибровочные
nop ; NOPы.
;=========================================================================

Регистры Reg_1, Reg_2, Reg_3 должны быть прописаны в "шапке" той программы, в
текст которой "врезается" эта задержка.
Пояснение: названия этих регистров можно изменить. Соответственно, в "шапке" программы нужно "прописать"
изменённые названия. Если используются ранее "прописанные" регистры, то ничего "прописывать" не нужно.

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


значениями содержимого всех тех регистров, которые в ней задействованы (в данном
случае, на "вылете" из задержки, Reg_1 = Reg_2 = Reg_3 = 0).
В рассматриваемом случае, подготовительная часть "прислонена" к исполнительной
части, но если это нужно, то их можно и "разнести", но при условии того, что
подготовительная часть должна отрабатываться ранее исполнительной части, и в той
части программы, которая их разделяет, содержимое регистров Reg_1, Reg_2, Reg_3
не изменяется.
"Вышележащие" фиксированные задержки оформлены в виде групп команд и не имеют
названия, то есть, формально они не являются подпрограммами.
Если любой из них присвоить название, например, PAUZE, то на их исполнение можно
перейти с помощью команды goto PAUZE.
Если одна и та же группа команд задержки используются многократно, то
целесообразно произвести командную оптимизацию, то есть, оформить её в виде
вызываемой ПП.
Например:
;=========================================================================
; Задержка на 1000000 м.ц., что соответствует 1000000 мкс. (кварц 4 Мгц.).
;=========================================================================
; Подготовительная часть.
;------------------------------------
PAUZE movlw .173 ;
movwf Reg_1 ; Предустановка
movlw .19 ; времязадающих
movwf Reg_2 ; констант.
movlw .6 ;
movwf Reg_3 ;
;------------------------------------
; Исполнительная часть.
;------------------------------------
SNOVA decfsz Reg_1,F ; Стандартный,
goto SNOVA ; 3-байтный,
decfsz Reg_2,F ; декрементный
goto SNOVA ; счётчик.
decfsz Reg_3,F ;
goto SNOVA ;
nop ; Калибровочные
nop ; NOPы.
return ; Возврат по стеку.
;=========================================================================

А вот так это выглядит в случае 3-разового вызова этой ПП:


;***************************************************************************************************
; Программа, позволяющая проверить (в симуляторе) работу ПП фиксированной задержки.
; В симуляторе, установлена частота кварца 4 Мгц. (1м.ц. = 1мкс.).
;***************************************************************************************************
LIST p=16f84A ; Используется PIC16F84A.
#include <p16f84a.inc>; Подключение INC-файла PIC16F84A.
__CONFIG 03FF1H ; Бит защиты выключен, WDT выключен, XT - генератор.
;----------------------------------------
; "Прописка" регистров общего назначения.
3
;----------------------------------------
cblock 20h ; Назначение адреса первого регистра блока
; (можно назначить и другой начальный адрес).
Reg_1 ; Регистры
Reg_2 ; 3-байтного
Reg_3 ; счётчика.
endc ; Конец блока.
;------------------------------------
org 0 ; Выполнение программы начинается c 0-го PC-адреса.
goto START ; Переход на начало программы.
;***********************************************************************************************
;========================================
; ПП задержки на 1 000 000 мкс. (1 сек.)
;========================================
; Подготовительная часть.
;------------------------------------
PAUZE movlw .172 ; БЫЛО .173
movwf Reg_1 ; Предустановка
movlw .19 ; времязадающих
movwf Reg_2 ; констант.
movlw .6 ;
movwf Reg_3 ;
;------------------------------------
; Исполнительная часть.
;------------------------------------
SNOVA decfsz Reg_1,F ; Стандартный,
goto SNOVA ; 3-байтный,
decfsz Reg_2,F ; декрементный
goto SNOVA ; счётчик.
decfsz Reg_3,F ;
goto SNOVA ;
;;; nop ; ЭТОТ NOP НЕ НУЖЕН (ЛИШНИЙ).
nop ; Калибровочный NOP.
return ; Возврат по стеку.
;====================================================================================================
; Начало программы.
;====================================================================================================
START nop ; Символизирует часть программы.
call PAUZE ; Вызов ПП задержки 1 сек. <- ТОЧКА ОСТАНОВКИ №1
nop ; Символизирует часть программы. <- ТОЧКА ОСТАНОВКИ №2
call PAUZE ; Вызов ПП задержки 1 сек.
nop ; Символизирует часть программы.
call PAUZE ; Вызов ПП задержки 1 сек.
nop ; Символизирует часть программы.
goto $ ; "Мертвяк".
;**************************************************************************************************
end ; Конец программы.

Работу этой программы можно проверить в симуляторе.


Время "засекается" в секундомере (не забудьте в нём выставить 4 Мгц.).
Для осуществления замера интервала времени отработки задержки, нужно пошагово
"дойти" до точки остановки №1, затем сбросить секундомер в ноль и "запустить
автомат".
Обратите внимание на коррекцию, которая выделена красным цветом.
Это точная калибровка/подгонка.
Дело в том, что в этом случае, отрабатывается команда вызова (call) и команда
возврата (return).
Каждая из них отрабатывается за 2 м.ц., что "затягивает" задержку на 2 +2 = 4 м.ц.
Значит нужно уменьшить время отработки "материнской" задержки на 4 м.ц., что и
сделано.
А именно, уменьшение, на единицу, числового значения предустановки младшего
регистра счётчика (Reg_1) уменьшает время отработки задержки на 3 м.ц. и минус
один NOP (1 м.ц.).
В "вышележащем" случае, вызываются фиксированные задержки одной и той же
величины, но во многих иных случаях, нужны неоднократно вызываемые,
фиксированные задержки различных "времяноминалов" (в зависимости от того, какая именно часть
программы исполняется) .
Конечно же, можно "сваять" несколько соответствующих, вызываемых ПП, но ведь их
можно и объединить в одну многофункциональную ПП фиксированных задержек.
"Многофункциональная" в том смысле, что эта ПП является как бы "набором" задержек
тех величин, которые необходимы конструктору, причём, во многих случаях более
оптимальным/удобным, чем "набор", состоящий из нескольких вызываемых ПП.
4
Выбор того или иного "номинала" задержки происходит посредством вызова
соответствующей метки.
Например, нужно "сваять" многофункциональную ПП фиксированной задержки, в
которой имеется возможность многократного выбора (по желанию конструктора) любого из
трёх (можно "сваять" и большее их количество) интервалов времени задержки: 1 сек., 50 мс., 10 мс.,
и чтобы "по нулям" (1 000 000 м.ц., 50 000 м.ц., 10 000 м.ц.).
Один из вариантов программной реализации такого техзадания выглядит так:
;***************************************************************************************************
; Программа, позволяющая проверить (в симуляторе) работу многофункциональной (1 сек., 50 мс., 10 мс.)
; ПП фиксированной задержки. В симуляторе, установлена частота кварца 4 Мгц. (1м.ц. = 1мкс.).
;***************************************************************************************************
LIST p=16f84A ; Используется PIC16F84A.
#include <p16f84a.inc>; Подключение INC-файла PIC16F84A.
__CONFIG 03FF1H ; Бит защиты выключен, WDT выключен, XT - генератор.
;----------------------------------------
; "Прописка" регистров общего назначения.
;----------------------------------------
cblock 20h ; Назначение адреса первого регистра блока
; (можно назначить и другой начальный адрес).
Reg_1 ; Регистры
Reg_2 ; 3-байтного
Reg_3 ; счётчика.
endc ; Конец блока.
;------------------------------------
org 0 ; Выполнение программы начинается c 0-го PC-адреса.
goto START ; Переход на начало программы.
;***********************************************************************************************
;========================================================================================
; ПП многофункциональной задержки на 1 сек., 50 мс., 10 мс. (определяется выбором метки).
;========================================================================================
; Задержка 1 сек. (1 000 000 мкс.).
;------------------------------------
PAUZE_1S movlw .171 ;
movwf Reg_1 ; Предустановка
movlw .19 ; времязадающих
movwf Reg_2 ; констант.
movlw .6 ;
movwf Reg_3 ;
nop ; Калибровочный NOP.
nop ; Калибровочный NOP.
goto SNOVA ; Переход в исполнительную часть.
;------------------------------------
; Задержка 50 мс. (50 000 мкс.).
;------------------------------------
PAUZE_50MS movlw .235 ;
movwf Reg_1 ; Предустановка
movlw .65 ; времязадающих
movwf Reg_2 ; констант.
movlw .1 ;
movwf Reg_3 ;
goto SNOVA ; Переход в исполнительную часть.
;------------------------------------
; Задержка 10 мс. (10 000 мкс.).
;------------------------------------
PAUZE_10MS movlw .249 ;
movwf Reg_1 ; Предустановка
movlw .13 ; времязадающих
movwf Reg_2 ; констант.
movlw .1 ;
movwf Reg_3 ;
;------------------------------------
; Исполнительная часть.
;------------------------------------
SNOVA decfsz Reg_1,F ; Стандартный,
goto SNOVA ; 3-байтный,
decfsz Reg_2,F ; декрементный
goto SNOVA ; счётчик.
decfsz Reg_3,F ;
goto SNOVA ;
return ; Возврат по стеку.
;====================================================================================================
; Начало программы.
;====================================================================================================
START nop ; Символизирует часть программы.
call PAUZE_1S ; Вызов ПП задержки 1 сек. <- ТОЧКА ОСТАНОВКИ №1
nop ; Символизирует часть программы. <- ТОЧКА ОСТАНОВКИ №2
call PAUZE_50MS ; Вызов ПП задержки на 50 мс.
nop ; Символизирует часть программы.
call PAUZE_10MS ; Вызов ПП задержки на 10 мс.
5
nop ; Символизирует часть программы.
goto $ ; "Мертвяк".
;**************************************************************************************************
end ; Конец программы.

Как видите, исполнительная часть не "тиражируется", а одна-разъединственная.


В данном случае, она "ориентируется на байтность" самой продолжительной задержки
(1 сек., 3-байтный счёт).
Но ведь остальные-то задержки (50 мс. и 10 мс.) 2-байтные, а если в незадействованном
байте исполнительной части "лежит" 0 (в данном случае, речь идёт о Reg_3), то фактическая
задержка будет во много раз больше расчётной, ведь декремент нуля даст .255, ну и
так далее.
Значит, в случаях работы с 2-байтными задержками, в 3-м байте нужно предустановить
1, что и сделано (Reg_3 = 1).
В этом случае, первый же декремент содержимого Reg_3, в конечном итоге (я это
называю "транзитным проскоком проверки"), приведёт к возврату (return), что есть окончание
отработки ранее выбранной, 2-байтной, фиксированной задержки.
Так как вызов ПП и возврат из неё, а также переход в исполнительную часть
(по окончании предустановок времязадающих констант задержек на 1 сек. и 50 мс.), а также предустановки 1
(см. предустановки Reg_3 задержек на 50 мс. и 10 мс.), затягивают расчётные интервалы времени
отработки задержек, то их нужно соответствующим образом скорректировать (в сторону
уменьшения).
Для реализации этого, в большинстве случаев, достаточно уменьшить числовое
значение предустановки регистра младшего разряда (в данном случае, Reg_1) и "врезать" (или
убрать "лишние") нужное количество калибровочных NOPов (если это необходимо).
Проверка результатов коррекции осуществляется в MPLAB-секундомере, вплоть до
получения нужного результата.
Тактика программной реализации подобного рода ПП может быть и иная, но суть одна
и та же.
В "нижележащей" разновидности ПП фиксированной задержки, время задержки
определяется содержимым W.
Перед "влётом" в такую ПП, в W (аккумулятор) записывается константа или копируется
содержимое какого-то регистра.
Например, суть работы с константами выглядит так:
;***************************************************************************************************
; Программа, позволяющая проверить (в симуляторе) работу ПП фиксированной задержки.
; В симуляторе, установлена частота кварца 4 Мгц. (1м.ц. = 1мкс.).
;***************************************************************************************************
LIST p=16f84A ; Используется PIC16F84A.
#include <p16f84a.inc>; Подключение INC-файла PIC16F84A.
__CONFIG 03FF1H ; Бит защиты выключен, WDT выключен, XT - генератор.
;----------------------------------------
; "Прописка" регистров общего назначения.
;----------------------------------------
cblock 20h ; Назначение адреса первого регистра блока
; (можно назначить и другой начальный адрес).
Reg ; Регистр 1-байтного счётчика.
endc ; Конец блока.
;------------------------------------
org 0 ; Выполнение программы начинается c 0-го PC-адреса.
goto START ; Переход на начало программы.
;***********************************************************************************************
;============================================================================
; ПП многофункциональной задержки (время задержки определяется содержимым W).
;============================================================================
PAUSE_X movwf Reg ; W -> Reg
decfsz Reg,F ; Стандартный, 1-байтный,
goto $-1 ; декрементный счетчик.
return ; Возврат по стеку.
;====================================================================================================
; Начало программы.
;====================================================================================================
START nop ; Символизирует часть программы.
movlw .50 ; В данном случае, .50, но можно и другие значения.
call PAUSE_X ; Вызов ПП задержки.
nop ; Символизирует часть программы.
movlw .100 ; В данном случае, .100, но можно и другие значения.
call PAUSE_X ; Вызов ПП задержки.
nop ; Символизирует часть программы.

6
movlw .150 ; В данном случае, .150, но можно и другие значения.
call PAUSE_X ; Вызов ПП задержки.
nop ; Символизирует часть программы.
goto $ ; "Мертвяк".
;****************************************************************************************************
end ; Конец программы.

В данном случае, это 3-разовый вызов, но можно вызвать и любое количество раз.
Подставляя различные числовые значения констант (.0 … .255), можно убедиться в том,
что время отработки задержки будет изменяться пропорционально этому значению.
Если в W копируется не константа, а содержимое какого-то регистра, то
movlw <константа> заменяется на movf <регистр>,W
Примечание: вызываемую программу можно переместить, из начала программы, в её конец (перед директивой end).
В этом случае, в "шапке" программы, команду goto START можно убрать.

“Врезки” во внутренний цикл фиксированной задержки.


По причине того, что все фиксированные, декрементные/инкрементные задержки
отрабатываются циклично, в исполнительную часть любой такой задержки, с целью
“затягивания” интервала времени её отработки, можно “врезать” некую команду или
группу команд.
При прочих, равных условиях (в частности, числовые значения времязадающих констант не изменяются),
такого рода “врезка” (она отрабатывается не за 0 секунд, а поболее) увеличивает интервал времени
отработки внутреннего цикла фиксированной задержки, а значит и интервал времени
отработки их заданного, суммарного количества (что и есть итоговый результат).
Если речь идёт о равенстве интервалов времени отработки “материнской” (это та, в
которой нет “врезки”) и “дочерней” (это та, в которой есть “врезка”) фиксированных задержек, то в
некоторых случаях, можно “сконструировать дочернюю” задержку, “байтность” которой
менее “материнской”.
В простейшем случае, можно “врезать” одну или несколько “нейтральных” команд NOP
(одна команда NOP увеличивает время отработки цикла задержки на 1 м.ц.), одну или несколько команд
goto $+1 (одна команда goto $+1 увеличивает время отработки цикла задержки на 2 м.ц.) или их
комбинацию (зависит от конкретных обстоятельств).
Если же речь идёт о том, что WDT включен, и интервал времени отработки задержки
соизмерим с интервалом времени “срабатывания” WDT (а тем паче более его), то во
внутренний цикл фиксированной, декрементной/инкрементной задержки, в обязательном
порядке, должна быть “врезана” команда clrwdt, а иначе, в интервале времени
отработки задержки, “сработает” WDT (сброс на начало программы) и последующая часть
программы (та, которая исполняется после окончания задержки) никогда не будет исполнена.
Если “дочь” должна отрабатываться за такое же время, за которое отрабатывается
“мать”, то в “дочери” необходимо произвести (с использованием MPLAB-секундомера)
соответствующую коррекцию числовых значений времязадающих констант.
Простой пример такой коррекции (“врезка” - один NOP. Время отработки “дочери” = времени отработки
“матери” = 1 сек.), выглядит так:

;***************************************************************************************************
; Программа, позволяющая проверить (в симуляторе) работу ПП фиксированной задержки c “врезкой”.
; В симуляторе, установлена частота кварца 4 Мгц. (1м.ц. = 1мкс.).
;***************************************************************************************************
LIST p=16f84A ; Используется PIC16F84A.
#include <p16f84a.inc>; Подключение INC-файла PIC16F84A.
__CONFIG 03FF1H ; Бит защиты выключен, WDT выключен, XT - генератор.
;----------------------------------------
; "Прописка" регистров общего назначения.
;----------------------------------------
cblock 20h ; Назначение адреса первого регистра блока
; (можно назначить и другой начальный адрес).
Reg_1 ; Регистры
Reg_2 ; 3-байтного
Reg_3 ; счётчика.
endc ; Конец блока.
;------------------------------------
org 0 ; Выполнение программы начинается c 0-го PC-адреса.
;***********************************************************************************************
;===============================================================================================
; Начало программы.
;===============================================================================================
nop ; Символизирует часть программы.

7
;=======================================
; ПП задержки на 1 000 000 мкс. (1 сек.)
;=======================================
; Подготовительная часть.
;------------------------------------
movlw .165 ; Без “врезки”, было .173
movwf Reg_1 ; Предустановка
movlw .207 ; времязадающих (Без “врезки”, было .19)
movwf Reg_2 ; констант.
movlw .4 ; Без “врезки”, было .6
movwf Reg_3 ;
;------------------------------------
; Исполнительная часть.
;------------------------------------
SNOVA nop ; "Врезка", увеличивающая время отработки внутреннего
; цикла (если WDT включен, то NOP заменяется на clrwdt).
decfsz Reg_1,F ; Стандартный,
goto SNOVA ; 3-байтный,
decfsz Reg_2,F ; декрементный
goto SNOVA ; счётчик.
decfsz Reg_3,F ;
goto SNOVA ;
;;; nop ; ЭТОТ NOP НЕ НУЖЕН (ЛИШНИЙ).
nop ; Калибровочный NOP.
;------------------------------------
goto $ ; "Мертвяк". <- ТОЧКА ОСТАНОВКИ
;**************************************************************************************************
end ; Конец программы.

Если WDT выключен и “врезка” не приводит к уменьшению “байтности” счётчика, то


эта “врезка” просто не выгодна (зачем нужен достаточно трудоёмкий подбор значений времязадающих
констант? Проще воспользоваться виндопрограммой расчёта задержек) .
Исключением являются случаи работы с включенным WDT, интервал времени
“срабатывания” которого соизмерим или менее интервала отработки фиксированной
задержки.
В этих случаях, без “врезки” хотя бы одной команды clrwdt (плюс подбор значений
времязадающих констант) не обойтись.
Ниже приведён пример того, как использование “врезки” уменьшает “байтность” счёта,
с 3-байтного, до 2-байтного (плюс, если это нужно, возможность сброса WDT. См. комментарии):
;***************************************************************************************************
; Программа, позволяющая проверить (в симуляторе) работу ПП фиксированной задержки c “врезкой”.
; В симуляторе, установлена частота кварца 4 Мгц. (1м.ц. = 1мкс.).
;***************************************************************************************************
LIST p=16f84A ; Используется PIC16F84A.
#include <p16f84a.inc>; Подключение INC-файла PIC16F84A.
__CONFIG 03FF1H ; Бит защиты выключен, WDT выключен, XT - генератор.
;----------------------------------------
; "Прописка" регистров общего назначения.
;----------------------------------------
cblock 20h ; Назначение адреса первого регистра блока
; (можно назначить и другой начальный адрес).
Reg_1 ; Регистры 2-байтного
Reg_2 ; счётчика.
endc ; Конец блока.
;------------------------------------
org 0 ; Выполнение программы начинается c 0-го PC-адреса.
;***********************************************************************************************
;===============================================================================================
; Начало программы.
;===============================================================================================
nop ; Символизирует часть программы.
;=========================================
; ПП задержки на 250 000 мкс. (0,25 сек.)
;=========================================
; Подготовительная часть.
;------------------------------------
movlw .1 ;
movwf Reg_1 ; Предустановка
movlw .196 ; времязадающих
movwf Reg_2 ; констант.
;------------------------------------
; Исполнительная часть.
;------------------------------------
SNOVA goto $+1 ; "Врезка", увеличивающая время отработки внутреннего
; цикла (если WDT включен, то NOP и clrwdt).
decfsz Reg_1,F ; Стандартный,
goto SNOVA ; 2-байтный,

8
decfsz Reg_2,F ; декрементный
goto SNOVA ; счётчик.
;------------------------------------
goto $ ; "Мертвяк". <- ТОЧКА ОСТАНОВКИ
;**************************************************************************************************
end ; Конец программы.

Выше, с целью уяснения сути, приведены примеры простых “врезок”, но ничто не


мешает “врезать” и нечто более сложное, причём, без ограничений “степени
сложности”. Суть задержки от этого не изменяется.
При прочих, равных условиях, чем “массивнее” (по времени отработки) “врезка”, тем менее
“байтность” счёта.
Во многих случаях, задержку с “врезкой”, представляющей собой (это о “врезке”) цикл
отработки достаточно “крутой” функциональности, при условии последовательной
отработки строго заданного количества таких циклов, выгодно (в понятийном смысле) назвать
счётчиком проходов (это название придумано мной. Можно назвать и иначе).
Например, “скелет” программной процедуры 2/10 преобразования (для случая отработки 8-ми
проходов) выглядит так:
;....................................
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
; ПП 2_10 преобразования для случаев преобразования 1-байтных, двоичных чисел в 2-разрядные,
; 2_10 числа.
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
; Подготовка к преобразованию.
;-----------------------------------
movlw .8 ; Запись, в регистр Count, числа проходов
movwf Count ; преобразования, равного количеству
; битов регистра Reg_L.
clrf LED0 ; Очистка регистра LED0 (подготовка к сдвигам).
;---------------------------------------------------------------------------
; Циклический сдвиг влево (побитная "переправка" содержимого Reg_L, в LED0).
;---------------------------------------------------------------------------
LOOP16 rlf Reg_L,F ; Циклический сдвиг влево 1-байтного двоичного
; числа, записанного в регистре Reg_L,
; на одну позицию, через бит С регистра STATUS.
rlf LED0,F ; Циклический сдвиг влево 1-байтного двоичного
; числа, записанного в регистре LED0,
; на одну позицию, через бит С регистра STATUS.
;-----------------------------------
decfsz Count,F ; Декремент (-1) содержимого регистра Count,
; с сохранением результата в нем же.
goto adjDEC ; Если результат не=0, то переход в ПП adjDEC
; Если результат =0 (все проходы отработаны),
; то программа исполняется далее.
;------------------------------------
; Распределение полубайтов.
;------------------------------------
;....................................
;....................................
goto $ ; В данном случае, это "мертвяк", а в других
; случаях - выход из ПП 2_10 преобразования.
;------------------------------------
; Преобразование формы числа.
;------------------------------------
adjDEC ..........................
;....................................
goto LOOP16 ; Переход на следующий цикл числовых преобразований.
;------------------------------------
;....................................

Как видите, в подготовительной части задаётся фиксированное количество проходов


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

9
“Экзотические” в том смысле, что они отличаются, от стандартных, более “лихо
закрученным, кольцевым сюжетом”.
Пример (2-байтный счёт):
;***************************************************************************************************
; Программа, позволяющая проверить (в симуляторе) работу ПП фиксированной задержки.
; В симуляторе, установлена частота кварца 4 Мгц. (1м.ц. = 1мкс.).
;***************************************************************************************************
LIST p=16f84A ; Используется PIC16F84A.
#include <p16f84a.inc>; Подключение INC-файла PIC16F84A.
__CONFIG 03FF1H ; Бит защиты выключен, WDT выключен, XT - генератор.
;----------------------------------------
; "Прописка" регистров общего назначения.
;----------------------------------------
cblock 20h ; Назначение адреса первого регистра блока
; (можно назначить и другой начальный адрес).
Reg_1 ; Регистры 2-байтного
Reg_2 ; счётчика.
endc ; Конец блока.
;------------------------------------
org 0 ; Выполнение программы начинается c 0-го PC-адреса.
;***********************************************************************************************
;====================================
; ПП задержки на 30 401 мкс.
;====================================
; Подготовительная часть.
;------------------------------------
movlw .100 ;
movwf Reg_1 ; Предустановка
;------------------------------------------------------------
; Исполнительная часть, с “элементом” подготовительной части.
;------------------------------------------------------------
SNOVA_1 movlw .100 ; времязадающих
movwf Reg_2 ; констант.

SNOVA_2 decfsz Reg_2,F ; Нестандартный,


goto SNOVA_2 ; 2-байтный,
decfsz Reg_1,F ; декрементный
goto SNOVA_1 ; счётчик.
;------------------------------------
goto $ ; "Мертвяк". <- ТОЧКА ОСТАНОВКИ
;**************************************************************************************************
end ; Конец программы.

Как видите, имеется не одна метка, а две, и “кусок” подготовительной части входит в
состав исполнительной части.
А это задержка, на такое же время, только не “экзотическая”, а стандартная:
;***************************************************************************************************
; Программа, позволяющая проверить (в симуляторе) работу ПП фиксированной задержки.
; В симуляторе, установлена частота кварца 4 Мгц. (1м.ц. = 1мкс.).
;***************************************************************************************************
LIST p=16f84A ; Используется PIC16F84A.
#include <p16f84a.inc>; Подключение INC-файла PIC16F84A.
__CONFIG 03FF1H ; Бит защиты выключен, WDT выключен, XT - генератор.
;----------------------------------------
; "Прописка" регистров общего назначения.
;----------------------------------------
cblock 20h ; Назначение адреса первого регистра блока
; (можно назначить и другой начальный адрес).
Reg_1 ; Регистры 2-байтного
Reg_2 ; счётчика.
endc ; Конец блока.
;------------------------------------
org 0 ; Выполнение программы начинается c 0-го PC-адреса.
;***********************************************************************************************
;====================================
; ПП задержки на 30 401 мкс.
;====================================
; Подготовительная часть.
;------------------------------------
movlw .122 ;
movwf Reg_1 ; Предустановка
movlw .40 ; времязадающих
movwf Reg_2 ; констант.
;------------------------------------
; Исполнительная часть.
;------------------------------------
SNOVA decfsz Reg_1,F ; Стандартный,
goto SNOVA ; 2-байтный,

10
decfsz Reg_2,F ; декрементный
goto SNOVA ; счётчик.
;------------------------------------
goto $ ; "Мертвяк". <- ТОЧКА ОСТАНОВКИ
;**************************************************************************************************
end ; Конец программы.

Можно применить и то, и другое, но стандартная задержка удобнее (комфортно


рассчитывается в виндопрограмме Петра Высочанского) , а значения времязадающих констант
“экзотической” задержки нужно подбирать (виндопрограммы, в которой рассчитываются такие задержки, в
наличии пока нет).
"Плавающие" задержки.
В любом микроконтроллере есть так называемые аппаратные модули, которые
"запускаются в работу" программно, что есть начало отработки соответствующих,
аппаратных процессов, значительная часть которых отрабатывается в довольно-таки
"массивных" интервалах времени (вплоть до нескольких мс.).
Если аппаратный процесс последовательно отрабатывается несколько раз, то с целью
недопущения "накладок" одного на другое, необходима идентификация окончания
текущего, аппаратного процесса.
И в самом деле, по здравому разумению, последующий, аналогичный, аппаратный
процесс нужно начинать только после окончания отработки предыдущего, а иначе
произойдёт "накладка" одного на другое, которая ничем хорошим не заканчивается.
То есть, прежде чем программно "запускать в работу" последующий, аппаратный
процесс, который аналогичен текущему, целесообразно программно "дождаться"
окончания текущего, аппаратного процесса.
Если предположить, что "специализированные" (под это дело), программные критерии
окончания текущего, аппаратного процесса отсутствуют, то не остаётся ничего другого,
как применить фиксированную задержку, причём, с "перебором" (по времени),
гарантированно обеспечивающим отсутствие "бяк" (при любом "раскладе").
А именно, RC-генераторы, которые тактируют многие аппаратные модули, имеют
относительно низкую термостабильность ("гуляние" частоты), плюс, технологический "разброс"
параметров R и С.
То есть, в случае применения фиксированной задержки, нужно ориентироваться не на
типовое время отработки аппаратного процесса, а на максимальное время его
отработки.
Например, типовое время отработки аппаратного процесса EEPROM-записи, в одну
EEPROM-ячейку, - 4 мс., но для обеспечения "безбяковости" массового тиражирования
устройства, нужна задержка порядка 10 мс.
То есть, в этом случае, исполнение программы довольно-таки существенно
"притормаживается" (относительно конкретного оптимума), плюс, довольно-таки приличное
количество команд задержки.
Нужно отдать должное разработчикам, так как они устранили это недоразумение путём
"укомплектования" аппаратных модулей флагами окончания соответствующих,
аппаратных процессов.
То есть, каждый аппаратный модуль имеет "свой" флаг окончания аппаратного
процесса, любой из которых относится к флагам 2-й группы.
А именно, одно из состояний такого флага устанавливается программно, а другое -
аппаратно.
После того как аппаратный процесс закончен, его можно снова "запустить в работу"
(какое угодно количество раз), то ли сразу же после окончания предыдущего, аппаратного
процесса, то ли позднее (когда конструктору захочется).
Соответственно, имеется критерий окончания аппаратного процесса, на который и
ориентирована так называемая (мной. Кстати, я придумал такое название) "плавающая" задержка.
То есть, после осуществления "запуска в работу" текущего, аппаратного процесса, либо
"на влёте" в него (если нужно "переждать" окончание предыдущего, аналогичного, аппаратного процесса) ,
организуется простенькая, "плавающая" задержка, в которой проверяется состояние
соответствующего флага.
Лично мне, больше нравится первое ("после", а не "до"). К этому и "привяжусь".
В принципе, суть проста: сначала производятся какие-то программные,
подготовительные операции, потом аппаратный процесс программно "запускается в
11
работу", а затем рабочая точка программы "закольцовывается" в "плавающей" задержке
и мотает в ней "витки" до тех пор, пока соответствующий флаг не изменит своё
состояние на противоположное ("сигнал" окончания отработки аппаратного процесса), после чего
программа исполняется далее.
Например, при работе с аппаратным модулем АЦП, эта суть выглядит так:
; ...................................
;-------------------------------------------
; Подготовительные операции.
;-------------------------------------------
; ...................................
;-------------------------------------------
; Начало аналого-цифрового преобразования.
;-------------------------------------------
bsf ADCON0,GO ; "Запуск в работу" аппаратной процедуры АЦП.
;-----------------------------------------------
; Ожидание окончания АЦП ("плавающая" задержка).
;-----------------------------------------------
btfsc ADCON0,GO ; Ожидание окончания аналого-цифрового
goto $-1 ; преобразования.
;--------------------------------------------
; АЦП закончено. Результат - в ADRESH/ADRESL.
;--------------------------------------------
; ...................................

А при работе с аппаратным модулем EEPROM-записи, эта суть выглядит так:


; ...................................
;-------------------------------------------
; Подготовительные операции.
;-------------------------------------------
; ...................................
;-------------------------------------------
; Начало EEPROM-записи одного байта данных.
;-------------------------------------------
bsf EECON1,WR ; "Запуск в работу" аппаратной процедуры записи.
;---------------------------------------------------------
; Ожидание окончания EEPROM-записи ("плавающая" задержка).
;---------------------------------------------------------
btfsc EECON1,WR ; Ожидание окончания
goto $-1 ; EEPROM-записи.
;----------------------------------------------------------------------------------------
; EEPROM-запись закончена. В ранее выбранную EEPROM-ячейку записано ранее заданное число.
;----------------------------------------------------------------------------------------
; ...................................

Как видите, "плавающая" задержка, вне зависимости от продолжительности


"пережидаемого" аппаратного процесса, очень компактна, и она как бы "подстраивается"
под время его отработки ("тютелька в тютельку". В том смысле, что "временнЫх переборов" либо нет, либо
они есть, но такие незначительные, что ими можно пренебречь) .
Поэтому и названа "плавающей" (а можно назвать и "адаптирующейся").
То же самое применимо и к относительно сложным внешним (по отношению к ПИКу)
устройствам, собранных на основе "своих", специфических микроконтроллеров.
Например, ЖК-модуль на основе микроконтроллера HD44780.
В нём есть флаг занятости, с названием BF, который "срабатывает" по факту
окончания отработки текущего, аппаратного ЖК-процесса.
Суть одна и та же, но только по отношению к опросу внешнего (по отношению к ПИКу)
устройства.
А именно, в этом случае, канал порта, подключённый к соответствующему выводу
ЖК-модуля, в комплексе с осуществлением необходимых, для опроса флага BF,
подготовительных операций, в интервале времени опроса флага BF, должен работать
"на вход" (опрос флага), а после окончания аппаратного ЖК-процесса (в этом случае, происходит
выход из "плавающей" задержки), его нужно перенастроить на работу "на выход" (см. ПП ENTER_BF
программы, например, BP_MOD.asm), в комплексе с подготовительными операциями, которые
необходимы для дальнейшей работы ЖК-модуля.

Возможны дополнения и корректировки.

Текущая работа 2011 года        http://ikarab.narod.ru         E-mail: karabea@lipetsk.ru

12