Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Эрни Каспер Программирование на языке Ассемблер...doc
Скачиваний:
120
Добавлен:
09.11.2019
Размер:
954.88 Кб
Скачать

Глава 3.

3.Кросс-средства фирмы 2500 a.D. Software, Inc. Для семейства i8051

Глава 4

4.Программирование арифметических действий

4.1.Кодирование информации в микроконтроллере

Микроконтроллер и управляемый им объект входят в состав изделия, взаимодействующего с пользователем. При помощи периферийных устройств микроконтроллер получает информацию о состоянии объекта и выдает команды управления объектом, а также воспринимает команды пользователя и выдает сигналы пользователю. Вся информация для осуществления этих действий представляется в микроконтроллере в виде двоичных кодов. На начальном этапе программирования необходимо четко определить полный состав информации, которая используется для взаимодействия микроконтроллера с управляемым объектом и с пользо­вателем изделия, и выбрать рациональные способы кодирования этой информации. Программисту приходится заниматься всеми подробностями кодирования информации в связи с отсутствием операционной системы и сервисных программ в условиях строго ограниченных ресурсов.

Кодирование информации для обмена с периферией определяется интерфейсом микросхем, с которыми связан микроконтроллер, и/или электрической схемой устройства. При выборе способа кодирования информации, используемой в микроконтроллере для решения задач управления объектом, программист должен исходить из критериев наиболее эффективного ее представления с точки зрения использования объема памяти и скорости работы программы. Поэтому кодирование внутренних переменных в микроконтроллере должно соответствовать системе команд, используемых при их обработке. Для обработки внутренних переменных, которые могут быть представлены неотрицательными целыми числами в формате байта, наиболее целесообразно использовать 8-разрядный позиционный двоичный код. В этом случае система команд микрокон­троллеров семейства i8051 обеспечивает обработку информации посред­ством прямого и обратного счета, сложения, вычитания, умножения и деления.

Но в микроконтроллере приходится кодировать значительно более разнообразную числовую информацию. На практике число может быть получено одним из двух принципиально различных способов: счетом или измерением. В случае счета количества предметов или определения их порядковых номеров получаются целые числа. Неправильное (не соответ­ствующее истинному положению вещей) определение целого числа является ошибкой (mistake). В случае измерения числа получаются сопос­тавлением двух сопоставимых характеристик объектов или процессов, одна из которых может изменяться, а другая выбрана в качестве эталона. При этом число не обязательно должно быть целым и в принципе опреде­ляется с некоторой погрешностью (error). При выборе способа представ­ления чисел нужно четко различать, какого рода числа используются и обрабатываются программой. Использование двоичных кодов в микрокон­троллере не исключает возможностей представления чисел в десятичной системе счисления. Но ее лучше применять для взаимодействия с пользо­вателем, а для внутреннего представления чисел целесообразнее исполь­зовать двоичную систему.

Начнем с кодирования положительных целых чисел в позиционной системе, характеризующейся использованием символов, называемых цифрами. Общее количество цифр, используемых в любой системе счисле­ния, равно ее основанию (включая цифру 0). Цифра 0 представляет ника­кое количество независимо от положения в записи числа. Количественное значение остальных цифр зависит от их позиции (положения) в записи числа. Поясним сказанное на примере двоичной системы счисления, использующей наименьшее количество цифр: 0 и 1. Количественное значение цифры 1 рассмотрим на примере представления положительного целого числа байтом, состоящим из 8 двоичных разрядов с номерами от нулевого (самый младший разряд расположен справа) до седьмого (самый старший разряд расположен слева). "Вес" цифры 1 для О, 1, 2, 3, 4, 5, 6 и 7 разрядов не одинаков и составляет соответственно 1, 2, 4, 8, 16, 32, 64 и 128, то есть удваивается при переходе на 1 разряд влево. Таким образом 1 байт может быть использован для представления всех (без изъятия!) положительных целых чисел от 0 до 255. При необходимости записи положительных чисел превышающих 255 нужно использовать более 1 байт. Например, двоичное "слово", состоящее из двух байтов, может представлять все положительные целые числа от 0 до 65535.

Но это не единственный способ кодирования положительных целых чисел. В технике часто используется двоичный рефлексный код, назы­ваемый также кодом Грея. Ниже приведена таблица 4-разрядных позици­онного и рефлексного двоичных кодов.

Десятичное число

Шестнадцатеричная цифра

Позиционный код

Рефлексный код

0

0

0000

0000

1

1

0001

0001

2

2

0010

ООН

3

3

ООН

0010

4

4

0100

ОНО

5

5

0101

0111

б

6

0110

0101

7

7

0111

0100

8

8

1000

1100

9

9

1001

1101

10

А

1010

1111

11

В

1011

1110

12

С

1100

1010

13

D

1101

1011

14

Е

1110

1001

15

F

1111

1000

Рефлексный код удобен для использования в некоторых типах преобразова­телей аналогового сигнала в цифровой. Изменение содержимого только одного разряда при переходе сигнала с одного уровня на другой обеспечивает отсутствие ошибок преобразования, хотя оно не может устранить погреш­ность. Для тех, кого интересует общее правило получения рефлексного кода, укажем алгоритм его получения из позиционного. Для получения рефлексного кода нужно вычислить функцию неравнозначности (ИСКЛЮ­ЧАЮЩЕЕ ИЛИ) от исходного числа и его частного, полученного делением на два. На практике бывает необходимо выполнять обратное преобразо­вание, но оно немного сложнее и будет рассмотрено позднее.

Преимущество позиционного представления чисел состоит в том, что, во-первых, для представления любых сколь угодно больших чисел используются одни и те же цифры, во-вторых, все арифметические опе­рации со сколь угодно большими числами могут быть выполнены как конечная последовательность единообразных действий с цифрами, пред­ставленными в отдельных разрядах этих чисел. Разумеется, при этом необходимо выполнять эти действия в определенной последовательности и учитывать результат выполнения действий с предшествующими разря­дами. А правила всех поразрядных арифметических операций сводятся к таблице сложения и таблице умножения, имеющих для двоичной системы счисления наипростейший (по сравнению с остальными системами счисле­ния) вид:

0 + 0 = 0

0 + 1 = 1

1 + 0 = 1

1 + 1 = 10

0*0 = 0

0*1 = 0

1*0 = 0

1*1 = 1

Таблица умножения в двоичной системе оказалась проще таблицы сло­жения потому, что произведение двух цифр не выходит за пределы одного разряда, а значение суммы может выйти за его пределы. Это всем известный перенос, который школьники учатся "держать в уме". По этой причине таблица сложения должна быть дополнена для случая переноса из преды­дущего разряда.

Перенос 0 Перенос 1

0 + 0 = 0 1

0 + 1 = 1 10

1 + 0 = 1 10

1 + 1 = 10 11

Приведенных сведений вкупе с опытом школьных упражнений по сложе­нию, вычитанию, умножению и делению "столбиком" (как говаривали старые учителя, "по Маленину-Буренину") в последующем будет вполне достаточно для самостоятельной проверки читателями корректности приведенных программ арифметических вычислений.

При прямом счете, сложении и умножении положительных чисел всегда получаются положительные числа. В микроконтроллерах семейства i8051 выход результата прямого счета за пределы разрядной сетки никак не контролируется. Выход результата сложения положительных чисел за пределы одного байта приводит к установке бита переноса в 1. Выход результата умножения положительных чисел за пределы одного байта приводит к установке бита переполнения в 1. Если результат операции выходит за пределы байта, то для его правильного представления нужно использовать дополнительные двоичные разряды. Способ кодирования при этом не изменяется, но нужно рассмотреть способы обработки чисел, представленных несколькими байтами. Результатом обратного счета или вычитания могут быть отрицательные числа. Получение отрицательного числа в результате обратного счета никак не контролируется. Выход результата вычитания за пределы представления положительного числа приводит к установке бита переноса в 1. Для работы с отрицательными числами необходимо рассмотреть, во-первых, вопросы их кодирования, а во-вторых, возможности обработки этих кодов существующим набором команд. Отложив программирование арифметических действий с много­байтными и отрицательными кодами, остановимся на кодировании отри­цательных чисел.

Поскольку одним байтом может быть закодировано только 255 чи­сел, приходится ограничиться представлением положительных чисел до +127, при этом 7 разряд используется для кодирования знака и для поло­жительных чисел принимается равным 0. Для отрицательных чисел можно принять значение 7 разряда равным 1. Остается выбрать кодиро­вание для остальных разрядов. Традиционно применяемый в текстах способ записи числа в виде знака и модуля использовался и для двоичного кодирования в некоторых вычислительных машинах, потому что был удобным для аппаратной реализации умножения и деления. Для системы команд 18051 при кодировании чисел знаком и модулем ни одна арифме­тическая операция не обеспечит корректных результатов. Однако сущест­вует кодирование, при котором корректно выполняются операции прямо­го и обратного счета, сложение и вычитание. Приведем пример обратного счета в случае 4-разрядного двоичного кода от числа +7 до числа -8.

Десятичное

Двоичный

число

код

+ 7

0111

+ 6

0110

+ 5

0101

+ 4

0100

+ 3

0011

+2

0010

+ 1

0001

0

0000

-1

1111

-2

1110

-3

1101

-4

1100

-5

1011

-6

1010

-7

1001

-8

1000

Для отрицательных чисел такой код называется дополнительным, потому что он дополняет код соответствующего (равного по модулю) положи­тельного числа до количества кодируемых чисел (для 4 разрядов — до 16, для байта — до 256, а для слова — до 65536). (Для числа -8 в этой таблице соответствующего положительного числа нет, а число 0 неотрицательное.) При кодировании отрицательных чисел дополнительным кодом знаковому разряду байта нужно приписать вес -128, а знаковому разряду слова — вес -32768. Такой вариант кодирования позволяет представить одним байтом все числа от-128 до +127., а двумя байтами — числа от -32768 до +32767.

Арифметические операции ADD (ADDC) и SUBB при использовании дополнительного кода выполняются корректно. Если результат сложения или вычитания выходит за пределы представления чисел со знаком, то бит переполнения устанавливается в 1. Следует отметить нежелатель­ность использования в однобайтовых арифметических операциях кодов, представляющих -128 для одного байта и -32768 для двух байтов, из-за отсутствия кодов представляющих соответствующие положительные числа. В операции обратного счета DEC результатом уменьшения 0 на 1 является код, соответствующий числу 255 для кодирования чисел без знака или числу -1 для кодирования со знаком. При выполнении этой операции признак переполнения также не вырабатывается. Аналогичным образом работает и INC, так что результаты обеих операций будут неверны при выходе за пределы представления чисел заданным кодом. При коди­ровании целых чисел без знака это будет увеличение 255 для INC и уменьшение 0 для DEC, а при кодировании целых чисел со знаком -увеличение 127 и уменьшение -128 соответственно. Но выполнение этих команд не влияет на содержимое битов переноса и переполнения. Ариф­метические операции MUL и DIV не обеспечивают корректных результатов и при кодировании отрицательных чисел дополнительным кодом, поэтому умножение и деление с отрицательными операндами нужно программиро­вать особо.

До тех пор пока арифметические операции (кроме деления) использу­ются для работы с целыми числами, полученными посредством счета, их результаты будут точными. Для представления результата операции деления в общем случае нужны дробные числа. Дробные числа нужны и для представления чисел, полученных посредством измерений. В этом случае есть два подхода. Наиболее универсальным является представление чисел при помощи порядка и мантиссы. Но в микроконтроллере использование чисел с плавающей запятой вряд ли целесообразно с точки зрения расхо­да его ресурсов, хотя для карманных калькуляторов это оправдано их назначением. Более рационально применять такой выбор масштабов, чтобы использовать целые числа или числа с фиксированной запятой. Поэтому здесь рассматривается только программирование арифметических операций с целыми числами.