Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
AVR / 1_Uniproff / Лабораторный практикум 2.doc
Скачиваний:
44
Добавлен:
20.03.2015
Размер:
395.78 Кб
Скачать

Выполнение арифметических операций. Обмен данными с eeprom.

Цель работы:изучение способов организации и исследование программ выполнения арифметических операций; изучение организации обмена данными микропроцессора с EEPROM.

Краткие сведения из теории

Из двух способов определения чисел с фиксированной и плавающей точкой, первый получил наибольшее распространение при программировании восьмиразрядных микропроцессоров. Это связано с отсутствием специальных команд, позволяющих оперировать микропроцессору числами с плавающей точкой.

Число с фиксированной точкой можно представить двоичными числами без знака, имеющими значения от 0 до 255. В свою очередь, двоичное восьмиразрядное число с фиксированной точкой можно представить как число со знаком, имеющее значение от –128 до +127. При этом отрицательные числа представляются в дополнительном коде, а старший, седьмой, разряд числа используется как знаковый. Такое представление чисел не позволяет выполнять арифметические операции с использованием переноса при сложении и заема при вычитании.

Проведение арифметических операций сложения, вычитания, умножения, деления, вычисления специальных функций рассмотрим на примерах соответствующих подпрограмм.

Программа сложения массива однобайтных чисел с получением двухбайтного результата – П-3.1. Слагаемые должны быть расположены в последовательных адресах памяти. Входными параметрами подпрограммы являются адрес первого слагаемого, записанный в регистровую пару Z, и число слагаемых, записанное в регистре R16. Выходным параметром подпрограммы является сумма, записанная в паре регистров R1:R0. Алгоритм программы сложения состоит в том, что после прибавления каждого элемента массива определяется переполнение R0 (флаг C=1), и если это имеет место, то содержимое регистра R1 увеличивается на 1. Таким образом, за счет суммирования единиц переноса получается старший байт суммы.

П-3.1

Адрес

Маш. код

Метка

Мнемокод

Комментарий

0000

ED0F

MAIN:

LDI R16,0xDF

Главная программа

Устанавливаем указатель стека

0001

BF0D

OUT 0x3D,R16

0002

E6E0

LDI R30,0x60

Устанавливаем указатель Z на начало массива данных

0003

27FF

CLR R31

0004

E005

LDI R16,0x05

Указываем размер массива (5 элементов)

0005

D001

RCALL ADDB

Вызов подпрограммы сложения

0006

9508

RET

Завершение программы

0007

2400

ADDB:

CLR R0

Очищаем регистры выходного параметра R0

0008

2C10

MOV R1,R0

и R1.

0009

9021

NEXT:

LD R2,Z+

Загружаем из памяти по адресу Z(R31:R30) элемент массива в регистр R2; при этом Z увеличивается на 1.

000A

0C02

ADD R0,R2

Прибавляем R2 к R0 (без учета переноса).

000B

F408

BRCC NO_C

Если нет переполнения – переход на NO_C,

000C

9413

INC R1

иначе – увеличиваем R1 на 1.

000D

950A

NO_C:

DEC R16

Уменьшаем кол-во элементов, которые осталось просуммировать.

000E

F7D1

BRNE NEXT

Если элементы еще есть, то переход на NEXT,

000F

9508

RET

иначе – возврат из подпрограммы ADDB.

Микропроцессор может производить арифметические операции с числами двойной или большей длиной машинного слова. Так как МП имеет 8-разрядное АЛУ, то операции с такими числами должны проводиться по байтам начиная с младших байтов. Например, операция сложения чисел 17F5+3411 будет проводиться в следующем виде:

Старший байт

Флаг С

Младший байт

Числа

00010111

+

11110101

+

17F5

+

00110100

00010001

3411

+1

 1 (перенос)

01001100

00000110

4C06

Операция вычитания чисел 6F5C-13C5 будет осуществляться в таком виде виде:

Старший байт

Флаг С

Младший байт

Числа

01101111

-

01011100

-

6F5C

-

00010011

11000101

13C5

-1

 1 (заем)

01011011

10010111

5B97

Из приведенных примеров видно, что при суммировании(вычитании) младших байтов чисел необходимо применять команду ADD (SUB), а для сложения (вычитания) остальных – команду ADC (SBC), которая будет учитывать состояние флага C регистра статуса SREG.

Программа нахождения разности чисел, имеющих одинаковую длину П-3.2. Входные параметры R16 – длина чисел в байтах, X – адрес младшего байта вычитаемого, Y – адрес младшего байта уменьшаемого. Каждое из чисел записывается последовательно в ячейки памяти, начиная с младших байтов. Результат заносится в область памяти, отведенную под вычитаемое. В случае, если уменьшаемое меньше вычитаемого, на выходе будет установлен флаг переноса.

П-3.2

Адрес

Маш. код

Метка

Мнемокод

Комментарий

0000

ED0F

MAIN:

LDI R16,0xDF

Главная программа

Устанавливаем указатель стека

0001

BF0D

OUT 0x3D,R16

0002

E6A0

LDI R26,0x60

Устанавливаем указатель X на младший байт вычитаемого

0003

27BB

CLR R27

0004

E8C0

LDI R28,0x80

Устанавливаем указатель Y на младший байт уменьшаемого

0005

27DD

CLR R29

0006

E004

LDI R16,0x04

Указываем размер числа (4 байта)

0007

D001

RCALL SUBB

Вызов подпрограммы вычитания

0008

9508

RET

Завершение программы

0009

9488

SUBB:

CLC

Сбрасываем флаг переноса С для вычитания младших байтов чисел без переноса..

000A

900C

NEXT:

LD R0,X

Загружаем байт вычитаемого числа из памяти.

000B

9019

LD R1,Y+

Загружаем байт уменьшаемого числа из памяти с постинкрементом адреса.

000C

0810

SBC R1,R0

Вычитаем с учетом переноса: R1=R1-R0-C

000D

921D

ST X+,R1

Результат записываем по адресу байта вычитаемого числа с постинкрементом адреса.

000E

950A

DEC R16

Уменьшаем количество байт, которые осталось обработать.

000F

F7D1

BRNE NEXT

Если байты еще есть, то переход на NEXT,

0010

9508

RET

иначе – выход из подпрограммы.

Выполнение команд ST, DEC, BRNE не воздействует на состояние флага переноса, поэтому на выходе из подпрограммы состояние флага будет определено последней выполненной командой SBC. Таким образом, если уменьшаемое было меньше вычитаемого, флаг будет установлен, в противном случае – сброшен.

Умножение чисел. Существует несколько алгоритмов умножения чисел. В самом простом случае умножение можно заменить многократным сложением, например 14*3= 14+14+14. Существенный недостаток этого способа– значительная длительность процесса вычисления. В более сложном случае умножение осуществляется в столбец. Этот алгоритм применим и для умножения двоичных чисел, например:

0110

* 0011

= 6

= 3

0110

0110

0000

0000

00010010

=18

При вычислении результата по данному алгоритму необходимо осуществить многократное суммирование со сдвигом влево множимого, при одновременной проверке содержимого разрядов множителя со стороны его младшего разряда. При этом, если в очередном разряде множителя записана «1», то множимое прибавляется к сумме и сдвигается влево на один разряд, а если в разряде записан «0», то произойдет только сдвиг множимого. Сдвиг множимого влево можно заменить сдвигом суммы вправо. По этому алгоритму (рис.3.1) работает подпрограмма умножения двух однобайтных чисел с получением двухбайтного результата – П-3.3. Входные параметры: регистр R16 – множимое, регистр R17 – множитель. Результат перемножения записывается в регистры R1:R0.

П-3.3

Адрес

Маш. код

Метка

Мнемокод

Комментарий

0000

ED0F

MAIN:

LDI R16,0xDF

Главная программа

Устанавливаем указатель стека

0001

BF0D

OUT 0x3D,R16

0002

E90C

LDI R16,0x9C

Задаем множимое

0003

E31F

LDI R17,0x3F

Задаем множитель

0004

D001

RCALL MULT

Вызов подпрограммы умножения

0005

9508

RET

Завершение программы

0006

2411

MULT:

CLR R1

Очищаем содержимое регистров результата

0007

2400

CLR R0

0008

2422

CLR R2

Устанавливаем указатель разряда в 00000001

0009

9423

INC R2

000A

9488

CLC

Очищаем флаг C

000B

922F

M1:

PUSH R2

Сохраняем указатель разряда в стеке

000C

2221

AND R2,R17

Проверяем содержимое очередного разряда множителя

000D

2C21

MOV R2,R1

Загружаем старший байт суммы в R2 (команда MOV не влияет на регистр статуса)

000E

F009

BREQ M2

Если в разряде множителя 0, то переход к M2

000F

0E20

ADD R2,R16

Прибавляем к R2 множимое

0010

9427

M2:

ROR R2

Сдвигаем сумму вправо с переносом (младший бит переходит в C)

0011

2C12

MOV R1,R2

Сохраняем результат в R1

0012

9407

ROR R0

Сдвигаем младший байт суммы вправо с переносом (C переходит в старший разряд)

0013

902F

POP R2

Получаем из стека указатель разряда

0014

1C22

ROL R2

Сдвигаем указатель на следующий разряд

0015

F7A8

BRCC M1

Если разряд не последний, продолжаем с M1,

0016

9508

RET

иначе – выход из подпрограммы.

Деление чисел. Деление двоичных чисел, как и чисел, представленных в любой другой системе счисления, основывается на последовательном вычитании делителя из делимого и остатков от деления. Однако двоичное деление реализуется проще, так как использование только двух цифр (0 и 1) исключает в каждом цикле деления необходимость определения числа делителей, содержащихся в текущем значении делимого или остатка (достаточно только сравнить их).

Схема алгоритма деления двоичных чисел приведена на рис.3.2. Подпрограмма деления в программе П-3.4 построена по этому алгоритму. Входными параметрами для нее являются: регистрR16 – делимое и регистр R17 – делитель; выходными параметрами: частное - R1 и остаток R0.

Вычисление специальных функций. Для вычисления специальных функций (sin x, cos x, tg x, ln x, x2 и др.) применяются специальные алгоритмы. Функции sin x, cos x, ln x можно вычислить, воспользовавшись их разложением в ряд:

для любого x (рад)

для любого x (рад)

для 0 < x  1

Число членов ряда определяется из условия получения требуемой точности.

Для вычисления функции с точностью до целых чисел, можно применить алгоритм, основанный на том, что квадрат числа можно определить сложением последовательности нечетных чисел:

Число

Сумма нечетных чисел

Результат

1

1

=

1

2

1+3

=

22

3

1+3+5

=

32

4

1+3+5+7

=

42

5

1+3+5+7+9

=

52


Исходя из приведенного примера видно, что какое число необходимо возвести в квадрат, такое же количество последовательных нечетных чисел начиная с 1 необходимо сложить.

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

Входной параметр R16 – число x, выходной параметр R0 – значение x2.

П-3.4

Адрес

Маш. код

Метка

Мнемокод

Комментарий

0000

ED0F

MAIN:

LDI R16,0xDF

Главная программа

Устанавливаем указатель стека

0001

BF0D

OUT 0x3D,R16

0002

E90C

LDI R16,0x9C

Задаем делимое

0003

E31F

LDI R17,0x3F

Задаем делитель

0004

D001

RCALL DIVB

Вызов подпрограммы деления

0005

9508

RET

Завершение программы

0006

922F

DIVB:

PUSH R2

Запоминаем в стеке состояние вспомогательных регистров

0007

923F

PUSH R3

0008

92FF

PUSH R31

0009

2411

CLR R1

Обнуляем частное

000A

2400

CLR R0

Обнуляем остаток

000B

E0F8

LDI R31,0x08

Устанавливаем счетчик битов

000C

1F00

M1:

ROL R16

Сдвигаем старший бит делимого в C

000D

2C20

MOV R2,R0

Копируем промежуточное делимое в R2

000E

1C22

ROL R2

Сдвигаем C в младший разряд R2

000F

1A21

SUB R2,R17

Вычитаем делитель из R2

0010

F408

BRCC M2

Если С=1 – восстановить содержимое R2

0011

0E21

ADD R2,R17

путем прибавления делителя

0012

2C02

M2:

MOV R0,R2

Возвращаем в R0 промежуточное делимое

0013

B63F

IN R3,0x3F

Инверсия флага переноса C

0014

9408

SEC

0015

FC30

SBRC R3,0

0016

9488

CLC

0017

1C11

ROL R1

Сдвигаем С в младший разряд частного

0018

95FA

DEC R31

Уменьшаем счетчик битов

0019

F791

BRNE M1

Пока все биты не проверены переходим к M1

001A

91FF

POP R31

Восстанавливаем из стека состояние вспомогательных регистров

001B

903F

POP R3

001C

902F

POP R2

001D

9508

RET

Возврат из подпрограммы

Для работы программы П-3.5 необходимо заполнить таблицу квадратов чисел в оперативной памяти с адреса 0x60 следующими числами: 0x00, 0x01, 0x04, 0x09, 0x10, 0x19, 0x24, 0x31, 0x40, 0x51, 0x64. Подпрограмма SQR вычисляет квадрат числа от 0 до 10.

П-3.5

Адрес

Маш. код

Метка

Мнемокод

Комментарий

0000

ED0F

MAIN:

LDI R16,0xDF

Главная программа

Устанавливаем указатель стека

0001

BF0D

OUT 0x3D,R16

0002

E005

LDI R16,0x05

Задаем число

0003

D001

RCALL SQR

Вызов подпрограммы SQR

0004

9508

RET

Завершение программы

0005

93FF

SQR:

PUSH R31

Запоминаем в стеке состояние вспомогательных регистров

0006

93EF

PUSH R30

0007

27FF

CLR R31

Очищаем старший байт регистра Z

0008

E6E0

LDI R30,0x60

Задаем смещение младшему байту регистра Z, равное адресу начала таблицы квадратов

0009

0FE0

ADD R30,R16

Вычисляем абсолютный адрес значения

000A

8000

LD R0,Z

Загружаем в R0 значение

000B

91EF

POP R30

Восстанавливаем из стека состояние вспомогательных регистров

000C

91FF

POP R31

000D

9508

RET

Выход из подпрограммы

Поскольку таблица квадратов имеет постоянные данные, то нет смысла хранить их в оперативной памяти. При отключения питания микроконтроллера все данные, находящиеся в оперативной памяти теряются. Таким образом, чтобы снова получить таблицу квадратов в SRAM МК, все значения необходимо программно вычислить и записать начиная с адреса 0x60. Для этого потребуется дополнительно реализовать подпрограмму возведения в степень, что приведет к излишнему расходу памяти. Выходом в данной ситуации является использование энергонезависимой памяти EEPROM микроконтроллера. Записав один раз таблицу квадратов в EEPROM (на стадии прошивки микроконтроллера) мы можем не беспокоиться о потере данных.

Программирование EEPROM. EEPROM можно рассматривать как отдельное устройство, доступ к которому осуществляется через порты ввода/вывода.

Порт 0x1E называется регистром адреса (EEAR), 7 разрядов которого адресуют 128 ячеек памяти. Старший разряд зарезервирован и всегда читается как 0.

Порт 0x1D называется регистром данных (EEDR). В режиме записи EEPROM этот 8-ми битный регистр должен содержать данные, которые будут записаны в энергонезависимую память по адресу в EEAR. В режиме чтения в этот регистр попадают данные, считанные из EEPROM по адресу, заданному в EEAR.

Порт 0x1C называется регистром управления (EECR), который устанавливает режимы обращения к EEPROM (чтение, запись, разрешение записи).

Управление EEPROM осуществляется установкой битов порта EECR:

Бит 0 – EERE – разрешение чтения из EEPROM. Сигнал EERE является стробом чтения из EEPROM. После установки нужного адреса в регистре EEAR, необходимо установить бит EERE. После того, как бит EERE будет аппаратно очищен, в регистр EEDR будет выставлен считанный байт данных. Чтение EEPROM занимает одну команду и не требует отслеживания бита EERE. При установке бита EERE, МП останавливается на 2 цикла перед тем, как будет выполнена следующая команда. Перед чтением необходимо убедиться что EEPROM не занят.

Бит 1 – EEWE – разрешение записи в EEPROM. Сигнал EEWE является стробом записи в EEPROM. После установки правильных адреса и данных для записи в EEPROM необходимо установить бит EEWE. При записи «1» в бит EEWE должен быть установлен бит разрешения записи (EEMWE), тогда происходит запись в EEPROM.

После того, как время записи истечет (от 2.5 мс до 4 мс в зависимости от напряжения), бит EEWE очищается аппаратно. Вы можете отслеживать этот бит и ожидать его установки в 0, перед тем как записать (или считать) следующий байт. При установке бита EEWE, МП останавливается на 2 цикла перед исполнением следующей команды.

Бит 2 – EEMWE – управление разрешением записи. Этот бит определяет, будут ли записаны данные при установке EEWE. Если бит EEMWE установлен, то при установке EEWE данные записываются по выбранному адресу в EEPROM. Если этот бит сброшен, то установка EEWE не имеет эффекта. После программной установки этот бит сбрасывается аппаратно через 4 такта микропроцессора.

Биты 3-7 – зарезервированы.

Для записи в EEPROM должна соблюдаться следующая последовательность действий:

  1. Ждем готовности EEPROM (сброса EEWE)

  2. Устанавливаем адрес (записываем адрес в EEAR)

  3. Устанавливаем данные (записываем данные в EEDR)

  4. Устанавливаем в 1 бит EEMWE (разрешение записи)

  5. Не позже 4-х тактов после установки EEMWE устанавливаем EEWE.

Для чтения EEPROM должна соблюдаться следующая последовательность действий:

  1. Ждем готовности EEPROM (сброса EEWE)

  2. Устанавливаем адрес (записываем адрес в EEAR)

  3. Устанавливаем в 1 бит EERE (строб чтения)

  4. Читаем данные из порта EEDR.

Если регистры данных или адреса изменяются во время операции записи, то запись в ячейку прерывается и результат операции записи становится неопределенным. В связи с этим, перед началом цикла записи в EEPROM, необходимо запретить прерывания, если в подпрограммах прерывания осуществляется доступ к EEPROM.

Подпрограмма П-3.6 осуществляет запись в EEPROM. Адрес задается в регистре R16, данные – в регистре R17.

П-3.6

Метка

Мнемокод

Комментарий

EEPROM_WR:

SBIC 0x1C,1

Проверяем бит 1 (EEWE)

RJMP EEPROM_WR

Если не сброшен, то снова проверяем

OUT 0x1E,R16

Устанавливаем адрес в EEAR

OUT 0x1D,R17

Устанавливаем данные в EEDR

SBI 0x1C,2

Разрешаем запись EEMWE = 1

SBI 0x1C,1

Подаем строб на запись EEWE =1

RET

Выход из подпрограммы

Подпрограмма П-3.7 осуществляет чтение из EEPROM. Адрес задается в регистре R16, данные возвращает - R17.

П-3.7

Метка

Мнемокод

Комментарий

EEPROM_RD:

SBIC 0x1C,1

Проверяем бит 1 (EEWE)

RJMP EEPROM_RD

Если не сброшен, то снова проверяем

OUT 0x1E,R16

Устанавливаем адрес в EEAR

SBI 0x1C,0

Подаем строб на чтение EERE = 1

IN R17,0x1D

Получаем из порта данные в выходной регистр

RET

Выход из подпрограммы

Соседние файлы в папке 1_Uniproff