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

5/2.

Конструирование электронного термометра на основе “связки” PIC16F84A –


DS1820 (DS18S20) с выводом показаний в ЖКИ модуль на основе HD44780.
Объяснение работы базовых процедур 1-Wire протокола.

“Раскрутка” будет происходить по принципу последовательного “вгрызания в детали”, в


процессе конструирования конкретного устройства.
Техническое задание на разработку:
Необходимо сконструировать электронный термометр с одним датчиком температуры
DS1820 (DS18S20), соединенным с базовым блоком (на основе PIC16F84A) короткой
3-проводной линией.
Результаты измерения нужно вывести в ЖКИ модуль на основе HD44780.
Диапазон измерения температуры: от - 55 до +125 градусов Цельсия.
Шаг замера температуры: 0,5 градуса Цельсия.
Сигналы управления внешними исполнительными устройствами не формируются.
Таким образом, речь идет о “простейшем”, индикаторном (информирующем) устройстве.
Потом потом будет “тренировка” в поэтапном усложнении устройства, за счет введения
дополнительных функций.

Как видите, ничего особо сложного в принципиальной схеме нет: имеет место быть
стандартное подключение ЖКИ модуля и очень простое подключение датчика.
Разбираюсь с командами и последовательностью их исполнения.
Команды, которые нужно применить в данном случае, упоминались в предыдущем
разделе. Напоминаю:

1
Объясняю смысл “боевой раскраски”.
Система команд DS1820 состоит из двух групп команд:
1. 5 команд, работающих с ПЗУ,
2. 6 команд, работающих с оперативной памятью (с ОЗУ) и энергонезависимой
памятью (EEPROM).
Так вот, светло – желтым цветом помечена команда 1-й группы.
Остальные 2 команды, это команды 2-й группы.
Полная “разрисовка” всех команд будет позднее, а пока работаю с тем, что есть (с
тем, что требуется).
Теперь, с учетом процедуры инициализации, возникает вопрос о последовательности их
исполнения.
Немного элементарной логики, в комплексе со здравым смыслом, и получается вот что (в
общем виде):

Словосочетание “передаем импульс сброса, игнорируя ответ датчика на него” означает


то, что PIC16F84A “принимает на веру” факт безошибочности отработки процедуры
инициализации датчика, то есть, после окончания импульса сброса, он, не уходя в
анализ состояния линии DQ, просто формирует фиксированную задержку (“пережидает”
ответ датчика).
В случае использования короткой линии с малым уровнем помех (что и имеет место
быть), это вполне приемлемо.
Процедура инициализации должна предшествовать любой команде из числа команд,
входящих в 1-ю группу.
В данном случае, это команда пропуска процедуры выбора активного датчика Skip
ROM (датчик всего один).
Кроме того, что эта “связка” должна исполняться в начале цикла замера температуры
(см. верхние 2 строки таблицы рис. 3), она должна быть исполнена и перед
применением команды, разрешающей считывание байтов из ячеек оперативной памяти
Read Scratchpad (см. строки 5 и 6).
Это связано с алгоритмом работы DS1820, заданным разработчиками.
Естественно, прежде чем считывать результат замера, нужно запустить процедуру
преобразования температуры (команда Convert T) и подождать, пока эта процедура
закончится.
В конце цикла замера температуры, нужно считать, из области оперативной памяти
DS1820, первые 2 байта (результат замера), в заранее назначенные 2 регистра общего
назначения, с целью их дальнейшей обработки.
В данном случае, под словом “обработка” понимается все то, что связано с выводом
результата замера на индикацию.
Обращаю Ваше внимание на то, что, в данном случае, нет никакой практической
необходимости считывать из области оперативной памяти все ее содержимое, так как,
кроме первых двух байтов, остальные не используются.
Итак, “контуры” устройства обозначены и можно лезть в детали.

2
Альберто предоставил базовую процедуру работы с датчиком, за что ему большое
спасибо.
Для начала, я ее “обкарнал” (упростил) под специфику разрабатываемого устройства,
“прилепил” к ней требуемые “детальки”, подымил паяльником и добился того, чтобы
это “сооружение” полноценно заработало.
Получилось вот что:

;********************************************************************************
; DS1820.asm ЭЛЕКТРОННЫЙ ТЕРМОМЕТР НА ОСНОВЕ ДАТЧИКА ТЕМПЕРАТУРЫ DS1820
; М/контроллер и DS1820 работают по интерфейсу 1-Wire.
; Работа с одним датчиком.
;********************************************************************************
; "Практикум по конструированию устройств на PIC контроллерах".
; Эта программа входит в состав 5-го раздела.
; Авторы: Alberto Rolando Senelyuk (Argentina),
; Корабельников Евгений Александрович (Русь-матушка),
; http://ikarab.narod.ru karabea@lipetsk.ru
;********************************************************************************
; Используется м/контроллер PIC16F84A. Частота кварца 4 Мгц.
; Сигнальный вывод (DQ) датчика DS1820 подключается к выводу RA4.
; Между выводом RA4 и шиной питания подключается подтягивающий резистор
; номиналом 4,7-5,1 кОм.
; DS1820 включается по схеме с активным питанием, т.е.: вывод 1 - общий,
; вывод 2 - сигнальный,
; вывод 3 - питание (+5в).
; Информация выводится в русифицированный ЖКИ модуль 16х2 на
; основе м/к HD44780 (по 4-разрядному интерфейсу).
; Функции выводов порта А:
; RA0 - RW (ЖКИ),
; RA1 - RS (ЖКИ),
; RA2 - E (ЖКИ),
; RA4 - вывод DQ датчика DS1820.
;-------------------------------
; Объем программы: 237 команд.
;================================================================================
LIST p=16F84a ; Используется м/контроллер PIC16F84A.
__CONFIG 03FF1H ; Бит защиты выключен, WDT выключен,
; XT-генератор.
;================================================================================
; Определение положения регистров специального назначения.
;================================================================================
IndF equ 00h ; Доступ к памяти через FSR.
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.
;================================================================================
; Определение названия и положения регистров общего назачения.
;================================================================================
N equ 0Ch ; Счетчик битов.
Temp equ 0Dh ; Многофункциональный регистр временного
; хранения.
Temp_MSB equ 0Eh ; Байт знака температуры (старший байт).
Temp_LSB equ 0Fh ; Байт значения температуры (младший байт).
Flag equ 10h ; Регистр флагов.
Count equ 11h ; Многофункциональный счетчик.
LED0 equ 12h ; Регистры двоично-десятичного
LED1 equ 14h ; преобразования.
;================================================================================
; Определение места размещения результатов операций.
;================================================================================
W equ 0 ; Результат направить в аккумулятор.
3
F equ 1 ; Результат направить в регистр.
;================================================================================
; Присваивание битам названий.
;================================================================================
C equ 0 ; Флаг переноса-заема.
Z equ 2 ; Флаг нулевого результата.
RP0 equ 5 ; Бит выбора банка.
DQ equ 4 ; Бит порта A для управления DS1820.
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.
;================================================================================
org 0 ; Начать выполнение программы
goto START ; с подпрограммы START.
;********************************************************************************

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


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

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

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 ; Возврат по стеку.


;********************************************************************************

;********************************************************************************
; Подпрограмма вывода на индикацию.
;********************************************************************************
; Выбор 6-го слева знакоместа 2-й строки.
;----------------------------------------------------------
DISPLAY movlw b'11000101' ; Выбор ячейки DD RAM с адресом 45h, что
; соответствует установке курсора в 6-е слева
; знакоместо 2-й строки.
call ENTER_BF ; "Плавающая" задержка со стробом под команду
; 11000101.
;----> Возврат по стеку из ПП ENTER_BF.
;----------------------------------------------------------
; Определение и вывод на индикацию знака температуры (+/-).
;----------------------------------------------------------
btfsc Temp_MSB,0 ; В бите №0 старшего байта температуры
; 0 или 1 ?
goto MINUS ; Если 1, то переход в ПП MINUS.
movlw 2Bh ; Если 0, то на индикацию
bsf PortA,RS ; выводится символ "+".
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.

5
;----> Возврат по стеку из ПП ENTER_BF.
goto SDVIG ; После вывода на индикацию символа "+",
; переход на обработку младшего байта
; температуры.
MINUS movlw 2Dh ; На индикацию выводится
bsf PortA,RS ; символ "-".
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
;----------------------------------------------------------
; Перевод двоичного числа младшего байта температуры
; из отрицательной области температур в положительную.
;----------------------------------------------------------
comf Temp_LSB,F ; После вывода на индикацию символа "-", все
incf Temp_LSB,F ; биты младшего байта температуры
; инвертируются и к результату прибавляется 1.
;================================================================================
; Подпрограмма обработки содержимого младшего байта температуры.
;================================================================================
; Деление числа, записанного в младшем байте температуры, на 2
; и запись, в бит №0 регистра Flag, признака символов "0" или "5".
;--------------------------------------------------------------------------------
SDVIG clrf Flag ; Flag=0 (подготовка к работе).
rrf Temp_LSB,F ; Деление на 2.
btfsc Status,C ; В бите С 0 или 1 ?
bsf Flag,0 ; Если С=1, то в бит №0 регистра Flag
; записывается 1 (признак символа "5").
; Если С=0, то в бите №0 регистра Flag так и
; останется "лежать" 0 (признак символа "0"),
; и программа будет исполняться далее.
;--------------------------------------------------------------------------------
; Установка (или нет) признака добавления (к показаниям) символа "1"
; (признак устанавливается при температуре от 100 градусов и выше).
;--------------------------------------------------------------------------------
movlw .100 ;
subwf Temp_LSB,W ; Temp_LSB - .100 = ? Результат - в W.
btfss Status,C ; Результат положительный или отрицательный?
goto BIN2_10 ; Если отрицательный, то признак добавления
; символа "1" не устанавливается (бит №7
; регистра Flag=0).
bsf Flag,7 ; Если положительный, то устанавливается
; (бит №7 регистра Flag=1).
;********************************************************************************
; Подпрограмма двоично-десятичного преобразования (для двух десятичных чисел).
;********************************************************************************
BIN2_10 bcf Status,C ; Сброс флага переноса-заема.
movlw .8 ; Запись в регистр Count числа
movwf Count ; проходов преобразования.
clrf LED0 ; Сброс регистра LED0.
;--------------------------------------------------------------------------------
; Циклический сдвиг влево через бит С регистра Status.
;--------------------------------------------------------------------------------
LOOP_16 rlf Temp_LSB,F ; Циклический сдвиг влево содержимого
; регистра Temp_LSB.
rlf LED0,F ; Циклический сдвиг влево содержимого
; регистра LED0.
decfsz Count,F ; Декремент содержимого регистра Count,
; с сохранением результата в нем же.
goto adjDEC ; Если результат не = 0, то переход в ПП
; adjDEC, а если = 0, то программа
; исполняется далее.
;--------------------------------------------------------------------------------
; Порязрядное распределение полубайтов.
;--------------------------------------------------------------------------------
swapf LED0,W ; Запись старшего полубайта LED0
andlw 0Fh ; в младший полубайт LED1
6
movwf LED1 ;

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


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

goto ASC ; Переход в ПП ASC.


;--------------------------------------------------------------------------------
; Запись в регистр FSR адреса регистра LED0 для дальнейшей косвенной адресации
; к нему в ПП adjBCD.
;--------------------------------------------------------------------------------
adjDEC movlw LED0 ; Запись в регистр FSR адреса регистра LED0
movwf FSR ; с дальнейшим переходом в ПП adjBCD.
call adjBCD ;
;---> Возврат по стеку из ПП adjBCD.
goto LOOP_16 ; Переход на следующее кольцо числовых
; преобразований.
;--------------------------------------------------------------------------------
; Основные операции преобразования двоичных чисел в двоично-десятичные.
;--------------------------------------------------------------------------------
adjBCD clrwdt ; Сброс сторожевого таймера WDT.
movlw 3 ; Суммирование содержимого текущего LED
addwf 0,W ; (LED0...3) с числом 03h, с записью
; результата операции, через регистр W,
movwf Temp ; в регистр Temp.
btfsc Temp,3 ; Анализ состояния бита №3 регистра Temp.
movwf 0 ; Если бит №3 = 1, то содержимое регистра Temp
; копируется в текущий LED.
movlw 30 ; Если бит №3 = 0, то содержимое текущего LED
addwf 0,W ; складывается с константой 30h, с записью
movwf Temp ; результата операции, через регистр W, в
; регистр Temp.
btfsc Temp,7 ; Анализ состояние бита №7 регистра Temp.
movwf 0 ; Если бит №7 = 1, то содержимое регистра Temp
; копируется в текущий LED.
retlw 0 ; Если бит №7 = 0, то регистр W очищается и
; происходит возврат по стеку в ПП adjDEC.
;********************************************************************************
; Процедура преобразования кода.
;================================================================================
ASC movlw 30h ; Запись в регистр W числа 30h.
iorwf LED0,F ; Логическое "ИЛИ" содержимого регистра W и
; регистра LED0 с сохранением результата
; в LED0.
iorwf LED1,F ; То же самое для LED1.
;********************************************************************************
; Вывод на индикацию результата измерения.
;********************************************************************************
; Вывод (или нет) на индикацию символа "1" (выводится при Т=100 градусов и выше).
;================================================================================
btfss Flag,7 ; Бит №7 регистра Flag =0 или =1 ?
goto C_00_99 ; Если =0, то символ "1" на индикацию не
; выводится.
movlw 31h ; Если =1, то символ "1" (31h)
bsf PortA,RS ; на индикацию выводится.
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
;================================================================================
; Вывод на индикацию двух символов результата измерения
; (в диапазоне от 00 до 99 градусов).
;================================================================================
C_00_99 movf LED1,W ; Вывод на индикацию байта,
bsf PortA,RS ; записанного в регистре LED1.
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
7
;----> Возврат по стеку из ПП ENTER_BF.
movf LED0,W ; Вывод на индикацию байта,
bsf PortA,RS ; записанного в регистре LED0.
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
;================================================================================
; Вывод на индикацию пары символов ",0" или ",5".
;================================================================================
movlw 2Ch ; Вывод на индикацию
bsf PortA,RS ; символа "," (2Ch).
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
btfsc Flag,0 ; Бит №0 регистра Flag =0 или =1 ?
goto _5 ; Если =1, то далее (goto _5), на
; индикацию будет выведен символ "5".
movlw 30h ; Если =0, то на индикацию
bsf PortA,RS ; выводится символ "0" (30h).
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
return ; Возврат по стеку.

_5 movlw 35h ; Вывод на индикацию


bsf PortA,RS ; символа "5" (35h).
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
return ; Возврат по стеку.
;********************************************************************************

;================================================================================
; Подпрограмма табличного вычисляемого перехода.
;================================================================================
TEXT addwf PC,F ; Приращение PC на величину содержимого W.
retlw 0x20 ; "пусто"
retlw 0x20 ; "пусто"
retlw 0x54 ; "T"
retlw 0x45 ; "E"
retlw 0x4D ; "M"
retlw 0xA8 ; "П"
retlw 0x45 ; "E"
retlw 0x50 ; "P"
retlw 0x41 ; "A"
retlw 0x54 ; "T"
retlw 0xA9 ; "У"
retlw 0x50 ; "P"
retlw 0x41 ; "A"
retlw 0x3A ; ":"
retlw 0x20 ; "пусто"
retlw 0x20 ; "пусто"
;================================================================================

;********************************************************************************
; НАЧАЛО ПРОГРАММЫ
;********************************************************************************
START clrf PortA ; Сброс всех защелок порта А.
clrf PortB ; Сброс всех защелок порта В.
bsf Status,RP0 ; Переход в 1-й банк.
clrf TrisA ; Все выводы портов А и В
clrf TrisB ; работают на выход.
bcf Status,RP0 ; Переход в 0-й банк.

8
call LCD_INIT ; Условный переход в процедуру "рабочей"
; инициализации.
;----> Возврат по стеку из ПП LCD_INIT.
;------------------------------
; Вывод символов в 1-ю строку.
;------------------------------
movlw .16 ; Запись числа .16 (количества выводимых в
movwf Count ; строку символов) в регистр Count.
WR_1 movf Count,W ; Копирование содержимого регистра Count в W.
sublw .16 ; .16-Count=... (результат записывается в W).
call TEXT ; Условный переход в ПП TEXT.
;----> Возврат по стеку из ПП TEXT.
bsf PortA,RS ; Вывод на индикацию текущего символа.
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
decfsz Count,F ; Подготовка к выводу на индикацию
; следующего символа таблицы.
goto WR_1 ; Если результат декремента не=0, то переход
; в ПП WR_1.
; Если результат декремента =0, то программа
; исполняется далее.

;########################################################################
; Начало работы с датчиком DS1820.
;########################################################################
; Инициализация DS1820.
;--------------------------------------------------------------------------------
SNOVA call DQ_INIT ; Инициализация DS1820.
;----> Возврат по стеку из ПП DQ_INIT.
;--------------------------------------------------------------------------------
; Команда Skip_ROM (CCh).
; Команда пропуска процедуры сравнения серийного номера. Применяется в случае
; использования одного датчика (как в данном случае).
;--------------------------------------------------------------------------------
movlw 0CCh ; Запись команды CCh
movwf Temp ; в регистр Temp.
call OUT_BYTE ; Переход в ПП передачи байта OUT_BYTE.
;----> Возврат по стеку из ПП OUT_BYTE.
;--------------------------------------------------------------------------------
; Команда Start_Conv (44h).
; Эта команда запускает процесс преобразования температуры.
; В течение времени ее исполнения, DS1820 не реагирует на команды "мастера".
; Это время нужно просто переждать.
;--------------------------------------------------------------------------------
movlw 44h ; Запись команды 44h
movwf Temp ; в регистр Temp.
call OUT_BYTE ; Переход в ПП передачи байта OUT_BYTE.
;----> Возврат по стеку из ПП OUT_BYTE.
;--------------------------------------------------------------------------------
; Ожидание завершения процесса преобразования температуры.
; То что Вы видите ниже, есть один из способов реализации "плавающей" (следящей)
; задержки (можно применить фиксированную задержку).
;--------------------------------------------------------------------------------
WAIT call IN_BYTE ; Переход в ПП приема байта IN_BYTE.
;----> Возврат по стеку из ПП IN_BYTE.
movlw b'11111111' ; Запись в W числа FFh.
subwf Temp,W ; Temp - FFh = ...
btfss Status,Z ; Z=0 или Z=1 (нулевой результат)?
goto WAIT ; Если Z=0, то ждем дальше.
; Если Z=1 (Temp заполнен единицами, то
; есть, на линии появился и надежно
; зафиксировался уровень 1), то программа
; исполняется далее.
;--------------------------------------------------------------------------------
9
; Инициализация DS1820.
;--------------------------------------------------------------------------------
call DQ_INIT ; Инициализация DS1820.
;----> Возврат по стеку из ПП DQ_INIT.
;--------------------------------------------------------------------------------
; Еще одна команда Skip_ROM (CCh).
;--------------------------------------------------------------------------------
movlw 0CCh ; Запись команды CCh
movwf Temp ; в регистр Temp.
call OUT_BYTE ; Переход в ПП передачи байта OUT_BYTE.
;----> Возврат по стеку из ПП OUT_BYTE.
;--------------------------------------------------------------------------------
; Команда Read Scratchpad (BEh).
; Чтение содержимого блокнотной памяти в части касающейся байтов температуры.
;--------------------------------------------------------------------------------
movlw 0BEh ; Запись команды BEh
movwf Temp ; в регистр Temp.
call OUT_BYTE ; Переход в ПП передачи байта OUT_BYTE.
;----> Возврат по стеку из ПП OUT_BYTE.

call IN_BYTE ; Чтение младшего байта температуры.


;----> Возврат по стеку из ПП IN_BYTE.
movwf Temp_LSB ; Запись принятого байта в регистр Temp_LSB.

call IN_BYTE ; Чтение старшего байта температуры.


;----> Возврат по стеку из ПП IN_BYTE.
movwf Temp_MSB ; Запись принятого байта в регистр Temp_MSB.
;---------------------------------------------------
; Итог; в Temp_MSB записан старший байт температуры,
; а в Temp_LSB записан младший байт температуры
;---------------------------------------------------
call DISPLAY ; Переход в ПП вывода результата измерения
; на индикацию.
;----> Возврат по стеку из ПП DISPLAY.
goto SNOVA ; Переход на новый цикл измерения.
;********************************************************************************

;================================================================================
; Подпрограмма нициализации 1-Wire устройства (DS1820).
;================================================================================
DQ_INIT call PIN_HI ; Установка вывода в высокоимпедансное
; состояние: за счет подтягивающего резистора,
; на линии устанавливается 1.
;----> Возврат по стеку из ПП PIN_HI.
call PIN_LO ; Установка на линии нуля.
;----> Возврат по стеку из ПП PIN_LO.
movlw .90 ; Установка количества проходов по 10мкс.
call PAUSE_X ; Переход в ПП задержки
; (задержка=90х10=900мкс.)
;----> Возврат по стеку из ПП PAUSE_X.
call PIN_HI ; Установка вывода в высокоимпедансное
; состояние: за счет подтягивающего резистора,
; на линии устанавливается 1.
;----> Возврат по стеку из ПП PIN_HI.
movlw .60 ; Установка количества проходов по 10мкс.
call PAUSE_X ; Переход в ПП задержки
; (задержка=60х10=600мкс.).
;----> Возврат по стеку из ПП PAUSE_X.

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


;********************************************************************************
; Подпрограмма задержки.
;================================================================================
; Задание количества проходов по 10 мкс.
;----------------------------------------

10
PAUSE_X movwf Count ; Копирование количества проходов из W
; в Count.
;----------------------------------------
; Пауза в 10 мкс.
;----------------------------------------
PAUSE_10 nop ;
goto $+1 ; Одноразрядный,
goto $+1 ; вычитающий
goto $+1 ; счетчик
decfsz Count,F ; с "врезкой".
goto PAUSE_10 ;

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


;================================================================================

;************************************************************************
; БАЗОВЫЕ ПРОЦЕДУРЫ ЧТЕНИЯ/ЗАПИСИ по 1-Wire протоколу.
;************************************************************************
; Подпрограмма передачи "мастером" байта: цикл передачи бита начинается
; импульсом низкого уровня длительностью 1...15 мкс, далее следует передаваемый
; бит. Цикл завершается импульсом высокого уровня длительностью не менее 1 мкс.
;================================================================================
OUT_BYTE movlw .8 ; Запись количества бит передаваемого
movwf N ; байта в регистр N.

METKA_1 rrf Temp,F ; Сдвиг вправо содержимого передаваемого


; байта.
btfss Status,C ; В бите С "лежит" 0 или 1 ?
goto OUT_0 ; Если С=0, то переход в ПП передачи нуля.
goto OUT_1 ; Если С=1, то переход в ПП передачи единицы.

METKA_2 decfsz N,F ; Уменьшение на 1 содержимого счетчика битов.


goto METKA_1 ; Если результат не =0, то переход на
; метку METKA_1.
return ; Если результат =0, то возврат по стеку.

;================================================================================
; Подпрограмма приема "мастером" байта: цикл приема бита начинается импульсом
; низкого уровня длительностью 1...15 мкс, после чего DS1820 выставляет на
линии ; бит. Цикл завершается импульсом высокого уровня длительностью не менее 1
мкс.
;================================================================================
IN_BYTE movlw .8 ; Запись количества бит принимаемого
movwf N ; байта в регистр N.
clrf Temp ; Очистка регистра принимаемого байта.

IN_BYTE_1 call PIN_LO ; Формирование на линии уровня 0.


;----> Возврат по стеку из ПП PIN_LO.

call PIN_HI ; Формирование на линии уровня 1.


;----> Возврат по стеку из ПП PIN_HI.
nop ; Калибровочный NOP.
;-------------------------------------------------------------------
; Запись, в бит С, уровня текущего бита, выдаваемого DS1820 в линию.
;-------------------------------------------------------------------
btfss PortA,DQ ; На линии 0 или 1 ?
bcf Status,C ; Если на линии 0, то в бите С выставляется 0
btfsc PortA,DQ ; Если на линии 1 (а также после исполнения
; предыдущей команды), то еще одна проверка
; состояния линии.
bsf Status,C ; Если на линии 1, то в бите С выставляется 1
; Если на линии 0 (а также после исполнения
; предыдущей команды), то программа
; исполняется далее.
11
;-------------------------------------------------------------------
; Последовательное заполнение битами регистра Temp.
;-------------------------------------------------------------------
rrf Temp,F ; Сдвиг содержимого регистра Temp вправо
; (через C).
movlw .4 ; Установка количества проходов по 10мкс.
call PAUSE_X ; Переход в ПП задержки
; (задержка=4х10=40мкс.).
;----> Возврат по стеку из ПП PAUSE_X.
decfsz N,F ; Уменьшение на 1 содержимого счетчика битов.
goto IN_BYTE_1 ; Если результат не=0, то переход
; на прием следующего бита.
movf Temp,W ; Если =0, то копирование принятого байта в
; регистр W.
return ; Возврат по стеку.
;================================================================================

;================================================================================
; Подпрограмма передачи бита с уровнем "0".
;================================================================================
OUT_0 call PIN_LO ; Переход в ПП установки уровня 0.
; Начало передачи.
;----> Возврат по стеку из ПП PIN_LO.
movlw .6 ; Установка количества проходов по 10мкс.
call PAUSE_X ; Переход в ПП задержки
; (задержка=6х10=60мкс.).
;----> Возврат по стеку из ПП PAUSE_X.
call PIN_HI ; Переход в ПП установки уровня 1.
; Конец передачи.
;----> Возврат по стеку из ПП PIN_HI.
goto METKA_2 ; Переход на новый цикл передачи бита.

;================================================================================
; Подпрограмма передачи бита с уровнем "1".
;================================================================================
OUT_1 call PIN_LO ; Переход в ПП установки уровня 0.
; Начало передачи.
;----> Возврат по стеку из ПП PIN_LO.
call PIN_HI ; Переход в ПП установки уровня 1.
; (передача 1).
;----> Возврат по стеку из ПП PIN_HI.
movlw .6 ; Установка количества проходов по 10мкс.
call PAUSE_X ; Переход в ПП задержки
; (задержка=6х10=60мкс.).
;----> Возврат по стеку из ПП PAUSE_X.
goto METKA_2 ; Переход на исполнение процедуры декремента
; и анализа содержимого счетчика битов.

;--------------------------------------------------------------------------------
; Формирование на линии уровня "1" за счет подтягивающего резистора
;--------------------------------------------------------------------------------
PIN_HI bsf Status,RP0 ; Переход в банк 1.
bsf TrisA,DQ ; Настройка вывода RA4 на работу "на вход".
bcf Status,RP0 ; Переход в банк 0.
return ; Возврат по стеку.

;--------------------------------------------------------------------------------
; Формирование на линии уровня "0" средствами микроконтроллера
;--------------------------------------------------------------------------------
PIN_LO bcf PortA,DQ ; Установка 0 на выходе защелки вывода RA4.
bsf Status,RP0 ; Переход в банк 1.
bcf TrisA,DQ ; Настройка вывода RA4 на работу "на выход".
bcf Status,RP0 ; Переход в банк 0.
return ; Возврат по стеку.
;********************************************************************************

12
end ; Конец программы.
Работа программы.

В ПП START, все выводы портов настраиваются на работу “на выход”, и на выходах


всех защелок выставляются нули.
И это естественно, так как далее требуется выдача “мастером” команд, а не
считывание им чего-либо (считывание будет потом).
Остальные настройки - по умолчанию.
Далее следует подготовить к работе ЖКИ модуль (инициализация ЖКИ модуля), что и
имеет место быть (call LCD_INIT).
Процедура инициализации ЖКИ модуля просто банально скопирована из программы
bf_fr…asm.
После возврата по стеку из процедуры инициализации ЖКИ модуля, осуществляется
вывод в 1-ю строку тестовой надписи.
Здесь тоже нет ничего нового. Единственное отличие - в тексте надписи.
На индикацию, стандартным образом, выводится надпись “ТЕМПЕРАТУРА:”, причем, она
выводится только один раз (на 1-м “витке” полного цикла программы) и будет
“мозолить глаза” вплоть до выключения питания устройства.
ПП ENTER_BF также “передрана” из программы bf_fr…asm.
После вывода на индикацию тестовой надписи, свидетельствующей о факте
благополучного завершения процедуры “рабочей” инициализации ЖКИ модуля, рабочая
точка программы входит в группу команд работы с датчиком температуры DS1820.
Далее выполняется последовательность действий, “разрисованная” на рис. 3.
Эта группа команд начинается с подпрограммы, построенной по “администраторскому”
принципу.
При помощи системы условных переходов и возвратов из них, она “разруливает”
вполне определенную последовательность действий (см. рис. 3).
1-м пунктом идет инициализация датчика DS1820, с игнорированием его отклика (call
DQ_INIT).
После перехода в ПП DQ_INIT, первым делом, нужно выставить на сигнальной линии
(DQ) единицу (см. рис. 3 предыдущего подраздела).
Это нужно для того чтобы, в дальнейшем, можно было бы сформировать, на ней спад
(строб) импульса сброса.
При этом, условие “между двумя соседними перепадами, на линии DQ, должно пройти
время не менее 1 мкс.” гарантированно обеспечивается за счет исполняемых команд.
На линии DQ, все единичные уровни “выставляются” за счет внешнего, подтягивающего
резистора.
Единица на линии DQ “выставляется” только после перевода выводов м/схем
“мастера” и “помощника”, подключенных к линии DQ, в высокоимпендансные состояния.
В переводе на русский, это означает то, что, через подтягивающий резистор, единица,
на линии DQ, “выставляется” только в случае работы вывода ПИКа, подключенного к
линии DQ, “на вход”.
При этом, транзистор каскада с открытым стоком (ОС), входящий в состав датчика
DS1820, должен быть закрыт.
Это соответствует либо работе вывода DQ датчика “на вход” (при приеме им сигнала,
вырабатываемого “мастером”), либо передаче датчиком, в линию DQ, битов с
единичными уровнями (обеспечиваются за счет того же подтягивающего резистора).
Примечание: на линии DQ, “мастер” формирует единицу не обычным образом, то есть,
в режиме работы “на выход” (за счет резистора нагрузки оконечного каскада защелки),
а за счет перестройки направления работы вывода порта, подключенного к линии DQ,
c режима работы “на выход” на режим работы “на вход” (за счет внешнего,
подтягивающего резистора).
Это то, о чем я упоминал ранее и что нужно обязательно “обкатать” на практике.
Такая “комбинация из двух пальцев” “проворачивается” в ПП PIN_HI.
ПП PIN_HI проста до безобразия - перестройка вывода RA4 на работу “на вход”.
После ее осуществления, вывод RA4 переводится в высокоимпендансное состояние,
после чего, на линии DQ, за счет подтягивающего резистора, устанавливается
единичный уровень.
Все… И никаких премудростей.
13
Далее, возврат по стеку в ПП DQ_INIT.
Кстати, ПП DQ_INIT можно классифицировать как еще одну “администраторскую” ПП.
Единица на линии DQ выставлена, теперь можно начинать формирование импульса
сброса, что и имеет место быть (call PIN_L0).
Нулевой уровень, в отличие от единичного, “мастер” формирует обычным образом
(другого не дано), то есть, путем установки нулевого уровня на выходе защелки
вывода RA4, с последующей перестройкой направления работы вывода RA4 с работы
“на вход” на работу “на выход”.
В этом тоже нет никаких премудростей.
Далее, возврат по стеку в ПП DQ_INIT.
Теперь нужно подождать не менее 480 мкс. для того чтобы обеспечить необходимую
длительность импульса сброса.
В данном случае, сформирована задержка в 600 мкс.
После возврата из ПП задержки (PAUSE_X), нужно закончить формирование импульса
сброса путем выставления, на линии DQ, единицы, что и имеет место быть
(call PIN_HI).
Работа ПП PIN_HI описана выше, повторяться не буду.
Так как анализ отклика датчика на импульс сброса производить не нужно (см.
техническое задание на разработку), то производится еще одна задержка
длительностью 600 мкс.
Сразу же после возврата по стеку из ПП задержки PAUSE_X, происходит возврат в
“администраторскую” подпрограмму.
Обращаю Ваше внимание на то, что, после этого возврата, на линии DQ, будет
“стоять” единица (за счет подтягивающего резистора), и стоять она будет до тех пор,
пока “мастер” не сформирует на линии DQ уровень нуля.
Итак, инициализация датчика завершилась и можно командовать.
Так как датчик один и поэтому нет смысла производить адресацию, то в соответствии
с рис. 3 этого подраздела, ПИК выдает, в линию DQ, команду CCh (Skip ROM).
В отличие от простенькой процедуры инициализации, процедура передачи “мастером”
команды ориентирована на “полновесный” байт, причем, “механика” передачи “мастером”
байта одинакова для байтов любой функциональности.
Это означает то, что, если объяснить принцип передачи байта одной команды, то
будет объяснен и принцип передачи байтов других команд, что я сейчас и сделаю.
Сначала числовое значение команды Skip ROM (CCh) записывается в регистр
оперативной памяти Temp для того, чтобы, в дальнейшем, можно было осуществить
операции с его содержимым.
После этого, происходит переход по стеку в ПП передачи байта OUT_BYTE.
ПП OUT_BYTE представляет собой ПП поочередной (последовательной) передачи, в
линию DQ, битов байта, начиная с бита младшего, двоичного разряда.
Устроена она стандартно: в начале, в счетчик битов, записывается число битов байта
(8), а в конце, содержимое счетчика битов декрементируется.
Если результат декремента не =0, то происходит обработка следующего бита, а если
=0, то считается, что байт обработан, и происходит возврат в “администраторскую” ПП.
Итак, перед входом в ПП OUT_BYTE, на линии DQ “стоит” единица (что-то типа
ждущего режима), и, в соответствии с рис. 6 предыдущего подраздела, нужно
сформировать на линии переход от 1 к 0 и “попридержать” этот ноль в течение
1 … 15 мкс., но сначала нужно подготовить текущий бит к выводу его на линию DQ в
том смысле, что, для начала, его нужно “выпихнуть” в бит С регистра Status.
Делается это по такому же принципу, как и аналогичное “выпихивание” при передаче
бита по интерфейсу I2C, только с использованием команды rrf (так как сначала
передается бит младшего разряда).
После того, как текущий бит “ушел” в бит С, производится анализ его значения, и в
зависимости от того, каково оно, исполняется либо ПП передачи нуля (OUT_0), либо
ПП передачи единицы (OUT_1).
Предположим, что текущим является бит с уровнем 1, то есть, произошел условный
переход в ПП OUT_1.
Вот в ней-то, перво – наперво и нужно сформировать, на линии DQ, переход от 1 к 0
и “попридержать” этот ноль в течение 1 … 15 мкс., что и происходит в ПП PIN_L0.

14
После возврата из ПП PIN_L0, происходит переход в ПП установки уровня единицы
PIN_HI (так как в линию выводится 1), после чего она благополучно “заторчит” на
линии DQ в течение 60 мкс.
Итог: бит с уровнем 1 на линию DQ выведен.
В конце ПП OUT_1, происходит переход на исполнение процедуры декремента и
анализа содержимого счетчика битов (goto METKA_2).
В случае, если, после декремента содержимого счетчика битов, результат не =0, то
начинается процедура вывода на линию DQ следующего бита (goto METKA_1).
Теперь предположим, что текущим является бит с уровнем 0, то есть, произошел
условный переход в ПП OUT_0.
Переход от 1 к 0, на линии DQ, формируется точно так же, как и в том случае, когда
текущим является бит с уровнем 1, но далее, выставлять, на линии DQ, единицу не
нужно по той простой причине, что передается бит с уровнем 0.
А раз это так, то после установки, на линии DQ, уровня нуля, производится задержка
на 60 мкс., и никаких “выкрутасов”.
Но зато в конце ПП OUT_0, нужно сменить 0 на 1 (в ПП OUT_1 этого нет) для того,
чтобы в дальнейшем можно было сформировать строб.
Далее следует все тот же переход goto METKA_2 и аналогичная процедура декремента
и анализа содержимого счетчика битов.
Вся эта “круговерть” будет продолжаться до тех пор, пока в линию DQ не будет
выведен бит самого старшего разряда (№7).
Итог: на линию DQ выведен байт команды Skip ROM с числовым значением CCh.
После этого, происходит возврат рабочей точки программы, по стеку, из ПП OUT_BYTE,
в “администраторскую” ПП.
Теперь можно запустить процесс преобразования температуры, то есть, выполнить
команду Start Conv.
“Механика” вывода (передачи), на линию DQ, байта этой команды (а также и других
команд) ничем не отличается от “механики” вывода, на линию DQ, команды Skip ROM.
Разница только в числовом значении байта.
Если как следует разобраться, то ничего сложного в этом нет.
После передачи команды Start Conv, нужно “покурить”, то есть, подождать, пока
процесс преобразования температуры завершится.
Следовательно, нужно уйти в задержку.
В простейшем случае, можно сформировать фиксированную задержку такой величины,
чтобы она “перекрыла” максимальное время отработки этого процесса, но выгоднее
использовать “плавающую” задержку, так как она менее “тормозная”.
В данном случае, использована “хитрая и изящная”, “плавающая” задержка, принцип
организации которой, лично мне, очень понравился (см. ПП WAIT).
И в самом деле, никакого флага нет. Тогда как она работает?
Ответ: критерием окончания процесса преобразования температуры является
возможность считывания, с линии DQ, байта с числовым значением FFh (1111 1111).
Разбираемся.
Особенность DS1820 (а также и других DS…) такова, что если, после запуска процесса
преобразования температуры, “мастер” “попытается” считать еще не сформированный
результат преобразования температуры, то DS1820, после первой же такой “попытки”,
выдаст, в линию DQ, нулевой уровень, который на ней и “заторчит” вплоть до
окончания процесса преобразования температуры.
Сразу же после окончания процесса преобразования температуры, DS1820 отпустит
линию, после чего на ней, за счет подтягивающего резистора, установится единица.
Таким образом, периодическое считывание байтов с линии DQ рано или поздно
закончится считыванием байта, все биты которого являются единицами, и произойдет
это сразу же после того, как процесс преобразования температуры закончится.
Вот Вам и принцип работы этой разновидности “плавающей” (следящей) задержки.
В данном случае, флагом является искусственно “спровоцированный” (программными и
аппаратными средствами) 0 на линии DQ, который, по окончании процесса, заменяется
на 1.
Кто скажет что это не изящно и не оригинально? Даже жаль, что не я придумал этот
“перл”.
Ну ничего, на мой (и на Ваш) век “хитрых, задних проходов” хватит.
15
Пошли дальше.
Предположим, что процесс преобразования температуры успешно закончился и
“плавающая” задержка “сработала”.
Далее, в соответствии с рис. 3, нужно “запустить в работу” “связку” типа
“инициализация – команда Skip ROM”.
Это мы уже проходили (см. выше). Повторяться не буду.
Наконец-то! Дорвался до “счастья”! Можно считать результат замера температуры.
Точно таким же способом, как и при запуске в работу всех предшествующих команд,
запускаю в работу байт команды Read Scratchpad, с числовым значением байта BEh.
После окончания передачи этого байта в линию DQ и возврата из ПП передачи байта
OUT_BYTE, осуществляется переход в ПП приема байта IN_BYTE.
Сначала, из области оперативной памяти DS1820, в соответствии с алгоритмом
процедуры чтения, определенным разработчиками, будет считан младший байт
температуры.
Читаю. Пошел в ПП IN_BYTE.
Со счетчиком битов - точно такая же “история”, как и в случае передачи байта.
Далее, нужно подготовить регистр Temp к последовательному его заполнению
считываемыми битами (clrf Temp).
Далее, в соответствии с рис. 7 предыдущего подраздела, нужно сформировать, на
линии DQ, импульс с нулевым уровнем продолжительностью 1 … 15 мкс.
Следовательно, нужно сначала “уйти” в ПП PIN_L0, вернуться по стеку, а затем “уйти”
в ПП PIN_HI.
Работа этих ПП описана выше.
Один NOP, который исполняется после возврата из ПП PIN_HI, нужен для “подгонки”
момента считывания бита под сформулированное ранее условие: считывание бита
нужно производить в непосредственной близости от правой границы 15-микросекундного
интервала времени, отсчитываемого от строба (перехода от 1 к 0).
Далее, производится запись, в бит С регистра Status, уровня текущего бита,
выставленного DS1820 на линии DQ, с целью дальнейшей его “переправки” в регистр
Temp.
“Механика” этой записи описана ранее, повторяться не буду.
После того, как в бит С будет записан уровень текущего бита, происходит сдвиг
вправо содержимого регистра Temp (rrf Temp,F), в результате чего, содержимое бита С
записывается в бит №7 регистра Temp.
Итог: бит считан.
Теперь нужно “переждать” то время, в течении которого DS1820 выставляет, на линии
DQ, текущий бит.
Заданная задержка в 40 мкс. является частью суммарной задержки, значение которой
больше (плюс, задержки исполняемых команд).
После этого, все “формальности” соблюдены и можно готовиться к переходу на
исполнение цикла чтения следующего бита (или закончить чтение байта).
Содержимое счетчика битов декрементируется, а результат этой операции
анализируется (decfsz N,F).
Если результат не нулевой, то циклы чтения битов повторяются до тех пор, пока не
считается весь байт.
После этого, считанный байт будет “лежать” в регистре Temp.
Для обеспечения его дальнейшего копирования в регистр хранения младшего байта
температуры (через W), содержимое регистра Temp копируется в регистр W, после чего
происходит возврат по стеку в группу команд, обслуживающих исполнение команды
Read Scratchpad.
Вот в ней-то и происходит копирование принятого байта в регистр младшего байта
температуры (movwf Temp_LSB).
После этого, описанным выше способом, происходит считывание старшего байта
температуры и запись его в регистр старшего байта температуры.
В данном случае, из области оперативной памяти DS1820, происходит считывание
только первых (верхних) двух байтов.
Если появится потребность в считывании остальных байтов (она появится позднее), то
это делается точно так же, как и описано выше.

16
Обращаю Ваше внимание на то, что адресация к области оперативной памяти
происходит однократно, при помощи команды Read Scratchpad.
При этом, происходит адресация к регистру младшего байта температуры.
По мере считывания байтов, происходят автоинкременты, обеспечивающие вполне
определенный (заданный разработчиками) порядок (сверху вниз) считывания байтов из
области оперативной памяти DS1820 (см. картинку области оперативной памяти).
Вернусь к своим “котлетам”.
Итак, оба байта результата замера температуры считаны и “лежат” в регистрах
Temp_LSB (младший байт температуры) и Temp_MSB (старший байт температуры).
Теперь нужно сделать так, чтобы эти байты можно было бы вывести в дисплей ЖКИ
модуля, в виде соответствующих символов.
То есть, нужно осуществить некие числовые преобразования (см. рис. 5 предыдущего
подраздела).
Группы команд, обеспечивающих такие преобразования, я вынес в ПП DISPLAY.
ПП DISPLAY начинается процедурой активации 2-й строки (в 1-й строке - тестовая
надпись), с одновременным выбором того знакоместа, в которое будет выводиться на
индикацию первый символ (команда 11000101).
“Конструкцию” показаний определяю такой: знак температуры – значение температуры –
символ “запятая” – символ “0” или “5” (в зависимости от числового значения
температуры).
Так как я использую порядок вывода символов на индикацию типа “слева направо”
(дисплей не сдвигается), то первым нужно вывести знак температуры.
Он “лежит” в старшем байте температуры.
Не мудрствуя лукаво, анализирую числовое значение не всего байта регистра
Temp_MSB, а только состояние одного его бита (младшего, но можно и другого. Все-
равно во всех битах записаны либо единицы, либо нули).
В этом случае, количество команд минимально.
Если бит №0=0, то выводится символ “+” (2Bh), а если бит №0=1, то выводится
символ “-“ (2Dh). Вот и вся премудрость.
Далее, нужно разобраться с числовой, температурной “свистопляской”.
Для положительных температур все понятно: делим на 2.
А вот числовое значение отрицательной температуры нужно сначала инвертировать,
затем разделить на 2 и после этого приплюсовать единицу (можете проверить на
бумаге).
Деление на 2 происходит в любом случае.
Кроме того, заранее нужно “озаботиться” “механикой” формирования символа (“0” или
“5”) после запятой и формирования символа “1” в старшем разряде показаний, в
случаях, когда температура “зашкаливает” за 100-градусную отметку.
Таким образом, дальнейшие действия ставятся в зависимость от результата анализа
знака температуры.
При наличии отрицательной температуры, на индикацию выводится символ “-“, а затем
происходит инверсия всех битов регистра Temp_LSB (comf Temp_LSB,F), с
последующим инкрементом результата этой инверсии (incf Temp_LSB,F).
После этого, рабочая точка программы, “самоходом”, переходит в ПП SDVIG.
При наличии положительной температуры, на индикацию выводится символ “+“, а затем
происходит безусловный переход в ту же ПП SDVIG, только без инверсии и
инкремента.
Теперь нужно подготовить к работе регистр Flag (clrf Flag), речь о котором пойдет
ниже, и разделить содержимое регистра Temp_LSB на 2 (вне зависимости от знака
температуры).
Деление на 2 происходит путем сдвига вправо содержимого регистра Temp_LSB.
При этом, младший бит (№0) “уходит” в бит С регистра Status.
“Гибели” бита №0 допустить нельзя, так как в нем заложен признак символа,
выводимого на индикацию после запятой (“0” или “5”).
Вот для этого и требуется регистр Flag, в байт которого можно “заложить” до 8-ми
признаков чего-либо.
В этой программе используются 2 его бита (организовано 2 признака).
Бит с №0 я задействовал для сохранения признака символа после запятой.

17
Если бит №0=0, то это соответствует выведению на индикацию символа “0”, а если он
=1, то это соответствует выведению на индикацию символа “5”.
“Закладка” в бит №0 нуля или единицы происходит путем банального переноса нуля
или единицы из бита С (при помощи команды ветвления btfsc).
По-моему, разобраться в этом не сложно (см начало ПП SDVIG).
Этот признак будет “лежать” в регистре Flag до тех пор, пока я “не соизволю его
извлечь”.
Далее нужно “озаботиться” формированием символа “1” в старшем разряде показаний,
в случае превышения температурой отметки в 100 градусов.
“Корни” этой “заботы” находятся в моем решении обойтись, в процедуре двоично-
десятичного преобразования, всего двумя регистрами LED….
Дело в том, что, в этом случае, имеет место быть выигрыш по количеству команд
(убыло больше чем прибыло), а процедура двоично-десятичного преобразования
существенно упрощается, плюс, какой-никакой, а выигрыш по скорости имеется.
Короче, с символом “1” я работаю не в ПП двоично-десятичного преобразования, а
отдельно (“на выносе”).
Принцип: сравнение содержимого регистра Temp_LSB с числом .100.
Если делается вывод о том, что температура меньше 100 градусов, то в бите №7
регистра Flag так и останется “лежать” установленный в нем ранее ноль, и далее
исполняется процедура двоично-десятичного преобразования.
Если делается вывод о том, что температура больше 100 градусов, то в бит №7
регистра Flag записывается 1, и далее, опять же, исполняется процедура двоично-
десятичного преобразования.
Таким образом, в бит №7 регистра Flag, кроме признака цифры, находящейся после
запятой (бит №0), “закладывается” признак символа “1”, который, в дальнейшем, будет
выведен на индикацию только в случае превышения температурой “порога” в 100
гадусов.
Во всех остальных случаях, символ “1” на индикацию выводиться не будет.
Итак, подготовка к выводу всех “прибамбасов” закончена и можно уходить в процедуру
двоично-десятичного преобразования, что и имеет место быть.
Это стандартная процедура, только “адаптированная” к двухразрядному результату.
После превышения числа 99, будет осуществлен переход на следующее “кольцо”
преобразований.
Например, при температуре 100 градусов, на индикацию выведутся символы 00, при
температуре 101 градус - символы 01 и т.д.
После окончания двоично-десятичного преобразования, нужно учесть специфику
таблицы знакогенератора примененного ЖКИ модуля, то есть, нужно осуществить
стандартную процедуру преобразования кода.
В данном случае, она очень простая и содержит всего 3 команды.
Теперь можно выводить на индикацию результат измерения.
Это нужно производить в определенном порядке.
Знак температуры уже выведен на индикацию ранее, следовательно, нужно ответить на
вопрос о том, нужно ли выводить на индикацию символ “1” или нет?
Значит нужно “заанализировать” ранее сформированный признак наличия или
отсутствия единицы в старшем разряде результата измерения температуры (бит №7
регистра Flag).
Если абсолютное значение температуры не превышает 100 градусов (бит №7=0), то
процедура вывода на индикацию символа “1” обходится, а если равно или выше 100
градусов, то на индикацию выводится символ “1” (31h) .
Любой из этих сценариев заканчивается переходом рабочей точки программы в ПП
C_00_99.
ПП C_00_99 есть подпрограмма вывода на индикацию перекодированного результата
обработки младшего байта температуры.
Она проста и незамысловата: на индикацию, последовательно, стандартным образом,
выводятся символы, соответствующие числам, “лежащим” в регистрах LED1 (десятки) и
LED0 (единицы).
Объяснять тут особо нечего.
Остаются две пары символов “,0” или “,5”.

18
Символ “запятая” выводится в любом случае, значит и мудрить нечего. Как говорится,
“вперед и с песней”.
А вот далее, нужно “заанализировать” признак символов “0” или “5”, ранее
“заложенный” в бит №0 регистра Flag, что и имеет место быть.
Если бит №0=0, то на индикацию выводится символ “0” (30h).
Если бит №0=1, то на индикацию выводится символ “5” (35h).
Итог: результат измерения температуры выведен на индикацию.
Далее, осуществляется возврат по стеку в конец “администраторской” ПП процедуры
работы с датчиком DS1820, после чего следует переход на ее начало (goto SNOVA),
что соответствует началу следующего полного цикла программы, который отработается
по описанному выше алгоритму (кроме ПП START и процедуры вывода на индикацию
тестовой надписи. Они исполняются только на 1-м “витке”).
И т.д., “до посинения” (пока не будет выключено питание).

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

Из этой картинки видно, что имеет место быть две команды анализа состояния линии
DQ, и соответственно, момент считывания нуля отстоит от строба на 12 мкс., а момент
считывания единицы отстоит от строба на 14 мкс.
Указанное выше условие выполняется.
Общее замечание: добрую половину программы занимает группа команд работы с ЖКИ
модулем.
Если индикация не нужна, то группа команд работы с датчиком не такая уж и
большая.
Над описанным выше термометром я “изгалялся” как только мог, начиная от
нагревания датчика паяльником и заканчивая помещением его в морозилку.
Работает, каналья. Хоть бы хны.
Вот это, я понимаю, работяга! Траншею роет так, что только лопата мелькает.
Если направить эту энергию в нужное русло, то много кое-чего полезного можно
“наворочать”.
Далее постараюсь “сваять” нечто более солидное (работа с несколькими датчиками).
Пока не знаю что, но “голь на выдумки хитра”.
Разберусь по ходу дела.

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

20

Оценить