Файл: Самоучитель по программированию PIC контроллеров для начинающих (Е.А. Корабельников,2008).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 16.06.2025
Просмотров: 3618
Скачиваний: 3
;********************************************************************************
START ......................................
......................................
YES ......................................
......................................
goto PLUS
......................................
......................................
;================================================================================
;Суммирование двух трехбайтных двоичных чисел. Результат суммирования -
;трехбайтное двоичное число.
;================================================================================
PLUS |
movf |
RegL,W |
; Скопировать содержимое регистра RegL |
|
; в регистр W. |
||||
addwf |
TimerL,F |
; Сложить содержимое регистров W и TimerL с |
||
; сохранением результата в регистре TimerL. |
||||
btfss |
Status,C |
; Опрос бита № |
0 (флага С) регистра Status. |
|
goto |
PLUS_1 |
; Если бит № 0 |
=0, то переход в ПП PLUS_1. |
|
incf |
TimerM,F |
; Если бит № 0 |
=1, то инкремент содержимого |
|
;регистра TimerM с сохранением результата
;в нем же.
btfss |
Status,Z |
; Опрос бита № |
2 (флага Z) регистра Status. |
||
goto |
PLUS_1 |
; Если бит |
№ 2 |
=0, то переход в ПП PLUS_1. |
|
incf |
TimerH,F |
; Если бит |
№ 2 |
=1, то инкремент содержимого |
|
; регистра |
TimerH с сохранением результата |
||||
; в нем же. |
|||||
PLUS_1 |
movf |
RegM,W |
; Скопировать содержимое регистра RegM |
||
; в регистр W. |
|||||
addwf |
TimerM,F |
; Сложить содержимое регистров W и TimerM с |
|||
; сохранением результата в регистре TimerM. |
|||||
btfsc |
Status,C |
; Опрос бита № |
0 (флага С) регистра Status. |
||
incf |
TimerH,F |
; Если бит |
№ 0 |
=1, то инкремент содержимого |
|
; регистра |
TimerH с сохранением результата |
||||
; в нем же. |
|||||
movf |
RegH,W |
; Если бит |
№ 0 |
=0, то скопировать содержимое |
|
; регистра |
RegH в регистр W. |
||||
addwf |
TimerH,F |
; Сложить содержимое регистров W и TimerH с |
|||
; сохранением результата в регистре TimerH. |
|||||
goto |
YES |
; Безусловный переход в ПП YES. |
|||
;-------------------------------------------------------------------------------- |
|||||
......................................
......................................
;********************************************************************************
end ; Конец программы.
=================================================================================
АРИФМЕТИЧЕСКИЕ ПРИМЕРЫ СУММИРОВАНИЙ
=================================================================================
Случай отсутствия переносов
---------------------------------------------------------------------------------
80 |
120 |
100 |
|
60 |
50 |
100 |
|
---------------- |
|||
140 |
170 |
200 |
Значения чисел сумм не превышают 255. |
---------------------------------------------------------------------------------
Случай наличия переносов № 1
---------------------------------------------------------------------------------
Младший разряд |
||
150 |
120 |
100 |
100 |
180 |
200 |
-------------------------------- |
||
250+1=251 |
300+1-256=45 300-256=44 |
|
-------------------------------- |
||
251 |
45 |
44 |
202
При суммировании младших и средних разрядов значения сумм превысили 255 (2 переноса).
---------------------------------------------------------------------------------
Случай наличия переносов № 2. Дополнительно задействуется флаг Z (опрос его состояния).
---------------------------------------------------------------------------------
Младший разряд |
||
150 |
130 |
100 |
100 |
125 |
200 |
--------------------------------- |
||
250+1=251 |
255+1-256=0 |
300-256=44 |
--------------------------------- |
||
251 |
0 |
44 |
При суммировании младших и средних разрядов значения сумм превысили 255 |
||
(2 переноса). |
||
---------------------------------------------------------------------------------
Файл программы, с неформализованными комментариями, называется c_dc_1.asm
(находится в папке "Тексты программ").
Это выглядит так:
;********************************************************************************
;ПРИМЕР ИСПОЛЬЗОВАНИЯ ФЛАГА "C" (А ТАКЖЕ И ФЛАГА "Z")
;********************************************************************************
; c_dc_1.asm Стандартная подпрограмма суммирования двух трехбайтных чисел
;********************************************************************************
......................................
......................................
......................................
......................................
;================================================================================
;Суммирование двух трехбайтных двоичных чисел. Результат суммирования -
;трехбайтное двоичное число.
;================================================================================
PLUS |
movf |
RegL,W |
; Скопировать |
содержимое регистра RegL |
|
; в регистр W. |
|||||
addwf |
TimerL,F |
; Сложить содержимое регистров W и TimerL с |
|||
; сохранением |
суммы в регистре TimerL. |
||||
btfss |
Status,C |
; Флаг С поднят? |
|||
goto |
PLUS_1 |
; Если нет, то переход в ПП PLUS_1. |
|||
incf |
TimerM,F |
; Если да, то |
инкремент содержимого |
регистра |
|
; TimerM с сохранением результата в |
нем же. |
||||
btfss |
Status,Z |
; Флаг Z поднят? |
|||
goto |
PLUS_1 |
; Если нет, то переход в ПП PLUS_1. |
|||
incf |
TimerH,F |
; Если да, то |
инкремент содержимого |
регистра |
|
; TimerH с сохранением результата в |
нем же. |
||||
PLUS_1 |
movf |
RegM,W |
; Скопировать |
содержимое регистра RegM |
|
; в регистр W. |
|||||
addwf |
TimerM,F |
; Сложить содержимое регистров W и TimerM с |
|||
; сохранением |
суммы в регистре TimerM. |
||||
btfsc |
Status,C |
; Флаг С поднят? |
|||
incf |
TimerH,F |
; Если да, то |
инкремент содержимого |
регистра |
|
; TimerH с сохранением результата в |
нем же. |
||||
movf |
RegH,W |
; Если нет, то скопировать содержимое |
|||
; регистра RegH в регистр W. |
|||||
addwf |
TimerH,F |
; Сложить содержимое регистров W и TimerH с |
|||
; сохранением |
результата в регистре |
TimerH. |
|||
goto |
YES |
; Безусловный |
переход в ПП YES. |
||
;-------------------------------------------------------------------------------- |
|||||
......................................
......................................
Проект под них создавать не нужно.
203
Просто откройте их в MPLAB (File Open).
Вы видите перед собой подпрограмму, которая реализует трехбайтное, суммирующее устройство.
Вданном случае, осуществляется суммирование 3-хбайтного результата измерения частоты и 3-хбайтной поправки (константы), которая представляет собой значение установленной пользователем (или по умолчанию) промежуточной частоты (пример взят из программы частотомера-цифровой шкалы).
Вспомните первый случай вычисляемого перехода, который был рассмотрен ранее. Одной из команд этого вычисляемого перехода является команда goto PLUS.
Таким образом, при наличии определенного состояния клавиатуры, происходит безусловный переход в ПП PLUS, в которой и осуществляется указанное выше суммирование.
Теперь нужно кое-что пояснить.
Микроконтроллер работает только с двоичными числами.
То, что в тексте программы, форма представления чисел может быть иной, это всего-лишь "элемент" удобства (спасибо разработчикам MPLAB).
Вконечном итоге, все сведётся к той или иной разновидности двоичных чисел, с которыми и будет происходить работа.
Пример.
Предположим, что возникла необходимость в отображении символов десятичной системы исчисления.
Например, в линейке индикаторов или в жидкокристаллическом модуле.
Для того чтобы "провернуть это дельце", сначала нужно произвести соответствующие операции с классическими, двоичными числами, вплоть до получения двоичного числа результата.
После этого, нужно перевести классическое, двоичное число результата, в двоичнодесятичную форму (разновидность двоичной формы чисел).
После этого, нужно осуществить перекодировку двоично-десятичных чисел под те индикаторы, которые применяются (еще одна разновидность двоичной формы чисел). После этого, результат такого перекодирования можно вывести на индикацию.
Влюбом из этих случаев, происходит работа с двоичными числами.
Вернее, с теми или иными их разновидностями.
Как осуществляется перекодирование, было рассмотрено ранее (второй пример вычисляемого перехода), а как осуществляется перевод двоичных чисел в двоичнодесятичные, будет рассмотрено позднее.
Сейчас же, я покажу, как формируется трехбайтное двоичное число, предназначенное для дальнейшего отображения в линейке из 7-ми 7-сегментных индикаторов частотомера - цифровой шкалы (работа в подрежиме суммирования результата измерения и значения промежуточной частоты).
Подпрограмма PLUS_1 находится внутри подпрограммы PLUS.
Следовательно, если речь идет о ПП PLUS, то имеются ввиду все команды подпрограммы, включая и команды, входящие в состав ПП PLUS_1.
Вспомните то, о чем говорилось в разделе, посвященному работе с EEPROM памятью данных.
Вее ячейки, предварительно, можно записывать какие-нибудь числа, которые затем используются в работе программы.
Врассматриваемом случае, в 3 ячейки EEPROM памяти данных, с учетом порядка старшинства, записывается, предварительно вычисленное программистом, трехбайтное, двоичное число, которое задает значение промежуточной частоты.
После включения питания, числа из этих ячеек, с соблюдением порядка старшинства, копируются в регистры RegH, RegM, RegL (см. текст программы).
Врегистрах TimerH, TimerM, TimerL, на момент начала исполнения ПП PLUS, находится трехбайтное, двоичное число результата измерения частоты.
ВПП PLUS, cуммирование происходит побайтно, начиная с младших байтов слагаемых. То есть, сначала производится суммирование содержимого регистров RegL и TimerL, затем
RegM и TimerM, а затем RegH и TimerH.
После выполнения команд сложения, производится опрос состояния флага С, по результатам которого делается вывод о наличии или отсутствии необходимости переноса в более старший разряд (инкремента содержимого, следующего по разрядности, регистра Timer). Критерий прост: превышение или нет, числовым значением суммы, "границы" числового
204
диапазона байта (числа .255).
Если это превышение есть, то флаг С поднимается, и по факту этого, далее, осуществляется инкремент (+1) содержимого следующего, по старшинству, регистра.
"С другого бока": если такой инкремент происходит, то это означает то, что осуществлен перенос в следующий, по старшинству, разряд трехбайтного регистра
TimerH/TimerM/TimerL.
При наличии этого переноса, значение байта следующего, по старшинству, регистра TimerM(H), сначала увеличивается на 1, а затем, получившийся результат, суммируется с содержимым регистра RegM(H).
Если после суммирования, переноса нет (С=0), то инкремента содержимого следующего, по старшинству, регистра не происходит (команда инкремента обходится).
После исполнения команд сложения, их результаты сохраняются все в тех же регистрах Timer (c "привязкой" к соответствующим разрядам L, M, H).
Обращаю Ваше внимание на то, что инкремента содержимого младшего байта (переноса в младший байт), находящегося в регистре TimerL, никогда не происходит.
По той причине, что он младший и переносить в него нечего.
Таким образом, в данном случае, перенос может происходить только из младшего разряда L, в средний разряд M и из среднего разряда M, в старший разряд H.
Так как перенос из самого старшего разряда осуществлять некуда, то программист должен рассчитать количество разрядов многобайтного регистра таким образом, чтобы исключить переполнение регистра самого старшего разряда (того, в котором сохраняется результат суммирования).
То есть, в части касающейся суммирования чисел самого старшего разряда, арифметический результат суммирования не должен превышать .255.
В противном случае, произойдет "выход на второй виток счета" (неверный результат суммирования).
Например, 3-хбайтный регистр сможет безошибочно отобразить числа от 0 до 256х256х256-1=16777215.
Если нужно отобразить результат суммирования больший, чем 16777215, то нужно организовывать 4-байтный регистр (добавить регистры RegHH и TimerHH) и соответственно, добавить, в подпрограмму PLUS, команды, организующие суммирование содержимого регистров RegHH и TimerHH, а также и перенос из разряда H в разряд HH.
Снизу от директивы end, Вы видите "арифметические примеры суммирований".
Пример № 1: случай отсутствия переносов.
В этом случае, связи между байтами не работают (так как переносов нет), и просто осуществляется последовательные, побайтные суммирования, в пределах пары одноименных байтов (L+L, M+M, H+H) регистров Reg и Timer, начиная с младших байтов
(RegL+TimerL=… ).
Результаты анализов состояний битов C и Z будут нулевыми.
По этой причине, рабочая точка программы будет "обходить стороной" все команды инкрементов.
Пример № 2: случай наличия переносов в разряды M и H, при отсутствии нулевого результата операций суммирования.
Побайтное суммирование начинается с младших байтов (L) регистров Reg и Timer.
Врезультате этого суммирования, происходит "выход" на второе кольцо 8-битного, полного цикла чисел (переполнение), и флаг С поднимается ("сигнал" переноса в следующий разряд). После опроса состояния флага С, рабочая точка программы уходит в сценарий "инкремент содержимого регистра TimerM", что и есть практическое осуществление переноса.
После этого, происходит суммирование байтов средних разрядов (M) регистров Reg и Timer.
Врезультате этого суммирования, также происходит "выход" на второе кольцо 8-битного, полного цикла чисел (с учетом предшествующего инкремента содержимого регистра TimerM), и флаг С снова поднимается.
После этого, рабочая точка программы уходит в сценарий "инкремент содержимого регистра TimerH", что также есть практическое осуществление переноса.
После этого, происходит суммирование байтов старших разрядов (H) регистров Reg и Timer.
Вэтом случае, переноса быть не должно (мотивация - см. выше).
Всё. Процесс суммирования завершен.
205
После этого (а также и в других случаях) исполняется команда goto YES, и рабочая точка программы "покидает" ПП PLUS для того чтобы далее "делать какие-нибудь полезные дела". Если предположить, что ПП PLUS входит в состав программы частотомера-цифровой шкалы, то после выхода рабочей точки программы из ПП PLUS, происходит ее безусловный переход в подпрограммы преобразования двоичных чисел в двоично-десятичные, затем, в ПП кодирования, после чего, результат перекодировки выводится в порт, для отображения в линейке 7-сегментных индикаторов.
Пример № 3: случай наличия переносов в разряды M и H, при наличии нулевого результата операции суммирования байтов (слагаемые - не нулевые).
Его разница с примером № 2 заключается в том, что при суммировании чисел, "лежащих" в "средних" байтах (M) регистров Reg и Timer, "выход" на второе кольцо 8-битного полного цикла чисел происходит на число равное нулю.
Вэтом случае, поднимается флаг нулевого результата Z, и перенос в старший разряд (то есть, инкремент содержимого регистра TimerH) осуществляется после опроса состояния не флага С, а флага Z.
Сразу возникает вопрос: "А какова надобность задействования, для переноса, флага нулевого результата Z, ведь казалось бы, можно обойтись только флагом С"?
Существуют такое понятие, как "наихудший вариант", на который всегда (а не только в этом случае) нужно ориентироваться.
Вданном случае, он выглядит так: в регистре "лежит" число .255, а из более младшего разряда, осуществлен перенос.
Вэтом случае, .255+1(перенос)=256-256=.0 (выход на самое начало 2-го "витка").
То есть, должен быть осуществлен инкремент содержимого следующего, по старшинству, байта.
Давайте разбираться.
Для данной программы, при суммировании разрядов L (addwf TimerL,F), флаг С работает, так как применяется команда (addwf), влияющая на его состояние (см. распечатку команд). По этой причине, перенос в разряд M (при его наличии) будет безошибочно осуществлен. А вот при организации переноса, из разряда M, в разряд H, в рассматриваемом случае, анализ состояния флага С просто бесполезен, так как флаг С не "реагирует" на команду incf (см. распечатку команд).
То есть, после инкремента числа .255, флаг С как был опущенным, так он таким и останется. Соответственно, инкремента содержимого регистра TimerH произведено не будет, что есть ошибка суммирования.
Значит нужно "искать заменитель".
На числовой результат исполнения команды incf реагирует только флаг Z (см. распечатку команд), и состояние этого флага обязательно нужно опросить.
Соответственно, при организации переноса, из разряда M, в разряд H, для "нейтрализации вышеобозначенной бяки", организована группа команд анализа состояния флага Z.
Общий принцип: при наличии переноса, к содержимому регистра следующего, по
старшинству разряда, тем или иным способом, нужно прибавить единицу. При отсутствии переноса, единица не прибавляется.
"Наихудший вариант" выглядит так (один из примеров):
150 255 255
0 0 1
151 0 0
С суммированием младших байтов (L), нет никаких проблем:
.255+.01=.256=.00 плюс перенос (инкремент) в регистр разряда M.
После инкремента содержимого регистра разряда M, флаг Z поднимется, после чего содержимое регистра разряда H будет увеличено на единицу: .150+.0+.1переноса=.151 Этот способ организации переносов, внутри многобайтного регистра, и реализован в предлагаемой Вашему вниманию ПП PLUS.
Предоставляется прекрасный повод для тренировки в составлении блок-схемы подпрограммы, и я советую Вам это сделать.
В дальнейшем, проще будет "ориентироваться".
ПП PLUS является типичным образцом подпрограммы с достаточно "развитой" системой
206