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

6/6/2.

Пример практического применения режима захвата: расширение


функциональности частотомера (с ЖКИ модулем на основе HD44780) за счет
"доукомплектования" его функцией измерения периода (с переводом программы
с PIC16F84A на PIC16F628A и организацией "навязчивой EEPROM – рекламы").

Если имеется результат измерения частоты, то, при помощи программно реализуемого
деления единицы на этот результат, можно осуществить математическое
преобразование частоты в период, но это не есть замер периода в "чистом" виде.
Это есть "калькулятор".
Если речь идет о замерах и частоты, и периода, то, на мой взгляд, "солидный"
измерительный прибор должен производить эти замеры за один полный цикл
программы, с выводом на индикацию обеих результатов замеров, и без использования
"калькуляторного заменителя" (см. выше).
Таким образом, речь идет о двух, независимых друг от друга, процедурах измерения
параметров сигнала, последовательно исполняемых за время одного полного цикла
программы.
В этом случае, существует возможность объективной оценки точности замера (по
совокупности показаний), и лишние "рубильники" отсутствуют, так как не нужно
осуществлять выбор того или иного режима измерения.
В идеале, измерительный прибор (да и другие устройства тоже) не должен напрягать
извилину пользователя обилием органов управления.
"Железяка сама должна думать" о создании комфортных условий для пользователя и
беспроблемно выдавать полную и точную информацию о том, чего пользователь
"вожделеет".
Одной такой "малобюджетной штуковиной" можно заменить целый комплекс
измерительных устройств, стоящий немалых денег.
И это, при желании и "долбежке в одну точку", абсолютно реально.
Когда-нибудь я такую "железяку" обязательно сделаю, а сейчас, в контексте текущей
темы, попытаюсь ублажить и Вас, и себя.
Что касается меня, то "уж больно руки чешутся".
Так и "зудит".
А тут такой повод подвернулся ("и волки сыты, и овцы целы")…
И отклонения от текущей темы не будет, если я слегка "взбрыкну" в обозначенном
выше направлении.
"Взбрыкиваю".
Необходимо "обкатать", "добытую" ранее информацию, в "железе".
Для обеспечения "рождения дочери" (лучше бы, конечно, сына, но слово "программа" -
женского рода), стимулирую "детородные функции матери", в качестве которой
используется программа "чистого" (без цифровой шкалы) частотомера bf_fr_9.asm.
Сначала необходимо перевести ее с PIC16F84A на PIC16F628A (так как используются
TMR1 и CCP).
О "механике" такого перевода было уже достаточно много сказано ранее, и поэтому не
буду повторяться.
После этого, в него нужно ввести дополнительную функцию измерения периода,
причем, с условием создания, для пользователей программы bf_fr_9.asm (в "железе"),
максимальных удобств.
В соответствии с ранее высказанной "концепцией", замеры и частоты, и периода (а не
или частоты, или периода) должны быть произведены в пределах одного полного
цикла программы, и без наличия ветвлений, связанных с выбором режима измерения
(на передней панели устройства отсутствует переключатель "замер частоты"/"замер
периода").
То есть, после окончания замера частоты, должен сразу же начаться замер периода
(или наоборот), и оба результата этих замеров, в том же полном цикле программы,
должны быть выведены на индикацию.
Короче, за один полный цикл программы, "делаются все дела", результаты которых
"преподносятся на блюдечке с голубой каемочкой" (выводятся на индикацию в ЖКИ
модуль на основе HD44780).

1
Эту задумку полезно реализовать и с "глобальной" точки зрения, так как сие есть
"тренинг" в осуществлении "крупных врезок" (в последовательном усложнении
программы).
Рано или поздно, но необходимость этого неизбежно будет иметь место быть, и
поэтому обязательно нужно иметь хотя бы представление о том, как делаются такие
"дела" (быть "во всеоружии").
В этой связи, "выдаю на гора" образ - прыжок с парашютом.
Встреча с землей неизбежна, и "неумеха" сильно рискует переломать себе ноги (или
еще чего-нибудь).
И еще один существенный момент, на который обязательно нужно обратить внимание.
Формально, я рассказываю об измерении периода равномерной импульсной
последовательности (с относительно стабильным периодом), но по большому счету,
речь идет о замере интервала времени между двумя событиями захвата, попадающими
в "зону" разрешения прерываний от модуля CCP, которые могут быть инициированы
как равномерной, так и неравномерной (например, сформированной по
случайному/псевдослучайному закону) импульсными последовательностями.
Это означает то, что измерителю периода "по барабану", равномерна ли, подаваемая
на вывод RB3, импульсная последовательность или она неравномерна.
Он будет мерить и то, и другое, но при соблюдении естественного условия: интервал
времени между двумя соседними захватами не должен выходить за границы
диапазона измерения.
Это существенно расширяет диапазон практического применения такого принципа
замера интервалов времени и делает его, в пределах дозволенного, универсальным.
Чем более расширяются границы дозволенного (увеличивается диапазон измерения),
тем более классным будет измерительный прибор (естественно, при сохранении
точности измерения).
После такого рода "промывания мозгов" (а оно вполне оправдано, так как
"переломанные ноги" не есть хорошо), можно и практическим делом заняться.
Тем из Вас, кто имеет "железяку" под программы bf_fr_9.asm/bf_fr_12.asm, для того
чтобы проверить работу опубликованной ниже программы, не нужно будет сильно
напрягаться, так как:
1. PIC16F84A просто вынимается из панельки (можно использовать для других целей),
а вместо него вставляется PIC16F628A (с соответствующей прошивкой).
2. Доработка принципиальной схемы "проста как мычание коровы".
По 1-му пункту, в соответствии со сказанным ранее, комментировать нечего.
"Мычание коровы" 2-го пункта заключается в том, что нужно просто взять
"коротюсенькую проволочину" и соединить ей (припаять) вывод RB3 с точкой
соединения выводов RA3 и RA4.
Больше никаких "телодвижений" делать не нужно.
Из сказанного следует то, что функция блокировочного вывода RA3 расширяется, так
как наряду с его "старой" функцией (при измерении частоты), имеет место быть еще и
"новая" функция - разблокировка счетного входа модуля CCP в начале цикла
измерения периода и блокировка счетного входа модуля CCP в его конце.
Зачем это нужно, ведь можно обойтись и без этого, соединив вывод RB3 напрямую
(минуя "развязывающий" резистор), с выходом внешнего формирователя импульсов?
Можно сделать и так, но тогда нужно "забивать себе голову" местоположением команд
настройки модуля CCP, так как более чем на 16 – 1 (учет перехода в 0-й банк) = 15
м.ц. удалять ее, от машинного цикла разрешения прерываний, не желательно, так как
этим можно "подрезать" верхнюю границу диапазона измерения периодов.
А вот в описанном выше случае, такое "забитие головы" исключается (можно "засунуть
ее хоть к черту на кулички"), так как команда разблокировки счетного входа модуля
CCP исполняется непосредственно перед разрешением прерываний от модуля CCP, и
поэтому "ефрейторский зазор", о котором шла речь в предыдущем подразделе,
обеспечивается даже в случаях крайней степени забывчивости.
И "лишних" команд "кот наплакал".
Раз это так, то нужно использовать это "подвернувшееся счастье", что я и сделал.
В связи с этим, возникает вопрос: "Кабы бардальеро не заполучить, ведь, во время
разблокировки под измерение периода, разрешается счет TMR0"?

2
Русский, народный ответ: ну и черт сним, с этим "бардальеро" (кстати, автор этого
слова - Шукшин. Жаль, что он мало пожил).
Пускай TMR0 "потешится", пока происходит замер периода.
Все равно ему (не TMR0, а "бардальеро") будет "Гитлер капут", так как, в начале
процедуры измерения частоты, имеет место быть предустановка нуля (clrf Tmr0), да и
результат предшествующего измерения частоты благополучно "осел" в LEDах, и
"повлиять на него TMR0 никак не может - руки коротки".

"Дочь" "материнской" программы bf_fr_9.asm называется Hz_Mks_1.asm.


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

;********************************************************************************
; Hz_Mks_1.asm ПРОГРАММА 2-ДИАПАЗОННОГО 8-РАЗРЯДНОГО ЧАСТОТОМЕРА-ИЗМЕРИТЕЛЯ
; ПЕРИОДА С ИСПОЛЬЗОВАНИЕМ ЖКИ МОДУЛЯ НА ОСНОВЕ HD44780.
; Для измерения периода, задействован модуль CCP, работающий в режиме захвата.
;********************************************************************************
; "Практикум по конструированию устройств на PIC контроллерах"
; (http://ikarab.narod.ru)
; Корабельников Евгений Александрович karabea@Lipetsk.ru
;********************************************************************************
; Длительности интервалов времени измерения: 1сек., 10сек.
; "Помощник": ЖКИ модуль на основе м/контроллера 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.
;----------------------------------------------
; Объем программы: 487 слов в памяти программ.
;********************************************************************************
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 ; Регистр разрешения прерываний от

3
; периферийных модулей.
PIR1 equ 0Ch ; Регистр флагов прерываний от
; периферийных модулей.
T1CON equ 10h ; Регистр управления модулем таймера TMR1.
CCP1CON equ 17h ; Регистр управления модулем CCP.
CCPR1L equ 15h ; Регистр младшего разряда CCP.
CCPR1H equ 16h ; Регистр старшего разряда CCP.
;================================================================================
; "Прописка" регистров общего назначения.
;================================================================================
; Регистры оперативной памяти частотомера.
;---------------------------------------------------
LED0 equ 70h ; Регистр младшего разряда LED0.
LED1 equ 71h ; ------------"----------- LED1.
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 ; Самый старший.
;---------------------------------------------------
; Регистры временного хранения "захваченных" чисел.
;---------------------------------------------------
; №1
;-------------------------
Temp1_L equ 2Ah ; Младший.
Temp1_H equ 2Bh ; Старший.
;-------------------------
; №2
;-------------------------
Temp2_L equ 2Ch ; Младший.
Temp2_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 ; Многофункциональный регистр.
4
Count equ 25h ; Регистр числа выводимых в строку символов.
Flag equ 26h ; Регистр указателя конца замера периода.
BitC equ 27h ; Регистр хранения бита С регистра Status.
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 ; Флаг переноса-заема.
CCP1IF equ 2 ; Флаг прерывания от модуля CCP.
;================================================================================
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-я перезапись.
;--------------------------------------------------------------------------------
movf CCPR1L,W ; Содержимое регистра CCPR1L
movwf Temp2_L ; копируется в регистр Temp2_L.
movf CCPR1H,W ; Содержимое регистра CCPR1H
movwf Temp2_H ; копируется в регистр Temp2_H.
bsf Status,Z ; Установка признака конца замера периода.
;-----------------------------------
bcf PIR1,CCP1IF ; Сброс флага CCP1IF.
retfie ; Возврат из прерывания.
;--------------------------------------------------------------------------------
; 1-я перезапись.
;--------------------------------------------------------------------------------
WRITE_1 movf CCPR1L,W ; Содержимое регистра CCPR1L
movwf Temp1_L ; копируется в регистр Temp1_L.
movf CCPR1H,W ; Содержимое регистра CCPR1H
movwf Temp1_H ; копируется в регистр Temp1_H.
bcf Status,Z ; Установка признака продолжения
5
; замера периода.
;-----------------------------------
bcf PIR1,CCP1IF ; Сброс флага CCP1IF.
retfie ; Возврат из прерывания.
;********************************************************************************

;********************************************************************************
; ----------------------- "РАБОЧАЯ" ЧАСТЬ ПРОГРАММЫ ----------------------
;********************************************************************************
; "Рабочая" инициализация ЖКИ модуля.
;================================================================================
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.
6
;-------------------------------------------------
; Подготовка к проверке.
;------------------------
bsf Status,RP0 ; Переход в 1-й банк.
movlw b'11110000' ; Запись в W "11110000"
movwf TrisB ; RB4...7 работают на вход, а RB0...3
; работают на выход.
bcf Status,RP0 ; Переход в 0-й банк.

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
7
; (44,33,22,11,00) в регистр W.
;----------------------------------------------------------
; Вывод символов результатов измерения периода в 1-ю строку
; ("врезка" в процедуру косвенной адресации).
;----------------------------------------------------------
bsf PortA,RS ; Установка на линии RS "1"
; (режим записи данных).
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП 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.
8
;----------------------------------------------------------
movlw LED7 ; Стандартная процедура косвенной адресации с
movwf FSR ; "переправкой" содержимого регистра, сначала,
SNOVA movf IndF,W ; LED7, а затем и всех остальных LED
; (6,5,4,3,2,1,0) в регистр W.
;----------------------------------------------------------
; Вывод символов результатов измерения во 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 ; Остальное - то же самое.
9
call ENTER_BF ; -----------"------------
;----> Возврат по стеку из ПП ENTER_BF.

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


bsf PortA,RS ; Остальное - то же самое.
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 ; выбор внешнего тактового сигнала с вывода

10
; RA4/TOCK1, приращение TMR0 по переднему
; фронту, подтягивающие резисторы порта В
; включены.
bcf Status,RP0 ; Переход в 0-й банк.

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


movwf CMCON ; компараторов.

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 ; "Плавающая" задержка со стробом под вывод
11
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
decfsz Count,F ; Подготовка к выводу на индикацию
; следующего символа таблицы.
goto WR_3 ; Если результат декремента не=0, то переход
; в ПП WR_3.
; Если результат декремента =0, то программа
; исполняется далее.

;********************************************************************************
; ПОДПРОГРАММА ОПРОСА КЛАВИАТУРЫ.
;********************************************************************************
; Подготовка к опросу клавиатуры.
;------------------------------------------------------------
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 ; -------"--------
12
movlw .220 ; -------"--------
movwf SecL ; -------"--------
movlw .251 ; -------"--------
movwf Kalib ; -------"--------
movlw .124 ; -------"--------
movwf Kalib_1 ; -------"--------
movlw .01 ; -------"--------
movwf Mem_1 ; -------"--------

;************************************************************************
; СНАЧАЛА ЗАМЕРЯЕМ ЧАСТОТУ.
;************************************************************************
; Подготовительные операции.
;-------------------------------------
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 м.ц.

13
;-----------------------
PAUSE clrwdt ; Сброс WDT с функцией задержки на 1 м.ц.
decfsz Kalib,F ; Однобайтный вычитающий счетчик с шагом
goto PAUSE ; константы 4 м.ц. (за счет "врезки" команды
; clrwdt).
;-----------------------
; Шаг константы: 3 м.ц.
;-----------------------
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 ; Условный переход в ПП двоично-десятичного
14
; преобразования.
;----> Возврат по стеку из ПП BIN2_10.

;================================================================================
; Процедура преобразования стандартного весового кода в код ASCII (ANSI).
;================================================================================
movlw 30h ; Запись в регистр W числа 30h.
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, то переход на
; повторную проверку на незначащие нули.

;************************************************************************
; ТЕПЕРЬ ЗАМЕРЯЕМ ПЕРИОД.
;************************************************************************
VIHOD movlw 2 ; Запись, в указатель конца замера
movwf Flag ; периода, числа перезаписей.
;--------------------------------------
; Настройка модуля CCP.
;--------------------------------------
clrf CCP1CON ; Выключение модуля CCP
; (рекомендовано разработчиками).

15
movlw b'00000111' ; Захват по каждому 16-му переднему
movwf CCP1CON ; фронту сигнала на выводе RB3.
;--------------------------------------
; Сброс флага прерываний от модуля CCP.
;--------------------------------------
bcf PIR1,CCP1IF ; Сброс флага CCP1IF.
;--------------------------------------------------------------------------------
; Разрешение прерываний от модуля CCP, подключение предделителя
; к WDT и разблокировка счетного входа модуля CCP.
;--------------------------------------------------------------------------------
clrwdt ; Сброс WDT.
clrf Tmr0 ; Сброс в ноль Tmr0 и предделителя.

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-й банк.
;---------------------------------------------------------
; ИТОГ: в Temp1_H/Temp1_L "лежит" результат 1-го замера,
; в Temp2_H/Temp2_L "лежит" результат 2-го замера.
;================================================================================
; Обработка результатов подсчета.
;================================================================================
; Процедура вычитания, по кольцу, Temp1_H/Temp1_L из Temp2_H/Temp2_L.
;---------------------------------------------------------------------
bcf BitC,0 ; Очистка регистра хранения бита C.
movf Temp1_L,W ; Temp2_L - Temp1_L = ...
subwf Temp2_L,F ; Результат - в Temp2_L.

btfss Status,C ; Результат "+" или "-" ?


bsf BitC,0 ; Если "-", то в BitC,0 записывается 1.
movf Temp1_H,W ; Если "+", то в BitC,0 "лежит" ранее
; предустановленный 0 и Temp1_H --> W.
subwf Temp2_H,F ; Temp2_H - Temp1_H = ...
; Результат - в Temp2_H.
btfsc BitC,0 ; В бите №0 регистра BitC 0 или 1 ?
decf Temp2_H,F ; Если 1, то содержимое Temp2_H
; декрементируется.
; Если 0, то содержимое Temp2_H
; не декрементируется.
;----------------------------------------------------------------
16
; ИТОГ: результат замера, умноженный на 16, - в Temp2_H/Temp2_L.
;--------------------------------------------------------------------------------
; Деление содержимого Temp2_H/Temp2_L на 16.
;--------------------------------------------------------------------------------
bcf Status,C ; Сброс бита С.
rrf Temp2_H,F ; Сдвиг вправо содержимого регистра Temp2_H.
rrf Temp2_L,F ; Сдвиг вправо содержимого регистра Temp2_L.

bcf Status,C ;
rrf Temp2_H,F ; Аналогично.
rrf Temp2_L,F ;

bcf Status,C ;
rrf Temp2_H,F ; Аналогично.
rrf Temp2_L,F ;

bcf Status,C ;
rrf Temp2_H,F ; Аналогично.
rrf Temp2_L,F ;
;------------------------------------------------------
; ИТОГ: в Temp2_H/Temp2_L - истинный результат замера.
;********************************************************************************
; Процедура двоично-десятичного преобразования для замера периода.
;********************************************************************************
bcf Status,C ; Сброс флага С.
movlw .24 ; "Закладка" в регистр Count1 числа
movwf Count1 ; проходов преобразования.
clrf LED00 ; Сброс регистра LED00.
clrf LED11 ; ------"------ LED11.
clrf LED22 ; ------"------ LED22.
clrf Temp_0 ; Сброс "обманного" регистра.
;--------------------------------------------------------------------------------
; Сдвиг влево через бит С регистра Status.
;--------------------------------------------------------------------------------
LOOP_16_1 rlf Temp2_L,F ; Побитная
rlf Temp2_H,F ; "переправка"
rlf Temp_0,F ; содержимого
rlf LED00,F ; Temp_0/Temp2_H/Temp2_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 ; -------------------------------
17
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.
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).
18
;-------------------------------------
; Переход на следующий, текущий LED.
;-------------------------------------
decf FSR,F ; Уменьшение адреса текущего LED на 1.
decf Total,F ; Уменьшение содержимого указателя разрядов
; на 1.
;-------------------------------------
; 2-я проверка на нулевой результат.
;-------------------------------------
btfss Status,Z ; Проверка состояния флага нулевого результата
goto SNOVA_00 ; Если содержимое Total не=0, то переход на
; повторную проверку на незначащие нули.
;----------------------------------------------------------------------
; Теперь можно вывести результат замера частоты и периода на индикацию.
;----------------------------------------------------------------------
VIHOD_1 goto DISPLAY ; Переход в ПП вывода на индикацию.

;********************************************************************************
; Процедура двоично-десятичного преобразования для замера частоты.
;********************************************************************************
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


19
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).
; После возврата по стеку, переход к обработке следующего 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 ; Конец программы.

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

Работа программы.
Так как сначала производится замер частоты, то ПП START ориентирована на
обеспечение подготовки к замеру частоты.
Она примерно такая же, как и в программах bf_fr_...asm, только в нее добавлены
группы команд отключения модуля компараторов (в связи с переходом на PIC16F628A)
и настройки модуля TMR1.
Что касается последнего, то это то, о чем я говорил ранее: группа команд настройки
модуля TMR1 вынесена, из процедуры измерения периода, в ПП START.
Далее производится инициализация ЖКИ модуля и вывод на индикацию тестовой
надписи.
Все то же самое, что и в "материнской" программе, только надпись другая.
Ее содержание выбрано не просто так, а с рекламным умыслом.
Впереди Вас ждет объяснение того, как можно, с помощью "продуктов" своего
творчества, организовать принудительную рекламу или сделать так, чтобы
пользователь, поневоле, запомнил что-то, с Вашей точки зрения, нужное.
После этого начинается опрос двухкнопочной клавиатуры.
Так как речь идет о "чистом" частотомере (без функции цифровой шкалы), то я
посчитал нужным "убить" предел измерения 0,1 сек.
Суеты с ним много, а толка маловато, так как погрешность измерения высока.
После этого, программа частотомера прилично упростилась, и те из Вас, кто
испытывал трудности при "въезде" в трехдиапазонный частотомер, могут использовать
это "убийство" себе во благо.
ПП досчета "убивать" не стал, хотя это вполне можно сделать.
Не исключено, что "убью", но позже.
Так как диапазон измерения 0,1 сек. "канул в небытие", то освободилось одно
состояние клавиатуры - обе кнопки нажаты (00).
Это хорошо, так как в будущем на него можно будет "посадить" включение какого-
нибудь "прибамбаса".
Разумнее всего освободить именно это состояние, в связи с неудобством "жатия" двух
кнопок.
Правда, придется произвести "оргперестановки", но это относительно не трудно.
Состояние клавиатуры 00 нужно "к чему-то приспособить", так как конструкция
вычисляемых переходов (я решил их оставить и "не менять шило на мыло")
предполагает переход на исполнение этого сценария.
Да и любознательность пользователя нужно учесть.
А вдруг он возжелает нажать на обе кнопки?
Самый простой выход из этого положения - замена команды goto … (той, которая
расположена сразу же за командой вычисляемого перехода) на nop.
В этом случае, будет исполнен тот сценарий перехода, который находится ниже NOPа.
Так я и сделал.
Таким образом, при нажатии на обе кнопки, будет включен (или подтвержден)
диапазон измерения 1 сек.
Если нажать на одну кнопку, то включится один диапазон измерения, а если нажать
на другую кнопку, то включится другой диапазон измерения.
Управление - проще не придумаешь (а это и нужно).
Код кнопки диапазона измерения 10 сек. - 0000 0010, то есть, это есть число 2.
Эту константу и нужно "заложить", вместо 0, в подпрограмме Sec10, в регистр Mem_1
(оперативная память диапазона), что и сделано.
Во избежание шунтирования, внутренним, подтягивающим резистором вывода RB3,
нагрузки оконечного каскада внешнего формирователя импульсов (это то, о чем
21
говорилось в предыдущем подразделе), подтягивающие резисторы порта В отключаются
на время измерения и частоты, и периода (перед меткой On), и включаются в начале
процедуры опроса клавиатуры, что, на время опроса клавиатуры, обеспечивает
"подтяжку" кнопок к плюсу источника питания.
В остальном, процедуры измерения частоты, 2/10 преобразования и преобразования
кода ("привязанные" к измерению частоты) ничем не отличаются от соответствующих
процедур "материнской" программы, а проще говоря, они из нее просто "передраны"
один к одному.
Что же касается процедуры гашения незначащих нулей, то я в ней "убил" группу
команд коррекции содержимого указателя разрядов Total в случае, если установлен
предел измерения 0,1 сек.
Причина должна быть понятна - отсутствие диапазона измерения 0,1 сек.
Кроме того, я, со спокойной совестью, "ухлопал" еще и команду записи в указатель
полной отработки процедуры гашения незначащих нулей признака этой отработки
(bsf Count1,0), так как ответ на вопрос "Ставить запятую или заменить ее на "пробел"?",
не важен.
Напоминаю, что, в "материнской" программе, в случае, если на вход частотомера не
подается сигнала, десятичная запятая "гасится" (если ЧМ работает на пределе
измерения 10 сек.) путем замены ее на символ "пробел".
Дело в том, что, в рассматриваемом случае, при отсутствии измеряемого сигнала,
блокируя "все, что на дисплее шевелится", на индикацию автоматически выводится
тестовая надпись.
При малейшем появлении измеряемого сигнала, она "исчезает", "уступая место"
результатам измерения.
В данном случае, эта надпись указывает на URL моего сайта, но она может быть и
другой (даже "бегущую строку" можно вывести. Нет проблем).
Это то, на что я намекал выше.
Как Вы думаете, в "подкорке эксплуататора" эта информация отложится?
Поневоле отложится.
Это и есть навязчивая реклама (то есть, "двигатель прогресса", чтоб ей пусто было)
или способ борьбы с забывчивостью, если это не реклама.
Как это "проворачивается"?
А очень просто. Ниже сами удивитесь.
Итак, замер частоты закончился, и в "частотных LEDaх" (есть еще и "периодные
LEDы") "осел" результат измерения частоты.
Он там может "лежать и дожидаться своего часа" очень долго (пока включено
питание), и за это время можно замерить не только период, но даже и выспаться.
А раз это так, то можно произвести безбоязненный замер периода.
Процедура измерения периода "передрана" из универсальной "заготовки" предыдущего
подраздела, только группа команд настройки модуля TMR1 вынесена из нее в ПП
START.
Команда выключения "подтяжки" порта В (bsf OptionR,7) вынесена в начало процедуры
измерения частоты.
Но зато кое-что и добавлено (в соответствии со спецификой разработки).
Во-первых, перед разрешением прерываний от модуля CCP, осуществляется
разблокировка счетного входа (bsf TrisA,3).
Это нужно сделать потому что, в конце процедуры измерения частоты, счетный вход
(а он общий) блокируется (см. метку Off).
Если его не разблокировать, то просто нечего будет измерять.
А теперь подошло время разобраться с "рекламными делами".
"Собака здесь порылась" в том, что, при отсутствии измеряемого сигнала, рабочая
точка программы "намертво зависает" в "плавающей" задержке (я предупреждал, что
она дебил).
Причина этого "висяка" должна быть понятна - отсутствие прерываний, и поэтому флаг
Z "не может" подняться.
Если WDT будет выключен, то оба последних (перед "пропаданием" сигнала)
результата измерения (или их "хвостики"), из-за наличия в ЖКИ модуле оперативной
памяти показаний, просто – напросто зафиксируются на дисплее "на веки вечные" (до

22
тех пор, пока, при включенном питании, на измерительный вход прибора не будет
подан сигнал).
Что будет, если включить WDT (примечание: в цикле "плавающей" задержки нет
команды clrwdt)?
А будет то, что WDT сработает, и программа начнет исполняться с начала.
В конечном итоге, рабочая точка программы "заскочит" в ту же "плавающую" задержку
и опять же в ней "зависнет".
После этого, снова сработает WDT, и все это "безобразие" будет повторяться "до
посинения".
Обращаю Ваше внимание на то, что, в ходе этого "безобразия", замеры частоты
происходят, но их результаты не выводятся на индикацию по той причине, что
команда перехода в процедуру вывода результатов замеров на индикацию
(goto DISPLAY) находится в конце процедуры измерения периода.
На индикацию будет выводиться тестовая надпись.
Русский, революционный вопрос: "Как с этим бороться"?
А зачем бороться? Зачем, "чуть что, так сразу в морду и на Колыму"?
Мы "цари природы или папуасы"?
"Цивилизованные гомо сапиенсы" сначала подумают, а нельзя ли обратить вред в
пользу, а только после этого, если такое не возможно, "морды бить" (если за дело, то
не возбраняется, и даже нужно).
По – моему, никакого "открытия Америки" в этом нет, но тем не менее, "на эти грабли
частенько наступают".
При включенном WDT и отсутствии измеряемого сигнала, на индикацию выводится
тестовая надпись?
Ну и пусть выводится. Это даже хорошо.
Мне только остается обеспечить некоторую "перестраховочную" инерционность (18-ти
мс. маловато), то есть, перед разрешением прерываний от модуля CCP, нужно
отключить предделитель от TMR0 и подключить его к WDT (с "массивным" Кдел.
предделителя).
После запрета прерываний, обеспечиваю обратное переключение, что есть "возврат в
исходное положение".
Переключаю.
Для того чтобы переключить предделитель с TMR0 на WDT, нужно сделать
следующее (рекомендации разработчиков):

bcf Status,RP0 ; Переход в 0-й банк.


clrwdt ; Сброс WDT.
clrf Tmr0 ; Сброс TMR0 и предделителя.
bsf Status,RP0 ; Переход в 1-й банк.

movlw b'00101111' ; Вместо нулей можно ставить единицы.


movwf OptionR ; Биты с №№5,3,2,1,0 должны быть
; единицами (внешний такт с вывода RA4
; подключение предделителя к WDT
; с максимальным Кдел.).
clrwdt ; Сброс WDT.

movlw b'хх1х1ХХХ' ; Внешний такт с вывода RA4,


movwf OptionR ; подключение предделителя к WDT
; с требуемым Кдел. (ХХХ).
bcf Status,RP0 ; Переход в 0-й банк.

х - зависит от конкретной задумки,


ХХХ - требуемый Кдел. предделителя.
Команды, выделенные синим цветом, нужно исполнить только в тех случаях, если, до
переключения предделителя с TMR0 на WDT, был установлен Кдел. предделителя,
соответствующий комбинациям битов PS2…0 000 или 001.
В остальных случаях, эти 3 команды использовать не нужно.

23
Если на момент начала перенастройки, работа происходила в 0-м банке (а это
наиболее вероятно), то самая верхняя команда не нужна.
Команды этой процедуры, которые работают в 1-м банке, выгоднее всего (зачем нужны
лишние "банковские" команды?) врезать в ближайший "сектор" работы в 1-м банке.
В части касающейся предмета разговора, синие команды не нужны, так как выставлен
максимальный Кдел. предделителя.
Первая сверху команда тоже не нужна, так как, на момент начала перенастройки,
происходит работа в 0-м банке.
Из-за того, что я не стал менять Кдел. предделителя (значения битов PS2…0 регистра
OptionR равны 111), можно, вместо двух байт – ориентированных команд
(movlw b'хх1х1ХХХ' и movwf OptionR), использовать одну бит – ориентированную
команду (bsf OptionR,3 - подключение предделителя к WDT, с Кдел. предделителя
=128), "врезав" ее в имеющийся "сектор" работы в 1-м банке).
Получается всего 3 дополнительные команды.
Для того чтобы переключить предделитель с WDT на TMR0, нужно сделать
следующее (рекомендации разработчиков):

clrwdt ; Сброс WDT.


bsf Status,RP0 ; Переход в 1-й банк.
movlw b'хх1х0ХХХ' ; Внешний такт с вывода RA4,
movwf OptionR ; подключение предделителя к TMR0
; с Кдел.= ХХХ.
bcf Status,RP0 ; Переход в 0-й банк.

х - зависит от конкретной задумки,


ХХХ - требуемый Кдел. предделителя.
Для данного типа переключения, также справедливы указанные выше "ухищрения".
Поэтому, использованы только 2 дополнительные команды (clrwdt и bcf OptionR,3 -
подключение предделителя к TMR0, с Кдел. предделителя =256).
Они исполняются сразу же после запрета прерываний от модуля CCP.
Таким образом, состояния остальных битов регистра OptionR (кроме бита №3) не
меняются.
Это означает то, что, на момент начала любого замера частоты, "счетные настройки"
TMR0 останутся такими же, какими они были заданы в ПП START, а время
срабатывания WDT будет приблизительно 2,3 сек. (18 мс. х 128).
В конечном итоге, будет иметь место быть "перестраховочная" задержка, с момента
"исчезновения" сигнала на измерительном входе устройства (а вдруг он снова
"объявится"?) и до момента "появления" рекламной надписи.
Ее можно сделать меньшей, установив меньший Кдел. предделителя (для WDT, но не
для TMR0), но в этом случае, количество перестроечных команд увеличится.
Можно обойтись и без указанной выше перенастройки (рассказываю о ней, прежде
всего, в обучающих целях).
В случае, если "исчезновение" сигнала произошло во время замера частоты с
временем измерения 10 сек. и WDT сработал, то, после "появления" сигнала, замер
частоты будет происходить на пределе измерения 1 сек.
И это должно быть понятным, так как, после сброса программы на начало, по
умолчанию, выставляется время измерения 1 сек.
Если это не нравится, то можно оганизовать энергонезависимую память настроек.
Вот, собственно говоря, и вся "премудрость" конкретной задумки.
Естественно, что тактика задумки может быть и другой, но стратегия (принцип)
процедуры измерения периода остается неизменной.
После приведения результата измерения периода к "божескому виду", исполняется
процедура 2/10 преобразования, "привязанная" к измерению периода.
Я не стал "рожать" одну, универсальную ("сдвоенную") процедуру 2/10 преобразования
(а также "сдвоенные" процедуры преобразования кода и гашения незначащих нулей),
работающую по принципу "Фигаро здесь, Фигаро там", а просто использовал две
отдельных процедуры (для измерения частоты и для измерения периода), так как,
во-первых, не вижу какого-то существенного выигрыша, а во-вторых, усложнение
"процедуры" Вашего "въезда" в работу программы не входит в мои текущие планы.
24
Процедура 2/10 преобразования, "привязанная" к измерению периода, имеет следующие
особенности.
Из-за наличия перехода/возврата по стеку и регистра Mem, функционально не
"привязанного" к процедурам измерения частоты или периода, ПП adjBCD является
общей (для обеих процедур 2/10 преобразования).
Это, в пределах рассматриваемого сейчас "куска" программы, единственная "сдвоенная"
подпрограмма.
В части касающейся процедуры 2/10 преобразования, применяемой при измерении
периода, имеется одна проблема, суть которой состоит в следующем.
Необходимо преобразовать в десятичную форму двоичное число, "лежащее" в регистре
Temp2_H/Temp2_L (16 проходов преобразования).
При таком "раскладе", алгоритм стандартной ПП Bin2_10 позволяет сформировать 4
десятичных разряда.
Максимум, что можно "засунуть" в 4 десятичных разряда, это число 9999.
При превышении этой "границы", будет происходить работа по кольцу.
Temp2_H/Temp2_L отображает числа до 65535 (в двоичной форме).
Получается, что ПП Bin2_10 существенно ограничивает ("режет") числовой диапазон
измерения со стороны больших (ударение на "о") значений.
Каков выход из этого положения?
Если, в результате стандартного подхода, нужный результат не достигается, то нужно
поступать нестандартно.
Для того чтобы организовать 6 десятичных разрядов (в данном случае, требуется 5
десятичных разрядов, но 1 "на ум пошел", в смысле запаса), нужно, чтобы исходное,
двоичное число было не 2-байтным, а 3-байтным (24 прохода преобразования).
Значит нужно "родить" недостающий, третий байт.
Вопрос: "Что в нем должно лежать"?
Ответ: ноль.
Вот так и "родился" регистр, который я назвал "обманным" (Temp_0 - якобы, самый
старший разряд).
Таким образом, 2-байтный регистр Temp2_H/Temp2_L "превратился" в 3-байтный
регистр Temp_0/Temp2_H/Temp2_L.
Ну а дальше все по стандарту.
В результате такого 2/10 преобразования, как минимум, имеет место быть способность
к "выдаче на гора" десятичных чисел до 65535 (при отсутствии переносов из Temp2_H
в Temp_0, что и имеет место быть), а как максимум, способность к "выдаче на гора"
десятичных чисел до 999999 (при организации переносов из Temp2_H в Temp_0).
То есть, имеется запас, который позволяет наращивать диапазон измерения периода
(до 999999 мкс.), "не забивая себе голову" проблемами 2/10 преобразования.
Так как LED0 … LED7 использовать нельзя (в них "лежит" результат замера частоты),
то организована "новая" группа регистров LED (LED00 … LED55).
Пошли дальше.
Процедура преобразования кода "адаптирована" под LED00 … LED55.
Это есть единственное ее принципиальное отличие от процедуры преобразования кода,
примененной при измерении частоты.
Обе процедуры гашения незначащих нулей тоже "клоны".
Принципиальные различия только в количествах проходов и в адресах, которые
записываются в регистр FSR при входе в эти процедуры.
Можно было бы и "ужать", совместив функции (два в одном), но по причинам,
указанным выше, я не стал этого делать.
После отработки процедуры гашения незначащих нулей (той, которая исполняется при
замере периода), осуществляется переход в ПП вывода результатов измерений
частоты и периода на индикацию в ЖКИ модуль на основе HD44780 (goto DISPLAY).
ПП "рабочей" инициализации - без изменений.
ПП ENTER_BF - без изменений.
В ПП EEPR, процедура чтения из EEPROM "адаптирована" под PIC16F628A.
Тестовая надпись заменена на "рекламную".
Надписи "FREQUENCY T=", "10s ", "1,0s" и "0,1s" "убиты".
Вместо них выводятся надписи " 1c" или "10с" (в конце 2-й строки), и не через
EEPROM, а "напрямую".
25
Местоположение результата замера частоты (во 2-й строке) осталось неизменным.
Вместо надписи "Hz", на индикацию выведена надпись "гц".
В 1-ю строку выводится результат замера периода и сопровождающая этот результат,
надпись "мкс".
Так как предел измерения "0,1 сек." "убит" и при отсутствии сигнала на входе прибора
нет необходимости совершать какие-то "телодвижения" ("рекламная" надпись "давит
все"), ПП DISPLAY значительно упростилась.
Она может помочь в случае, если, при "въезде" в ЖКИ модуль на основе HD44780,
имеются понятийные проблемы.
После отработки ПП DISPLAY, полный цикл программы завершается, и происходит
переход на начало следующего полного цикла программы (goto INKEY - переход на
опрос клавиатуры).
Программа Hz_Mks_1.asm проверена в железе.
Можете сами убедиться в ее работоспособности.
Текст программы прилагается к этому подразделу.

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

26

Вам также может понравиться