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

6/6/4. Использование режима захвата при измерении длительности импульса.

Пример введения, в двухдиапазонный частотомер (PIC16F628A, ЖКИ на основе


HD44780), дополнительной функции измерения длительности импульса, с
автоматическим переключением поддиапазонов
(диапазон измерения от 16 мкс. до 131071 мкс., шаг измерения 1 мкс.).

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


дальнейшем я буду называть импульсом, к конкретному уровню.
Длительность импульса есть величина интервала времени между двумя соседними,
комплиментарными (взаимно противоположными) перепадами.
Если речь идет не об одном, отдельном импульсе, а о нескольких импульсах,
входящих в состав периодической, импульсной последовательности, то, строго говоря, в
интервале времени между началом формирования 1-го перепада текущего такта и
окончанием формирования 1-го перепада следующего такта, формируется 2 импульса с
различными уровнями.
Импульс типа переход 0/1 - задержка - переход 1/0.
Импульс типа переход 1/0 - задержка - переход 0/1.
В 1-м случае, импульс будет иметь единичный уровень.
Во 2-м случае, импульс будет иметь нулевой уровень.
Часто их называют положительным и отрицательным импульсами (или даже
импульсами положительной и отрицательной полярности), что совсем не корректно, так
как, за исключением редких случаев, они формируются в одной и той же области
напряжений (чаще всего - в положительной).
На кой ляд нужен этот понятийный "бардак", который только запутывает?
С целью его недопущения, формулирую четкие "правила игры".
"Статус" импульса "присваивается" импульсу, имеющему единичный уровень.
Тогда как "обозвать" импульс с нулевым уровнем?
Он называется "скважиной" ("промежутком").
Таким образом, скважина есть интервал времени между двумя соседними импульсами.
Чувствуете "куда ветер дует"?
А "дует" он совсем не просто так, а на такое понятие как "скважность".
Вот Вам и совмещение, в едином целом, того, что вольно или не вольно "рвется на
части".
Что получится, если разъединить "сиамских близнецов"?
В 99,9 процентах случаев - ничего хорошего.
Но, тем не менее, такое разъединение происходит сплошь и рядом, причем,
"понятийнотопорными методами".
У меня "такой номер не пройдет".
Есть импульсы (с положительными уровнями) и есть скважины между этими
импульсами.
Точка.
От этого и буду "плясать".
Вообще-то, с этим и раньше не мешало бы определиться, но лучше поздно, чем
никогда.
Итак, нужно замерить длительность импульса.
Так как процедура замера длительности периода, в основном, освоена, то разумнее
всего присвоить ей "статус живородящей матери" и "застимулировать ее детородные
функции".
С 1-м захватом все понятно, так как именно с него начинается замер и периода, и
длительности импульса.
Теперь, для того чтобы замерить длительность текущего импульса, нужно перестроить
тип захвата с "захвата по каждому 16-му переднему фронту (переход от 0 к 1)
сигнала на выводе RB3" на "захват по каждому заднему фронту (переход от 1 к 0)
сигнала на выводе RB3".
Что касается последнего типа захвата, то другого просто не дано (все претензии - к
разработчикам), так как это единственный тип захвата, который происходит по заднему
фронту сигнала на выводе RB3 (все остальные типы захватов ориентированы на
передний фронт).

1
Где перестраиваться?
"Плавающая" задержка, поневоле, "оставлена в покое", значит остается ПП
прерывания.
Другого, опять же, не дано.
Вопрос: "В какой из сценариев ПП прерывания врезать группу команд перестройки
типа захвата"?
Ответ: в 1-й сценарий.
Во 2-м сценарии, эту перестройку осуществлять нельзя хотя бы по той простой
причине, что подсчет длительности импульса производится между 1-м и 2-м событиями
захватов ("после драки кулаками не машут").
При переключении типа события захвата, нужно учитывать следующую специфику.
Если, на момент перестройки типа захвата, ранее, был установлен некий тип захвата
(любой), то, после перестройки типа захвата, первый (после этой перестройки) захват
будет произведен "по старинке", и только начиная со 2-го захвата, они будут
производиться в соответствии с "новой" настройкой типа захвата (аппаратная
специфика).
Естественно, что такая перестройка совсем не есть "зер гут", и особенно в данном
случае, когда за один цикл измерения осуществляется только 2 захвата.
Вопрос: "Как быть"?
Ответ: перед перестройкой типа захвата, нужно сбросить (выключить) модуль CCP.
Только в этом случае, первый же захват будет произведен в соответствии с
установленной настройкой.
То что Вы прочитали, есть рекомендации разработчиков, которые я добросовестно
выполнил.
Это выглядит так:

clrf CCP1CON ; Выключение (сброс) модуля CCP.


movlw b'00000100' ; Захват по каждому заднему фронту
movwf CCP1CON ; сигнала на выводе RB3.

Эту группу команд и нужно "врезать" в 1-й сценарий ПП прерывания.


Вопрос: "Куда именно"?
Ответ: удобнее всего - сразу же после команд числовой коррекции TMR1.
Можно "врезать" и до них, но в этом случае нужно сменить числовое значение
константы (с .9 на .12).
Команда bcf Status,Z обязательно должна располагаться после (а не до) группы команд
перестройки типа захвата, так как в ней имеется команда clrf, поднимающая флаг Z.
Величина интервала времени, от момента возникновения 1-го захвата и до окончания
возврата рабочей точки программы (из 1-го сценария ПП прерывания) в "плавающую"
задержку, имеет принципиальное значение.
А эта величина, за счет "врезки", увеличилось на 3 машинных цикла, и ничего с этим
не поделаешь, так как "ни одного слова из песни не выкинешь".
С последствиями разберемся позднее, а пока нужно "выстроить скелет".
Предположим, что все распрекрасно: перестройка типа захвата произошла, и рабочая
точка программы вернулась, из 1-го прерывания, в "плавающую" задержку.
В ней начинается "подсиживание" события 2-го захвата, но инициализируемого уже не
каждым 16-м передним фронтом сигнала на выводе RB3, а каждым задним фронтом
сигнала на выводе RB3.
Вдруг, откуда не возьмись, нарисовался страшный и ужасный (грозный начальник с
кнутом, дубинкой и мощным оральником) задний фронт импульса.
Используя свою луженую глотку (соловей – разбойник отдыхает), он издает мощнейший
и ужаснейший вопль (дескать, разбаловались тут без меня, обормоты, но и для
обозначения своего присутствия тоже).
Аппаратная часть ПИКа (великий, хитропопый специалист по переводу стрелок) также
вопит ПОЛУНДРА (лишние неприятности никому не нужны, да и стрелки перевести
можно) и отвешивает увесистый пинок рабочей точке программы (обленилась,
понимаешь ли, пасясь на зеленом лужку и кушая казенную травку).

2
От такой неожиданной неожиданности, с удивленными глазами идеально круглой
формы, та улетает во 2-й сценарий ПП прерывания и попадает в ее цепкие лапы (тот
же грозный начальник, только рангом пониже).
Во 2-м сценарии ПП прерывания, над бедной женщиной (точкой) издеваются точно так
же (один к одному), как и при измерении периода.
После этого, ее, измочаленную и потерявшую веру в человечество, футболят в
плавающую задержку, из которой она, не солоно хлебавши (вот гады, даже попастись
не дали!), вылетает, как ошпаренная, по сценарию типа закончен бал, погасли свечи.
Далее, она имеет возможность перевести дух и восстановить утерянную веру в
человечество, а также и все свои потрепанные женские прелести (до следующего
безобразия).
Вывод: тяжела и неказиста доля русского связиста (в данном случае, связистки), и его
(ее) нужно всячески уважать за такой тяжкий, но почетный и необходимый труд.
Кавычки ставить не стал: слишком много идиотских моментов, хотя, если разобраться,
они взяты из нашей реальной жизни, в которой этого добра навалом (смех сквозь
слезы).
Надеюсь на то, что со смыслом сказанного Вы сознательно и подсознательно
разберетесь.
Итак, в Temp_H/Temp_L что-то "осело".
Что?
Результат подсчета, который делить на 16 не нужно!
Почему?
Потому, что 2-й захват произошел при установленном типе захвата по каждому
заднему фронту.
Это соответствует Кдел. предделителя модуля CCP = 1, то есть, деления просто не
происходит.
Вопрос: "К чему приводит смена Кдел. предделителя с 16-ти на 1"?
Ответ: она приводит к тому, что:
- при обработке результата подсчета, не нужно применять процедуру деления на 16,
а проще говоря, ее можно смело "убить".
- при сохранении неизменным шага измерения (1 мкс.), нижняя граница диапазона
измерения "отодвигается", минимум, до 65535 мкс., а с учетом того, что имеет место
быть контроль состояния флага переполнения TMR1 (и "оргвыводы" из этого), нижняя
граница диапазона измерения "отодвигается" еще дальше - до
65536 + 65536 – 1 = 131071 мкс.
Все это распрекрасно, но не стоит забывать про закон сохранения энергии: если в
одном месте прибыло, то в другом месте должно убыть.
Вопрос: "Что прибыло, понятно. От чего убыло"?
Ответ: убыло "с другого конца": верхняя граница диапазона измерения понизилась.
На сколько?
Это выяснится позднее. Сейчас же, с полной уверенностью можно сказать только то,
что, при таком "раскладе", длительность импульса в 1 мкс. не замеришь.
А теперь ближе к практике, то есть, к "железяке".
"Мать" - программа Hz_Mks_2.asm.
"Дочь" - программа Hz_Mks_3.asm.
В целях обеспечения комфортных условий Вашего "въезда" в процедуру измерения
длительности импульса, программа Hz_Mks_3.asm адаптирована только под измерение
длительности импульса (вместо измерения периода, производится измерение
длительности импульса).
Сейчас Вы своими глазами увидите то, что, в процедурах измерения периода и
длительности импульса, много общего (просто сравните тексты программ
Hz_Mks_2.asm. и Hz_Mks_3.asm).

;********************************************************************************
; Hz_Mks_3.asm ПРОГРАММА 2-ДИАПАЗОННОГО 8-РАЗРЯДНОГО ЧАСТОТОМЕРА-ИЗМЕРИТЕЛЯ
; ДЛИТЕЛЬНОСТИ ИМПУЛЬСА С ИСПОЛЬЗОВАНИЕМ ЖКИ МОДУЛЯ НА ОСНОВЕ HD44780.
; Для измерения длительности импульса, задействован модуль CCP,
; работающий в режиме захвата.
;********************************************************************************

3
; "Практикум по конструированию устройств на PIC контроллерах"
; (http://ikarab.narod.ru)
; Корабельников Евгений Александрович karabea@Lipetsk.ru
;********************************************************************************
; Длительности интервалов времени измерения частоты: 1сек., 10сек.
; Диапазон измерения длительности импульса от 16 до 131071 мкс.,
; шаг измерения 1 мкс.
; "Помощник": ЖКИ модуль на основе м/контроллера HD44780: 2 строки по 16 символов
; 4-разрядный, двунаправленный интерфейс: задействованы выводы порта В RB4...7.
; Выводы порта В RB0 и RB1 задействованы под двухкнопочную клавиатуру
; (Кн1 и Кн2 соответственно).
; Вывод порта В RB3 - счетный вход модуля CCP, работающего в режиме захвата.
; Вывод порта В RB2 не задействован.
; Функции выводов порта А:
; RA0 - RW,
; RA1 - RS,
; RA2 - E,
; RA3 - блокировочный вывод,
; RA4 - счетный вход TMR0,
; Выводы RA3, RA4 и RB3 между собой электрически соединены.
; Кварц 4000 Кгц (1 м.ц.= 1 мкс.).
; Используется PIC16F628A.
;----------------------------------------------
; Объем программы: 482 слова в памяти программ.
;********************************************************************************
LIST p=16F628A ; "Привязка" MPLAB к микроконтроллеру
; PIC16F628A.
__CONFIG 03F25H ; Определение значений битов конфигурации:
; бит защиты выключен, WDT включен,
; стандартный генератор XT.
;================================================================================
; "Прописка" регистров специального назначения.
;================================================================================
IndF equ 00h ; Доступ к памяти через FSR.
Tmr0 equ 01h ; Таймер TMR0.
OptionR equ 01h ; Регистр Option-банк1.
PC equ 02h ; Счетчик команд.
Status equ 03h ; Регистр Status.
FSR equ 04h ; Регистр косвенной адресации.
PortA equ 05h ; Регистр Port A.
TrisA equ 05h ; Регистр Tris A-банк1.
PortB equ 06h ; Регистр Port B.
TrisB equ 06h ; Регистр Tris B-банк1.
IntCon equ 0Bh ; Регистр IntCon.
EEData equ 1Ah ; Регистр EEData-банк1.
EECon1 equ 1Ch ; Регистр EECon1-банк1.
EEAdr equ 1Bh ; Регистр EEAdr-банк1.
EECon2 equ 1Dh ; Регистр EECon2-банк1.
CMCON equ 1Fh ; Регистр управления модулем компараторов.
PIE1 equ 0Ch ; Регистр разрешения прерываний
; от периферийных модулей.
PIR1 equ 0Ch ; Регистр флагов прерываний
; от периферийных модулей.
T1CON equ 10h ; Регистр управления модулем таймера TMR1.
CCP1CON equ 17h ; Регистр управления модулем CCP.
CCPR1L equ 15h ; Регистр младшего разряда CCP.
CCPR1H equ 16h ; Регистр старшего разряда CCP.
TMR1L equ 0Eh ; Регистр младшего разряда TMR1.
TMR1H equ 0Fh ; Регистр старшего разряда TMR1.
;================================================================================
; "Прописка" регистров общего назначения.
;================================================================================
; Регистры оперативной памяти частотомера.
;---------------------------------------------------
LED0 equ 70h ; Регистр младшего разряда LED0.
LED1 equ 71h ; ------------"----------- LED1.
4
LED2 equ 72h ; ------------"----------- LED2.
LED3 equ 73h ; ------------"----------- LED3.
LED4 equ 74h ; ------------"----------- LED4.
LED5 equ 75h ; ------------"----------- LED5.
LED6 equ 76h ; ------------"----------- LED6.
LED7 equ 77h ; Регистр старшего разряда LED7.
;---------------------------------------------------
; Регистры оперативной памяти измерителя
; длительности импульса.
;---------------------------------------------------
LED00 equ 30h ; Регистр младшего разряда LED00.
LED11 equ 31h ; ------------"----------- LED11.
LED22 equ 32h ; ------------"----------- LED22.
LED33 equ 33h ; ------------"----------- LED33.
LED44 equ 34h ; ------------"----------- LED44.
LED55 equ 35h ; Регистр старшего разряда LED55.
;---------------------------------------------------
; Регистры счетчика частоты.
;---------------------------------------------------
TimerL equ 78h ; Младший.
TimerM equ 79h ; Средний.
TimerH equ 7Ah ; Старший.
TimerHH equ 7Bh ; Самый старший.
;---------------------------------------------------
; Регистры временного хранения "захваченных" чисел.
;---------------------------------------------------
Temp_L equ 2Ch ; Младший.
Temp_H equ 2Dh ; Старший.
;---------------------------------------------------
; Регистры счетчика "грубой" доводки.
;---------------------------------------------------
SecL equ 20h ; Младший.
SecM equ 21h ; Средний.
SecH equ 22h ; Старший.
;---------------------------------------------------
; Регистры счетчика "точной" доводки.
;---------------------------------------------------
Kalib equ 7Ch ; Регистр счетчика "точной" доводки 4 м.ц.
Kalib_1 equ 7Dh ; Регистр счетчика "точной" доводки 3 м.ц.
;---------------------------------------------------
; Прочие.
;---------------------------------------------------
Mem equ 7Eh ; Регистр буферной памяти 2/10 преобразования.
Mem_1 equ 7Fh ; Регистр оперативной памяти клавиатуры.
Total equ 23h ; Указатель разрядов.
Count1 equ 24h ; Многофункциональный регистр.
Count equ 25h ; Регистр числа выводимых в строку символов.
Flag equ 26h ; Регистр указателя конца замера
; длительности импульса.
Bit equ 27h ; Регистр указателя переполнения TMR1.
Temp_0 equ 28h ; "Обманный" регистр.
;================================================================================
; Присвоение названий местам размещения результатов операций.
;================================================================================
F equ 1 ; Результат направить в регистр.
W equ 0 ; Результат направить в аккумулятор.
;================================================================================
; Присвоение названий битам регистров специального назначения.
;================================================================================
RP0 equ 5 ; Бит переключения банков.
RW equ 0 ; Бит №0 регистра PortA (вывод RA0 - линия RW)
RS equ 1 ; Бит №1 регистра PortA (вывод RA1 - линия RS)
E equ 2 ; Бит №2 регистра PortA (вывод RA2 - линия E)
BF equ 7 ; Бит №7 регистра PortB.
Z equ 2 ; Флаг нулевого результата.
C equ 0 ; Флаг переноса-заема.
5
CCP1IF equ 2 ; Флаг прерывания от модуля CCP.
TMR1IF equ 0 ; Флаг прерывания по переполнению TMR1.
;================================================================================
org 2100h ; Разрешение записи в EEPROM надписи.
DE " http://www. " ; Надпись в ячейках с адресами
; .00h ... 15h.
DE " ikarab.narod.ru" ; Надпись в ячейках с адресами
; .16h ... 31h.
;================================================================================
; Подготовка к началу исполнения программы.
;================================================================================
org 0 ; Начальная точка отсчета в PC - нулевой адрес
goto START ; Переход на начало программы.
org 4 ; Начать исполнение ПП прерывания c команды,
; которая, в PC, имеет адрес 04h.
;********************************************************************************

;================================================================================
; Подпрограмма прерывания.
;================================================================================
; Анализ содержимого указателя конца замера.
;-------------------------------------------
decfsz Flag,F ; Flag,F - 1 = ... Результат - в Flag.
goto WRITE_1 ; Если результат не=0, то производится
; проход №1.
; Если результат =0, то производится
; проход №2.
;--------------------------------------------------------------------------------
; Проход №2.
;--------------------------------------------------------------------------------
btfsc PIR1,TMR1IF ; Флаг прерывания по переполнению TMR1
; поднят или опущен?
bsf Bit,0 ; Если поднят, то Bit,0 устанавливается в 1.
; Если опущен, то в Bit,0 остается "лежать"
; ранее предустановленный 0 и программа
; исполняется далее.
movf CCPR1L,W ; Содержимое регистра CCPR1L
movwf Temp_L ; копируется в регистр Temp_L.
movf CCPR1H,W ; Содержимое регистра CCPR1H
movwf Temp_H ; копируется в регистр Temp_H.
bsf Status,Z ; Установка признака конца замера.
;-----------------------------------
bcf PIR1,CCP1IF ; Сброс флага прерывания от модуля CCP.
retfie ; Возврат из прерывания.
;--------------------------------------------------------------------------------
; Проход №1.
;--------------------------------------------------------------------------------
WRITE_1 movlw .9 ; Числовая
movwf TMR1L ; коррекция
clrf TMR1H ; TMR1H/TMR1L.

clrf CCP1CON ; Сброс модуля CCP.


movlw b'00000100' ; Захват по каждому заднему фронту
movwf CCP1CON ; сигнала на выводе RB3.

bcf Status,Z ; Установка признака продолжения замера.


;-----------------------------------
bcf PIR1,TMR1IF ; Сброс флага прерывания по переполнению TMR1.
bcf PIR1,CCP1IF ; Сброс флага прерывания от модуля CCP.
retfie ; Возврат из прерывания.
;********************************************************************************

;********************************************************************************
; ----------------------- "РАБОЧАЯ" ЧАСТЬ ПРОГРАММЫ ----------------------
6
;********************************************************************************
; "Рабочая" инициализация ЖКИ модуля.
;================================================================================
LCD_INIT movlw b'00101000' ; Установка: 4-разрядный интерфейс, 2 строки,
; 5х7 точек.
call ENTER_BF ; "Плавающая" задержка со стробом
; под команду 00101000.
;----> Возврат по стеку из ПП ENTER_BF.
LCD_INIT_1 movlw b'00101000' ; Установка: 4-разрядный интерфейс, 2 строки,
; 5х7 точек.
call ENTER_BF ; "Плавающая" задержка со стробом
; под команду 00101000.
;----> Возврат по стеку из ПП ENTER_BF.

movlw b'00001100' ; Установка: дисплей включен, видимое


; отображение курсора выключено.
call ENTER_BF ; "Плавающая" задержка со стробом
; под команду 00001100.
;----> Возврат по стеку из ПП ENTER_BF.

movlw b'00000001' ; Установка: очистка дисплея со сбросом


; данных, установка курсора в начало
; 1-й строки.
call ENTER_BF ; "Плавающая" задержка со стробом
; под команду 00000001.
;----> Возврат по стеку из ПП ENTER_BF.

return ; Возврат по стеку.


;================================================================================
; ПП "плавающей" задержки на основе анализа состояния флага занятости BF
; (вариант для 4-разрядного интерфейса).
;================================================================================
ENTER_BF movwf Mem ; Переправка старшего п/байта регистра W на
movwf PortB ; линии RB4...7
; (состояния линий RB0...3 не важны).
;------------------------------------------
; Запуск в работу старшего п/байта (строб).
;------------------------------------------
nop ; Задержка в 1 м.ц.
bsf PortA,E ; Установка на линии Е "1".
nop ; Задержка в 1 м.ц.
bcf PortA,E ; Установка на линии Е "0".
;------------------------------------------
swapf Mem,W ; Смена п/байтов с сохранением результата
; операции в W.
movwf PortB ; Переправка младшего п/байта регистра W на
; линии RB4...7
; (состояния линий RB0...3 не важны).
;------------------------------------------
; Запуск в работу младшего п/байта (строб).
;------------------------------------------
nop ; Задержка в 1 м.ц.
bsf PortA,E ; Установка на линии Е "1".
nop ; Задержка в 1 м.ц.
bcf PortA,E ; Установка на линии Е "0".
;-------------------------------------------------
; Проверка состояния флага занятости BF.
;-------------------------------------------------
; Подготовка к проверке.
;------------------------
bsf Status,RP0 ; Переход в 1-й банк.
movlw b'11110000' ; Запись в W "11110000"
movwf TrisB ; RB4...7 работают на вход,
; а RB0...3 работают на выход.
bcf Status,RP0 ; Переход в 0-й банк.

7
bcf PortA,RS ; Установка на линии RS "0" (режим команд).
bsf PortA,RW ; Линия RW в "1" (режим чтения данных).
nop ; Задержка в 1 м.ц.
bsf PortA,E ; Установка на лини Е "1".
POVTOR nop ; Задержка в 1 м.ц.
;-----------------------
; Сама проверка.
;-----------------------
btfsc PortB,BF ; Проверка состояния флага занятости BF.
goto POVTOR ; Если BF=1, то продолжение задержки до тех
; пор, пока BF не установится в "0"
; (программа исполняется далее).
;-----------------------
; Завершение процедуры.
;-----------------------
clrf PortA ; Сброс в "0" всех защелок порта А
; (RW=0, RS=0, E=0).
bsf Status,RP0 ; Переход в 1-й банк.
clrf TrisB ; Все выводы порта В работают на выход.
bcf Status,RP0 ; Переход в 0-й банк.

return ; Возврат по стеку.


;================================================================================
; Чтение данных из текущей ячейки EEPROM памяти.
;================================================================================
EEPR bsf Status,RP0 ; Переход в 1-й банк.
movwf EEAdr ; Выбор адреса ячейки.
bcf EECon1,2 ; Запрет записи.
bsf EECon1,0 ; Разрешение чтения.
movf EEData,W ; Считывание байта в регистр W.
bcf Status,RP0 ; Переход в 0-й банк.
return ; Возврат по стеку.
;********************************************************************************
; Вывод на индикацию результатов измерений и сопровождающих их надписей.
;********************************************************************************
DISPLAY call LCD_INIT_1 ; Условный переход в процедуру
; "рабочей" инициализации.
;----> Возврат по стеку из ПП LCD_INIT_1.
;-----------------------------------------
; Задание положения курсора в 1-й строке.
;-----------------------------------------
movlw b'10000011' ; Копирование в W адреса 4-го слева
; знакоместа.
call ENTER_BF ; "Плавающая" задержка со стробом под команды
; выбора ячеек DD RAM.
;----> Возврат по стеку из ПП ENTER_BF.
;================================================================================
; Вывод результатов измерения длительности импульса в 1-ю строку.
;================================================================================
movlw .6 ; Задание количества знакомест (десятичных
movwf Total ; разрядов дисплея), в которые будут
; выводиться результаты измерений.
;----------------------------------------------------------
; Косвенная адресация к содержимому текущих LED.
;----------------------------------------------------------
movlw LED55 ; Стандартная процедура косвенной адресации с
movwf FSR ; "переправкой" содержимого регистра, сначала,
SNOVA_1 movf IndF,W ; LED55, а затем и всех остальных LED
; (44,33,22,11,00) в регистр W.
;----------------------------------------------------------
; Вывод символов результатов измерения периода в 1-ю строку
; ("врезка" в процедуру косвенной адресации).
;----------------------------------------------------------
bsf PortA,RS ; Установка на линии RS "1"
; (режим записи данных).
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
8
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
;----------------------------------------------------------
; Переход на следующий LED, который далее станет текущим.
;----------------------------------------------------------
decf FSR,F ; Уменьшение адреса текущего LED на 1.
;----------------------------------------------------
decf Total,F ; Уменьшение содержимого указателя разрядов
; на 1.
btfss Status,Z ; Анализ состояния флага нулевого результата Z
goto SNOVA_1 ; Если результат декремента Total не=0,
; то переход в ПП SNOVA_1.
; Если он =0, то программа исполняется далее.
;----------------------------------------------------------
; Вывод на индикацию надписи "мкс".
;----------------------------------------------------------
movlw 0BCh ; Запись в W символа "м" (0BCh).
bsf PortA,RS ; Установка на линии RS "1"
; (режим записи данных).
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.

movlw 0BAh ; Запись в W символа "к" (0BAh).


bsf PortA,RS ; Остальное - то же самое.
call ENTER_BF ; -----------"------------
;----> Возврат по стеку из ПП ENTER_BF.

movlw 63h ; Запись в W символа "с" (63h).


bsf PortA,RS ; ; Остальное - то же самое.
call ENTER_BF ; -----------"------------
;----> Возврат по стеку из ПП ENTER_BF.
;================================================================================
; Вывод результатов измерения частоты во 2-ю строку.
;================================================================================
; Вычисляемый переход в зависимости от установленного
; предела измерения (1/10 сек.)
;----------------------------------------------------
movfw Mem_1 ; Копирование содержимого регистра Mem_1
; в регистр W.
addwf PC,F ; Сам вычисляемый переход.
nop ; Для 1 сек.
goto $+3 ; Для 1 сек.
movlw b'11000001' ; Для 10 сек. (копирование в W адреса
; 2-го слева знакоместа).
;----------------------------------------------------
goto $+2 ; Переход на команду call ENTER_BF.
movlw b'11000010' ; Копирование в W адреса 3-го слева
; знакоместа.
call ENTER_BF ; "Плавающая" задержка со стробом под команды
; выбора ячеек DD RAM.
;----> Возврат по стеку из ПП ENTER_BF.
;----------------------------------------------------------
; Определение позиции результатов измерения в строке.
;----------------------------------------------------------
movlw .8 ; Задание количества знакомест (десятичных
movwf Total ; разрядов дисплея), в которые будут
; выводиться результаты измерений.
;----------------------------------------------------------
; Косвенная адресация к содержимому текущих LED.
;----------------------------------------------------------
movlw LED7 ; Стандартная процедура косвенной адресации с
movwf FSR ; "переправкой" содержимого регистра, сначала,
SNOVA movf IndF,W ; LED7, а затем и всех остальных LED
; (6,5,4,3,2,1,0) в регистр W.
;----------------------------------------------------------
9
; Вывод символов результатов измерения во 2-ю строку
; ("врезка" в процедуру косвенной адресации).
;----------------------------------------------------------
bsf PortA,RS ; Установка на линии RS "1"
; (режим записи данных).
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
;----------------------------------------------------------
; Переход на следующий LED, который далее станет текущим.
;----------------------------------------------------------
decf FSR,F ; Уменьшение адреса текущего LED на 1.
;----------------------------------------------------
; Вычисляемый переход в зависимости от установленного
; предела измерения (1/10 сек.)
;----------------------------------------------------
movfw Mem_1 ; Копирование содержимого регистра Mem_1
; в регистр W.
addwf PC,F ; Сам вычисляемый переход.
nop ; Для 1 сек. (запятая не выставляется).
goto NO_PIN ; Для 1 сек. (запятая не выставляется).
; Для 10 сек. - программа исполняется далее
; (запятая выставляется).
;----------------------------------------------------
; Установка запятой между предпоследним и последним
; десятичными разрядами, выводимыми на индикацию.
;----------------------------------------------------
movfw Total ; Копирование содержимого указателя разрядов
; в регистр W.
sublw .2 ; .2 - W(Total)=?
btfss Status,Z ; Анализ состояния флага нулевого результата Z
goto NO_PIN ; Если результат вычитания не=0, то запятая
; не выставляется.
movlw 2Ch ; Если результат вычитания =0, то запятая
; выставляется {запись в W символа "запятая"
; (2Сh)}.
bsf PortA,RS ; Установка на линии RS "1"
; (режим записи данных).
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
;----------------------------------------------------
; Здесь запятая не выставляется.
;----------------------------------------------------
NO_PIN decf Total,F ; Уменьшение содержимого указателя разрядов
; на 1.
btfss Status,Z ; Анализ состояния флага нулевого результата Z
goto SNOVA ; Если результат декремента Total не=0,
; то переход в ПП SNOVA.
; Если он =0, то программа исполняется далее.
;--------------------------------------------------------------------------------
; Формирование и вывод на индикацию символов, расположенных правее младшего
; разряда результата измерения.
;--------------------------------------------------------------------------------
movlw 0B4h ; Запись в W символа "г" (0B4h).
bsf PortA,RS ; ; Остальное - то же самое.
call ENTER_BF ; -----------"------------
;----> Возврат по стеку из ПП ENTER_BF.

movlw 0E5h ; Запись в W символа "ц" (0E5h).


bsf PortA,RS ; Остальное - то же самое.
call ENTER_BF ; -----------"------------
;----> Возврат по стеку из ПП ENTER_BF.

movlw 20h ; Запись в W символа "пробел" (20h).


bsf PortA,RS ; Остальное - то же самое.
10
call ENTER_BF ; -----------"------------
;----> Возврат по стеку из ПП ENTER_BF.
;------------------------------------------
; Выбор надписи (" 1c" или "10с").
;------------------------------------------
movfw Mem_1 ; Копирование содержимого регистра Mem_1 в W.
addwf PC,F ; Сам вычисляемый переход.
nop ; Для 1 сек.
goto SEC_1 ; Для 1 сек.
; Для 10 сек. - программа исполняется далее.
;------------------------------------------
; Вывод на индикацию надписи "10с".
;------------------------------------------
movlw 31h ; Запись в W символа "1" (31h).
bsf PortA,RS ; ; Остальное - то же самое.
call ENTER_BF ; -----------"------------
;----> Возврат по стеку из ПП ENTER_BF.
movlw 30h ; Запись в W символа "0" (30h).
bsf PortA,RS ; ; Остальное - то же самое.
call ENTER_BF ; -----------"------------
;----> Возврат по стеку из ПП ENTER_BF.
movlw 63h ; Запись в W символа "c" (63h).
bsf PortA,RS ; ; Остальное - то же самое.
call ENTER_BF ; -----------"------------
;----> Возврат по стеку из ПП ENTER_BF.
goto INKEY ; Переход на опрос клавиатуры
; (на новый цикл измерения).
;------------------------------------------
; Вывод на индикацию надписи " 1c".
;------------------------------------------
SEC_1 movlw 20h ; Запись в W символа "пробел" (20h).
bsf PortA,RS ; ; Остальное - то же самое.
call ENTER_BF ; -----------"------------
;----> Возврат по стеку из ПП ENTER_BF.
movlw 31h ; Запись в W символа "1" (31h).
bsf PortA,RS ; ; Остальное - то же самое.
call ENTER_BF ; -----------"------------
;----> Возврат по стеку из ПП ENTER_BF.
movlw 63h ; Запись в W символа "c" (63h).
bsf PortA,RS ; ; Остальное - то же самое.
call ENTER_BF ; -----------"------------
;----> Возврат по стеку из ПП ENTER_BF.
goto INKEY ; Переход на опрос клавиатуры
; (на новый цикл измерения).

;********************************************************************************
; Начало исполнения "программы".
;********************************************************************************
; Подготовительные операции.
;----------------------------------------
START clrf IntCon ; Запрет всех прерываний.
clrf PortA ; Сброс защелок порта A в "0"
; (RS=0, RW=0, E=0).
bsf Status,RP0 ; Переход в 1-й банк.
clrf TrisB ; Все выводы порта В работают на выход.
movlw b'00010000' ; Вывод RA4/TOCKI работает на вход,
movwf TrisA ; остальные - на выход.
movlw b'00100111' ; Предделитель с Кдел.=256 подключен к TMR0,
movwf OptionR ; выбор внешнего тактового сигнала с вывода
; RA4/TOCK1, приращение TMR0 по переднему
; фронту, подтягивающие резисторы порта В
; включены.
bcf Status,RP0 ; Переход в 0-й банк.

movlw 7 ; Выключение модуля


movwf CMCON ; компараторов.
11
movlw b'00000001' ; TMR1 включен, внутренний такт,
movwf T1CON ; Кдел. предделителя = 1.

movlw .01 ; По умолчанию - интервал


movwf Mem_1 ; времени измерения 1 сек.

call LCD_INIT ; Условный переход в процедуру "рабочей"


; инициализации.
;----> Возврат по стеку из ПП LCD_INIT.
;********************************************************************************
; Вывод тестовых надписей, свидетельствующих об успешном завершении процедуры
; "рабочей" инициализации и готовности к дальнейшей работе.
;********************************************************************************
; Вывод надписи " http://www. " в 1-ю строку.
;================================================================================
; Вывод символов в 1-ю строку.
;------------------------------
movlw .16 ; Запись числа .16 (количества выводимых в
movwf Count ; строку символов) в регистр Count.
WR_2 movf Count,W ; Копирование содержимого регистра Count в W.
sublw .16 ; .16-Count=... (результат записывается в W).
call EEPR ; Условный переход в ПП EEPR.
;----> Возврат по стеку из ПП EEPR.
bsf PortA,RS ; Установка на линии RS "1"
; (режим записи данных).
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
decfsz Count,F ; Подготовка к выводу на индикацию
; следующего символа таблицы.
goto WR_2 ; Если результат декремента не=0, то переход
; в ПП WR_2.
; Если результат декремента =0, то программа
; исполняется далее.
;================================================================================
; Вывод надписи " ikarab.narod.ru" во 2-ю строку.
;================================================================================
; Переход в начало 2-й строки.
;------------------------------
movlw b'11000000' ; Выбор ячейки DD RAM с адресом 40h (установка
; курсора в крайнее левое знакоместо
; 2-й строки).
call ENTER_BF ; "Плавающая" задержка со стробом
; под команду 11000000.
;----> Возврат по стеку из ПП ENTER_BF.
;------------------------------
; Вывод символов во 2-ю строку.
;------------------------------
movlw .16 ; Запись числа .16 (количества выводимых в
movwf Count ; строку символов) в регистр Count.
WR_3 movf Count,W ; Копирование содержимого регистра Count в W.
sublw .32 ;.32-Count=... (результат записывается в W).
call EEPR ; Условный переход в ПП EEPR.
;----> Возврат по стеку из ПП EEPR.
bsf PortA,RS ; Установка на линии RS "1"
; (режим записи данных).
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
decfsz Count,F ; Подготовка к выводу на индикацию
; следующего символа таблицы.
goto WR_3 ; Если результат декремента не=0, то переход
; в ПП WR_3.
; Если результат декремента =0, то программа
; исполняется далее.
12
;********************************************************************************
; ПОДПРОГРАММА ОПРОСА КЛАВИАТУРЫ.
;********************************************************************************
; Подготовка к опросу клавиатуры.
;------------------------------------------------------------
INKEY bsf Status,RP0 ; Переход в 1-й банк.
bcf OptionR,7 ; Включение, на время опроса клавиатуры,
; подтягивающих резисторов порта В.
movlw b'00001111' ; RB0...RB3 работают на вход,
movwf TrisB ; RB4...RB7 работают на выход.
bcf Status,RP0 ; Переход в 0-й банк.
clrf PortB ; Сброс всех защелок порта В.
;------------------------------------------------------------
; Опрос клавиатуры.
;------------------------------------------------------------
movf PortB,W ; Считывание числа с выводов порта B.
andlw b'00000011' ; "Нейтрализация" состояний RB7...RB2.
;------------------------------------------------------------
; Переход на заданное время измерения частоты.
;------------------------------------------------------------
MemK addwf PC,F ; Вычисляемый переход.
nop ; Установить интервал измерения 1 сек. 00
goto Sec1 ; Установить интервал измерения 1 сек. 01
goto Sec10 ; Установить интервал измерения 10 сек. 10
; Включение памяти. 4-е состояние клавиатуры. 11
;------------------------------------------------------------
; Включение памяти состояния клавиатуры после отжатия кнопок.
;------------------------------------------------------------
movf Mem_1,W ; Если обе кнопки клавиатуры отжаты, то, после
goto MemK ; окончания текущего цикла измерения,
; следующий цикл измерения будет производиться
; с таким же временем измерения частоты,как и
; в предшествующем цикле, не меняясь до
; следующего нажатия кнопок.
;--------------------------------------------------------------------------------
; Установка величины выбранного интервала времени измерения (1/10 сек.).
;--------------------------------------------------------------------------------
;-----------Для времени измерения = 10 сек.----------
Sec10 movlw .13 ; Запись константы
movwf SecH ; в регистр SecH.
movlw .181 ; Запись константы
movwf SecM ; в регистр SecM.
movlw .163 ; Запись константы
movwf SecL ; в регистр SecL.
movlw .250 ; Запись константы
movwf Kalib ; в регистр Kalib.
movlw .122 ; Запись константы
movwf Kalib_1 ; в регистр Kalib_1.
movlw .02 ; Запись константы
movwf Mem_1 ; в регистр Mem_1.
goto START_1 ; Переход на новый цикл измерения.

;-----------Для времени измерения = 1 сек.-----------


Sec1 movlw .2 ; -------"--------
movwf SecH ; -------"--------
movlw .69 ; -------"--------
movwf SecM ; -------"--------
movlw .220 ; -------"--------
movwf SecL ; -------"--------
movlw .251 ; -------"--------
movwf Kalib ; -------"--------
movlw .124 ; -------"--------
movwf Kalib_1 ; -------"--------
movlw .01 ; -------"--------
movwf Mem_1 ; -------"--------
13
;************************************************************************
; СНАЧАЛА ЗАМЕРЯЕМ ЧАСТОТУ.
;************************************************************************
; Подготовительные операции.
;-------------------------------------
START_1 clrf IntCon ; Запрет всех прерываний.
clrf TimerH ; Сброс в 0 регистра TimerH.
clrf TimerHH ; Сброс в 0 регистра TimerHH.
clrf Tmr0 ; Сброс в 0 регистра TMR0.
;-------------------------------------
; Начало счета - на метке "On"
;-------------------------------------
bsf Status,RP0 ; Переход в 1-й банк.
bsf OptionR,7 ; Выключение, на время измерений частоты и
; периода, подтягивающих резисторов порта В.
movlw b'00011000' ; Выводы RA3 и RA4/TOCKI работают на вход.
On movwf TrisA ; Копирование содержимого W в регистр TrisA,
; начало счета.
bcf Status,RP0 ; Переход в 0-й банк.
;--------------------------------------------------------------------------------
; Проверка TMR0 на переполнение №1
; (заполнение старшего байта счетчика частоты TimerH и, в случае его
; переполнения, - самого старшего байта счетчика частоты TimerHH).
;--------------------------------------------------------------------------------
CYCLE btfss IntCon,2 ; TMR0 переполнен или нет?
goto DO_NOTHING ; Нет - переход на DO_NOTHING.

incfsz TimerH,F ; Да - инкремент TimerH, и, если TimerH не


goto RESET ; переполнен, то переход на метку RESET.

incf TimerHH,F ; Если TimerH переполнен, то инкремент


; TimerHH.
RESET bcf IntCon,2 ; Сброс флага переполнения TMR0.
goto O_K ; Переход в ПП O_K.

DO_NOTHING goto $+1 ; Выравнивающая задержка


goto $+1 ; величиной 2х2=4 м.ц.
clrwdt ; Выравнивающая задержка в 1 м.ц.
; с функцией сброса WDT.
;--------------------------------------------------------------------------------
; Формирование значения интервала времени измерения "грубо".
;--------------------------------------------------------------------------------
O_K clrwdt ; Сброс WDT с функцией задержки на 1 м.ц.

decfsz SecL,F ; --------"---------


goto CYCLE ; --------"---------
; Трехбайтный вычитающий
decfsz SecM,F ; счетчик с "врезкой"
goto CYCLE ; в его полный цикл
; подпрограммы CYCLE.
decfsz SecH,F ; --------"---------
goto CYCLE ; --------"---------
;--------------------------------------------------------------------------------
; Формирование значения интервала времени измерения "точно".
;--------------------------------------------------------------------------------
; Шаг константы: 4 м.ц.
;-----------------------
PAUSE clrwdt ; Сброс WDT с функцией задержки на 1 м.ц.
decfsz Kalib,F ; Однобайтный вычитающий счетчик с шагом
goto PAUSE ; константы 4 м.ц.
; (за счет "врезки" команды clrwdt).
;-----------------------
; Шаг константы: 3 м.ц.
;-----------------------

14
PAUSE_1 decfsz Kalib_1,F ; Однобайтный вычитающий счетчик с шагом
goto PAUSE_1 ; константы 3 м.ц. (без "врезки").
;-------------------------------------
; Конец счета - на метке Off.
;-------------------------------------
clrf PortA ; Сброс в 0 содержимого регистра PortA.
bsf Status,RP0 ; Переход в 1-й банк.
movlw b'00010000' ; Запись в W константы.
Off movwf TrisA ; Копирование константы из W в регистр TrisA:
; вывод RA4 работает на вход, RA3 блокирует
; счет (конец счета).
bcf Status,RP0 ; Переход в 0-й банк.
;--------------------------------------------------------------------------------
; Проверка TMR0 на переполнение №2.
;--------------------------------------------------------------------------------
btfss IntCon,2 ; TMR0 переполнен?
goto ANALYSE ; Нет - переход в ПП ANALYSE.
incfsz TimerH,F ; Да - инкремент TimerH, и, если TimerH не
goto ANALYSE ; переполнен, то переход в ПП ANALYSE.
incf TimerHH,F ; Если TimerH переполнен, то инкремент
; TimerHH.
;--------------------------------------------------------------------------------
; Копирование содержимого регистра TMR0 в регистр TimerM.
;--------------------------------------------------------------------------------
ANALYSE movf Tmr0,W ; Содержимое регистра TMR0
movwf TimerM ; копируется в регистр TimerM.
;--------------------------------------------------------------------------------
; Сброс в 0 содержимого регистра TimerL.
;--------------------------------------------------------------------------------
clrf TimerL ; Очистка регистра TimerL.
;--------------------------------------------------------------------------------
; Подпрограмма досчета.
;--------------------------------------------------------------------------------
COUNT_IT incf TimerL,F ; Инкремент содержимого регистра TimerL.
;--------------------------------------------------------------------------------
; Кратковременная разблокировка счетного входа TMR0.
;--------------------------------------------------------------------------------
bsf PortA,3 ; Формирование на выводе RA3 единицы.
nop ; Задержка в 1 м.ц.
bcf PortA,3 ; Формирование на выводе RA3 нуля.
nop ; Задержка в 1 м.ц.
clrwdt ; Сброс сторожевого таймера WDT.
;--------------------------------------------------------------------------------
; Сам досчет.
;--------------------------------------------------------------------------------
movf Tmr0,W ; Копирование содержимого TMR0 в W.
bcf Status,Z ; Сброс флага нулевого результата Z.
subwf TimerM,W ; Вычесть из TimerM содержимое W
; с сохранением в W.
btfsc Status,Z ; Результат операции вычитания
; равен или нет нулю?
goto COUNT_IT ; Да, равен --> переход в ПП COUNT_IT.
incf TimerL,F ; Нет, не равен --> инкремент
; содержимого TimerL.
comf TimerL,F ; Инвертирсия всех битов TimerL.
incf TimerL,F ; Инкремент TimerL.
incf TimerL,F ; Инкремент TimerL.

call BIN2_10 ; Условный переход в ПП двоично-десятичного


; преобразования.
;----> Возврат по стеку из ПП BIN2_10.

;================================================================================
; Процедура преобразования стандартного весового кода в код ASCII (ANSI).
;================================================================================
movlw 30h ; Запись в регистр W числа 30h.
15
iorwf LED0,F ; Логическое "ИЛИ" содержимого регистра W и
; регистра LED0 с сохранением результата
; в LED0.
iorwf LED1,F ; То же самое для LED1.
iorwf LED2,F ; -------"------- LED2.
iorwf LED3,F ; -------"------- LED3.
iorwf LED4,F ; -------"------- LED4.
iorwf LED5,F ; -------"------- LED5.
iorwf LED6,F ; -------"------- LED6.
iorwf LED7,F ; -------"------- LED7.
;================================================================================
; Процедура гашения незначащих нулей.
;================================================================================
movlw .7 ; Запись количества проверяемых разрядов
movwf Total ; (8-1=7) в указатель разрядов Total.
;----------------------------------------------------------
; Косвенная адресация к содержимому текущих LED... .
;----------------------------------------------------------
movlw LED7 ; Стандартная процедура косвенной адресации с
movwf FSR ; "переправкой" содержимого регистра, сначала,
; LED7, а затем и всех остальных текущих LED
; (6,5,4,3,2,1,0) в регистр W.
SNOVA_0 movlw 30h ; Запись числа 30h в регистр W.
subwf IndF,W ; Вычесть из данных регистра с адресом в FSR
; (из содержимого текущего LED) число 30h
; с сохранением результата в W.
;-------------------------------------
; 1-я проверка на нулевой результат.
;-------------------------------------
btfss Status,Z ; Проверка состояния флага нулевого результата
goto VIHOD ; Если содержимое W не=0, то выход из
; процедуры.
movlw 20h ; Если содержимое W =0, то запись символа
movwf IndF ; "пробел" в регистр с адресом в FSR
; (в текущий LED).
;-------------------------------------
; Переход на следующий, текущий LED.
;-------------------------------------
decf FSR,F ; Уменьшение адреса текущего LED на 1.
decf Total,F ; Уменьшение содержимого указателя разрядов
; на 1.
;-------------------------------------
; 2-я проверка на нулевой результат.
;-------------------------------------
btfss Status,Z ; Проверка состояния флага нулевого результата
goto SNOVA_0 ; Если содержимое Total не=0, то переход на
; повторную проверку на незначащие нули
; (goto SNOVA_0).

;************************************************************************
; ТЕПЕРЬ ЗАМЕРЯЕМ ДЛИТЕЛЬНОСТЬ ИМПУЛЬСА.
;************************************************************************
VIHOD movlw 2 ; Запись, в указатель конца замера
movwf Flag ; длительности импульса, числа перезаписей.
;--------------------------------------
; Настройка модуля CCP.
;--------------------------------------
clrf CCP1CON ; Выключение модуля CCP
; (рекомендовано разработчиками).
movlw b'00000111' ; Захват по каждому 16-му переднему
movwf CCP1CON ; фронту сигнала на выводе RB3.
;--------------------------------------
; Сброс флага прерываний от модуля CCP.
;--------------------------------------
bcf PIR1,CCP1IF ; Сброс флага CCP1IF.

16
;--------------------------------------------------------------------------------
; Разрешение прерываний от модуля CCP, подключение предделителя
; к WDT и разблокировка счетного входа модуля CCP.
;--------------------------------------------------------------------------------
clrwdt ; Сброс WDT.
clrf Tmr0 ; Сброс в ноль Tmr0 и предделителя.

clrf Bit ; Подготовка к работе бита №0 регистра Bit.

bcf Status,Z ; Подготовка флага Z к работе.

movlw b'11000000' ; Глобальное разрешение прерываний и


movwf IntCon ; разрешение прерываний от периферийных
; модулей.
bsf Status,RP0 ; Переход в 1-й банк.
bsf OptionR,3 ; Подключение предделителя к WDT (К=128).
bsf TrisA,3 ; Разблокировка счетного входа модуля CCP
; (начало счета).
movlw b'00000100' ; Разрешение прерываний
movwf PIE1 ; от модуля CCP.
bcf Status,RP0 ; Переход в 0-й банк.
;--------------------------------------------------------------------------------
; "Плавающая" задержка с выходом из нее через 2 прерывания от модуля CCP.
;--------------------------------------------------------------------------------
btfss Status,Z ; Если флаг Z опущен, то ждем его поднятия.
goto $-1 ; Если флаг Z поднялся, то программа
; исполняется далее.
;--------------------------------------------------------------------------------
; Запрет прерываний, подключение предделителя к Tmr0
; и блокировка счетного входа модуля CCP.
;--------------------------------------------------------------------------------
clrf IntCon ; Запрет прерываний.
clrwdt ; Сброс WDT.
bsf Status,RP0 ; Переход в 1-й банк.
bcf TrisA,3 ; Блокировка счетного входа модуля CCP
; (конец счета).
bcf OptionR,3 ; Подключение предделителя к Tmr0 (К=256).
bcf Status,RP0 ; Переход в 0-й банк.
;--------------------------------------------------------------------------------
; Блокировка ложных поднятий флага TMR1IF, если результат замера равен
; 65535 (11111111 11111111).
; Примечание: 65536 = 00000001 00000000 00000000.
;--------------------------------------------------------------------------------
movf Temp_H,W ;
sublw .255 ; .255 - Temp_H = ...
btfss Status,Z ; Результат равен или не равен нулю ?
goto $+5 ; Если =0, то обход команд анализа
; содержимого Temp_L.
movf Temp_L,W ; Если не=0, то
sublw .255 ; .255 - Temp_H = ...
btfsc Status,Z ; Результат равен или не равен нулю ?
bcf Bit,0 ; Если =0, то бит указателя переполнения TMR1
; (Bit,0) сбрасывается в 0 ("убийство" ложного
; переполнения).
; Если не=0, то этого "убийства"
; не происходит.
;--------------------------------------------------------------------------------
; Анализ указателя переполнения TMR1 (бита №0 регистра Bit).
; Если Bit,0 = 0, то переполнения TMR1 не было.
; Если Bit,0 = 1, то переполнение TMR1 было.
;--------------------------------------------------------------------------------
clrf Temp_0 ; Сброс "обманного" регистра.

btfsc Bit,0 ; Если переполнение TMR1 было, то результат


bsf Temp_0,0 ; подсчета увеличивается на 65536.
; Если переполнения TMR1 не было, то этого
17
; не происходит.
;------------------------------------------------------
; ИТОГ: в Temp_H/Temp_L - истинный результат замера.
;********************************************************************************
; Процедура двоично-десятичного преобразования для замера длительности импульса.
;********************************************************************************
bcf Status,C ; Сброс флага С.
movlw .24 ; "Закладка" в регистр Count1 числа
movwf Count1 ; проходов преобразования.
clrf LED00 ; Сброс регистра LED00.
clrf LED11 ; ------"------ LED11.
clrf LED22 ; ------"------ LED22.
;--------------------------------------------------------------------------------
; Сдвиг влево через бит С регистра Status.
;--------------------------------------------------------------------------------
LOOP_16_1 rlf Temp_L,F ; Побитная
rlf Temp_H,F ; "переправка"
rlf Temp_0,F ; содержимого
rlf LED00,F ; Temp_0/Temp_H/Temp_L
rlf LED11,F ; в
rlf LED22,F ; LED22/LED11/LED00.
;-----------------------------------
decfsz Count1,F ; Анализ числа проходов
goto adjDEC_1 ; преобразования.
;--------------------------------------------------------------------------------
; Порязрядное распределение полубайтов регистров LED00...22
; по младшим полубайтам регистров LED00...55.
;--------------------------------------------------------------------------------
swapf LED22,W ; Запись старшего полубайта LED22
andlw 0Fh ; в младший полубайт LED55.
movwf LED55 ; -------------------------------

movfw LED22 ; Запись младшего полубайта LED22


andlw 0Fh ; в младший полубайт LED44.
movwf LED44 ; -------------------------------

swapf LED11,W ; Запись старшего полубайта LED11


andlw 0Fh ; в младший полубайт LED33.
movwf LED33 ; -------------------------------

movfw LED11 ; Запись младшего полубайта LED11


andlw 0Fh ; в младший полубайт LED22.
movwf LED22 ; -------------------------------

swapf LED00,W ; Запись старшего полубайта LED00


andlw 0Fh ; в младший полубайт LED11.
movwf LED11 ; -------------------------------

movfw LED00 ; Запись младшего полубайта LED00


andlw 0Fh ; в младший полубайт LED00.
movwf LED00 ; -------------------------------
;--------------------------------------------------------------------------------
; ИТОГ: десятичные числа лежат в младших полубайтах
; LED55/LED44/LED33/LED22/LED11/LED00.
;--------------------------------------------------------------------------------
goto ASC ; Конец 2/10 преобразования.
; Переход в ПП преобразования кода.
;--------------------------------------------------------------------------------
; Подготовка к косвенной адресации (происходит в ПП adjBCD).
; После возврата по стеку, переход к обработке следующего LEDа.
;--------------------------------------------------------------------------------
adjDEC_1 movlw LED00 ; Запись в регистр FSR адреса регистра LED00
movwf FSR ; с дальнейшим переходом в ПП adjBCD.
call adjBCD ;
;---> Возврат по стеку из ПП adjBCD.
movlw LED11 ; То же самое для регистра LED11.
18
movwf FSR ;
call adjBCD ;
;---> Возврат по стеку из ПП adjBCD.
movlw LED22 ; То же самое для регистра LED22.
movwf FSR ;
call adjBCD ;
;---> Возврат по стеку из ПП adjBCD.
goto LOOP_16_1 ; Переход на следующее кольцо
; числовых преобразований.

;================================================================================
; Процедура преобразования стандартного весового кода в код ASCII (ANSI).
;================================================================================
ASC movlw 30h ; Запись в регистр W числа 30h.
iorwf LED00,F ; Логическое "ИЛИ" содержимого регистра W и
; регистра LED00 с сохранением результата
; в LED00.
iorwf LED11,F ; То же самое для LED11.
iorwf LED22,F ; -------"------- LED22.
iorwf LED33,F ; -------"------- LED33.
iorwf LED44,F ; -------"------- LED44.
iorwf LED55,F ; -------"------- LED55.
;================================================================================
; Процедура гашения незначащих нулей.
;================================================================================
movlw .5 ; Запись количества проверяемых разрядов
movwf Total ; (6-1=5) в указатель разрядов Total.
;----------------------------------------------------------
; Косвенная адресация к содержимому текущих LED... .
;----------------------------------------------------------
movlw LED55 ; Стандартная процедура косвенной адресации с
movwf FSR ; "переправкой" содержимого регистра, сначала,
; LED55, а затем и всех остальных текущих LED
; (44,33,22,11,00) в регистр W.
SNOVA_00 movlw 30h ; Запись числа 30h в регистр W.
subwf IndF,W ; Вычесть из данных регистра с адресом в FSR
; (из содержимого текущего LED) число 30h
; с сохранением результата в W.
;-------------------------------------
; 1-я проверка на нулевой результат.
;-------------------------------------
btfss Status,Z ; Проверка состояния флага нулевого результата
goto VIHOD_1 ; Если содержимое W не=0, то выход из
; процедуры (goto VIHOD_1).
movlw 20h ; Если содержимое W =0, то запись символа
movwf IndF ; "пробел" в регистр с адресом в FSR
; (в текущий LED).
;-------------------------------------
; Переход на следующий, текущий LED.
;-------------------------------------
decf FSR,F ; Уменьшение адреса текущего LED на 1.
decf Total,F ; Уменьшение содержимого указателя разрядов
; на 1.
;-------------------------------------
; 2-я проверка на нулевой результат.
;-------------------------------------
btfss Status,Z ; Проверка состояния флага нулевого результата
goto SNOVA_00 ; Если содержимое Total не=0, то переход на
; повторную проверку на незначащие нули
; (goto SNOVA_00).
;------------------------------------------------
; Теперь можно вывести результат замера частоты
; и длительности импульса на индикацию.
;------------------------------------------------
VIHOD_1 goto DISPLAY ; Переход в ПП вывода на индикацию.

19
;********************************************************************************
; Процедура двоично-десятичного преобразования для замера частоты.
;********************************************************************************
BIN2_10 bcf Status,C ; Сброс флага C.
movlw .32 ; "Закладка" в регистр Count1 числа
movwf Count1 ; проходов преобразования.
clrf LED0 ; Сброс регистра LED0.
clrf LED1 ; ------"------ LED1.
clrf LED2 ; ------"------ LED2.
clrf LED3 ; ------"------ LED3.
;--------------------------------------------------------------------------------
; Сдвиг влево через бит С регистра Status.
;--------------------------------------------------------------------------------
LOOP_16 rlf TimerL,F ;
rlf TimerM,F ; Побитная
rlf TimerH,F ; "переправка"
rlf TimerHH,F ; содержимого
rlf LED0,F ; TimerHH/TimerH/TimerM/TimerL
rlf LED1,F ; в
rlf LED2,F ; LED3/LED2/LED1/LED0.
rlf LED3,F ;
;-----------------------------------
decfsz Count1,F ; Анализ числа проходов
goto adjDEC ; преобразования.
;--------------------------------------------------------------------------------
; Порязрядное распределение полубайтов регистров LED0...3
; по младшим полубайтам регистров LED0...7.
;--------------------------------------------------------------------------------
swapf LED3,W ; Запись старшего полубайта LED3
andlw 0Fh ; в младший полубайт LED7
movwf LED7 ; -------------------------------

movfw LED3 ; Запись младшего полубайта LED3


andlw 0Fh ; в младший полубайт LED6
movwf LED6 ; -------------------------------

swapf LED2,W ; Запись старшего полубайта LED2


andlw 0Fh ; в младший полубайт LED5
movwf LED5 ; -------------------------------

movfw LED2 ; Запись младшего полубайта LED2


andlw 0Fh ; в младший полубайт LED4
movwf LED4 ; -------------------------------

swapf LED1,W ; Запись старшего полубайта LED1


andlw 0Fh ; в младший полубайт LED3
movwf LED3 ; -------------------------------

movfw LED1 ; Запись младшего полубайта LED1


andlw 0Fh ; в младший полубайт LED2
movwf LED2 ; -------------------------------

swapf LED0,W ; Запись старшего полубайта LED0


andlw 0Fh ; в младший полубайт LED1
movwf LED1 ; -------------------------------

movfw LED0 ; Запись младшего полубайта LED0


andlw 0Fh ; в младший полубайт LED0
movwf LED0 ; -------------------------------
;--------------------------------------------------------------------------------
; ИТОГ: десятичные числа лежат в младших полубайтах
; LED7/LED6/LED5/LED4/LED3/LED2/LED1/LED0.
;--------------------------------------------------------------------------------
return ; Конец 2/10 преобразования. Возврат по стеку.
;--------------------------------------------------------------------------------
; Подготовка к косвенной адресации (происходит в ПП adjBCD).
20
; После возврата по стеку, переход к обработке следующего LEDа.
;--------------------------------------------------------------------------------
adjDEC movlw LED0 ; Запись в регистр FSR адреса регистра LED0
movwf FSR ; с дальнейшим переходом в ПП adjBCD.
call adjBCD ;
;---> Возврат по стеку из ПП adjBCD.
movlw LED1 ; То же самое для регистра LED1.
movwf FSR ;
call adjBCD ;
;---> Возврат по стеку из ПП adjBCD.
movlw LED2 ; То же самое для регистра LED2.
movwf FSR ;
call adjBCD ;
;---> Возврат по стеку из ПП adjBCD.
movlw LED3 ; То же самое для регистра LED3.
movwf FSR ;
call adjBCD ;
;---> Возврат по стеку из ПП adjBCD.
goto LOOP_16 ; Переход на следующее кольцо
; числовых преобразований.
;--------------------------------------------------------------------------------
; Основные операции преобразования двоичных чисел в двоично-десятичные: операции
; сложения LED с константами 03h и 30h, с условиями по 3-му и 7-му битам.
;--------------------------------------------------------------------------------
adjBCD clrwdt ; Сброс сторожевого таймера WDT.
movlw 3 ; Суммирование содержимого текущего LED с
addwf 0,W ; числом 03h, с записью результата операции,
movwf Mem ; через регистр W, в регистр Mem.

btfsc Mem,3 ; Анализ состояния бита №3 регистра Mem.


movwf 0 ; Если бит №3 = 1, то содержимое регистра Mem
; копируется в текущий LED.

movlw 30 ; Если бит №3 = 0, то содержимое текущего LED


addwf 0,W ; складывается с константой 30h, с записью
movwf Mem ; результата операции, через регистр W,
; в регистр Mem.
btfsc Mem,7 ; Анализ состояние бита №7 регистра Mem.
movwf 0 ; Если бит №7 = 1, то содержимое регистра Mem
; копируется в текущий LED.
retlw 0 ; Если бит №7 = 0, то регистр W очищается и
; происходит возврат по стеку в ПП adjDEC
; или adjDEC_1.
;********************************************************************************
end ; Конец программы.

Принцип "боевой раскраски" такой же, как и в предыдущем подразделе.

Работа программы.
В границах "основного тела" программы, работа программы Hz_Mks_3.asm, начиная с
ПП START и до начала группы команд обработки результата измерения длительности
импульса, происходит точно так же, как и работа программы Hz_Mks_2.asm.
Это означает то, что, при "ваянии" процедуры измерения длительности импульса,
соответствующий, "приличный кусок" программы просто – напросто "передирается" из
программы Hz_Mks_2.asm.
С целью обеспечения минимального количества различий между текстами программ
Hz_Mks_2.asm и Hz_Mks_3.asm, я не стал менять первично устанавливаемый (до 1-го
захвата) Кдел. предделителя модуля CCP, и оставил его прежним (16), но, в целях
уменьшения времени цикла замера, его можно уменьшить до 4 (CCP1CON = 00000110)
и даже до 1 (CCP1CON = 00000101).
После возникновения события 1-го захвата (по 16-му переднему фронту), исполняется
1-й сценарий ПП прерывания, в котором быстренько происходит перестройка типа
захвата на захват по каждому заднему фронту.

21
После отработки 1-го сценария ПП прерывания, рабочая точка программы
возвращается в "плавающую" задержку, и начинается ожидание 2-го события захвата,
происходящего уже не по каждому 16-му переднему фронту управляющего сигнала, а
по каждому заднему фронту управляющего сигнала (в соответствии с установленным
типом захвата).
Сразу же после окончания формирования заднего фронта управляющего сигнала (на
выводе RB3), происходит 2-й захват, и рабочая точка программы "улетает" во 2-й
сценарий ПП прерывания.
Далее, вплоть до начала группы команд обработки результата измерения длительности
импульса, программа Hz_Mks_3.asm работает так же, как и программа Hz_Mks_2.asm.
Далее, по причине, указанной выше, результат замера не нужно делить на 16, а сразу
можно осуществить блокировку ложных поднятий флага TMR1IF.
Так как значение поддиапазонной поправки изменилось с числа 4095 на число 65535,
то нужно скорректировать числовое значение только одной константы старшего разряда
(заменить .15 на .255).
Далее, производится проверка указателя переполнения.
Команду clrf Temp_0 я вынес из ПП 2/10 преобразования в начало этой проверки
потому, что, на этот раз, регистр Temp_0 оказался востребованным (по причине
увеличения байтности поддиапазонной поправки. Задействуются, ранее
"зарезервированные", 5-й и 6-й десятичные разряды дисплея).
Перед проверкой состояния указателя переполнения, содержимое регистра Temp_0
нужно сбросить в 0, что и имеет место быть (ранее, это происходило в ПП 2/10
преобразования).
После этого, производится стандартная проверка указателя переполнения, с
соответствующими "оргвыводами", заключающимися во введении (или нет), в результат
измерения, поддиапазонной поправки 65536.
После этого, вплоть до вывода результата измерения на индикацию, программа
Hz_Mks_3.asm работает точно так же, как и программа Hz_Mks_2.asm.
В конечном итоге, программа Hz_Mks_2.asm "превращена" в программу Hz_Mks_3.asm с
приложением минимума усилий.
Это как раз тот случай, когда "одна малюсенькая, но хитрая штучка" существенно
изменяет функциональность программы.
Естественно, что об этой "штучке" нужно иметь четкое представление.
Теперь давайте разберемся с величиной "подрезания" верхней границы диапазона
измерения длительности импульса.
------------------------------------
------------------------------------
;--------------------------------------------------------------------------------
; Проход №1.
;--------------------------------------------------------------------------------
WRITE_1 movlw .9 ; Числовая
movwf TMR1L ; коррекция
clrf TMR1H ; TMR1H/TMR1L.

clrf CCP1CON ; Сброс модуля CCP.


movlw b'00000100' ; Захват по каждому заднему фронту
movwf CCP1CON ; сигнала на выводе RB3.

bcf Status,Z ; Установка признака продолжения замера.


;-----------------------------------
bcf PIR1,TMR1IF ; Сброс флага прерывания по переполнению TMR1.
bcf PIR1,CCP1IF ; Сброс флага прерывания от модуля CCP.
retfie ; Возврат из прерывания.
;********************************************************************************
------------------------------------
------------------------------------
Подсчитываю количество машинных циклов отработки 1-го сценария ПП прерывания.
9 м.ц. до команды clrf CCP1CON включительно + 1 м.ц. команды movlw b'00000100' +
1 м.ц. команды movwf CCP1CON + 1 м.ц. команды bcf Status,Z + 1 м.ц. команды
bcf PIR1,TMR1IF + 1 м.ц. команды bcf PIR1,CCP1IF + 2 м.ц. команды retfie.
Получается 16 машинных циклов или, в переводе на микросекунды, 16 микросекунд.
22
В данном случае, это и есть верхняя граница диапазона измерения длительности
импульса.
Если длительность измеряемого импульса будет менее 16 мкс., то событие 2-го
захвата произойдет не в "плавающей" задержке, а во время отработки 1-го сценария
ПП прерывания, что есть функциональное нарушение работы измерителя длительности
импульса.
В результате этого нарушения, "на гора" будет выдан неверный результат измерения.
Проверил в "железе".
Соответствует: до 15-ти мкс. - "бардак", на 15-ти мкс. - неустойчивые показания
("смесь" из "зер гут" и "Гитлер капут"), начиная с 16-ти мкс. и более, все ОК.

Программа Hz_Mks_3.asm проверена в "железе" и работает вполне прилично.


"Сдаю в эксплуатацию".
Тем из Вас, кто отслеживает (в "железе") текущую тему, нужно только поменять
прошивку и ничего более.
Текст программы Hz_Mks_3.asm прилагается.

К вопросу об измерении скважности.


Если имеется результат измерения периода и результат измерения длительности
импульса (а это можно сделать в одном цикле измерения), то величина скважности
просто вычисляется путем организации математической операции деления (результат
можно вывести на индикацию и в процентах).
В части касающейся применения ЖКИ модуля на основе HD44780 (2х16), дисплей
будет полностью "забит" результатами замера частоты, периода и длительности
импульса (с сопровождающими надписями).
В этом случае, можно "разрезервировать" ранее "зарезервированное" состояние
клавиатуры 00 (обе кнопки нажаты) и использовать это состояние для запуска
процедуры вычисления скважности.
Можно и еще что-нибудь придумать (в памяти программ, свободного места "выше
крыши").

К вопросу о перспективах.
Надеюсь на то, что я наглядно Вам показал, как можно, практически с "нуля" и до
уровня прилично работающего "железа", "раскрутить" то, что раньше было "мутью"
(работа в режиме реального времени. Чистый экспромт).
Если продолжить в таком же духе и взяться за дело как следует (в том смысле, что,
не отвлекаясь, заняться только им), то я могу дать абсолютно точную гарантию того,
что, в конечном итоге, "родится" дешевый, простой (по схемотехнике) и малюсенький
измерительный прибор, производящий комплексный замер частоты, периода,
длительности импульса и скважности, имеющий хорошие технические характеристики и
"обалденное" соотношение типа "цена/качество".
Можно и еще что-нибудь к нему "пришпилить", например, графический модуль (кроме
вывода в него всех результатов замеров, можно еще и импульс нарисовать, правда,
по деньгам, дороже обойдется).
И т.д., и т.п. Нет проблем. И никакой фантастики.
Все это (а также и многие другие задумки) абсолютно реально.
Лично у меня такое желание есть, но я привык расставлять приоритеты (чего и Вам
советую), а в соответствии с ними, есть дела и поважнее, чем отдельно взятая
"железяка".
Вот когда Вы будете "печь эти железяки как блинчики", тогда другое дело.
А пока, поработаю "тараном" (так считают некоторые из Вас. Это приятно).
От меня не убудет (по причине наличия "железного лба" и "боевого опыта битья
головой об стену").
Работаем дальше.

23
"Практикум по конструированию устройств на PIC контроллерах"      http://ikarab.narod.ru       E-mail: karabea@lipetsk.ru

24