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

5/8.

Переход с разрешения в 0,5 градусов на разрешение в 0,1 градус или о


пользе элементарного, здравого смысла.

DS1820 может измерять температуру с более высоким, чем 0,5 градусов, разрешением
(0,1 градус), но для этого нужно произвести вычисления по формуле:

T=TEMP_READ - 0.25 + (Count_D_C – Count_REM)/Count_D_C

TEMP_READ - результат замера температуры без учета единицы в младшем бите


регистра Temp_LSB (0,5 градуса участия в расчетах не принимают).
Count_D_C - количество градаций одного градуса. Для DS1820 оно всегда равно 10h,
т.е. 16 градаций на 1 градус.
Count_REM - остаток от измерения, который всегда меньше .16-ти.
Примечание: ячейки области оперативной памяти DS1820, с этими названиями, имеют
номера №7 и №8.
Эта информация взята из фирменного технического описания, я только слегка изменил
названия регистров, но на суть это никоим образом не влияет.
Еще не почувствовали, что что-то тут вызывает смутные подозрения?
Наиболее любопытным советую пока отложить дальнейшее чтение и самостоятельно
“порыться” в этой формуле.
Ответ.
И в самом деле, лично я, на практике убедился, что, вне зависимости от результата
измерения, в регистре Count_D_C всегда “лежит” число 10h.
Из этого возникает большой и мощный вопрос: “Зачем, в процедуре указанного выше
вычисления, вообще нужен регистр Count_D_C, ведь в нем все время “лежит”
фиксированная константа, которую можно просто напрямую использовать в этой
процедуре, без задействования регистра Count_D_C ?. Значение-то ее известно.”
Да, регистр Count_D_C, помимо этого, задействуется в процедуре вычисления
контрольной суммы, но это из другой “оперы” и вовсе не объясняет необходимости
использования регистра Count_D_C в вычислениях, производимых по указанной выше
формуле.
А не проще ли, в ходе этих вычислений, просто использовать константу 10h (.16)?
Я специально просмотрел стандартную процедуру этого вычисления и пришел к
однозначному выводу, что регистр Count_D_C в ней просто не нужен (а он
задействуется).
Если, после соответствующей “командной коррекции” (команды операций с регистрами
заменяются на команды операций с константами), “влепить” вместо него константу 10h
(.16), то ничего в работе этой процедуры не изменится.
Хотя, особого выигрыша и нет, но формула становится более “удобоваримой”:

T=TEMP_READ - 0.25 + (16 – Count_REM)/16

Я указал число (16) в десятичной форме, но можно написать и 10h.


Ладно, проехали. Это “мелочь пузатая”.
А вот дальше, при более “плотном въезде”, начинаются большие и мощные
недоумения.
Для того чтобы понять, о чем идет речь, нужно понять принцип расчета и
проанализировать результаты “голой математики”.
16 градаций на 1 градус означает, что температурный интервал в 1 градус разбит на
16 частей (двоичная система исчисления).
Если бы он был разбит на 10 частей (десятичная система исчисления), то никаких
технических проблем, с определением моментов смен величин десятых долей градуса,
не было бы.
Эти моменты смен можно было бы “разбросать” по числовой оси (в пределах одного
градуса) равномерно, что, кроме получения технических “удобств” (простая и понятная
программная процедура), соответствует минимуму погрешности измерения температуры
в температурном интервале величиной в 1 градус.
Но градаций-то не 10, а 16.

1
Что получается?
А получается “геморрой”, которые разработчики, не мудрствуя лукаво, подарили всем
нам (могли бы и “подсуетиться”…).
Его “материальным воплощением” и является приведенная выше формула.
Ладно, данность есть данность и придется работать с тем, что есть, уповая на
здравый смысл разработчиков.
Уповать-то конечно можно, но и проверить не помешает.
В необходимости последнего, лично меня, убедил грандиозный “бардак”, который
“порождает” указанная выше формула.
Я просмотрел несколько программ, в которых используется данное вычисление и
убедился, что их авторы просто бездумно копируют соответствующую процедуру
вычисления, предлагаемую разработчиками.
Ни один из них не только не пытался “сразиться с этим зверем”, но даже и не
удосужился “убить” регистр Count_D_C (см. выше), а это “на поверхности лежит”.
Что, по факту, имеется?
В приложении к ПИКам, имеется “мозгозаворотная”, “тормозная” процедура вычисления
“массой” в 90 команд, плюс проблемы с дальнейшим использованием результата этого
вычисления, плюс “куча” дополнительных регистров общего назначения и т.д.
Вопрос: “Ради чего льется такая масса крови”?
Это можно было бы как-то оправдать, если бы был толк в части касающейся
погрешности измерения (в пределах одного градуса).
Полез в математику.
Что означает (16 – Count_REM)/16 ?
Count_REM это остаток от измерения, который всегда меньше .16-ти, следовательно,
результат этого вычисления будет представлять собой десятичную дробь с нулем в
целой части и “массой” от одного до 4-х знаков после запятой, кроме случая
(16 – 16)/16 = 0.
Остальная часть формулы, в этом отношении, “погоды не делает”, так как, после
запятой, будет наблюдаться такая же “картина” (а именно это и интересует).
Что сие означает?
А означает это то, что придется производить округление, ведь нужен только один знак
после запятой.
Если от этого будет “точностный” толк, то можно и округлить.
Проверяю.
Ниже Вы видите пример “голого”, математического расчета, произведенного по
указанной выше формуле, с TEMP_READ = 20 и округлением до одной десятой.
Что касается числового значения TEMP_READ, то оно может быть различным. Суть не
в нем, а в том, что получается после запятой.

Табл. 1
16 – Count_REM (16-Count_REM) /16 TEMP_READ - 0.25 + Округление “Диаграмма”
(16 – Count_REM)/16
16 -1 = 15 0,9375 20,6875 20,7
16 – 2 = 14 0,875 20,625 20,6
16 – 3 = 13 0,8125 20,5625 20,6
16 – 4 = 12 0,75 20,5 20,5
16 – 5 = 11 0,6875 20,4375 20,4
16 – 6 = 10 0,625 20,375 20,4
16 – 7 = 9 0,5625 20,3125 20,3
16 – 8 = 8 0,5 20,25 20,3
16 – 9 = 7 0,4375 20,1875 20,2
16 – 10 = 6 0,375 20,125 20,1
16 – 11 = 5 0,3125 20,0625 20,1
16 – 12 = 4 0,25 20 20,0
16 – 13 = 3 0,1875 19,9375 19,9
16 – 14 = 2 0,125 19,875 19,9
16 – 15 = 1 0,0625 19,8125 19,8
16 – 16 = 0 0 19,75 19,8

2
Примечание: опытным путем (засылка “шпиона” и т.д.) я выяснил, что в регистре
Count_REM “лежит” одно число из числового диапазона .1 … .16 (см. табл. 1), то есть,
число .0 в нем никогда не “лежит”.
По поводу таблицы 1 могут быть разные суждения.
С точки зрения “голой” математики, число 0,25 вообще лишнее на этом “празднике
жизни”, так как оно “порждает” смещение результата вычисления относительно здравого
смысла (например, там где должно быть 20,0, получается 19,8 и т.д.).
Но так или иначе, неоспоримым фактом является то, что величина температурных
интервалов неравномерна (“гуляет”), что означает наличие “плавающей” погрешности
измерения температуры в пределах одного градуса.
И за это “великое счастье” еще нужно и несоразмерно “заплатить” (см. выше)!
“Да видел я такое счастье в гробу, в белых тапках”, как сказал один очень уважаемый
человек. И это как раз тот случай. Присоединяюсь.
Но мало быть “гробовых дел мастером”, для этого много ума не требуется, а нужно
предложить взамен “трупа” какой-то “живой организм”, который бы был, как минимум,
не хуже “покойника”, а в идеале - лучше, иначе какой смысл в этих “похоронах”?
Кстати, на Руси, с этим всегда были и есть большие проблемы: огреют работягу
дубиной по голове (отправят к праотцам), а затем делают круглые глаза и искренне
удивляются, что у горна (и т.д.) стоять некому и демография какая-то неправильная
получается.
Чур меня! Избавь Бог от такой напасти.
А раз это так, то нужно “извилиной шевелить”. Другого не дано.
“Вражеского шпиона (формулу) арестовываю и сажаю на нары”.
Далее следуют процедуры “выкручивания конечностей” и “дергания зубов”, в результате
чего “шпион раскололся” и выдал самую главную свою тайну: “центром вселенной”
является регистр Count_REM, в котором “лежит” “хвостик” (остаток) измерения.
Отдыхайте, господин “шпион”, вы больше не нужны.
Работаю с “важняком”. Все внимание на него.
Примечание: может также потребоваться константа .16 (но не регистр Count_D_C! Он
“убит”), хотя, забегая вперед, скажу, что можно обойтись и без нее.
Итак, в пределах одного градуса, имеется 16 градаций.
Для того чтобы вывести на индикацию десятые доли градуса, нужно 10 градаций.
16 : 10 = 1,6, следовательно, если “привязаться” к наиболее привычной и удобной для
восприятия форме представления чисел, то получится следующее соответствие:
Табл. 2
Десятые доли градуса 0 1 2 3 4 5 6 7 8 9
Остаток от измерения 0 1,6 3,2 4,8 6,4 8 9,6 11,2 12,8 14,4

В нижней строке Вы видите не что иное, как “пороговые” (“граничные”) значения


остатка от измерения, при достижении которых, в ЖКИ модуле, должны
“высвечиваться” (после запятой) те цифры (символы), которые расположены в верхней
строке.
Глядя на эту таблицу, становится понятной “привязка” разработчиков к “штатному” шагу
измерения температуры величиной 0,5 градуса: числа 0 и 8 это целые числа, с
которыми имеется минимум проблем.
Вот вам и объяснение наличия “,0” и “,5” в результате “штатного” измерения (путь
наименьшего сопротивления).
Во всех остальных случаях, числа нижней строки дробные.
Но остаток от измерения (Count_REM) не может быть дробным числом.
Остаток от измерения всегда есть целое число.
Вот это и есть та “стенка”, которую разработчики пытались “пробить головой”.
Они “ушли в дроби”, наивно пытаясь обойтись “малой кровью”, но, на мой взгляд,
ничего толкового из этого не получилось (только сами себе навредили) по причине
того, что десять копеек это не рубль.
Думаю, что и сами разработчики это прекрасно понимают.
Этим и объясняется наличие очень скудных, общих рассуждений по заявленной теме и
полная “муть” в деталях.
А не проще ли просто – напросто округлить числа нижней строки по уровню 0,5?

3
Получается вот что:

Табл. 3
Десятые доли градуса 0 1 2 3 4 5 6 7 8 9
Остаток от измерения 0 2 3 5 6 8 10 11 13 14

Вы видите в нижней строке только целые числа, а это уже совсем другая “опера”, так
как заумные вычисления “дали дуба” (не нужны).
Принцип формирования десятичной цифры после запятой, “заложенный” в эту таблицу,
по погрешности, как минимум, не хуже (если не лучше) того “счастья”, которое
предлагают разработчики, плюс на изумление простой (и понятный) способ его
программной реализации (нет вычислений).
Плюс, целая часть результата замера температуры (то, что левее запятой) “и пальцем
не тронута”.
То, что правее и левее запятой, образно выражаясь, “живет отдельной друг от друга
жизнью” в том смысле, что, после считывания байтов из области оперативной памяти
DS1820, взаимовлияние одного на другое (и наоборот) отсутствует.
Плюс, обеспечивается “простор для маневра” в том смысле, что можно без проблем,
сделать, например, разрешение в 0,2 градуса или, на свой лад, изменить “привязки”
чисел нижней строки таблицы к числам верхней строки таблицы.
Что касается последнего, то можно, например, сделать так:
Табл. 4
Десятые доли градуса 0 1 2 3 4 5 6 7 8 9
Остаток от измерения 0 1 2 4 6 8 10 12 14 15

А можно “раскидать” и по другому.


В любом из этих случаев, “плавающая” погрешность будет, но она будет не хуже
“плавающей” погрешности вычислений, предлагаемых разработчиками.
А теперь произведу сравнительную оценку:

Табл. 5А Табл.5В Табл. 5С


Округление “Диаграмма” Вариант №1 “Диаграмма” Вариант №2 “Диаграмма”
20,7 9 9
20,6 9 8
20,6 8 7
20,5 7 7
20,4 7 6
20,4 6 6
20,3 5 5
20,3 5 5
20,2 4 4
20,1 4 4
20,1 3 3
20,0 2 3
19,9 2 2
19,9 1 2
19,8 0 1
19,8 0 0

Таблица 5А это два последних столбца таблицы 1.


Таблица 5В составлена на основе таблицы 4.
Таблица 5С составлена на основе таблицы 5.
В части касающейся погрешностей измерения температуры в диапазоне одного градуса,
“диаграммы” таблиц 5В и 5С выглядят не только не хуже “диаграммы” таблицы 5А, но,
на мой взгляд, и лучше.
Перехожу к практике.
Каким образом реально “воплотить в жизнь” то, что “нарыто”?
А просто, и даже очень просто - при помощи банального вычисляемого перехода.
4
Он применяется как своеобразный, достаточно примитивный, перекодировщик чисел из
двоичной системы исчисления в десятичную.
Изначально, в качестве “матери”, я использовал программу DS1820.asm, и вот что
получилось (программа работает в “железе”):

;********************************************************************************
; 0_1grad1.asm ЭЛЕКТРОННЫЙ ТЕРМОМЕТР НА ОСНОВЕ ДАТЧИКА ТЕМПЕРАТУРЫ DS1820
; М/контроллер и DS1820 работают по интерфейсу 1-Wire.
; Разрешение 0,1 градус.
; Работа с одним датчиком.
;********************************************************************************
; "Практикум по конструированию устройств на 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.
;-------------------------------
; Объем программы: 254 команды.
;================================================================================
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 ; преобразования.
Count_REM equ 15h ; Применяются при измерении температуры
;================================================================================
; Определение места размещения результатов операций.
;================================================================================
W equ 0 ; Результат направить в аккумулятор.

5
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.
movwf PortB ; Переправка младшего п/байта регистра W на
; линии RB4...7.
;------------------------------------------
; Запуск в работу младшего п/байта (строб).
6
;------------------------------------------
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 ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
goto SDVIG ; После вывода на индикацию символа "+",
; переход на обработку младшего байта
; температуры.
MINUS movlw 2Dh ; На индикацию выводится
7
bsf PortA,RS ; символ "-".
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
;----------------------------------------------------------
; Перевод двоичного числа младшего байта температуры
; из отрицательной области температур в положительную.
;----------------------------------------------------------
comf Temp_LSB,F ; После вывода на индикацию символа "-", все
incf Temp_LSB,F ; биты младшего байта температуры
; инвертируются и к результату прибавляется 1.
;================================================================================
; Подпрограмма обработки содержимого младшего байта температуры.
;================================================================================
; Деление числа, записанного в младшем байте температуры, на 2.
;--------------------------------------------------------------------------------
SDVIG clrf Flag ; Flag=0 (подготовка к работе).
rrf Temp_LSB,F ; Деление на 2.
;--------------------------------------------
; btfsc Status,C ; УДАЛЕНО.
; bsf Flag,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
movwf LED1 ;

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


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

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


;--------------------------------------------------------------------------------
8
; Запись в регистр 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, с записью
movwf Temp ; результата операции, через регистр W, в
; регистр 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 ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
movf LED0,W ; Вывод на индикацию байта,
bsf PortA,RS ; записанного в регистре LED0.
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
9
;----> Возврат по стеку из ПП ENTER_BF.

;========================================================================
; Формирование запятой и символов после запятой.
;========================================================================
; Формирование запятой.
;-------------------------------------
movlw 2Ch ; Вывод на индикацию
bsf PortA,RS ; символа "," (2Ch).
call ENTER_BF ; "Плавающая" задержка со стробом под вывод
; данных на индикацию.
;----> Возврат по стеку из ПП ENTER_BF.
;-----------------------------------------------
; btfsc Flag,0 ; УДАЛЕНО.
; goto _5 ; УДАЛЕНО.
; movlw 30h ; УДАЛЕНО.
; bsf PortA,RS ; УДАЛЕНО.
; call ENTER_BF ; УДАЛЕНО.
;----> Возврат по стеку из ПП ENTER_BF.
; return ; УДАЛЕНО.
;_5 movlw 35h ; УДАЛЕНО.
; bsf PortA,RS ; УДАЛЕНО.
; call ENTER_BF ; УДАЛЕНО.
;----> Возврат по стеку из ПП ENTER_BF.
;-------------------------------------
; Формирование символов после запятой.
;-------------------------------------
movf Count_REM,W ; Копирование содержимого Count_REM в W.
sublw .16 ; .16 - Count_REM (от .1 до .16) = от .0
; до .15 (W).
call TEXT_1 ; Переход в перекодировщик 16/10.
bsf PortA,RS ; "Плавающая" задержка со стробом под вывод
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 ; "пусто"
;======================================================================
; Перекодировщик 16/10.
;======================================================================
; Вычисляемый переход под табл. 3 п/раздела 5/8 "Практикума...".
;----------------------------------------------------------------------
TEXT_1 addwf PC,F ; Приращение PC на величину содержимого W.
10
retlw 0x30 ; "0"
retlw 0x30 ; "0"
retlw 0x31 ; "1"
retlw 0x32 ; "2"
retlw 0x32 ; "2"
retlw 0x33 ; "3"
retlw 0x34 ; "4"
retlw 0x34 ; "4"
retlw 0x35 ; "5"
retlw 0x35 ; "5"
retlw 0x36 ; "6"
retlw 0x37 ; "7"
retlw 0x37 ; "7"
retlw 0x38 ; "8"
retlw 0x39 ; "9"
retlw 0x39 ; "9"
;----------------------------------------------------------------------
; Вычисляемый переход под табл. 4 п/раздела 5/8 "Практикума...".
;----------------------------------------------------------------------
;;;TEXT_1 addwf PC,F ; Приращение PC на величину содержимого W.
;;; retlw 0x30 ; "0"
;;; retlw 0x31 ; "1"
;;; retlw 0x32 ; "2"
;;; retlw 0x32 ; "2"
;;; retlw 0x33 ; "3"
;;; retlw 0x33 ; "3"
;;; retlw 0x34 ; "4"
;;; retlw 0x34 ; "4"
;;; retlw 0x35 ; "5"
;;; retlw 0x35 ; "5"
;;; retlw 0x36 ; "6"
;;; retlw 0x36 ; "6"
;;; retlw 0x37 ; "7"
;;; retlw 0x37 ; "7"
;;; retlw 0x38 ; "8"
;;; retlw 0x39 ; "9"
;========================================================================

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

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 ; Подготовка к выводу на индикацию

11
; следующего символа таблицы.
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), то программа исполняется далее.
;--------------------------------------------------------------------------------
; Инициализация 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.
12
;----> Возврат по стеку из ПП OUT_BYTE.

;------------------------------------------------------------------------
; Чтение содержимого области оперативной памяти DS1820.
;------------------------------------------------------------------------
call IN_BYTE ; ПРИЕМ МЛАДШЕГО БАЙТА ТЕМПЕРАТУРЫ.
;----> Возврат по стеку из ПП IN_BYTE.
movwf Temp_LSB ; Запись принятого байта в регистр Temp_LSB.

call IN_BYTE ; ПРИЕМ СТАРШЕГО БАЙТА ТЕМПЕРАТУРЫ.


;----> Возврат по стеку из ПП IN_BYTE.
movwf Temp_MSB ; Запись принятого байта в регистр Temp_MSB.
;----------------------------------------
; Формальное считывание байтов.
;----------------------------------------
call IN_BYTE ; Формальное считывание байта верхнего
; предела температуры.
;----> Возврат по стеку из ПП IN_BYTE.
call IN_BYTE ; Формальное считывание байта нижнего
; предела температуры.
;----> Возврат по стеку из ПП IN_BYTE.
call IN_BYTE ; Формальное считывание 1-го резервного байта.
;----> Возврат по стеку из ПП IN_BYTE.
call IN_BYTE ; Формальное считывание 2-го резервного байта.
;----> Возврат по стеку из ПП IN_BYTE.
;----------------------------------------
call IN_BYTE ; ПРИЕМ БАЙТА ОСТАТКА ИЗМЕРЕНИЯ.
;----> Возврат по стеку из ПП IN_BYTE.
movwf Count_REM ; Запись принятого байта в регистр Count_REM.
;---------------------------------------------------
; Итог; в Temp_MSB записан старший байт температуры,
; в Temp_LSB записан младший байт температуры,
; в Count_REM записан байт остатка измерения.
;---------------------------------------------------
call DISPLAY ; Переход в ПП вывода результата измерения
; на индикацию.
;----> Возврат по стеку из ПП DISPLAY.
goto SNOVA ; Переход на новый цикл измерения.
;********************************************************************************

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

13
; Задание количества проходов по 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 (а также после исполнения
; предыдущей команды), то программа
; исполняется далее.
;-------------------------------------------------------------------
; Последовательное заполнение битами регистра Temp.
14
;-------------------------------------------------------------------
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 ; Возврат по стеку.
;********************************************************************************
end ; Конец программы.

Черным цветом выделен предмет разговора.


Красным цветом выделены “рудименты и атавизмы” программы DS1820.asm, которые
“канули в небытие”.
Что касается последнего, то это все, что связано с формированием символов “0” и “5”
после запятой. Сама запятая оставлена (а как же без нее?).
15
Вместо этих двух символов, на индикацию будет выводиться тот или иной символ из
диапазона “0” … “9”.
В данном случае, для нормальной работы вычисляемого перехода, я организовал
“закладку” содержимого регистра Count_REM, в регистр W, с задействованием ранее
упоминавшейся константы .16 и операции вычитания.
В этом случае, непосредственно перед входом в вычисляемый переход, в регистре W
будет “лежать” то или иное число из числового диапазона .0 … .15 (что и требуется)
и группа команд вычисляемого перехода, визуально, воспринимается комфортно, так
как сверху будет 0, а снизу 9.
Можно и не использовать константу .16 (и соответственно, операцию вычитания), но в
этом случае, перед копированием содержимого регистра Count_REM в регистр W,
нужно произвести один декремент (так как диапазон чисел, хранящихся в регистре
Count_REM, составляет .1 … .16) и “поставить вычисляемый переход с ног на голову”
(сверху 9, снизу 0).
В обеих случаях, количество команд одно и то же.
По-моему, первое удобнее. Поэтому и использовал.
По умолчанию, организована перекодировка по алгоритму таблицы 3, но можно
перейти и на агоритм таблицы 4.
Для этого нужно заблокировать ПП TEXT_1, используемую по умолчанию, и
разблокировать ПП TEXT_1, которая, по умолчанию, заблокирована (см. текст
программы).
Можете придумать и свой алгоритм.
Принцип перекодировки настолько прост, что трудностей возникнуть не должно.
Далее.
Для того чтобы в регистре Count_REM “лежал” байт остатка вычисления, его,
предварительно, нужно туда записать.
В программе DS1820.asm, из области оперативной памяти DS1820, считываются только
2 байта из 9-ти, значит, хочешь - не хочешь, но прежде чем “добраться” до
считывания остатка вычисления, нужно произвести считывание байтов из
“предлежащих” ячеек (с 1-й по 6-ю).
Только после этого можно считать содержимое требуемой, 7-й ячейки.
Это Вы и видите в тексте программы.
Содержимое с 3-й по 6-ю ячеек считывается формально, то есть, без копирования
считанных байтов в регистры общего назначения, что, я надеюсь, вполне оправдано и
понятно.
Вот и все.
На мой взгляд, в предложенном способе формирования цифры после запятой, нет
ничего суперсложного, и это гораздо удобнее того, что предлагают разработчики, и
ничем не хуже.
Все это прекрасно работает в железе, а объем программы увеличился всего на 17
команд. И т.д., и т.п.
Вот так я, на ваших глазах, в режиме реального времени, и “извернулся”.
Так как все познается в сравнении, ниже опубликована подпрограмма расчета,
ориентированная на приведенную выше формулу. Можете сравнить.

;********************************************************************************
; ВЫЧИСЛЕНИЕ ТЕМПЕРАТУРЫ.
; T=TEMP_READ-0.25+(Count_D_C - Count_REM)/Count_D_C
;********************************************************************************
; R3:R2 = Count_D_C - Count_REM
movf Count_REM,W ;
subwf Count_D_C,W ; Count_D_C - Count_REM
movwf R2 ;
clrf R3 ;
;----------------------------------------------
; R1:R0 = R3:R2 * 10
movlw 0x0A ;
movwf R4 ;
clrf R5 ;
call mul_16 ; R1:R0 = R3:R2 * R5:R4
;----------------------------------------------
16
; R1:R0 = R1:R0 / Count_D_C
movf R0,W ;
movwf R2 ;
movf R1,W ;
movwf R3 ;
movf Count_D_C,W ;
movwf R4 ;
clrf R5 ;
call div_16 ; R1:R0 = R3:R2 / R5:R4
;----------------------------------------------
; R7:R6 = R1:R0 - 2;
movlw 0xFE ;
addwf R0,F ;
btfss Status,C ;
decf R1,F ; Перенос.
movf R0,W ;
movwf R6 ;
movf R1,W ;
movwf R7 ;
;----------------------------------------------
; R1:R0 = TEMP_READ * 10
rrf Temp_MSB,0 ;
rrf Temp_LSB,0 ; В W получился TEMP_READ.
movwf R2 ;
movf Temp_MSB,W ;
movwf R3 ;
movlw d'10' ;
movwf R4 ;
clrf R5 ;
call mul_16 ; R1:R0 = R3:R2 * R5:R4
;----------------------------------------------
; Temp = R1:R0 + R7:R6
movf R6,W ;
addwf R0,F ;
btfsc Status,C ;
incf R1,F ; Перенос.
movf R7,W ;
addwf R1,F ;
movf R0,W ;
movwf Temp_LSB ;
movf R1,W ;
movwf Temp_MSB ;
GT_exit:
return ;
;********************************************************************************
........................
........................
;=============================================================================
; Умножение. Использует R0,R1,R2,R3,R4,R5.
;=============================================================================
mul_16: ; R1:R0 = R3:R2 * R5:R4
clrf R0 ;
clrf R1 ;
mul16_Loop:
; R5:R4--;
decf R4,F ;
btfsc R4,7 ;
decf R5,F ;
btfsc R5,7 ;
goto mul16_exit ;
; R1:R0 += R3:R2.
movf R2,0 ;
addwf R0,1 ;
btfsc Status,C ;

17
incf R1,1 ; Перенос.
movf R3,0 ;
addwf R1,1 ;
clrwdt ;
goto mul16_Loop ;
mul16_exit:
return ;
;=============================================================================
; Деление. Использует R0,R1,R2,R3,R4,R5.
;=============================================================================
div_16: ; R1:R0 = R3:R2 / R5:R4
; В R3:R2 остаток.
clrf R0 ;
clrf R1 ;
movf R4,W ;
btfss Status,Z ;
goto div16_Loop ;
movf R5,W ;
btfss Status,Z ;
goto div16_Loop ;
return ;
div16_Loop:
; Вычитаем RR5:RR4 из RR3:RR2.
movf R4,W ;
subwf R2,F ; F = F - W
btfss Status,C ;
decf R3,F ; Перенос.
btfsc R3,7 ;
goto div16_exit ;
movf R5,W ;
subwf R3,F ;
btfss Status,C ;
goto div16_exit ;
; Увеличиваем частное на 1.
movlw 1 ;
addwf R0,F ;
btfsc Status,C ;
incf R1,F ;
clrwdt ;
goto div16_Loop ;
div16_exit:
movf R4,W ;
addwf R2,F ;
; btfss Status,C ;
incf R3,F ; Перенос.
movf R5,W ;
addwf R3,F ;
return ;
;=============================================================================

Примечание: ПП опубликована в “не обработанном” виде. Именно в таком виде и


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

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


18
19