Файл: Самоучитель по программированию PIC контроллеров для начинающих (Е.А. Корабельников,2008).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 16.06.2025
Просмотров: 3593
Скачиваний: 3
;================================================================================
; Определение места размещения результатов операций.
;================================================================================
W |
equ |
0 |
; |
Результат |
направить |
в |
аккумулятор. |
F |
equ |
1 |
; |
Результат |
направить |
в |
регистр. |
;.............................................................
;================================================================================
; Присваивание битам названий.
;================================================================================
C equ 0 ; Бит флага переноса-заёма.
;.............................................................
;================================================================================
org |
0 |
; |
Начать выполнение программы |
goto |
START |
; |
с подпрограммы START. |
;********************************************************************************
;********************************************************************************
; РАБОЧАЯ ЧАСТЬ ПРОГРАММЫ
;********************************************************************************
START ......................................
......................................
......................................
......................................
На момент начала ПП умножения, в регистр RegL должно быть записано однобайтное
двоичное число (множимое), которое нужно умножить на 10 (множитель).
Значения произведений отражаются в двухбайтном регистре RegL/RegH.
;================================================================================
;Подпрограмма умножения на 10 однобайтных двоичных чисел (.00 ... .255)
;================================================================================
;Подготовительные операции.
;-------------------------------------------------------------------------------- |
||||
bcf |
Status,C |
; Установка в |
0 бита № 0 регистра Status. |
|
movf |
RegL,W |
; Копирование |
содержимого регистра RegL |
|
; в регистр W. |
||||
clrf |
RegH |
; Сброс в 0 содержимого регистра RegH. |
||
;-------------------------------------------------------------------------------- |
||||
; Три последовательных умножения на 2 (умножение на 8). |
||||
;-------------------------------------------------------------------------------- |
||||
rlf |
RegL,F |
; Циклический |
сдвиг влево содержимого |
|
; регистра RegL с сохранением результата |
||||
; в нем же. |
||||
btfsc |
Status,C |
; Опрос состояния бита флага С. |
||
rlf |
RegH,F |
; Если С=1, то циклический |
сдвиг влево |
|
; содержимого |
регистра RegH c переносом в его |
|||
; младший разряд 1 из бита |
флага С, с |
|||
; сохранением |
результата в |
нем же (в RegH). |
||
;-------------------------------------------------------------------------------- |
||||
rlf |
RegL,F |
; Если С=0 (а |
также после исполнения |
|
; предшествующей команды), |
то циклический |
|||
; сдвиг влево |
содержимого регистра RegL с |
|||
; сохранением |
результата в |
нем же. |
||
btfsc |
Status,C |
; Опрос состояния бита флага С. |
||
rlf |
RegH,F |
; Если С=1, то циклический |
сдвиг влево |
|
; содержимого |
регистра RegH с переносом в его |
|||
; младший разряд 1 из бита |
флага С, с |
|||
; сохранением |
результата в |
нем же (в RegH). |
||
;-------------------------------------------------------------------------------- |
||||
rlf |
RegL,F |
; Если С=0 (а |
также после исполнения |
|
; предшествующей команды), |
то циклический |
|||
; сдвиг влево |
содержимого регистра RegL, с |
|||
; сохранением |
результата в |
нем же. |
||
btfsc |
Status,C |
; Опрос состояния бита флага С. |
||
rlf |
RegH,F |
; Если С=1, то циклический |
сдвиг влево |
|
; содержимого |
регистра RegH с переносом в его |
|||
; младший разряд 1 из бита |
флага С, с |
|||
211
;сохранением результата в нем же (в RegH).
;Если С=0 (а также после исполнения
;предшествующей команды), то программа
;исполняется далее (переход к суммированиям)
;--------------------------------------------------------------------------------
;2 последовательных суммирования сохраненного в регистре W множимого, к
;результату умножения множимого на 8.
;-------------------------------------------------------------------------------- |
||
addwf |
RegL,F |
; Сложить содержимое регистров RegL и W с |
; сохранением результата в регистре RegL. |
||
btfsc |
Status,C |
; Опрос состояния бита флага С. |
incf |
RegH,F |
; Если бит С=1, то инкремент содержимого |
; регистра RegH с сохранением результата |
||
; в нем же. |
||
addwf |
RegL,F |
; Если бит С=0 (а также после исполнения |
; предшествующей команды), то сложить |
||
; содержимое регистров RegL и W, с |
||
; сохранением результата в регистре RegL. |
||
btfsc |
Status,C |
; Опрос состояния бита флага С. |
incf |
RegH,F |
; Если бит С=1, то инкремент содержимого |
; регистра RegH, с сохранением результата |
||
; в нем же. |
||
;-------------------------------------------------------------------------------- |
||
........................ |
; Если бит С=0 (а также после исполнения |
|
........................ |
; предшествующей команды), то программа |
|
; исполняется далее. |
......................................
......................................
;********************************************************************************
end ; Конец программы.
Примечание: в конце ПП умножения, вместо сценария "программа исполняется далее", можно использовать сценарий условного или безусловного перехода в подпрограмму, находящуюся в любом "месте" текста рабочей части программы.
В этом случае, после команды последнего инкремента, должна быть исполнена команда call или goto соответственно.
Файл программы умножения на 10, с неформализованными комментариями,
называется Rlf_1.asm (находится в папке "Тексты программ").
Она выглядит так:
;********************************************************************************
;ПРИМЕР ИСПОЛЬЗОВАНИЯ ФЛАГА "C" В ОПЕРАЦИИ УМНОЖЕНИЯ НА 10
;********************************************************************************
; Rlf_1.asm Подпрограмма умножения 8-битных чисел на 10
;********************************************************************************
......................................
......................................
......................................
;================================================================================
;Подпрограмма умножения на 10 однобайтных двоичных чисел (.00 ... .255)
;================================================================================
;Подготовительные операции.
;-------------------------------------------------------------------------------- |
||
bcf |
Status,C |
; Предварительный сброс флага С. |
movf |
RegL,W |
; Копирование содержимого регистра RegL |
; в регистр W. |
||
clrf |
RegH |
; Предварительный сброс содержимого |
; регистра RegH. |
||
;-------------------------------------------------------------------------------- |
||
; Три последовательных умножения на 2 (умножение на 8). |
||
;-------------------------------------------------------------------------------- |
||
rlf |
RegL,F |
; Умножение на 2 числа, записанного в |
; регистре RegL, с сохранением результата |
||
212
; в нем же. |
||||
btfsc |
Status,C |
; Флаг С поднят или опущен |
? |
|
rlf |
RegH,F |
; Если поднят, то циклический сдвиг влево |
||
; содержимого |
регистра RegH с переносом в его |
|||
; младший разряд 1 из бита |
флага С, с |
|||
; сохранением |
результата в |
нем же (в RegH). |
||
;-------------------------------------------------------------------------------- |
||||
rlf |
RegL,F |
; Если опущен |
(а также после исполнения |
|
; предшествующей команды), |
то умножение на 2 |
|||
; числа, записанного в регистре RegL, с |
||||
; сохранением |
результата в |
нем же. |
||
btfsc |
Status,C |
; Флаг С поднят или опущен |
? |
|
rlf |
RegH,F |
; Если поднят, то циклический сдвиг влево |
||
; содержимого |
регистра RegH, с переносом в |
|||
; его младший |
разряд 1 из бита флага С, с |
|||
; сохранением |
результата в |
нем же (в RegH). |
||
;-------------------------------------------------------------------------------- |
||||
rlf |
RegL,F |
; Если опущен |
(а также после исполнения |
|
;предшествующей команды), то умножение на 2
;числа, записанного в регистре RegL, с
;сохранением результата в нем же.
btfsc |
Status,C |
; Флаг С поднят или опущен |
? |
||||
rlf |
RegH,F |
; Если поднят, то циклический сдвиг влево |
|||||
; содержимого |
регистра |
RegH, |
с |
переносом в |
|||
; его младший |
разряд 1 |
из бита |
флага С, с |
||||
; сохранением |
результата в |
нем |
же (в RegH). |
||||
; Если опущен |
(а также |
после |
исполнения |
||||
; предшествующей команды), |
то программа |
||||||
; исполняется |
далее (переход |
к |
суммированиям) |
||||
;--------------------------------------------------------------------------------
;2 последовательных суммирования сохраненного в регистре W множимого к
;результату умножения множимого на 8.
;-------------------------------------------------------------------------------- |
||
addwf |
RegL,F |
; Сложить результат умножения на 8 и множимое |
; (сохраненное в регистре W), с сохранением |
||
; результата в регистре RegL. |
||
btfsc |
Status,C |
; Флаг С поднят или опущен? |
incf |
RegH,F |
; Если флаг С поднят, то инкремент |
; содержимого регистра RegH, с сохранением |
||
; результата в нем же. |
||
addwf |
RegL,F |
; Если флаг С опущен (а также после |
; исполнения предшествующей команды), то |
||
; сложить результат предшествующего |
||
; суммирования и множимое, с сохранением |
||
; результата в регистре RegL. |
||
btfsc |
Status,C |
; Флаг С поднят или опущен? |
incf |
RegH,F |
; Если флаг С поднят, то инкремент |
; содержимого регистра RegH, с сохранением |
||
; результата в нем же. |
||
;-------------------------------------------------------------------------------- |
........................; Если флаг С опущен (а также после
........................; исполнения предшествующей команды), то ; программа исполняется далее.
......................................
......................................
;******************************************************************************** end ; Конец программы.
Всвое время, когда я разбирался с умножением, мне нужно было выбрать: или найти готовую ПП умножения, или составить ее самому.
Я выбрал последнее. Так "родилось сие творение".
И дело даже не в том, что наиболее вероятным результатом подобного рода работы является "изобретение колеса", а в том что после нее, наступает сильнейшее "просветление", и приобретается ценный опыт.
Вконечном итоге, такой "въедливый" и достаточно трудоемкий (на первых порах) стиль
213
"разборок с непонятностями", оказывается гораздо эффективнее, чем достаточно "мутный и ограниченный" стиль работы, связанный с поиском чего-то готового.
При этом, частенько, программист не вдается в детали того, что он находит.
По этой причине, велика вероятность возникновения затруднительных ситуаций. Вплоть до "тупиков".
На мой взгляд, критерием успешности является что-то типа этого: "Зачем искать готовую, нужную программу/подпрограмму? Проще, быстрее и качественнее составить ее самому." Итак, предположим, что нужно составить подпрограмму умножения.
Наиболее сложный "участок уже пройден". Простейший принцип умножения сформулирован. Ну и в чем дело? Как говорится, "вперед и с песней"!
Конструируем подпрограмму умножения однобайтного двоичного числа на 10.
Определяемся с регистрами общего назначения.
Так как множимое является числом, отображаемым одним байтом (.00 ... .255), то такое множимое может быть записано в один регистр общего назначения.
Так как множимое может принять любое значение из диапазона чисел от .00 до .255, то в результате циклических сдвигов, может происходить событие переноса.
Таким образом, максимальное значение произведения не может превысить числа
255х10=.2550
То есть, для отображения такого числа, одного регистра общего назначения мало и необходимо назначить еще один регистр общего назначения.
И в самом деле, двухбайтный регистр способен отобразить число от 0 до 256х256=65536-1=.65535, и число .2550 попадает в этот числовой диапазон.
Так как регистров общего назначения стало 2, то нужно определиться с порядком старшинства.
Под младший байт произведения (он же - байт множимого), "прописываем" регистр общего назначения с названием, например, RegL.
Вэтом байте будет осуществляться циклический сдвиг влево, и он же будет младшим байтом произведения.
Под старший байт произведения, "прописываем" регистр общего назначения с названием, например, RegH.
Вэтот байт, в ходе последовательных процедур умножения на 2, будут осуществляться переносы.
Теперь нужно определиться с начальными условиями.
Для этого нужно ответить на вопрос: "Какие числа должны быть записаны в регистры RegL, RegH и в бит флага С на момент начала исполнения первого, циклического сдвига?" Ответ: в регистр RegL будет записываться число множимого.
Байт регистра RegH нужно сбросить в 0 (clrf RegH).
Впротивном случае, это равносильно наличию переносов, которых не было, что неприемлемо (увеличенное, по сравнению с истинным, значение произведения). Бит флага С нужно сбросить в 0 (bcf Status,C).
Впротивном случае, результат умножения будет не верен.
Посмотрите в текст программы.
В"подготовительных операциях", Вы увидите обе этих команды.
В"шапке" программы, Вы увидите, что регистры RegL, RegH, а также и регистр Status, "введены в эксплуатацию" ("прописаны").
Исходя из сформулированных выше условий, ПП умножения должна содержать не только группы команд умножения на 2, но и группы команд суммирования, причем, одним из слагаемых обязательно должно быть множимое, и операции сложения должны исполняться после завершения операции умножения на 8 (3-х операций умножения на 2). Следовательно, в "подготовительных операциях" нужно сохранить множимое в каком-то регистре.
Под это дело, можно "прописать" еще один (третий) регистр общего назначения, а можно и скопировать множимое в регистр W, так как он, при исполнении процедур умножения на 2, не задействуется.
Поэтому, необходимости в увеличении количества задействованных регистров общего назначения, нет.
Вполне можно обойтись и двумя.
Следовательно, с целью дальнейшего использования множимого в группах команд
214
суммирования, в "подготовительных операциях", с помощью команды movf RegL,W, нужно сохранить множимое в регистре W.
Итак, группа команд "подготовительных операций" сформирована. Порядок их расположения, в этой группе, не имеет значения.
Можно "перетасовать их, как карты". Это не отразится на результате работы подпрограммы, так как все 3 команды "развязаны" относительно друг друга.
Теперь можно заняться "конструированием" группы команд умножения на 2.
Возникает вопрос: "Какие именно команды должны входить в группу команд умножения на 2 и в каком порядке, в пределах этой группы, они должны располагаться?"
Исходя из сказанного ранее, однозначным является то, что первой должна следовать команда циклического сдвига влево rlf RegL,F, а второй, команда опроса бита флага С (btfsc Status,C), а также и то, что перенос, в случае его наличия, должен осуществляться в младший разряд старшего байта (в регистр RegH).
Что дальше? Каким образом должно происходить "взаимодействие" младшего и старшего байтов при переносах?
На момент начала первого циклического сдвига влево, в регистре RegH установлен 0, и в дальнейшем, от переноса к переносу, значения чисел, "лежащих" в регистре RegH, должны только увеличиваться.
Вопрос: "По какому закону?"
Могут быть следующие варианты: суммирование, инкремент, циклический сдвиг влево. Суммирование отпадает, так как в этом случае, задача, в конечном итоге, сводится к "привязке" к нескольким значениям констант, практически реализовать которую очень затруднительно.
Инкремент, на первый взгляд, для операции суммирования, приемлем, но в этом случае, результат умножения будет отличаться от истинного.
Чтобы проверить правильность этого высказывания, давайте немного "погоняем нули с единицами на бумаге".
Умножим, например, число .194 (11000010) на 8 (2х2х2), применив, для переносов в старший байт, команды инкремента.
194 00000000 11000010 ; множимое, в бите С - ноль.
388 00000001 10000100 ; в бит С "пришла" 1 из старшего бита младшего байта, следовательно, инкремент старшего байта.
52100000010 00001001 ; из бита С "ушла" 1 в младший бит младшего байта,
вбит С "пришла" 1 из старшего бита младшего байта,
следовательно, инкремент старшего байта.
53100000010 00010011 ; из бита С "ушла" 1 в младший бит младшего байта,
вбит С "пришел" 0 из старшего бита младшего байта, следовательно, инкремента старшего байта нет.
В идеале, должен получиться результат 194х8=.1552, а получилось .531.
Вывод: при организации умножения посредством последовательных, "многоступенчатых" процедур умножения на 2, операции инкремента, для организации переносов в старший байт, применять нельзя.
Проанализировав результат (нужно .1552, а получилось .531), можно прийти к выводу, что при формировании нескольких переносов, наращивание значений чисел, формируемых в регистре RegH, должно происходить значительно бОльшими "темпами", чем в случае применения операций инкремента.
Исходя из этого, на "роль палочки - выручалочки претендует" все та же операция циклического сдвига влево, только применяемая по отношению к содержимому старшего байта.
И в самом деле, она эквивалентна операции умножения на 2, что обеспечивает более высокие "темпы прироста", чем при применении операции инкремента.
Таким образом и "родилась" группа команд умножения на 2, которые можно последовательно ("цепочкой") соединять между собой.
Посмотрите в текст программы.
Вы видите "цепочку" из трех групп команд умножения на 2 (умножение на 8).
Может возникнуть вопрос: "Как два байта делят между собой один бит флага С, ведь они оба работают с ним?"
А так и работают - по очереди.
215