Академический Документы
Профессиональный Документы
Культура Документы
Опять же, как это часто в жизни бывает, если имеет место быть “скелет”, то на него,
“по закону жанра”, “автоматически” начинает “наращиваться мясо”.
Именно по этому принципу и создаются те “навороты”, в которые, если не знать,
откуда “ноги растут” (а они всегда растут из одного места. В противном случае
получается черт знает что), можно “въезжать” долго и упорно, а можно и вообще “не
въехать”.
Таким образом, то, что Вы прочтете ниже, вполне закономерно, естественно и
нормально. Так и должно быть.
Информация от Сергея Рослика выделена темно – синим цветом.
1
Эту ПП в основном целесообразно использовать тогда, когда необходимо отобразить
десятичные числа в 1, 2, 3, 4 разрядах индикации.
Можно добавить и пятый разряд, но в нём максимально, что может отразиться, так это только
числа до 6 включительно (при двухбайтных данных), т.к. в два байта помещается только
числа до 65536.
Конечно, можно и увеличить число байт данных, но тогда увеличится и количество команд в
подпрограмме, и она, по этому показателю, будет проигрывать стандартной подпрограмме
BIN2_DEC.
2
;********************************************************************************
; BIN2_4.asm ПП преобразования двоичного кода в двоично-десятичный
; Используется м/контроллер PIC16F873. Частота кварца 4 Мгц.
; Автор: Рослик Сергей Львович.
;================================================================================
LIST p=16f873
__CONFIG 3731H
;================================================================================
; Определение положения регистров специального назначения.
;================================================================================
IndF equ 00h ; Доступ к памяти через FSR
PC equ 02h ; Счетчик команд.
Status equ 03h ; Регистр Status.
FSR equ 04h ; Регистр косвенной адресации.
;================================================================================
; Определение битов регистров.
;================================================================================
C equ 0 ; Бит регистра статус.
F equ 1
;********************************************************************************
;Назначение регистров общего назначения.
;********************************************************************************
BL equ 20h ; Младший регистр перекодируемого числа.
BM equ 21h ; Средний регистр перекодируемого числа.
LED0 equ 22h ; Разряд 1.
LED1 equ 23h ; Разряд 10.
LED2 equ 24h ; Разряд 100.
LED3 equ 25h ; Разряд 1000.
Count equ 26h ;
;********************************************************************************
org 0
goto START
;================================================================================
; Таблица констант для вычисления разности.
;================================================================================
CONST addwf PC,F
dt .24, .252, .232, .3, .156, .255, .100, .0, .246, .255, .10, .0
;================================================================================
; Начало выполнения подпрограммы.
;================================================================================
START movlw 1Dh ; Загрузка двоичного двухбайтного числа,
movwf BM ; которое необходимо преобразовать в
movlw 7Eh ; двоично-десятичный код.
movwf BL ;
;================================================================================
; Преобразование двухбайтного двоичного числа в четырехзначное десятичное число.
;================================================================================
BIN2_10 clrf LED0 ; Подготавливаем регистры для загрузки в
clrf LED1 ; них результатов двоично-десятичного
clrf LED2 ; преобразования.
clrf LED3 ;
clrf Count ; Счётчик манипуляции константами.
movlw LED3 ; Стандартная процедура косвенной адресации с
movwf FSR ; "переправкой" содержимого регистра,
movf IndF,W ; сначала, LED3, а затем и всех остальных
; регистров LED2, LED1, LED0.
NEXT movf Count,W ; Подготовка к вычисляемому переходу и выбора
call CONST ; констатнты вычитаемого из регистра BL.
addwf BL,F ; Операция разности с регистром BL.
btfsc Status,C ; Проверям, перенос был или нет.
incf BM,F ; Перенос был, BM+1.
movf Count,W ; Переноса не было.
addlw 1 ; Подготовка к вычисляемому переходу.
3
call CONST ; Выбераем вычитаемое для регистра BM.
addwf BM,F ; Операция разности с регистром BM.
incf IndF,F ; Подсчёт кол-ва делений числа, с переносом
; в LED.
btfsc Status,C ; Проверям, перенос был или нет.
goto NEXT ; Перенос был.
bsf Count,1 ; Инкремент счётчика на 2. :)
movf Count,W ; Подготовка к вычисляемому переходу.
call CONST ; констатнта слагаемого для регистра BL.
addwf BL,F ; Операция суммирования аккумулятора с
; регистром BL.
btfsc Status,C ; Проверям, перенос был или нет.
incf BM,F ; Перенос был BM+1.
movf Count,W ; Переноса не было.
addlw 1 ; Подготовка к вычисляемому переходу.
call CONST ; Константа слагаемого для регистра BM
addwf BM,F ; Операция суммирования аккумулятора с
; регистром BM.
decf IndF,F ; Декремент текущего LEDа, в регистре
; косвенной адресации.
decf FSR,F ; Загрузка следуещего регистра LED.
;********************************************************************************
; BIN2_4.asm Программа, демонстрирующая работу ПП преобразования двоичного
; кода в двоично-десятичный.
4
; Используется м/контроллер PIC16F873. Частота кварца 4 Мгц.
; Автор: Рослик Сергей Львович.
;********************************************************************************
; На входе: 2-байтное двоичное число (в 2-байтном регистре BL/BM).
; На выходе: 4-разрядное десятичное число (в младших полубайтах регистров
; LED3...LED0).
;********************************************************************************
LIST p=16f873 ; Используется PIC16F873.
__CONFIG 3731H
;================================================================================
; Определение положения регистров специального назначения.
;================================================================================
IndF equ 00h ; Доступ к памяти через FSR.
PC equ 02h ; Счетчик команд.
Status equ 03h ; Регистр Status.
FSR equ 04h ; Регистр косвенной адресации.
;================================================================================
; Присваивание названий биту и месту размещения результатов операций.
;================================================================================
C equ 0 ; Флаг переноса-заема.
F equ 1 ; Результат направить в регистр.
;================================================================================
; "Прописка" регистров общего назначения.
;================================================================================
BL equ 20h ; Младший регистр перекодируемого числа.
BM equ 21h ; Средний регистр перекодируемого числа.
LED0 equ 22h ; Разряд 1.
LED1 equ 23h ; Разряд 10.
LED2 equ 24h ; Разряд 100.
LED3 equ 25h ; Разряд 1000.
Count equ 26h ; Счетчик выбора констант из таблицы.
;================================================================================
org 0 ; Начать выполнение
goto START ; программы с ПП START.
;********************************************************************************
;================================================================================
; Таблица констант делителей (табличный вычисляемый переход).
;
================================================================================C
ONST addwf PC,F ; Приращение PC на величину содержимого W.
dt .24, .252, .232, .3, .156, .255, .100, .0, .246, .255, .10, .0
;================================================================================
;********************************************************************************
; НАЧАЛО ВЫПОЛНЕНИЯ ПРОГРАММЫ.
;********************************************************************************
; По умолчанию, используется число 1D7Eh (.7550), но может быть "заложено" и
; другое число.
;--------------------------------------------------------------------------------
START movlw 1Dh ; Загрузка в BM/BL двоичного двухбайтного
movwf BM ; числа, которое будет переведено
movlw 7Eh ; в двоично-десятичную форму.
movwf BL ;
;==============================================================================
; ПП преобразования двухбайтного двоичного числа в 4-разрядное десятичное число.
;==============================================================================
; Подготовительные операции.
;----------------------------------------
BIN2_10 clrf LED1 ; Подготовка к работе
clrf LED2 ; регистров результата
clrf LED3 ; 2/10 преобразования.
clrf Count ; Подготовка к работе счётчика выбора
; констант.
movlw LED3 ; Начало процедуры косвенной адресации:
movwf FSR ; запись в FSR адреса регистра LED3.
5
;================================================================================
; ПП формирования десятичного значения текущего LED с "привязкой" к конкретному
; делителю (константам).
; Деление происходит путем последовательного вычитания делителя из делимого, с
; подсчетом количества этих вычитаний ("оседает" в текущем LED), до момента,
; когда делитель становится больше делимого.
;================================================================================
NEXT movf Count,W ; Подготовка к выбору константы
; (то есть, к выбору делителя).
call CONST ; Выбор константы для регистра BL.
;----> Возврат по стеку из ПП CONST.
addwf BL,F ; BL-CONST=... (вычитание делителя из
; делимого в приложении к BL).
btfsc Status,C ; Перенос был или нет?
incf BM,F ; Если был, то BM+1=... (перенос в BM)
; Результат - в BM.
incf Count,W ; Если не было (а также после BM+1), то
; подготовка к выбору следующей константы.
call CONST ; Выбор константы для регистра BM.
;----> Возврат по стеку из ПП CONST.
addwf BM,F ; BM-CONST=... (вычитание делителя из
; делимого в приложении к BM).
incf IndF,F ; Подсчёт кол-ва вычитаний
;(текущий LED+1 =... Результат - в LED).
btfsc Status,C ; Перенос был или нет (делимое больше или
; меньше делителя)?
goto NEXT ; Если был (делимое больше делителя), то
; продолжаем вычитать.
;================================================================================
; Работа с остатком от деления.
;================================================================================
bsf Count,1 ; Если не был, то подготовка к выбору
movf Count,W ; константы (с адресом PC+02h) для
; формирования истинного значения остатка.
call CONST ; Выбор константы для регистра BL.
;----> Возврат по стеку из ПП CONST.
;-----------------------------------------
; Формирование истинного значения остатка.
;-----------------------------------------
addwf BL,F ; Операция суммирования содержимого W и BL.
btfsc Status,C ; Перенос был или нет?
incf BM,F ; Если был, то BM+1=... (перенос в BM)
; Результат - в BM.
incf Count,W ; Если не было (а также после BM+1),
; то подготовка к выбору константы.
call CONST ; Выбор константы для регистра BM.
;----> Возврат по стеку из ПП CONST.
addwf BM,F ; Операция суммирования содержимого W и BM.
decf IndF,F ; Устранение "перебора" в текущем LED.
;********************************************************************************
; Работа с текущей четверкой констант закончена
; (содержимое текущего LED сформировано).
;********************************************************************************
;================================================================================
; Переход на следующий LED и следующий, "привязанный" к нему, делитель.
;================================================================================
decf FSR,F ; Загрузка в FSR адреса следующего
; регистра LED.
incf Count,F ; Настройка для выбора необходимой константы
incf Count,F ; (для перехода на следующий делитель):
; Count+2=... Результат - в Count.
movf Count,W ; Count ---> W.
sublw .11 ; Проверка: все константы (делители)
btfsc Status,C ; перебрали или нет?
goto NEXT ; Если не все, то начинается работа со
6
; следующим LEDом и с "привязанной" к нему
; группой констант.
; Если все, то работаем с остатком от
; комплексного деления.
;================================================================================
; Работа с остатком от комплексного деления (окончание процедуры).
;================================================================================
movf BL,W ; Загружаем остаток в регистр
movwf LED0 ; десятичного разряда единиц.
Работа программы
7
Остальные две группы констант (для деления на 100 и на 10) организованы точно по
такому же принципу.
Числа .0 и .255 имеются в них по той простой причине, что для отображения чисел .
100 и .10 нужен только один байт, а для обеспечения нормальной работы
программной процедуры деления, нужно оперировать 2-мя байтами делителя.
По этой причине, делитель и имеет 2 байта.
Просто в случаях деления на 100 и на 10, старший байт делителя всегда равен нулю.
Итак, в таблице “лежат” все необходимые для работы “прибамбасы”.
Можно работать.
Сначала нужно “заложить” в регистры BL и BM двоичное число, форму которого нужно
преобразовать.
Это и имеет место быть.
Непосредственно к ПП преобразования формы числа эта “закладка” отношения не
имеет.
Если данная ПП преобразования формы числа входит в состав какой-то “боевой”
программы, то нужно озаботиться тем, чтобы “на подлете” к ПП преобразования
формы числа, в BL и BM “лежало” что-то полезное.
После этой “закладки”, отрабатываются подготовительные операции.
Об обнулениях распространяться не буду, и так все понятно, а вот о косвенной
адресации пару слов сказать нужно.
В конце подготовительных операций, в регистр FSR записывается адрес регистра LED
самого старшего разряда (LED3), то есть, того регистра, в котором, в конечном итоге,
“осядет” целое число делений на 1000.
Этот адрес только записывается в FSR и не более того.
Обращение к IndF будет не сразу же после этого, а позднее.
Итак, “формальности соблюдены” и можно вычитать из делителя 1000.
На 1-м “витке” полного цикла ПП преобразования формы числа, в регисте Count
“лежит” ноль (см. clrf Count), следовательно, после отработки вычисляемого перехода,
из содержимого регистра BL будет вычтена константа .24.
Еще раз напоминаю, что, хотя и имеет место быть команда суммирования (addwf), но
по факту, происходит операция вычитания, так как байт делителя инвертирован.
Об этом говорилось в предыдущем подразделе.
Так как производятся операции с 2-байтными числами, то соответственно, нужно
обработать и второй байт (BM), но сначала нужно обеспечить возможность переноса
из более младшего разряда.
Значит нужно проверить флаг С, и если он поднялся, то инкрементировать
содержимое регистра BM или не инкрементировать его, что и имеет место быть.
Далее, для того чтобы обработать содержимое регистра более старшего разряда (BM),
нужно сменить константу, то есть, использовать константу старшего разряда делителя.
Значит, для обеспечения выбора этой константы, нужно инкрементировать содержимое
регистра Count (incf Count,W), “уйти” в вычисляемый переход (call CONST), вернуться
из него, а затем исполнить команду addwf BM,F.
Все это и имеет место быть (см. текст программы).
В этом случае, также, по факту, происходит операция вычитания, так как “на свет
Божий извлечена” инвертированная константа делителя старшего разряда (.252).
Более старшего разряда нет. Значит и перенос в него организовывать не нужно (“бабу
с воза, кобыле легче).
Можно “ставить галочку” в текущем LEDе, то есть, инкрементировать его содержимое
(“задокументировать” факт отработки одного вычитания числа 1000 из делимого).
Так как задействуется косвенная адресация, то это “проще пареной репы”: incf IndF,F.
Далее нужно “упасть” на анализ знака остатка, получившегося в результате отработки
текущей (в процессе работы ПП, этих отработок может быть несколько) процедуры
вычитания числа 1000 из делимого, что и имеет место быть: btfsc Status,C.
Примечание: флаг С “срабатывает” по факту исполнения команды addwf BM,F.
Команда incf IndF,F на флаг С не воздействует.
Если в регистре BM будет “лежать” число большее тысячи, то рабочая точка
программы “отфутболивается” на повторное вычитание из делимого тысячи.
Далее снова происходит то, что описано выше, и это “отфутболивание” будет
происходить до тех пор, пока делимое не станет меньше делителя.
8
Обращаю Ваше внимание на то, что в течение всей этой “свистопляски” (в пределах
деления на 1000), содержимое регистра Count равно нулю.
И в самом деле, результат инкремента его содержимого записывается не в регистр
Count, а в регистр W (см. команду incf Count,W).
После того, как будет “засечен” факт отрицательного результата (делимое меньше
делителя), начинается “исправление числового дефекта”, связанного с “лишним”
вычитанием тысячи из делимого (числовое значение остатка не равно требуемому).
Значит нужно перейти на неинвертированную константу сначала младшего разряда
делителя, а затем и старшего.
Для того чтобы обеспечить эту возможность, нужно записать в регистр Count число 2
(“по верху”, “старого” и ставшего не нужным, нуля), что и имеет место быть (bsf
Count,1 - самое оптимальное решение), а затем скопировать его в регистр W (movf
Count,W).
Соответственно, в результате исполнения “вычисляемопереходных дел”, на “свет Божий
извлечется” не инвертированная константа младшего байта делителя (.232).
Далее следует команда addwf BL,F, которую, по факту, уже нельзя назвать командой
операции вычитания.
Почему? А потому, что константа не инвертирована.
В результате ее исполнения, в младшем байте регистра делимого (BL) “осядет”
истинное значение остатка от предшествующего деления на 1000 (в части касающейся
младшего байта этого остатка).
Далее, все по той же причине необходимости обеспечения переноса в более старший
разряд делимого, нужно посмотреть, был перенос (по результату исполнения команды
addwf BL,F) или нет?
Если был, то содержимое регистра BM инкрементируется, а если нет, то не
инкрементируется.
Любой из этих сценариев “упирается” в команду подготовки выбора следующей
константы incf Count,F, которая и исполняется.
После этого делаются “вычисляемопереходные дела”, в результате чего на “свет Божий
извлечется” не инвертированная константа старшего байта делителя (.3).
Далее производится суммирование старшего байта регистра делимого с этой константой,
в результате чего, в старшем байте регистра делимого (BM), “осядет” истинное
значение остатка от предшествующего деления на 1000 (в части касающейся старшего
байта этого остатка).
Теперь можно “ликвидировать перебор” результата деления на 1000, который возник
при последнем вычитании тысячи из делимого (когда делимое стало меньше
делителя).
При наличии процедуры косвенной адресации, это сделать просто: decf IndF,F и “дело
в шляпе”.
После этого, в LED3 будет “лежать” число делений на 1000, соответствующее истине.
Итог: деление на 1000 завершено.
В 2-байтном регистре BM/BL “лежит” двоичное число, десятичный эквивалент которого
равен точному остатку от деления “материнского”, двоичного числа на 1000.
Количество этих делений “ушло” в младший полубайт байта регистра результата
преобразования формы числа самого старшего разряда (LED3).
После этого, можно делить сначала на 100, а затем и на 10.
Для обеспечения такой возможности, нужно
1. сменить текущий LED,
2. сменить текущую группу констант,
после чего повторить все то, о чем шла речь выше.
Первое обеспечивается банальным декрементом содержимого регистра FSR (см.
адресные “прописки” регистров LED0…LED3 в “шапке” программы).
Второе обеспечивается двумя инкрементами содержимого регистра Count (+2).
Объяснение: после выхода рабочей точки программы из процедуры деления на 1000, в
регистре Count “лежит” число 2 (см. bsf Count,1).
Чтобы перейти на первую константу группы констант деления на 100, нужно, чтобы в
регистре Count “лежало” число 4.
Вот Вам и объяснение наличия двух инкрементов.
9
Далее, в целях обеспечения возможности перехода рабочей точки программы в группу
команд работы с остатком от комплексного деления (после окончания деления на 10),
производится анализ содержимого регистра Count на предмет нахождения в нем числа
.11.
Это и есть критерий такого перехода (или не перехода).
В частности, после отработки процедуры деления на 1000 и проверки содержимого
регистра Count на соответствие числу .11, такого соответствия обнаружено не будет, и
рабочая точка программы “улетит” в ПП NEXT, в которой будет отработана процедура
деления на 100.
В регистре BM/BL “осядет” остаток от деления на 100, а в регистре LED2 будет
“лежать” число количества делений на 100.
После выхода из процедуры деления на 100, в регистре Count будет лежать число
4 + 2 = 6.
Затем еще 2 инкремента, и в регистре Count будет “лежать” число 6 + 2 = 8, а это как
раз то, что нужно при делении на 10.
Далее - опять переход в ПП NEXT, в которой будет отработана процедура деления на
10.
В регистре BM/BL “осядет” остаток от деления на 10, а в регистре LED1 будет
“лежать” число количества делений на 10.
После выхода из процедуры деления на 10, в регистре Count будет лежать число
8 + 2 = 10.
Затем еще 2 инкремента, и в регистре Count будет “лежать” число 10 + 2 = 12.
Перебор констант закончен (окончание комплексного деления) и делить больше нечего.
Вот тут-то и срабатывает проверка на число .11.
У Сергея, для этой проверки, задействуется флаг DC (анализ результата исполнения
команды sublw .11 в пределах младшего полубайта), но я заменил его на более
привычный флаг С (то же самое, но в пределах байта).
При вычитании 12-ти из 11-ти, получается отрицательное число, следовательно, вместо
команды goto NEXT исполнится “виртуальный” NOP (команда goto NEXT обходится), и
рабочая точка программы “перескочит” на команду movf BL,W.
Эта и следующая за ней команда (movwf LED0) просто переписывают (через W)
содержимое остатка от комплексного деления в регистр LED0.
Все. Полный цикл программы закончен.
Задача решена.
Далее, в целях обеспечения “сервиса” в ходе отслеживания работы программы, Сергей
“подсуетился” и “поставил программу на счетчик”.
Это означает то, что можно, с комфортом, последовательно (в “полуавтомате”),
отследить все результаты преобразования формы чисел, начиная от двоичного числа,
величину которого можно задать в программе.
;********************************************************************************
; BIN2_4_1.asm Программа, демонстрирующая работу ПП преобразования двоичного
; кода в двоично-десятичный, с перебором всех значений двоичного
; числа, начиная от заданного.
; Используется м/контроллер PIC16F873. Частота кварца 4 Мгц.
; Автор: Рослик Сергей Львович.
;********************************************************************************
; На входе: 2-байтное двоичное число (в 2-байтном регистре BL/BM).
; На выходе: 4-разрядное десятичное число (в младших полубайтах регистров
; LED3...LED0).
10
;********************************************************************************
LIST p=16f873 ; Используется PIC16F873.
__CONFIG 3731H
;================================================================================
; Определение положения регистров специального назначения.
;================================================================================
IndF equ 00h ; Доступ к памяти через FSR.
PC equ 02h ; Счетчик команд.
Status equ 03h ; Регистр Status.
FSR equ 04h ; Регистр косвенной адресации.
;================================================================================
; Присваивание названий биту и месту размещения результатов операций.
;================================================================================
C equ 0 ; Флаг переноса-заема.
F equ 1 ; Результат направить в регистр.
;================================================================================
; "Прописка" регистров общего назначения.
;================================================================================
BL equ 20h ; Младший регистр перекодируемого числа.
BM equ 21h ; Средний регистр перекодируемого числа.
LED0 equ 22h ; Разряд 1.
LED1 equ 23h ; Разряд 10.
LED2 equ 24h ; Разряд 100.
LED3 equ 25h ; Разряд 1000.
Count equ 26h ; Счетчик выбора констант из таблицы.
SecL equ 27h ; Младший регистр счётчика витков.
SecM equ 28h ; Старший регистр счётчика витков.
;================================================================================
org 0 ; Начать выполнение
goto START ; программы с ПП START.
;********************************************************************************
;================================================================================
; Таблица констант делителей (табличный вычисляемый переход).
;============================================================================
CONST addwf PC,F ; Приращение PC на величину содержимого W.
dt .24, .252, .232, .3, .156, .255, .100, .0, .246, .255, .10, .0
;================================================================================
;********************************************************************************
; НАЧАЛО ВЫПОЛНЕНИЯ ПРОГРАММЫ.
;********************************************************************************
; В регистры SecM и SecL записывается двоичное число (“точка отсчета”).
;----------------------------------------------------------------------
START movlw 0 ;
movwf SecM ; Определение начальной
movlw 0 ; “точки отсчета”.
movwf SecL ; Можно определить и иначе.
;================================================================================
; Запись в регистр BM/BL значения текущего двоичного числа.
;================================================================================
COUNTER call INKREM ; Переход в ПП инкремента содержимого
; регистра SecM/SecL (а по факту -> BM/BL).
;----> Возврат по стеку из ПП INKREM.
movf SecL,W ; Загрузка в BM/BL двоичного двухбайтного
movwf BL ; числа, которое будет переведено
movf SecM,W ; в двоично-десятичную форму.
movwf BM ;
;================================================================================
; ПП преобразования двухбайтного двоичного числа в 4-разрядное десятичное число.
;================================================================================
; Подготовительные операции.
;----------------------------------------
BIN2_10 clrf LED1 ; Подготовка к работе
clrf LED2 ; регистров результата
clrf LED3 ; 2/10 преобразования.
11
clrf Count ; Подготовка к работе счётчика выбора
; констант.
movlw LED3 ; Начало процедуры косвенной адресации:
movwf FSR ; запись в FSR адреса регистра LED3.
;================================================================================
; ПП формирования десятичного значения текущего LED с "привязкой" к конкретному
; делителю (константам). Деление происходит путем последовательного вычитания
; делителя из делимого, с подсчетом количества этих вычитаний ("оседает" в
; текущем LED), до момента, когда делитель становится больше делимого.
;================================================================================
NEXT movf Count,W ; Подготовка к выбору константы
; (то есть, к выбору делителя).
call CONST ; Выбор константы для регистра BL.
;----> Возврат по стеку из ПП CONST.
addwf BL,F ; BL-CONST=... (вычитание делителя из
; делимого в приложении к BL).
btfsc Status,C ; Перенос был или нет?
incf BM,F ; Если был, то BM+1=... (перенос в BM)
; Результат - в BM.
incf Count,W ; Если не было (а также после BM+1), то
; подготовка к выбору следующей константы.
call CONST ; Выбор константы для регистра BM.
;----> Возврат по стеку из ПП CONST.
addwf BM,F ; BM-CONST=... (вычитание делителя из
; делимого в приложении к BM).
incf IndF,F ; Подсчёт кол-ва вычитаний
; (текущий LED+1 =... Результат - в LED).
btfsc Status,C ; Перенос был или нет (делимое больше или
; меньше делителя)?
goto NEXT ; Если был (делимое больше делителя), то
; продолжаем вычитать.
;================================================================================
; Работа с остатком от деления.
;================================================================================
bsf Count,1 ; Если не был, то подготовка к выбору
movf Count,W ; константы (с адресом PC+02h) для
; формирования истинного значения остатка.
call CONST ; Выбор константы для регистра BL.
;----> Возврат по стеку из ПП CONST.
;-----------------------------------------
; Формирование истинного значения остатка.
;-----------------------------------------
addwf BL,F ; Операция суммирования содержимого W и BL.
btfsc Status,C ; Перенос был или нет?
incf BM,F ; Если был, то BM+1=... (перенос в BM)
; Результат - в BM.
incf Count,W ; Если не было (а также после BM+1),
; то подготовка к выбору константы.
call CONST ; Выбор константы для регистра BM.
;----> Возврат по стеку из ПП CONST.
addwf BM,F ; Операция суммирования содержимого W и BM.
decf IndF,F ; Устранение "перебора" в текущем LED.
;***********************************************
; Работа с текущей четверкой констант закончена
; (содержимое текущего LED сформировано).
;***********************************************
;================================================================================
; Переход на следующий LED и следующий, "привязанный" к нему, делитель.
;================================================================================
decf FSR,F ; Загрузка в FSR адреса следующего
; регистра LED.
incf Count,F ; Настройка для выбора необходимой константы
incf Count,F ; (для перехода на следующий делитель):
; Count+2=... Результат - в Count.
12
movf Count,W ; Count ---> W.
sublw .11 ; Проверка: все константы (делители)
btfsc Status,C ; перебрали или нет?
goto NEXT ; Если не все, то начинается работа со
; следующим LEDом и с "привязанной" к нему
; группой констант.
; Если все, то работаем с остатком от
; комплексного деления.
;================================================================================
; Работа с остатком от комплексного деления (окончание процедуры).
;================================================================================
movf BL,W ; Загружаем остаток в регистр
movwf LED0 ; десятичного разряда единиц.
goto COUNTER ; Переход на новый виток программы.
;================================================================================
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
; ПП инкремента содержимого регистра SecM/SecL.
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
INKREM incfsz SecL,F ; SecL+1=...
return ; Если результат не=0, то возврат.
incfsz SecM,F ; Если результат =0, то SecM+1=...
return ; Если результат не=0, то возврат.
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;********************************************************************************
; Sravn.asm Программа, в которой можно сравнить работу ПП преобразования формы
; числа, предложенной Сергеем Росликом, и стандартной ПП
; преобразования формы числа.
; Используется м/контроллер PIC16F84A. Частота кварца 4 Мгц.
;********************************************************************************
; На входе: 2-байтное двоичное число (в 2-байтном регистре BL/BM).
; На выходе: 4-разрядное десятичное число (в младших полубайтах регистров
; LED3...LED0).
;********************************************************************************
LIST p=16f84a ; Используется PIC16F84A.
__CONFIG 3FF1h
;================================================================================
; Определение положения регистров специального назначения.
13
;================================================================================
IndF equ 00h ; Доступ к памяти через FSR.
PC equ 02h ; Счетчик команд.
Status equ 03h ; Регистр Status.
FSR equ 04h ; Регистр косвенной адресации.
;================================================================================
; Присваивание названий биту и месту размещения результатов операций.
;================================================================================
C equ 0 ; Флаг переноса-заема.
F equ 1 ; Результат направить в регистр.
;================================================================================
; "Прописка" регистров общего назначения.
;================================================================================
BL equ 20h ; Младший регистр перекодируемого числа.
BM equ 21h ; Средний регистр перекодируемого числа.
LED0 equ 22h ; Разряд 1.
LED1 equ 23h ; Разряд 10.
LED2 equ 24h ; Разряд 100.
LED3 equ 25h ; Разряд 1000.
Count equ 26h ; Счетчик выбора констант из таблицы.
Mem equ 1Fh ; Регистр оперативной памяти.
;================================================================================
org 0 ; Начать выполнение
goto START ; программы с ПП START.
;********************************************************************************
;================================================================================
; Таблица констант делителей (табличный вычисляемый переход).
;================================================================================
CONST addwf PC,F ; Приращение PC на величину содержимого W.
dt .24, .252, .232, .3, .156, .255, .100, .0, .246, .255, .10, .0
;================================================================================
;********************************************************************************
; НАЧАЛО ВЫПОЛНЕНИЯ ПРОГРАММЫ.
;********************************************************************************
; По умолчанию, используется число 1D7Eh (.7550), но может быть "заложено" и
; другое число.
;--------------------------------------------------------------------------------
START movlw 1Dh ; Загрузка в BM/BL двоичного 2-байтного
movwf BM ; числа, которое будет переведено
movlw 7Eh ; в двоично-десятичную форму.
movwf BL ;
;####################################################
; ВЫБОР ОДНОЙ ИЗ ДВУХ ПП ПРЕОБРАЗОВАНИЯ ФОРМЫ ЧИСЛА.
;####################################################
; ЕСЛИ ЗАБЛОКИРОВАТЬ ЭТУ КОМАНДУ, ТО
;;; goto Bin2_10 ; ПРОИЗОЙДЕТ ПЕРЕХОД В ПП СЕРГЕЯ РОСЛИКА,
; А ЕСЛИ ЭТУ БЛОКИРОВКУ СНЯТЬ, ТО ПРОИЗОЙДЕТ
; ПЕРЕХОД В СТАНДАРТНУЮ ПП ПРЕОБРАЗОВАНИЯ
; ФОРМЫ ЧИСЛА (Bin2_10).
;==============================================================================
; ПП преобразования 2-байтного двоичного числа в 4-разрядное десятичное число.
;==============================================================================
; Подготовительные операции.
;----------------------------------------
BIN2_10 clrf LED1 ; Подготовка к работе
clrf LED2 ; регистров результата
clrf LED3 ; 2/10 преобразования.
clrf Count ; Подготовка к работе счётчика выбора
; констант.
movlw LED3 ; Начало процедуры косвенной адресации:
movwf FSR ; запись в FSR адреса регистра LED3.
;================================================================================
; ПП формирования десятичного значения текущего LED с "привязкой" к конкретному
; делителю (константам). Деление происходит путем последовательного вычитания
14
; делителя из делимого, с подсчетом количества этих вычитаний ("оседает" в
; текущем LED), до момента, когда делитель становится больше делимого.
;================================================================================
NEXT movf Count,W ; Подготовка к выбору константы
; (то есть, к выбору делителя).
call CONST ; Выбор константы для регистра BL.
;----> Возврат по стеку из ПП CONST.
addwf BL,F ; BL-CONST=... (вычитание делителя из
; делимого в приложении к BL).
btfsc Status,C ; Перенос был или нет?
incf BM,F ; Если был, то BM+1=... (перенос в BM)
; Результат - в BM.
incf Count,W ; Если не было (а также после BM+1), то
; подготовка к выбору следующей константы.
call CONST ; Выбор константы для регистра BM.
;----> Возврат по стеку из ПП CONST.
addwf BM,F ; BM-CONST=... (вычитание делителя из
; делимого в приложении к BM).
incf IndF,F ; Подсчёт кол-ва вычитаний
; (текущий LED+1 =... Результат - в LED).
btfsc Status,C ; Перенос был или нет (делимое больше или
; меньше делителя)?
goto NEXT ; Если был (делимое больше делителя), то
; продолжаем вычитать.
;================================================================================
; Работа с остатком от деления.
;================================================================================
bsf Count,1 ; Если не был, то подготовка к выбору
; константы (с адресом PC+02h)
movf Count,W ; для формирования истинного значения
; остатка.
call CONST ; Выбор константы для регистра BL.
;----> Возврат по стеку из ПП CONST.
;-----------------------------------------
; Формирование истинного значения остатка.
;-----------------------------------------
addwf BL,F ; Операция суммирования содержимого W и BL.
btfsc Status,C ; Перенос был или нет?
incf BM,F ; Если был, то BM+1=... (перенос в BM)
; Результат - в BM.
incf Count,W ; Если не было (а также после BM+1),
; то подготовка к выбору константы.
call CONST ; Выбор константы для регистра BM.
;----> Возврат по стеку из ПП CONST.
addwf BM,F ; Операция суммирования содержимого W и BM.
decf IndF,F ; Устранение "перебора" в текущем LED.
;********************************************************************************
; Работа с текущей четверкой констант закончена
; (содержимое текущего LED сформировано).
;********************************************************************************
;================================================================================
; Переход на следующий LED и следующий, "привязанный" к нему, делитель.
;================================================================================
decf FSR,F ; Загрузка в FSR адреса следующего
; регистра LED.
incf Count,F ; Настройка для выбора необходимой константы
incf Count,F ; (для перехода на следующий делитель):
; Count+2=... Результат - в Count.
movf Count,W ; Count ---> W.
sublw .11 ; Проверка: все константы (делители)
btfsc Status,C ; перебрали или нет?
goto NEXT ; Если не все, то начинается работа со
; следующим LEDом и с "привязанной" к нему
; группой констант.
; Если все, то работаем с остатком от
; комплексного деления.
15
;================================================================================
; Работа с остатком от комплексного деления (окончание процедуры).
;================================================================================
movf BL,W ; Загружаем остаток в регистр
movwf LED0 ; десятичного разряда единиц.
goto $ ; СТОП-МАШИНА!
;********************************************************************************
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; СТАНДАРТНАЯ ПП ПРЕОБРАЗОВАНИЯ 2-БАЙТНЫХ ДВОИЧНЫХ ЧИСЕЛ В 4-РАЗРЯДНЫЕ
; ДЕСЯТИЧНЫЕ ЧИСЛА.
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Подготовка к преобразованию.
;================================================================================
Bin2_10 bcf Status,C ; Сброс флага переноса-заема.
movlw .16 ; Зпись в регистр Count числа проходов
movwf Count ; преобразования, равного суммарному
; количеству битов 2-разрядного регистра BM/BL
; (8*2=16).
clrf LED0 ; Сброс в 0 содержимого регистра LED0.
clrf LED1 ; -------"------ LED1.
clrf LED2 ; -------"------ LED2.
clrf LED3 ; -------"------ LED3.
;-------------------------------------------------------------------------------
; Примечание: процесс преобразования заканчивается при уменьшении числа проходов
; преобразования, которые заложены в регистр Count (.16), до нуля.
;================================================================================
; Циклический сдвиг влево.
;================================================================================
Loop16 rlf BL,F ; Циклический сдвиг влево 2-байтного двоичного
rlf BM,F ; числа, записанного в 2-байтном регистре
; BM/BL, на одну позицию, через бит С регистра
; STATUS.
rlf LED0,F ; Циклический сдвиг влево 2-байтного двоичного
rlf LED1,F ; числа, записанного в группе регистров
; LED0/LED1, на одну позицию, через бит С
; регистра STATUS.
decfsz Count,F ; Декремент (-1) содержимого регистра Count с
; сохранением результата в нем же.
goto adjDEC ; Если результат не=0, то переход в ПП adjDEC
; Если результат =0, то программа
; исполняется далее.
;================================================================================
; Поразрядное распределение содержимого регистров LED0 и LED1
; (их полубайтов) по младшим полубайтам регистров LED0...3.
;================================================================================
swapf LED1,W ; Запись старшего полубайта LED1
andlw 0Fh ; в младший полубайт LED3.
movwf LED3 ; --------------------------------
;================================================================================
; Запись в регистр FSR адресов регистров LED0, LED1 для дальнейшей косвенной
; адресации к ним в ПП adjBCD.
; Переход к обработке следующего LEDа - после возврата по стеку.
;================================================================================
adjDEC movlw LED0 ; Запись в регистр FSR, через регистр W,
movwf FSR ; адреса регистра LED0 с дальнейшим переходом
call adjBCD ; в ПП adjBCD (адрес следующей команды
; закладывается в стек).
;---> Возврат по стеку из ПП adjBCD.
movlw LED1 ; -----------------------------
movwf FSR ; То же самое для регистра LED1.
call adjBCD ; -----------------------------
;---> Возврат по стеку из ПП adjBCD.
goto Loop16 ; Проход всех LED (с LED0 по LED1). Переход в
; ПП Loop16, то есть на следующее кольцо
; числовых преобразований.
;================================================================================
; Основные операции преобразования двоичных чисел в двоично-десятичные:
; операции сложения LED0...3 и констант 03h,30h с условиями по 3-му и 7-му битам.
;================================================================================
adjBCD movlw 3 ; Сложить содержимое текущего LED с числом
addwf 0,W ; 03h, c записью результата операции, через
movwf Mem ; регистр W, в регистр Mem.
btfsc Mem,3 ; Анализ состояния 3-го бита регистра Mem.
movwf 0 ; Если бит № 3 =1, то содержимое регистра Mem
; копируется в текущий LED.
movlw 30 ; Если бит №3 =0, то содержимое текущего LED
addwf 0,W ; складывается с константой 30h, с последующей
movwf Mem ; записью результата операции, через регистр
; W, в регистр Mem.
btfsc Mem,7 ; Анализ состояния 7-го бита регистра Mem.
movwf 0 ; Если бит №7 =1, то содержимое регистра Mem
; копируется в текущий LED.
retlw 0 ; Если бит №7 =0, то регистр W очищается и
; происходит возврат по стеку в ПП adjDEC.
;================================================================================
end ; Конец программы.
18
"Практикум по конструированию устройств на PIC контроллерах" http://ikarab.narod.ru E-mail: karabea@lipetsk.ru
19