Файл: Самоучитель по программированию 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