Академический Документы
Профессиональный Документы
Культура Документы
Если имеется результат измерения частоты, то, при помощи программно реализуемого
деления единицы на этот результат, можно осуществить математическое
преобразование частоты в период, но это не есть замер периода в "чистом" виде.
Это есть "калькулятор".
Если речь идет о замерах и частоты, и периода, то, на мой взгляд, "солидный"
измерительный прибор должен производить эти замеры за один полный цикл
программы, с выводом на индикацию обеих результатов замеров, и без использования
"калькуляторного заменителя" (см. выше).
Таким образом, речь идет о двух, независимых друг от друга, процедурах измерения
параметров сигнала, последовательно исполняемых за время одного полного цикла
программы.
В этом случае, существует возможность объективной оценки точности замера (по
совокупности показаний), и лишние "рубильники" отсутствуют, так как не нужно
осуществлять выбор того или иного режима измерения.
В идеале, измерительный прибор (да и другие устройства тоже) не должен напрягать
извилину пользователя обилием органов управления.
"Железяка сама должна думать" о создании комфортных условий для пользователя и
беспроблемно выдавать полную и точную информацию о том, чего пользователь
"вожделеет".
Одной такой "малобюджетной штуковиной" можно заменить целый комплекс
измерительных устройств, стоящий немалых денег.
И это, при желании и "долбежке в одну точку", абсолютно реально.
Когда-нибудь я такую "железяку" обязательно сделаю, а сейчас, в контексте текущей
темы, попытаюсь ублажить и Вас, и себя.
Что касается меня, то "уж больно руки чешутся".
Так и "зудит".
А тут такой повод подвернулся ("и волки сыты, и овцы целы")…
И отклонения от текущей темы не будет, если я слегка "взбрыкну" в обозначенном
выше направлении.
"Взбрыкиваю".
Необходимо "обкатать", "добытую" ранее информацию, в "железе".
Для обеспечения "рождения дочери" (лучше бы, конечно, сына, но слово "программа" -
женского рода), стимулирую "детородные функции матери", в качестве которой
используется программа "чистого" (без цифровой шкалы) частотомера 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 никак не может - руки коротки".
;********************************************************************************
; 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.
;************************************************************************
; Начало исполнения "программы".
;************************************************************************
; Подготовительные операции.
;----------------------------------------
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-й банк.
;********************************************************************************
; Вывод тестовых надписей, свидетельствующих об успешном завершении процедуры
; "рабочей" инициализации и готовности к дальнейшей работе.
;********************************************************************************
; Вывод надписи " 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 ; Переход на новый цикл измерения.
;************************************************************************
; СНАЧАЛА ЗАМЕРЯЕМ ЧАСТОТУ.
;************************************************************************
; Подготовительные операции.
;-------------------------------------
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.
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,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 ; -------------------------------
;================================================================================
; Процедура преобразования стандартного весового кода в код 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 ; -------------------------------
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, нужно сделать
следующее (рекомендации разработчиков):
23
Если на момент начала перенастройки, работа происходила в 0-м банке (а это
наиболее вероятно), то самая верхняя команда не нужна.
Команды этой процедуры, которые работают в 1-м банке, выгоднее всего (зачем нужны
лишние "банковские" команды?) врезать в ближайший "сектор" работы в 1-м банке.
В части касающейся предмета разговора, синие команды не нужны, так как выставлен
максимальный Кдел. предделителя.
Первая сверху команда тоже не нужна, так как, на момент начала перенастройки,
происходит работа в 0-м банке.
Из-за того, что я не стал менять Кдел. предделителя (значения битов PS2…0 регистра
OptionR равны 111), можно, вместо двух байт – ориентированных команд
(movlw b'хх1х1ХХХ' и movwf OptionR), использовать одну бит – ориентированную
команду (bsf OptionR,3 - подключение предделителя к WDT, с Кдел. предделителя
=128), "врезав" ее в имеющийся "сектор" работы в 1-м банке).
Получается всего 3 дополнительные команды.
Для того чтобы переключить предделитель с WDT на TMR0, нужно сделать
следующее (рекомендации разработчиков):
26