Ошибка

МИКРОКОНТРОЛЛЕР AVR

Категория: Электроприводы
Опубликовано 11.07.2011 11:43
Автор: Super User
Просмотров: 4062

Глава 31

МИКРОКОНТРОЛЛЕР AVR

Микроконтроллеры AVR фирмы Atmel открывают одно из новых направлений в области разработки и архитектуры микроконтроллеров. Структура процессора AVR представляется как «высокопроизводительная RISC-архитектура с пониженным энергопотреблением» Гарвардского типа. Одним из основных достоинств этого контроллера является быстрое выполнение команд - он выполняет команду за один такт. AVR имеет, вероятно, наиболее разносторонний по своим возможностям процессор из всех микроконтроллеров, описанных в данной книге. Это означает, что при разработке приложений надо потратить немного больше времени на планирование размещения данных в памяти и регистрах, чем для других микроконтроллеров. Но благодаря своей разносторонности AVR очень прост в программировании как для разработчиков прикладных программ на языке ассемблера так и для тех, кто пишет компиляторы языков высокого уровня.

Рис. 31.1. Микроконтроллеры AVR8515 в корпусе PLCC и AVR1200 в корпусе DIP

Когда писалась эта книга, выпускались только модели AVR8515 и AVR1200. Модель 1200 - это сравнительно урезанная версия RISC-архитектуры AVR. Модель 8515 имеет полнофункциональную RISC-архитектуру и поддерживает большую часть из тех возможностей, которыми будет обладать семейство AVR, когда появится и другие, более новые модели. Главным преимуществом AVR является наличие памяти EEPROM для хранения программ с возможностью программирования в системе, а также расширенный набор команд с возможностью выполнения большинства команд за один машинный цикл.


Глава 32

АРХИТЕКТУРА ПРОЦЕССОРА AVR

После прочтения первой части книги, вы, вероятно, почувствовали, что основные варианты архитектуры процессоров, такие как Гарвардская и Принстонская (Фон-Неймана), довольно просты и понятны. После знакомства с микроконтроллером 68НС05 эта уверенность в вас, наверное, еще больше укрепилась. Но есть ряд других архитектур, которые не вполне соответствуют этим моделям. Если вы заглянете в документацию на AVR, то увидите структуру микроконтроллера, показанную на рис. 32.1. Хотя эта структура представляется достаточно сложной, но вы можете мысленно пройти по различным шинам (линиям на диаграмме) и получить представление о том, как идут через процессор потоки битов и байтов. Но есть некоторые особенности, которые не являются очевидными, и их придется объяснять позднее. Как и в любом процессоре, особенности AVR являются следствием общих принципов, использованных при разработке этих процессоров. После ознакомления с AVR станет понятно, что они реализованы на базе набора регистров, организация которого представлена в графическом виде на рис. 32.2. Такая организация обеспечивает высокую эффективность процессора при обработке данных. Однако оба приведенных рисунка не дают представления о том, как была оптимизирована архитектура AVR, чтобы соединить достоинства Гарвардской и Принстонской архитектур для достижения очень быстрого и эффективного выполнения программ.


Рис. 32.1. Структура микроконтроллера AVR 8515 фирмы Atmel

Рис. 32.2. Приоритеты регистров в архитектуре процессоров AVR

Регистры общего назначения и АЛУ

Простое ядро процессора, которое содержит регистры общего назначения и АЛУ, может выполнять 91 из 120 команд, реализуемых AVR. Каждая из этих команд использует содержимое регистров общего назначения (РОН) при выполнении операций (рис. 32.3.). Есть два типа команд, которые могут выполняться этим ядром. Арифметические операции выполняются над содержимым РОН, а операции изменения последовательности команд могут реализовать только переходы в программе, но не могут производить вызов подпрограмм или сохранение содержимого программного счетчика. Позднее в этой главе будет показано, как в действительности реализован программный счетчик в AVR.

Рис. 32.3. Структурная схема регистров общего назначения и АЛУ

При обращении к РОН и АЛУ используется только один способ адресации — прямая регистровая адресация, которая осуществляется путем указания адреса выбираемого регистра. В команде могут быть указаны адреса одного или двух регистров. Например, сложение содержимого двух регистров с сохранением результата в первом из них выполняется при помощи команды «add»:


add А, В

которая может быть записана математически в виде: А = А + В, или представлена графически, как показано на рис. 32.4.

Рис. 32.4. Пути передачи данных при выполнении команды AVR add A,B

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

Прибавление константы выполняется при помощи команды:

addiw A, const

что означает: А = А + const, и показано графически на рис. 32.5.

Содержимое программного счетчика инкрементируется после того, как очередная команда считывается из памяти, или принимает новое значение при выполнении команды безусловного перехода «jmp» (рис. 32.6).

Рис. 32.5. Пути передачи данных при выполнении команды adiw A, const

Рис. 32.6. Пути передачи данных при выполнении команды безусловного перехода jump label


Регистр состояния

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

Рис. 32.7. Архитектура AVR с учетом регистра состояния SREG

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

Номер бита

Обозначение

Назначение

0

С

Флаг пере носа/заем а

1

Z

Флаг нуля

2

N

Флаг отрицательного результата

3

V

Флаг переполнения

4

S

Флаг знака

5

н

Флаг переноса между тетрадами (полупереноса)

6

т

Временный бит

7

I

Бит общего разрешения прерываний


Основным признаком в регистре состояния является флаг нуля, который устанавливается в 1, когда результатом операции является ноль. Когда будут рассматриваться команды процессора, вы увидите, что многие команды могут изменить этот флаг, что делает его неудобным для передачи параметров. Вместо него лучше использовать флаг переноса С, который применяется для этих целей другими процессорами во многих приложениях. В ряде случаев более удобным может оказаться использование временного бита Т, с подошью которого можно задавать значение одного бита, в качестве условия ветвления программы.

Как и в большинстве микроконтроллеров и микропроцессоров, флаг переноса/заема С в AVR устанавливается после каждой операции сложения или вычитания. Он также используется для временного сохранения старшего или младшего бита операнда при операциях обыкновенных и циклических сдвигов, что типично для многих микроконтроллеров. При сложении флаг переноса устанавливается в 1, если результат больше $FF, а при вычитании - если результат меньше нуля.

Флаг переноса между тетрадами Н (полупереноса) устанавливается после выполнения сложения или вычитания, в процессе которого произошел перенос из младшей или заем в старшей тетраде (полубайте). Например, если вы прибавили 7 к содержимому регистра, в котором хранилось число 9:


add R16, R17 ; R16 = 9, R17 = 7

Регистр R17 содержит число 7, и после сложения с содержимым R16, в котором хранится 9, результатом будет число $10, которое не может быть размешено в младшей тетраде. В этом случае будем установлен флаг Н в регистре состояния. Если младшая тетрада результата имеет значение меньшее, чем 10, то флаг Н будет сброшен в 0.

Как и флаги полупереноса для всех других контроллеров, рассмотренных в этой книге, бит Н меняется при переносе/заеме из младшего шестнадцатеричного разряда (тетрады). Его изменение не основано на десятичном результате операции. Но если требуется контролировать декадный перенос при операциях с двоично-десятичными числами, бит полупереноса может быть непосредственно использован при выполнении операции сложения, как это показано выше. Если результат операции больше или равен 10, то устанавливается значение флага Н = 1, которое указывает, что правильный двоично-десятичный результат может быть получен путем прибавления числа 6.

Использование флагов отрицательного результата N, переполнения V и знака S может показаться довольно сложным, если рассматривать, как они устанавливаются в 1 или сбрасываются в 0 при арифметических операциях. Следует понять их назначение, и тогда их применение станет простым и логичным. Эти биты надо проверять только после операций сложения или вычитания, в процессе которых используются или получаются отрицательные числа, представляемые в дополнительном коде.


Флаг отрицательного результата N устанавливается в 1, если старший (знаковый) разряд результата (бит 7) равен 1. Когда знаковый разряд установлен в I, это часто означает, что результат отрицателен. Следует, однако, отметить, что знаковый разряд может быть установлен в 1 и в результате логической операции. В этом случае знаковый разряд не должен использоваться в каких-либо других целях, кроме указания но то, что он был установлен в 1 после соответствующей операции.

Флаг переполнения V устанавливается при сложении или вычитании двух чисел со знаком, представленных в дополнительном коде (дополнение до двух), и случае, если значение полученного результата выходит за пределы допустимого диапазона, который для восьмибитового числа со знаком составляет от -128 до +127. При сложении двух положительных чисел флаг V устанавливается в 1, если сумма больше 127, в случае сложения двух отрицательных чисел — если результат меньше -128. Этот флаг показывает, что результат не является правильным 8-разрядным числом со знаком.

Вы можете сказать, что на самом деле результат является правильным, только его нельзя разместить 8-разрядном регистре, и будете правы. Для разрешения этой ситуации служит флаг знака S, который позволяет представить результат сложения или вычитания 8-разрядных чисел в дополнительном коде в виде 9-разрядного числа со знаком. Если после операций сложения или вычитания чисел со знаком флаг переполнения V установлен в 1, то результатом будет 9-разрядное число со знаком, причем старшим (знаковым) разрядом числа является флаг S, а восемь бит результата будут храниться в 8-разрядном регистре-приемнике.


Бит Т — временный бит, который используется для хранения результата команд «BST» и «BLD» или для передачи однобитовых параметров. Хотя бит Т не изменяется никакими другими командами, он должен быть сохранен вместе с другими битами регистра состояния при выполнении прерываний или подпрограмм, которые могут изменить содержимое этого регистра.

Последним является общий флаг разрешения прерываний I. Когда он установлен в 1, запросы прерываний будут обслуживаться. Если флаг I сброшен в 0, то обслуживание прерываний будет отложено до тех пор, пока этот флаг не будет установлен в 1.

Адресация устройств ввода-вывода и памяти SRAM

Понимание того, как адресуются регистры общего назначения, а как SRAM, может быть довольно затруднено. Это особенно верно, когда контроллеры младших моделей семейства AVR1200 работают вместе с контроллерами AVR8515, реализующими полный набор функций. В этом разделе будет рассмотрена архитектура памяти и регистров для микроконтроллеров с полным набором функций, а затем кратко указаны отличия младших моделей этих приборов. Реализация обращения к памяти, регистрам общего назначения и регистрам ввода-вывода может показаться несколько сложной, так как существует два способа обращения к ним. Первый способ - прямое обращение к каждой из этих областей данных. Этот способ прямого доступа является основным при выполнении арифметических операций. Второй способ доступа объединяет все три области регистров и памяти, включая внешнюю память, образуя общее адресное пространство данных (рис 32.8).


Регистры ввода-вывода — это 64-байтовый блок, который содержит как регистры управления процессором, так и регистры интерфейса ввода-вывода. Команды «in» и «out» используются для обмена данными между РОН и регистрами ввода-вывода. Внутренняя память SRAM — это блок оперативной памяти для хранения переменных. Эта память доступна при помощи команд «toad» и «store», которые позволяют также обращаться к РОН и регистрам ввода-вывода, которые располагаются в соответствующих областях адресного пространства данных.

Рис. 32.8. Организация адресного пространства процессоров AVR

Последней областью в адресном пространстве данных является внешняя память. Вся оставшаяся часть 64-килобайтного пространства данных может быть использована для адресации внешней памяти SRAM или устройств ввода-вывода. Подключение внешней памяти будет рассмотрено в одном из следующих разделов.

Хотя различные модели микроконтроллеров семейства AVR отличаются составом регистров, имеется ряд регистров, общих для всех моделей, которые располагаются по одним и тем же адресам в пространстве регистров ввода-вывода.


Адреса

Регистры ввода-вывода

Область Данных

Имя

регистра

Назначение

$3F

$5F

SREG

Регистр состояния

$ЗЕ

$5Е

SPH

Указатель стека — старший байт

$3D

$5D

SPL

Указатель стека — младший байт

$ЗВ

$5В

GIMSK

Регистр маски прерываний

$ЗА

$5А

GIFR

Регистр запросов прерываний

$35

$55

MCUCR

Регистр управления микроконтроллера


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

Как отмечено в предыдущем разделе, при выполнении арифметических операций используются только регистры общего назначения, и их адреса не зависят от того, используется ли для обращения к ним адреса РОН (при использовании арифметических инструкций) или адресное пространство данных (при использовании команд «load»/«store»). Обращение к регистрам ввода-вывода производится либо при помощи команд «in»/«out» с использованием области адресов ввода-вывода или при помощи команд «load»/«store» в адресном пространстве данных. Если используются команды «load»/«store», то к абсолютному адресу должно быть прибавлено начальное смещение $20 (десятичное число 32), как показано в приведенной выше таблице адресов регистров ввода-вывода.

Обращение к внутренней памяти SRAM или внешней памяти производится только через адресное пространство данных при помощи команд «load»/«store», которые используют абсолютные адреса. Если надо считать операнд из внешней памяти, то обращение займет на один или два цикла больше, чем при использовании внутренней памяти.


Команды «load»/«store» позволяют использовать индексные регистры. В адресном пространстве РОН последние 6 регистров могут использоваться как три 16-разрядных индексных регистра, содержимое которых загружается либо из адресного пространства данных, либо из памяти программ. Эти индексные регистры имеют имена X (адреса $1А-$1В), Y (адреса S1C-S1D) и 7(адреса S1E-SIF). Индексный регистр Z может также использоваться для чтения из памяти программ отдельных байтов, что позволяет хранить в ней таблицы данных.

После всего вышесказанного структура AVR становится такой, как показано на рис. 32.9. В этой структуре показана шина адреса, которая используется для адресации регистров и оперативной памяти. Адрес может формироваться разными способами, например, он может быть указан в команде или определяться с использованием индексного регистра.

Что касается младшей модели микроконтроллеров AVR1200, то она не содержат оперативной памяти SRAM и не выполняет команды обращения к РОН и регистрам ввода-вывода, использующие единое адресное пространство данных (рис. 32.10.) В этой модели имеются три отдельных адресных пространства для памяти программ, РОН и регистров ввода-вывода, которые не объединяются в единое адресное пространство данных. К регистрам ввода-вывода можно обратиться только при помощи команд «in» и «out», a команды «load»/«store» фактически не используются. Младшие модели AVR имеют также только один индексный регистр Z, расположенный по адресам $1E-$1F в области регистров общего назначения. Этот индексный регистр может использоваться либо для выборки данных, хранящихся в РОН или в памяти программ.


Рис. 32.9. Структура AVR с памятью SRAM и регистрами ввода-вывода

Рис. 32.10. Области памяти в архитектуре младших моделей AVR

Программный счетчик и стек

Вы, вероятно, будете удивлены, узнав, что мы рассмотрели уже 90% структуры AVR. Единственной существенной частью архитектуры, которую осталось обсудить, являются программный счетчик команд и реализация стека. Реализация стека — главное отличие между младшими моделями AVR и другими микроконтроллерами этого семейства. В младших моделях AVR стек реализован в виде оперативной памяти типа LIFO («последний пришел - первый ушел»), добавленной к программному счетчику. Когда вызывается подпрограмма или происходит запрос прерывания, содержимое счетчика команд вводится в этот стек (рис. 32.11.). В AVR1200 такой стек имеет глубину в три элемента. Это значит, что вы можете иметь только три вложенные подпрограммы или два вложенных вызова функции в активном обработчике прерывания. Данное обстоятельство значительно ограничивает возможности этого микроконтроллера.

Рис. 32.11. Счетчик команд и стек в младших моделях AVR

Структурная схема для AVR1200 и других младших моделей приведена на рис 32.12. Другие модели семейства AVR не имеют таких жестких ограничений на объем стека, так как они используют для размещения стека внутреннюю память SRAM и, возможно, внешнюю память (рис. 32.13.) Такая структура позволяет использовать в качестве стека весь доступный объем оперативной памяти. Использование значительного объема памяти RAM в качестве стека дает ряд преимуществ при разработке приложений, которые будут рассмотрены ниже. Окончательная структурная схема микроконтроллеров AVR имеет вид, показанный на рис 32.14.


На этом мы завершаем обсуждение архитектуры AVR. Если вы вернетесь к началу этой главы и сравните структурную схему на рис. 32.14 со структурной схемой, представленной компанией Atmel, то обнаружите, что они не имеют ничего общего. Даже упрошенные структурные схемы в документации на микроконтроллеры AVR мало похожи на схему, приведенную на этом рисунке. Таким образом, у вас есть три структурные схемы микроконтроллера и ни одна из них не похожа на другую. Встает вопрос — какой же из этих схем можно доверять?

Рис. 32.12. Структурная схема младших моделей AVR с учетом стека

Рис. 32.13. Программный счетчик и стек в архитектуре старших моделей AVR

Рис. 32.14. Полная архитектура процессора AVH с указателем стека

Вы должны доверять той схеме, которая больше всего вам подходит. Структурные схемы, которые приведены в этом разделе, отражают мое понимание архитектуры и того, как в ней выполняются команды. То, что вы видите - это взгляд автора на устройство микроконтроллера. Я не имею никакого понятия о том, как устроен кристалл. Все, что я сделал, - это рассмотрел все используемые команды и способы адресации и попытался понять, как они совместно реализуются. Как вы увидите в главе, посвященной набору команд, окончательная структурная схема, приведенная на рис.32.14, выполняет все команды. Она будет использована для демонстрации способов адресации и путей, по которым передаются команды и данные.


Прерывания

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

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

Флаг I будет снова установлен в 1 в конце обработчика прерывания, когда выполняется команда возврата «reti». Он также может быть установлен в 1 в процессе обработки (после сохранения контекстовых регистров), чтобы разрешить вложенные прерывания. Средние и старшие модели AVR могут обрабатывать столько вложенных прерываний, на сколько хватит объема стека для сохранения содержимого программного счетчика и регистров контекста. Младшие модели имеют ограниченный объем стека (три позиции), который может быстро переполниться при выполнении вложенных прерываний или подпрограмм.


Способы адресации данных

При рассмотрении набора команд AVR вы, вероятно, будете поражены количеством различных способов адресации, которые поддерживаются полной архитектурой AVR. В этом разделе я хочу дать представление о том, как AVR выполняет команды, и как команды обращаются к РОН, регистрам ввода-вывода и памяти SRAM. Основным способом доступа к данным является прямое обращение к регистрам общего назначения. Обычно в формате команды отводятся пять бит, которые позволяют адресоваться к любому регистру. Прямое обращение к одному из РОН показано на рис. 32.15. Обычно такая адресация используется для операций с содержимым одного регистра (инкремент, декремент, инверсия знака, очистка и т.д.). Некоторые из этих команд дважды повторяют адрес в коде команды.

Рис. 32.15. Прямая адресация в AVR

Команды, оперирующие с двумя регистрами, действуют, в основном, аналогичным образом. В этих командах регистр-приемник («destination») указывается перед регистром-источником («source»), то-есть является первым параметром. Таким образом, команда

add RO, R1


реально выполняется так: RO = RO + Rl.Рассмотренные способы адресации операндов называются прямой регистровой адресацией (рис. 32.16.).

Рис. 32.16. Прямая адресация AVR к двум РОН

Операнды могут также входить в состав команды. В других контроллерах это называется «непосредственной адресацией». В AVR будем называть этот способ адресации «непосредственной прямой регистровой» (рис. 32.17.). Хорошим примером команды с такой адресацией является «ORI». Я хочу обратить ваше внимание на эту команду по одной важной причине. Так как поле адреса составляет 4 бита, вы можете обращаться только к 16 старшим РОН. Это, очевидно, окажет влияние на то, как разместить данные в ваших рабочих регистрах. Чтобы избежать ошибок, можно рекомендовать использовать в качестве рабочих 16 старших регистров общего назначения, имеющих адреса с $10no$lF.

Рис. 32.17. Непосредственная адресация AVR

Последняя форма прямой адресации, применяемая для доступа ко всему объему адресуемой памяти, использует второе слово команды для указания 16-разрядного адреса. При этом способе адресации данные, размещенные в любой точке адресуемой памяти, поступают в РОН или выбираются из них. Есть две особенности, на которые стоит обратить внимание при такой адресации. Первая особенность - опять доступны только 16 старших РОН. Вторая особенность - команды с такой адресацией не реализуются в младших моделях AVR1200. В этих моделях для передачи данных между РОН и набором регистров ввода-вывода используются команды «in» и «out», реализующие прямую адресацию двух регистров.


Последний способ обращения к данным — косвенная адресация. Если вы уже познакомились с технической документацией на микроконтроллеры AVR, то видели, что в ней используется пять рисунков для описания этого способа адресации, реализация которого иллюстрируется на рис. 32.18. На этом рисунке показана только косвенно-регистровая адресация и не приведены ее варианты с предекрементном и постинкрементном. Основные команды косвенной адресации используют содержимое индексных регистров в качестве адреса для выборки данных. Это очень похоже на индексную адресацию в большинстве других микроконтроллеров. Следует отметить, что это единственный режим, доступный и младших моделях AVR, где для обращения к РОН может использоваться только индексный регистр Z, а РОН и регистры ввода-вывода не образуют общее регистровое пространство.

Рис. &. 18. Косвенная адресация к РОН/ памяти данных в AVR

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


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

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

Глава 33

АППАРАТНЫЕ СРЕДСТВА AVR

Моим первым впечатлением после ознакомления с документацией на AVR1200 было, что мы имеем дело с микроконтроллером следующего поколения, существенно отличающимся от других микроконтроллеров, рассмотренных в этой книге. По многим характеристикам он превосходит другие микроконтроллеры, соединяя в себе лучшие свойства других приборов. Это не значит, что любые его аппаратные возможности реализуются путем подачи одной команды. Однако он представляет собой следующий шаг в улучшении характеристик микроконтроллера.


Типы корпусов

Вариантов корпусов, в которых выпускаются AVR, очень немного, особенно если сравнивать со множеством различных типов корпусов, в которых выпускаются микроконтроллеры 8051, 68НС05 и PIC. Компания Atmel в данный момент выпускает эти микросхемы только в пластмассовых и стандартных типах корпусов (рис. 33.1). Расположение выводов делает эти приборы почти совместимыми по выводам с 8051 (за исключением вывода «reset»).

Рис. 33.1. PDIP корпуса микроконтроллеров AVR 1200 и AVR8515

PDIP — это пластмассовый DIP-корпус с расстоянием между осями выводов 2,54 мм. Корпуса SMT имеют шаг 1,27 мм.

Следует обратить внимание, как реализован вариант микроконтроллера 8515 в PLCC-корпусе. Если вы посмотрите на обозначение выводов этого варианта 85! 5, то увидите, что они расположены так же, как в PDIP-варианте. за исключением того, что в середине каждой стороны есть неподключенные выводы. Это очень удобный и продуманный вариант с учетом того, что некоторые пользователи не имеют достаточного опыта работы с SMT-корпусами. а другие не любят работать с Р ГН-прототипами. Для многих микроконтроллеров SMT-варианты имеют другой набор выводов, чем РТН. включая дополнительные выводы «земли» и питания. А при таком размещении выводов, как у AVR, SMT-платы могут быть разработаны на основе PDIР - прототипов с наименьшими заботами и минимальным изменением разводки.


Системный тактовый генератор

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

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

AVR может использовать три различных источника системной частоты: кварцевый или керамический резонатор, внешний тактовый сигнал или встроенный RC-генератор (имеется не во всех моделях). Обычный диапазон частот для AVR — от 0 до 16 МГц. В сочетании с выполнением за каждый такт одной команды это делает AVR по настоявшему быстрым, особенно на частоте 16МГц

Справедливо ли будет сказать, что AVR, работающий на частоте 1 МГц, эквивалентен по производительности микроконтроллерам 68НС05 на частоте 2 МГц, PIC на 4 МГц или 8051 на 12 МГц? Конечно, нет. Такое сравнение будет некорректным, так как микроконтроллеры с различной архитектурой работают по-разному. Я бы не удивился, если бы вы написали программу для PIC, 8051 и 68НС05, которая работает быстрее, чем на AVR даже при более низкой частоте. Поэтому не следует говорить, что какая-либо архитектура лучше и работает быстрее и эффективнее, чем любая другая.


Кварцевый или керамический резонатор может быть подключен к AVR, как показано на рис.33.2. Если используется одна из этих схем, не подключайте какие-либо другие устройства ни к одному из выводов XTAL.

Рис. 33.2. Схемы подключения к AVR керамического и кварцевого резонаторов

Микроконтроллер AVR может синхронизироваться внешним тактовым сигналом, поступающим на вход XTAL1. Если вы собираетесь использовать один синхросигнал для нескольких AVR, можно рекомендовать схему, показанную на рис.33.3. Последний способ синхронизации — использование встроенного RC-генератора. Такой генератор на данный момент есть только в AVR1200, он обеспечивает тактовую частоту 1 МГц. Этот режим задается при помощи одного из битов конфигурации (fuse bit) при параллельном программировании контроллера. Встроенный RC-генератор не будет запушен, если программирование производится по последовательному интерфейсу.

Рис. 33.3. Генератор тактовой частоты для AVR на внешнем кварцевом резонаторе

Несколько замечаний по поводу встроенного RC-генератора. При его использовании возможен 10-процентный разброс значений тактовой частоты. Это означает, что данный генератор нельзя использовать в приложениях, требующих стабильности тактовой частоты. Тот факт, что внутренний RC-генератор может быть включен только при параллельном программировании контроллера, в некоторых случаях может ограничивать его полезность. Однако, чтобы смягчить это неудобство, фирма Atmel выпустила вариант контроллера AVR1200A, в котором этот генератор включен уже при его изготовлении.


Таймеры

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

Источником сигнала переключения таймеров/счетчиков является либо тактовая частота процессора, либо внешний синхросигнал. Тактовая частота процессора может использоваться непосредственно или предварительно делиться. Выбор источника сигнала и коэффициента деления производится с помощью мультиплексора (рис 33.4.) Биты CSxn, управляющие мультиплексором, расположены в регистре управления таймера TCCR0. В AVR 8515, который содержит два таймерных блока, имеется два мультиплексора - по одному на каждый таймерный блок. В AVR1200 есть только один таймерный блок и один мультиплексор. Содержимое таймера инкрементируется при поступлении переднего фронта переключающего сигналу. Поэтому синхросигнал со внешнего вывода микроконтроллера поступает мультиплексор в прямом и инвертированном виде. Значение внешнего синхросигнала проверяется при поступлении переднего фронта тактового сигнала процессора.


Рис.33.4. Предварительный делитель частоты таймера/ счетчика в AVR

Таймер 0 — очень простой 8-разрядный таймер, содержимое которого может быть считано или записано. Отключение входного сигнала происходит путем выбора «заземленного» входа при помощи мультиплексора. При переполнении счетчика реализуется маскируемое прерывание (рис. 33.5).

Таймер 1 является гораздо более сложным и может выдавать на выход AVR импульсы и ШИМ-сигналы. Таймер 1 работает так же, как и таймер 0, надо только принять во внимание, что таймер I - 16-разрядный, а таймер 0 — только 8-разрядный. Его большим достоинством является возможность реализации дополнительных функций, таких как таймер событий или генератор ШИМ-сигналов.

При работе в качестве таймера событий таймер 1 запоминает (захватывает) в регистре захвата состояние таймера в произвольный момент времени, который определяется изменением сигнала на внешнем входе захвата. Этот вход захвата подключен через устройство подавления шумов, которое ждет, пока закончится «дребезг» контактов. Если вы измеряете длительность входного импульса, меняя фронт сигнала захвата в промежутке времени между захватами, то можно не учитывать задержку для подавления дребезга, так как она одинакова как для переднего, так и для заднего фронта импульса.


Рис. 33.5. Структура таймера 0 (TimerO) в AVR

Рис. 33.6. Структура таймера 1 (Timer1) в AVR

Таймер 1 имеет два ШИМ-режима. Первый режим вызывает запрос прерывания, когда текущее значение счетчика таймера станет равным «А» или «В». Когда содержимое счетчика таймера 1 по величине сравняется с содержимым 16-разрядного регистра «В», таймер может быть сброшен, чтобы обеспечить формирование следующего ШИМ-сигнала. На рис 33.7 показано состояние выхода микроконтроллера в промежуточных точках программы. Обратите внимание, что обработчики прерываний по совпадению содержат всего по две команды. При этих прерываниях не используются какие-либо флаги разрешения прерывания IF, которые надо было бы сбрасывать.

Рис. 33.7. Пример программы вывода ШИМ-сигнала для таймера 1

Второй ШИМ-режим — это использование таймера 1 для вывода ШИМ-сигнала на выход ОС1А микроконтроллера без использования программы обработки. В этом режиме таймер считает до максимально возможного значения и, когда содержимое счетчика становится равным заданному значению А или В, сигнал на выводе ОС1А меняет свое состояние. Когда таймер достигает максимального значения, он начинает считать в обратном направлении, и цикл повторяется. На рис 33.8 содержимое счетчика таймера 1 прёдставлено пилообразной кривой, которая отражает его значение в разные моменты времени. Уровень сравнения - это заданное значение А или В.


Рис. 33.8. Значения сигналов при формировании ШИМ-сигнала с помощью таймера 1

Сторожевой таймер

Сторожевой таймер в микроконтроллерах AVR представляет собой отдельный таймер с собственным генератором на 1 МГц, который при включении будет отсчитывать нужный интервал времени. Если произойдет переполнение до того, как команда «WDR» сбросит счетчик таймера в 0, то производится перезапуск микроконтроллера (рис 33.9).

Рис. 33.9. Структура сторожевого таймера AVR

Сторожевой таймер включается при установке в 1 бита WDE в регистре управления сторожевого таймера WDTCR. Содержимое битов WDP0 - WDP2 этого регистра определяет интервал времени до того, как сторожевой таймер произведет перезапуск микроконтроллера.

WDP2

WDP1

WDP0

Период таймера

0

0

0

16 мс

0

0

1

32 мс

0

1

0

64 мс

0

1

1

128 мс

1

0

0

256 мс

1

0

1

512 мс

1

1

0

1,024 с

1

1

1

2,048 с


В AVR1200 сторожевой таймер может быть выключен простым сбросом в 0 бита WDE. В AVR8515 есть дополнительный бит WDTTOE, который должен быть установлен в 1 не более чем за четыре такта до того, как будет сброшен бит WDE. Это выполняется с помощью следующего фрагмента программы:

Sbi WDTCR, WDTTOE ; разрешение выключения WDT

Cbi WDTCR, WDE ; выключить WDT

Бит WDTTOE специально введен для того, чтобы предохранить сторожевой таймер от случайного выключения программой. Как и для аналогичных операций в других микроконтроллерах, когда время выполнения операции является критичным, надо запретить все прерывания, чтобы быть уверенным, что после команды «sbi» не произойдет запрос прерывания.

Если вы собираетесь включать сторожевой таймер в произвольный момент времени, а не только после включения питания или начального запуска, то перед тем, как установить бит WDE в 1, надо сбросить сторожевой таймер с помощью команды «WDR», чтобы быть уверенным, что таймер находится в начальном состоянии и не произойдет перезапуска до того, как вы ожидаете.

Параллельный ввод-вывод


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

Схема подключения внешнего вывода, показанная на рис. 33.10, дает представление о его работе. С каждым набором линий (который называется «портом») связано три адреса ввода-вывода, которые позволяют определять значение данных, записанных в порт, направление передачи данных («1» - вывод, «0» — ввод) и реальное значение сигнала на внешнем выводе. Вследствие этого есть возможность «подтянуть» выводы порта к высокому потенциалу для работы в режиме ввода данных, и использовать состояние некоторых выводов в качестве запроса прерываний.

Чтение данных может быть выполнено либо непосредственно с внешнего вывода, либо с выхода регистра данных порта. Такая возможность является важной особенностью работы порта. Если внешняя линия перегружена или случайно закорочена на «землю» или питание, то состояние внешнего выхода никогда не будет меняться. Поэтому в некоторых случаях очень важно иметь возможность прочитать содержимое регистра порта и сравнить его с реальным состоянием внешнего вывода.


Хотя линии ввода-вывода AVR работают подобно аналогичным линиям в других микроконтроллерах, они имеют одно существенное отличие. Оно заключается в том, что «подтягивание» внешнего вывода к высокому потенциaлy управляется не отдельными битами регистра, а для этого используется специальная комбинационная схема. Эта схема разрешает «подтягивание» только, когда внешний вывод работает в режиме ввода данных. На рис.33.11 показано, как работает линия ввода-вывода AVR при чтении состояния кнопки, которая подключает внешний вывод к «земле».

Рис. 33.10. Схема подключения внешнего вывода AVR

Рис. 33.11. Подключение внешнего вывода AVR с «подтягиванием» к высокому потенциалу

Последовательный ввод-вывод

Последовательные порты SPI и UART в AVR работают во многом так же, как в других микроконтроллерах. Интерфейс SPI предназначен для последовательной передачи данных между двумя AVR или AVR и параллельным реверсивным сдвиговым регистром. Аппаратные средства AVR не поддерживаются сложные протоколы синхронного последовательного обмена, такие, как I2C или CAN.

UART


В старшей модели AVR8515 данные могут асинхронно передаваться и приниматься по последовательному каналу в полнодуплексном режиме при помощи модуля UART. В AVR этот модуль так же, как в других микроконтроллерах, которые не имеют возможности передавать бит четности. Основной частью UART является генератор синхросигналов обмена, определяющий скорость передачи данных. Это программируемый счетчик, при помощи которого обеспечивается частота, в 16 раз превышающая скорость передачи. Значение, которое надо занести в регистр UBRR, определяющий скорость обмена UART («UART baud rate register»), вычисляется по формуле:

UBRR = f / (16 * Data_Rate)-1,

где Data_Rate — желаемая скорость передачи данных. Как и для других генераторов, задающих скорость передачи данных, необходимо проверить значение получаемой ошибки скорости обмена (отношение фактической скорости обмена к требуемой), прежде, чем использовать определенный кварцевый резонатор и конкретное значение UBRR.

Частота генератора в 16 раз превышает скорость передачи данных, чтобы дать возможность приемнику считывать значение с входной линии примерно в середине каждого бита в потоке поступающих данных. Структура приемника UART приведена на рис. 33.12. В этой схеме имеется специальное устройство — детектор фронта, который применяется для того, чтобы определить, что в данный момент времени присутствует на линии: поток передаваемых данных или какие-то помехи. Если передаются данные, то он определяет середину бита и указывает сдвиговому регистру приемника RX, когда надо начинать принимать данные из входного потока. Детектор фронта обеспечивает также обновление содержимого USR — регистра состояния UART в следующих случаях:


- при окончании приема байта данных;

- в случае возникновения ошибки приема, например, переполнения сдвигового регистра приемника, когда новые данные приняты раньше, чем из регистра RX считано предыдущее значение;

- при ошибке кадра, когда данные идут не с той скоростью, с какой ожидалось, что обычно определяется по отсутствию стоп-бита.

Рис. 33.12. Структура приемника последовательного порта AVR

Прием данных и сброс приемника осуществляется путем считывания содержимого UDR - регистра данных приемника Rx.

Как вы уже догадались, передатчик UART также содержит сдвиговый регистр (рис. 33.13). Устройство управления выводом позволяет передавать либо данные, либо сигнал режима ожидания (все «1» на линии). Для передачи символа достаточно записать его код в регистр данных передатчика Тх.

Рис. 33.13. Структура передатчика последовательного порта AVR

Как и в последовательных портах других контроллеров, данные в регистр передатчика можно записывать, когда предыдущий символ только начал передаваться. Загрузка в регистр новых данных сразу после того, как предыдущий символ поступил из него в сдвиговый регистр передатчика, позволяет достичь максимальной скорости передачи, когда старт-бит следующего байта данных следует непосредственно за стоп-битом предыдущего байта.


SPI

Хотя порт SPI есть на всех микроконтроллерах AVR для обеспечения возможности их программирования по последовательному интерфейсу (ISP), которая рассмотрена позднее в этой главе, он доступен для обмена данными с внешними устройствами только в некоторых моделях. В этих моделях SPl-порт работает почти так же, как аналогичный порт в 68НС05 (рис 33.14).

Рис. 33.14. Синхронный последовательный порт ввода/ вывода AVR

Для обмена с другими устройствами используются четыре вывода порта SPI. Например, совместная работа ведущего («master») и ведомого («slave») микроконтроллеров AVR может быть реализована, как показано на рис 33.15. Передачу инициирует ведущий AVR, который выдает синхросигналы обмена на вывод SCK. При этом вывод SCK ведомого контроллера будет работать в качестве входа синхросигнала. Чтобы включить порт SP1, надо установить в I бит SPE в регистре управления SPCR порта SPI. С помощью этого регистра можно выбрать режим работы SPI в качестве ведущего, однако если на внешний вывод SS поступает низкий уровень сигнала, то порт SP1 будет работать только в режиме ведомого.

Биты SPR в регистре SPCR используется для установки скорости передачи данных ведущим контроллером. Важно отметить, что ведущий контроллер не может использовать для синхронизации внешний синхросигнал, поэтому можно выбирать только одно из четырех значений частоты полученных делением частоты тактового сигнала процессора. Чтобы получить более высокую скорость передачи, вы должны увеличить тактовую частоту AVR.


Рис. 33.15. Синхронный последовательный обмен в AVR

Передача данных осуществляется ведущим контроллером путем записи информации в регистр данных SPDR порта SPI и последующим периодическим опросом (или ожиданием запроса прерывания) бита SPIF в регистре состояния SPSR этого порта для определения момента окончания передачи.

Аналоговый ввод-вывод

В настоящее время возможности аналогового ввода-вывода микроконтроллеров AVR ограничиваются наличием встроенного аналогового компаратора напряжений. Компаратор в AVR дает возможность не только сравнивать входное напряжение с опорным, но и измерять длительность импульса при помощи встроенного таймера. Схема компаратора может показаться несколько сложнее, чем вы ожидаете (рис 33.16). Выход компаратора находится в состоянии 1, если значение напряжения на неинвертирующем входе AIN0 больше, чем на инвертирующем AIN1. Состояние выхода может использоваться для реализации различных вариантов запроса прерывания, которые задаются при помощи битов ACIS1-0 в регистре прерывания и состояния аналогового компаратора ACSR.

Определить текущее состояния выхода компаратора можно путем опроса значения бита АСО в ACSR. Для уменьшения мощности потребления можно отключить компаратор, установив в 1 бит ACD в регистре ASCR. Перед тем, как включить или выключить компаратор, надо запретить все его прерывания путем сброса в 0 бита ACIE в ACSR, чтобы предотвратить возможность поступления ложных запросов прерывания от компаратора.


ACIS1

ACIS0

Тип прерывания

0

0

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

0

1

Прерывание при переключении выхода компаратора из 0 в 1

1

0

Прерывание при переключении выхода компаратора из 1 в 0

Рис. 33.16. Компаратор напряжения в AVR

В микроконтроллере AVR8515 к выходу компаратора можно подключить вход захвата таймера. При этом можно зафиксировать момент изменения сигнала на выходе компаратора, если в регистре ACSR бит ACIC установлен в I. Такая возможность позволяет измерять длительность сигнала, поступающего на компаратор. Аналогичное измерение можно также выполнить с помощью входа ICP, но использование компаратора позволяет измерять длительность сигнала, уровни которого отличаются от стандартных уровней 0 и 1. Чтобы измерить длительность импульса с стандартными уровнями ТТЛ/КМОП уровня с помощью комбинации таймер/компаратор, надо подать на отрицательный вход компаратора (вывод AINI) напряжение с выхода простого резистивного делителя, использующего два резистора по 10 КОм.


Конфигурирование микроконтроллера

В AVR есть два типа битов, задающих конфигурацию микроконтроллера. Биты конфигурирования «fuses» (плавкие перемычки) используются для выбора режима работы AVR, тогда как биты защиты «lock bits» выполняют такую же функцию, что и аналогичные биты в 8051. Хотя они не так структурированы, как биты конфигурации в микроконтроллерах PIC, однако они позволяют выполнять функции программирования и конфигурирования AVR. Биты конфигурирования «fuse bits» различны для разных типов AVR. В AVR1200 установка в 1 бита RCEN подключает встроенный RC-генератор, при этом внешние тактовые генераторы игнорируются. Когда бит SPIEN сброшен в 0, разрешается программирование микроконтроллера по последовательному интерфейсу через порт SPI. Во всех AVR1200 биты SPIEN и RCEN по умолчанию сброшены в 0, хотя можно заказать микроконтроллер AVR1200A, в котором они будут установлены в 1.

Микроконтроллер AVR8515 имеет биты SPIEN и FSTRT, которые позволяют при использовании внешнего тактового генератора производить быстрое включение микроконтроллера без обычной задержки в 16 мс.

Биты конфигурирования «fuse bits» недоступны при программировании по последовательному интерфейсу. Они могут быть установлены или сброшены только при параллельном программировании.


Биты защиты «Lock bits» используются для запрещения доступа к области программ в памяти EEPROM. Если установлен в 1 бит «lock 1», то запрещается программирование EEPROM, а когда установлен в 1 еще и бит «lock 2», то запрещается также и чтение содержимого EEPROM.

Память данных EEPROM

Операции чтения и записи области данных EEPROM в AVR довольно просты и надежны. Однако, по-моему, компании Atmel «следовало бы разместить область памяти EEPROM в пространстве адресов данных (над регистрами ввода-вывода), чтобы разрешить прямое обращение к ней. Это, правда, не так актуально, как для некоторых других контроллеров, например, PIC, которые не имеют такого большого количества регистров и памяти данных, как в AVR. Обращение к EEPROM производится при помощи команд с индексной адресацией, которые используют адрес, хранящийся в регистре EEAR.

Если EEPROM имеет емкость больше 256 байт, как в AVR8515, то используются два адресных регистра: EEARH — для хранения старшей части адреса и EEARL для хранения младшей части. Эти регистры должны сохранять правильный адрес до тех пор, пока не будет закончена операция чтения или записи.

Запись в память данных EEPROM производится следующим образом.


1. Ожидание сброса в 0 бита EEWE в регистре управления EECR памяти EEPROM

2. Запись в EEAR нового адреса (если нужно).

3. Запись в регистр данных EEDR памяти EEPROM новых данных (при необходимости).

4. Установка в 1 бита ЕЕМWE в EECR. Это может быть сделано при помощи команды SBI. (Бит EEMWE не используется в AVR 1200).

5. В течение четырех тактов после установки бита EEMWE установить EEWE в 1 для начала записи в EEPROM. Операция записи занимает от 2.5 до 4 мс.

Бит ЕЕМWE регистра EECR в AVR 8515 обеспечивает аппаратную блокировку записи для того, чтобы уменьшить вероятность случайного изменения EEPROM.

Чтение из EEPROM выполняется аналогичным образом.

1. Ожидание сброса в 0 бита EEWE в регистре EECR.

2. Запись нового адреса в регистр EEAR (при необходимости).

3. Установка в 1 бита EERE в EECR.

4. Чтение данных из EEDR.


Операция записи должна быть закончена до того, как программа произведет попытку чтения из EEPROM. Есть одна особенность, которую следует учитывать при работе с EEPROM, хотя она, возможно, не влияет на работу большинства приложений. После установки в 1 бита EERE процессор переходит в состояние ожидания в течение двух тактов, пока данные выбираются из EEPROM. Это означает, что выполнение команды «SBI EECR, EERE», которая инициирует операцию чтения, занимает не один такт, а три.

Программирование

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

Программирование по параллельному интерфейсу

Основной режим программирования микроконтроллеров AVR схож с аналогичным режимом для 8051 (рис. 33.17).


Управляющие линии, расположенные слева на приведенной схеме, служат для управления процессом программирования. До того, как будет произведено какое-либо действие по программированию, в микроконтроллер по шине данных должна быть загружена соответствующая команда. Когда команда поступила, управляющие биты ХА1/ХА0 устанавливаются в состояние 1/0, указывая, что на шине данных находится байт команды. Биты команды имеют следующее назначение.

Бит

Назначение

0

Тип EEPROM (0 - память программ, 1 - память данных)

1

Чтение из памяти программ/данных

2

Чтение битов защиты и конфигурирования

3

Чтение байтов сигнатуры (идентификационного кода)

4

Запись в - EEPROM программ/данных

Бит

Назначение

5

Запись битов защиты (блокирования)

6

Запись битов конфигурирования

7

Стирание кристалла


Рис. 33.17. Схема соединений для параллельного программирования AVR

Биты защиты «lock bits» используются для предотвращения изменения программы, записанной в AVR, или несанкционированного чтения кода, загруженного в память контроллера. Биты защиты могут быть сброшены в 0 во время выполнения команды «стирание кристалла» («erase chip»).

Биты конфигурирования («fuse bits») используются для управления режимом работы AVR, например, реализация быстрого запуска или использование встроенного RC-генератора. Значение этих битов может быть изменено только при параллельном программировании.

Назначение битов управления можно объяснить довольно легко. Биты XAI/ ХАО используются для управления процессом программирования: «00» - загрузка адреса, «01» — загрузка данных и «10» — загрузка команды. Необходимо отметить, что все команды имеют длину четыре байта. Если же для команды требуется меньше четырех байт (например, команда «Erase Chip» содержит только один байт), то все равно для ее выполнения значение сигнала на линии XTAL1 должно измениться четыре раза. При чтении данных меняется состояние сигнала на линии _ОЕ .

Сигналы _ОЕ и WR используются для управления вводом-выводом данных. Сигнал BS показывает, что происходит обращение к младшему или старшему байту памяти программ. Рассмотрев все это, можно показать, как программируется один байт, используя временные диаграммы, приведенные на рис 33.18. Данный рисунок поясняет назначение всех выводов. Для загрузки памяти программ надо установить необходимое значение сигналов на выводах ХА1/ХА0 и подать команду $10 на шину данных. Обратите внимание, что при передаче адреса бит BS следует за физическим адресом, в котором старший байт идет после младшего.


Как показано на рис 33.19, чтение байта из памяти программ производится в соответствии теми же соглашениями, которые приняты для записи.

Рис. 33.18. Запись при программировании AVR по параллельному интерфейсу

Рис. 33.19. Чтение при программировании AVR по параллельному интерфейсу

Каждый микроконтроллер AVR содержит три байта сигнатуры (идентификационный код), которые считываются при помощи трех последовательных операций чтения после подачи команды $08.

Программирование по последовательному интерфейсу

Как отмечено выше, последовательная загрузка EEPROM используется, в основном, в тех случаях, когда требуется программирование AVR в системе. Схема электрического соединения для программирования очень проста (рис. 33.20). Данные для программирования передаются и принимаются контроллером по последовательному синхронному интерфейсу (рис. 33.21).

Рис. 33.20. Схема включения AVR для программирования по последовательному интерфейсу

Рис. 33.21. Сигналы при передаче байта в режиме последовательного программирования по последовательному интерфейсу


На рис. 33.21 не соблюден реальный масштаб времени. Кварцевый резонатор должен работать на частоте около 1 МГц. Вместо него в AVRI200 или других моделях AVR можно использовать встроенный RC-генератор, который должен быть включен с помощью параллельного программирования. Длительность высокого уровня синхросигнала SCK должна быть больше четырех машинных тактов (больше 4 мкс при тактовой частоте 1МГц), а длительность низкого уровня - больше одного такта.

Команды последовательного программирования занимают четыре байта и имеют следующий формат.

Команда

Байт1

Байт2

БайтЗ

Байт4

Разрешение программирования

10101100

01010011

хххх хххх

хххх хххх

Стирание кристалла Чтение программы

1010 1100 0010 В000

100х хххх

Старший

байт адреса

хххх хххх

Младший байт адреса

хххх хххх

Читаемые данные

Запись программы

ото вооо

Старший

байт адреса

Младший байт адреса

Данные

Чтение EEPROM

1010 0000

хххх ххх0

Адрес

Читаемые данные

Запись EEPROM

1100 0000

хххх ххх0

Адрес

Данные

Запись битов зашиты

1010 1100

1Ихх21х

хххх хххх

хххх хххх

Чтение идентификационного кода

0011 0000

хххх хххх

хххх xxbb

Код по адресу «bb»


(«В» — 0 для младшего байта / 1 для старшего)

(«1» — бит зашиты 1, «2» — бит защиты 2)

При программировании AVR необходимо учитывать следующее. Чтобы перевести микроконтроллер в режим последовательного программирования необходимо после включения напряжения удерживать низкое значение сигнала на выводах _RST и SCK в течение 20 мс, прежде чем начать программирование. Если в памяти AVR находились данные, то сначала надо включить напряжение питания и выполнить команду «Стирание кристалла» (chip erase), затем выждать 10 мс, подать на вход Reset высокий уровень сигнала, после чего повторить описанную выше процедуру включения питания с вводом микроконтроллера в режим последовательного программирования.

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

Последнее, на что надо обратить внимание при последовательном программировании, — это отсутствие возможности опроса EEPROM и флэш-памяти программ о завершении процесса записи. Необходимо реализовать в программе управления записью соответствующие задержки: 10 мс для стирания памяти программ и 4 мс для записи байта в EEPROM и память программ.


Маркировка микроконтроллеров AVR

Компания Atmet обозначает AVR как AT90Sxxxx, где хххх — код модели. В то же время для микроконтроллеров Atmel, совместимых с i8051, используется обозначение AT89Sxxxx (я сделал ошибку, когда впервые заказывал несколько экземпляров AVR). Назначение различных символов при маркировке микроконтроллеров AVR 1200 и 8515 указано на рис. 33.22.

Рис. 33.22. Маркировка микроконтроллеров

Глава 34

РАЗРАБОТКА СИСТЕМ НА БАЗЕ AVR

При изучении справочных данных по AVR я увидел ряд особенностей, которые отражают их относительную молодость по сравнению с другими микроконтроллерами. Фирмы Ahnel разрабатывала этот микроконтроллер, начиная "с нуля", поэтому она смогла создать его с учетом лучших характеристик других микроконтроллеров, уже имевшихся на рынке. Это особенно заметно при взгляде на то, как AVR взаимодействует с другими устройствами системы.

Подключение питания


Подключение питания к AVR осуществляется очень просто, что, впрочем, справедливо и для других микроконтроллеров, описанных в этой книге. Дня этого требуется только напряжение +5В, шина «земля» и развязывающий конденсатор. Работать с AVR очень приятно, так как все его модели имеют широкий диапазон напряжений питания 2,7 В - 6,0 В, что позволяет легко реализовать батарейное питание, используя от 2 до 4 обычных батареек или никель-кадмиевых элемента.

Одна из особенностей, которая особенно мне нравится в AVR. это возможность параллельного программирования без использования напряжения + 12В. Дальше в этой главе возможность программирования AVR в системе будет рассмотрена более подробно. Мне хотелось указать на эту возможность здесь, чтобы повлиять на наш выбор микроконтроллера для использования в определенных приложениях, когда может потребоваться программирование AVR уже смонтированного на плату.

Что касается потребления энергии, то микроконтроллеры AVR потребляют несколько мА в рабочем режиме и несколько сотен мкА в режиме ожидания («sleep mode»).

Запуск

Вывод _Reset в AVR имеет внутреннее соединение с шиной питания через резистор («подтягивание» к питанию), что избавляет от необходимости использования внешнего соединения. В процессе отладки системы, когда надо постоянно перезапускать микроконтроллер и наблюдать за его поведением, все, что вам для этого нужно — это простая кнопка, которая будет замыкать вывод _Reset на землю (рис 34. 1). В законченной системе вы можете оставлять вывод _Reset не подключенным.


Рис. 34. 1. Запуск AVR при помощи внешнего выключателя

Включение питание в AVR выполняется типичным для микроконтроллеров/микропроцессоров способом. Оно может производиться либо внешней схемой, либо просто подачей напряжения Vcc (при этом используется внутренняя схема запуска). Если AVR включается путем подачи Vcc, то диаграммы внутренних сигналов имеют вид, показанный на рис 34. 2.

Сигнал POR на этом рисунке вырабатывается внутренней схемой запуска, которая используется, чтобы задержать включение AVR пока не стабилизируется напряжение питания. Триггер Шмидта включает эту схему, которая затем обеспечивает задержку в 3 мс (интервал времени Трог на рис. 34. 2). Как только это время задержки закончится, специальная схема блокировки ждет, пока не стабилизируется частота внутреннего генератора, прежде чем запустить программу на выполнение (интервал времени Tout на рис 34. 2). Номинально этот период составляет 15 мс, но если используется AVR с внешним генератором, он может быть уменьшен до 1 мс.

Рис. 34.2. Временная диаграмма сигналов при запуске AVR

Если во время выполнения программы на вход „Reset поступит сигнал низкого уровня длительностью более двух тактов, то выполнение программы сбрасывается в начальное состояние, а тактовый генератор продолжает работать. Когда на этом выводе снова установится высокий уровень, выполнение программы начнется с нулевого адреса.


Прерывания

Реализация прерываний в AVR довольно проста, хотя вы должны тщательно спланировать их выполнение. Вы можете написать обработчик прерываний всего из нескольких команд или обрабатывать прерывания в очень сложных приложениях.

Данный пример является обработчиком прерываний таймера для микроконтроллера AVR 1200, который состоит всего из трех команд.

Tmrlnt ; установить бит при переполнении таймера

cbi TOV0, T1FR

set ; установить в 1 флаг Т в регистре SREG

reti

Здесь предполагается, что флаг Т служит для индикации того, что произошло прерывание, и этот флаг должен опрашиваться в основной программе. На самом деле, использование при обработке прерываний команд, не изменяющих содержимое регистра SREG, является предметом особой заботы, так как, если они будут менять значения флагов, то информация о состоянии процессора будет потеряна для основной программы. Об этом не надо заботиться при использовании микроконтроллеров семейства 68НС05, потому что они сохраняют содержимое регистра состояния CCR в процессе обработки запроса прерывания, так что изменение CCR в обработчике не влияет на работу основной программы. В микроконтроллерах 8051 об этом не надо беспокоиться, так как их регистр состояния PSW не содержит флага нуля.


Если при обработчике прерывания меняется содержимое регистра состояния, то вы сначала должны его сохранить. Самым простым способом является выделение одного регистра общего назначения (РОН) для хранения содержимого SREG во время прерываний. В этом более общем случае обработчик прерываний таймера может выглядеть следующим образом.

Tmrlnt

; код, выполняемый при обработке прерываний

in

RO, SREG

; сохранение регистра состояния

; выполнение кода обработчика

out

SREG, R0

; восстановление регистра состояния

reti


Если у вас нет свободных РОН, то можно использовать следующий расширенный вариант обработчика.

IntHandler

; обработчик прерывания

push

R16

; сохранение регистров, используемых

; обработчиком

push

R17

in

R16, SREG

; сохранение регистра состояния

push

R16

; выполнение кода обработчика

pop

R16

; восстановление регистра состояния

out

SREG, R16

pop

R17

; восстановление используемых регистров

pop

R16

reti


Следует заметить, что команды «push» и «pop» могут быть заменены на «Id» и «st» с предекрементом/постинкрементом.

Старшие модели микроконтроллеров AVR используют стек в оперативной памяти, что означает, что можно довольно легко реализовать вложенные прерывания (почти как в 68НС05). После того, как началось выполнение обработчика прерывания, и было сохранено содержимое регистров контекста, можно выполнить команду «sei», чтобы разрешить обслуживание других прерываний.

Следует дать несколько комментариев относительно обработки прерываний в младших моделях микроконтроллеров, то есть в серии AVRI200. Так как они имеют очень маленький стек (только на 3 элемента) и не содержат памяти RAM (имеются только регистры общего назначения), вам придется более осторожно планировать обработчики прерываний, которые собираетесь использовать. Лично я всегда оставляю в запасе, по меньшей мере, три регистра общего назначения (или пять, если в обработчике прерываний предполагается использовать индексный регистр Z) для сохранения содержимого регистров контекста основной программы. Я не использую вложенные прерывания и исключаю вызовы функций внутри обработчика, а также, по возможности, стараюсь не использовать вызовы функции в основной программе. Реализовать обработчик прерывания, удовлетворяющий этим условиям, не очень сложно, зато это поможет избежать впоследствии лишних проблем, таких как переполнение стека.


Операционные системы реального времени (ОСРВ)

Если вы познакомились ранее с описанием реализации ОСРВ (и mykeRTOS) для семейства 68НС05, вы, вероятно, поняли, что полная архитектура AVR может быть достаточно легко использована для создания ОСРВ. При таком богатстве способов доступа к памяти, которое доступно программе для обращения к данным и указателям, написать настоящую программу реального времени будет довольно просто.

После всего вышесказанного следует принять ряд решений по поводу того, как будет работать ОСРВ, и как будут сохраняться данные. Так как микроконтроллеры AVR имеют большое количество регистров, доступных для большинства команд, в системах реального времени их можно использовать несколькими способами.

Первый способ — это разделить 32 регистра общего назначения на отдельные блоки для различных задач. Для выполнения всех арифметических команд необходимо два регистра (за исключением операций с непосредственными операндами). Это значит, что можно реализовать до 15 задач. В этой схеме два регистра резервируются для временного хранения данных ОСРВ, и индексный регистр используется для обслуживания задач (хотя, когда задача использует индексный регистр, надо еще запретить прерывания, чтобы не потерять его содержимое в случае, если аппаратное прерывание изменит код выполнения задачи). При такой схеме параметры, запрашиваемые ОСРВ, можно передавать через стек или через индексный регистр.


Такое распределение РОН, хотя и поддерживает большое количество задач, на мой взгляд, не является оптимальным. Вместо этого, если вы собираетесь использовать 32 регистра для сохранения параметров задач, то лучше разделить их на части по четыре регистра для стека задач, а последние четыре использовать в качестве индексных. При таком способе разделения регистров каждой задаче соответствует своя область стека. Распределение РОН на группы показано на рис. 34.3. При этом возможно выполнение до семи задач.

Другое решение можно предложить для того, чтобы можно было выполнять операции с непосредственными значениями. Вместо того, чтобы располагать подряд регистры в блоке каждой задачи, можно разместить один регистр в первых 16-ти адресах РОН, а остальные в старшей половине 32-адресного пространства РОН. Такой подход позволит выполнять арифметические операции как с содержимым РОН, так и с непосредственно заданными операндами. Чтобы избежать неожиданностей, лучше заранее определить регистры для каждой задачи, а не вычислять их в процессе выполнения программы. Например, можно определить, что задача n использует смешение п*4 для доступа к своему блоку информации. Программный код для такой модели ОСРВ может выглядеть следующим образом:


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

Более традиционный способ, при котором происходит сохранение всех регистров, также возможен. Но он имеет недостаток - очень большой требуемый объем памяти SRAM, используемой для записи всех регистров контекста задачи. Например, в микроконтроллерах AVR, которые имеют память SRAM объемом 512 байт, а сохранение содержимого всех регистров для каждой задачи требует минимум 32 байта, при использовании этого метода может поддерживаться не более 12 задач. Другим его недостатком является значительное время, необходимое для сохранения и восстановления всех регистров каждый раз, когда происходит прерывание или переключение задач. Я пробовал использовать этот вариант и обнаружил, что для его реализации необходимо 83 команды - это более чем в три раза превышает размер приведенного выше кода.

Рис. 34.3. Пример использования регистров AVR для реализации ОСРВ

Обратите внимание еще на одну вещь — явное использование команд «cli» и «reti» в программе ОСРВ. В AVR нет команды программного прерывания, поэтому бит 1 в регистре SREG не будет автоматически замаскирован при переключении задач. Поэтому при вызове процедуры ОСРВ надо замаскировать прерывания и сохранить содержимое SREG.


Микроконтроллеры AVR очень хорошо подходят для выполнения программ под управлением ОСРВ. Как и при создании ОСРВ для работы с микроконтроллерами 68НС05, необходимо потратить некоторое время, чтобы спланировать реализацию ОСРВ и задач, которые будут под ней выполняться.

При чтении этого раздела, вам, наверное, приходила в голову мысль, что реализация самой ОСРВ затерялась среди описания того, что должно быть учтено при ее разработке. Поэтому попытаемся все систематизировать. Перечислим наиболее важные аспекты, которые необходимо учесть при разработке ОСРВ;

1. Обеспечение интерфейса для обращения задач к ОСРВ.

2. Обеспечение надежного механизма для сохранения информации о текущей задаче в случае, если придет новый запрос к ОСРВ или случится аппаратное прерывание.

3. Создание системы сообщений, способной передавать информацию между задачами.

Это, пожалуй, все. Как вы будете это осуществлять, зависит только от вас. Преимуществом микроконтроллеров AVR является множество способов того, как можно реализовать ОСРВ. Надеюсь, что в этом разделе вы получили начальные сведения о различных способах решения проблемы, которые не основаны на традиционном подходе, потому что он, скорее всего, не будет оптимальным при использовании AVR.


Программирование в системе

Используя программирование по последовательному интерфейсу, можно менять программу в памяти микроконтроллера AVR, уже установленного в готовую к применению систему. Для этого плата с контроллером должна быть подключена к питанию и генератору тактовых сигналов (рис. 34.4).

Рис. 34.4. Схема подключения AVR для программирования в системе

На рис. 34.4 я включил согласующие резисторы в линиях программирования, чтобы быть уверенным, что если схема программирования подает на эти линии сигналы, уровень которых отличается от того, который поступает на них от других устройств системы, состояние выводов не изменится, и на них не возникнут «состязания» сигналов.

Для линии запуска используется другое подключение. Нормально на этой линии поддерживается высокий уровень сигнала, а программатор может подать на нее низкий, чтобы перевести контроллер в режим программирования по последовательному интерфейсу. Управление состоянием линии _Reset осуществляется схемой, имеющей выход с «открытым коллектором».

Можно ли использовать эту схему для программирования прикладной системы? Действительно можно, при этом я соединяю AVR с программатором при помощи 5-контактного IDC-разъема (для сигналов «земля», _Reset, M1SO, MOS1 и SCK) вместо того, чтобы использовать что-то вроде разъема DB-25 для подключения системы напрямую к принтерному порту персонального компьютера, как это делается в некоторых современных схемах программирования AVR.


Глава 35

СРЕДСТВА РАЗРАБОТКИ ДЛЯ AVR

Так как микроконтроллеры AVR появились на рынке недавно, для них пока нет большого количества средств разработки. Несмотря на это фирма Atmel уверена в том, что для AVR уже есть полный набор таких средств, и некоторые производители уже начали выпускать программные и аппаратные средства, доступные для пользователей.

Ассемблеры

Большая гибкость архитектуры AVR означает, что требуется продумать, как организовать использование регистров. Как вы, наверное, уже поняли, AVR имеет высокую степень ортогональности. Именно поэтому и требуется определенное планирование при распределении регистров.

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


Прочитав предыдущее утверждение, вы можете подумать, что я что-то упустил. И это действительно так. Если вы пишете приложение, которое интенсивно использует прерывания, то необходимо задуматься о планировании их обработки, что было отмечено в предыдущей главе. Если вы реализуете обработку прерываний в AVR, то должны принять обдуманное решение, содержимое каких контекстных регистров вы хотите сохранить перед выполнением функций обработчика прерывания. Так как при выполнении арифметических операций AVR может обращаться к любому из 32-х РОН, количество регистров, содержимое которых надо сохранять, может оказаться на удивление маленьким.

Рис. 35.1. Распределение РОН между основной программой и обработчиками прерываний в AVR

Например, в прикладной программе, использующей два обработчика прерываний, которые могут быть вложенными, я произвел разделение регистров, как показано на рис. 35.1. Такое разделение позволяет обработчикам прерываний работать без сохранения содержимого каких-либо РОН, используемых основной программой, так как обработчики прерываний имеют отдельные индексные регистры и регистры общего назначения. Единственным регистром, содержимое которого надо сохранять в этом примере, является регистр состояния, который сохраняется в сегменте «Сохраненное содержимое SREG» блока регистров каждого обработчика. При таком способе разделения регистров обработчик прерываний может быть очень простым.


Я лично не люблю загружать из памяти сразу большое количество регистров и пытаться запомнить, что в них находится. По-моему, это приводит к увеличению числа ошибок и затрудняет их выявление. Вместо этого лучше загружать из памяти содержимое регистров только тогда, когда оно требуется, и сохранять результат сразу после окончания обработки. Я хочу довести это до вашего сознания в первую очередь. Такая техника программирования выработалась у меня еще со времен программирования на ассемблере для IBM 370. Тогда я понял, как трудно запомнить, какой регистр за что отвечает. Поэтому при программировании на AVR я стараюсь держать в РОН только самые нужные переменные и загружать их из памяти, только когда они требуются. Чтобы избежать проблем с запоминанием, что хранит данный регистр, можно дать им символьное обозначение:

#define i R16 ; Обозначить регистр R16

Языки высокого уровня

Фирма Atmel утверждает, что архитектура AVR хорошо подходит для эффективного получения программных кодов с помощью компиляторов. Однако, моим первым впечатлением было, что это не совсем правильно. Разделение РОН и памяти SRAM может привести к неэффективности программного кода, а ограниченное количество РОН не позволит эффективно выполнить код. В процессе размышления о данной проблеме и изучения своих попыток написать компилятор для PIC, я понял, что AVR обладает некоторыми свойствами, которые позволяют относительно легко написать эффективный компилятор по сравнению с другими контроллерами, которые описаны в этой книге. Мои комментарии в этом разделе основываются на моем собственном стиле написания компиляторов и могут отличаться от того, что принято в лучших технологиях компиляции.


В большинстве компиляторов при вычислении выражений используются стековые операции. Например, операция

А = В + С

может быть представлена в виде последовательности стековых операций :

push В

push С

add ; Взять из стека два верхних элемента, сложить их

; вместе и поместить результат обратно в стек

pop A

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

Например, выражение:

А = В + (C*D)


может быть представлено следующим образом:

push В

push С

push D

mul

add

pop A

Для микроконтроллеров AVR, если все переменные «А», «В», «С» и «D» находятся в памяти SRAM (или в РОН; это не имеет значения при использовании команды загрузки «Id»), то исполняемый код, генерируемый компилятором, может иметь вид:

При этом оптимизирующий компилятор может определить избыточные операции загрузки переменных в стек и их извлечения и выдать следующий код:

Далее этот код может быть улучшен, если компилятор использует определенный набор регистров для каждого выражения. После дальнейшего сокращения программный код может иметь вид:


Приведенный выше пример использует глобальные переменные, доступные из любого места программы. Если же компилятор разрабатывается для языка, использующего локальные переменные и параметры, доступные только в данной процедуре, то AVR очень хорошо подходит для решения этой проблемы исключительно простым способом. Локальные переменные должны обслуживаться либо одним из индексных регистров, используя команды «load/store» с предекрементом и постинкрементом, которые позволяют эмулировать стек, либо при помощи стековых команд «push» и «pop». Лично я склоняюсь в сторону использования индексных регистров и эмуляции стека.

Если вами был написан компилятор языка С для AVR, и в вашей программе имеется такой фрагмент:

Как будет выглядеть откомпилированный и оптимизированный код для AVR? Перед вызовом функции Complex один индексный регистр должен быть определен как указатель стека данных, а другой — как указатель базового адреса. Когда данные помещаются в стек, указатель должен увеличиваться на единицу, чтобы указывать на следующий элемент стека. При вызове функции, указатель базового адреса должен указывать на текущую позицию. Итак, для приведенного выше С-кода компилятор может генерировать следующую последовательность команд AVR (здесь предполагается, что «X» — указатель стека данных, a «Y» — указатель базового адреса):


В этом примере для вычисления выражения В + (С * D), используется такое же количество команд и такой же объем в памяти, как и при использовании глобальных переменных в основной программе. Эта возможность делает AVR очень привлекательным при разработке компиляторов; можно работать с данными в разном формате без особых проблем с объемом используемой памяти.

Индексные регистры позволяют легко использовать указатели. Если содержимое регистра X служит в качестве указателя стека, а содержимое Y — в качестве указателя базового адреса, то остается еще регистр Z, который можно использовать для реализации чтения таблиц из памяти программ или в качестве индексного регистра общего назначения. В предыдущем примере можно также использовать указатель стека, но в этом случае при обращении к какому-либо параметру, находящемуся в стеке данных, содержимое указателя стека придется сохранять в регистрах X, Y или Z, чтобы найти смещение этого параметра в стеке. Гораздо проще вместо этого непосредственно использовать индексные регистры в операциях «ldd»/«std» с инкрементом.

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


Средства разработки

Для создания программ, представленных в этой книге я использовал свободно распространяемые ассемблер и симулятор для AVR фирмы Atmel и стартовый комплекс разработчика АТ89/90 Series Flash Microcontroller Starter Kit. Он состоит из программатора, образца микроконтроллера AVR1200 и программного обеспечения для разработки прикладных программ, а также включает CD-ROM со справочными данными на микроконтроллеры. При цене менее 100$ этот комплекс предоставляет действительно большой пакет средств для разработки приложений на базе AVR. Программатор может работать с любыми моделями Atmel 8051 (то есть с AT89S205I) и AVR в DIP-корпусах, имеющих 20 или 40 выводов (рис. 35.2).

Как и другие комплексы для разработки, представленные в этой книге, комплекс Starter Kit фирмы Atmel запускается из Microsoft Windows или командной строки DOS. Что необычно для этого комплекса, так это отсутствие полностью интегрированной среды разработки. Ассемблер, симулятор и программатор — это самостоятельные программы, работающие под управлением Windows, которые не являются настоящей интегрированной средой разработки (IDE). Хотя эти средства не интегрированы вместе, симулятор и программатор могут быстро загрузить в микроконтроллер файлы ассемблированной программы.


Ассемблер фирмы Atmel, называемый «wavrasm», является простым редактором текста, работающим под Windows, с интегрированной программой ассемблирования. На рис. 35.3. показан вид экрана, который появляется после завершения ассемблирования. В случае ошибки можно дважды щелкнуть на сообщении о ней, чтобы перейти на строку исходного текста, в которой она произошла.

Рис. 35.2. Стартовый комплекс разработчика на базе микроконтроллера с Flash-памятью серии АТ89/90

Рис. 35.3. Вид экрана ассемблера wavrasm фирмы Atmel

Если вы получили программу без синтаксических ошибок, прежде чем загружать программу в память микроконтроллера, вы можете проверить ее работу на симуляторе. Фирма Atmel предоставляет для этого два средства. Первое средство — «wavrsim» является симулятором, написанным под Windows, который загружает объектный файл «.obj» прикладной программы и позволяет выполнять ее по шагам в процессе отладки (рис. 35.4).

Рис. 35.4. Вид экрана симулятора wavrsim фирмы Atmel

Самым большим недостатком, который я обнаружил в этой программе, является то, что нельзя просматривать содержимое регистров ввода-вывода, кроме регистров TCCR0 и TCNT0 таймера 0 и некоторых регистров масок прерываний. Вывод на экран окна регистров, выбираемых пользователем, как, например, в окне регистров UMP или окне просмотра в MPLAB, был очень полезен для разработки приложений. После того как ошибка в программе найдена и исправлена, программа снова ассемблируется. Полученный «.оbу»-файл может быть снова быстро загружен с помощью меню «files» с перезапуском виртуального микроконтроллера, после чего выполнение программы продолжается.


Второе средство - симулятор «AVRStudio» (рис. 35.5), который является улучшенной версией «wavrsim» для Windows/95 и Windows/NT. Он может показывать содержимое регистров ввода-вывода, как видно на рис. 35.5, что является большим преимуществом по сравнению с «wavrsim», но в остальном, он очень похож на первоначальную версию.

Рис. 35.5. Вид экрана симулятора AVRStudio фирмы Atmel

Когда прикладная программа написана и отлажена на симуляторе, настает время ее загрузки («прошивки») в память микроконтроллера. Это производится при помощи программатора, поставляемого в составе Starter Kit, и экрана среды Windows для загрузки .hex файла, в формате Intel (рис. 35.6).

Рис. 35.6. Окно управления программатора из набора Starter Kit фирмы Atmel

После завершения процесса программирования микроконтроллер будет готов к работе. С помощью IDC-разъемов его можно соединить с макетной платой, а можно использовать и встроенные светодиоды и кнопочные выключатели.

Окно программатора может оставаться активным во время работы ассемблера/симулятора, чтобы оперативно модифицировать программу. Единственное, что мне не понравилось в этом программаторе - это отсутствие возможности выключения питания программируемого микроконтроллера. Во время работы мне приходилось вручную отключать питание, чтобы быть уверенным, что я не провожу «горячую замену» микроконтроллера при отладке приложения совместно с другими устройствами. Программное обеспечение программатора работало без каких-либо проблем при подключении и отключении платы программатора.


Глава 36

СИСТЕМА КОМАНД МИКРОКОНТРОЛЛЕРОВ AVR

Микроконтроллеры AVR имеют очень широкий набор команд. Как уже отмечалось в других главах, AVR позволяет более просто произвести разработку компиляторов, что также означает, что AVR может быть легко запрограммирован с использованием разнообразных команд, упрощающих решение задачи. Реализация большого набора команд — это палка о двух концах. Когда вы прочтете описание команд AVR в фирменной документации и начнете писать свою первую программу, то, вероятно, обнаружите, что довольно трудно запомнить все эти команды. Многие из них повторяются, одна и та же команда может иметь разные названия в зависимости от того, значения каких битов устанавливаются при ее выполнении или какие входные параметры модифицируются. При рассмотрении системы команд в этой главе я сократил их набор по двум причинам: во-первых, для экономии места, а во-вторых, чтобы объединить похожие команды в группы и дать вам возможность увидеть общую картину. Это сокращение получилось довольно значительным. В документации фирмы описана 121 команда, а в данной главе я сократил их количество почти вдвое.


Даже без такого сокращения система команд AVR является довольно понятной, хотя есть ряд вещей, на которые следует обратить внимание, когда вы пользуетесь документацией фирмы Atmel или данным мной описанием для создания прикладных программ. Первое, на что надо обратить внимание, это адреса регистров и диапазон данных, с которыми оперирует команда. Многие команды могут обращаться только к 16-ти старшим РОН и не имеют доступа к 16-ти младшим. Значения смещений и констант могут быть ограничены и оказаться не в том диапазоне, который вы ожидали. Вы должны знать обо всех этих ограничениях, когда будете планировать, какие РОН использовать и какие значения констант являются допустимыми в структурах данных.

Фирма Atmel делает следующее заявление по поводу микроконтроллера AVR 8515: «120 мощных команд, большинство из которых выполняется за один такт». Это подразумевает, что микроконтроллер позволяет гораздо проще создавать программы, критичные ко времени: если для любой команды требуется один цикл, вычисление времени значительно облегчается. Но лично у меня возникло много сомнений по поводу этого утверждения после того, как я подробно ознакомился с системой команд. Хотя большая часть команд действительно выполняется за один такт, многие все же требуют нескольких тактов. Что еще хуже, реальное время выполнения для многих команд трудно предсказуемо, например, команда «cpse» может выполняться за 1, 2 или 3 такта. Это не значит, что архитектура AVR плохо подходит реализации приложений, критичных ко времени. В большинстве случаев это не так, однако, данные приложения не так просто реализовать, как можно ожидать при первом знакомстве с документацией.


Последнее, что следует учитывать при знакомстве с набором команд AVR — это различие между «полноценными» старшими моделями AVR серии AVR 8515 и их младшими моделями серии AVR 1200. Младшие модели контроллеров реализуют часть полного набора команд AVR, в которых доступен только один индексный регистр Z. Хотя при переносе программы с младших моделей на старшие вряд ли возникнут проблемы, они весьма вероятны при переносе программ в обратном направлении. Даже с учетом всех этих предостережений, мне кажется, что AVR - это микроконтроллер очень простой для программирования благодаря богатству набора команд и особенностям его структуры, которые облегчают процесс программирования.

Команды пересылки данных AVR

Пересылка данных из одного места в другое является для AVR очень простой операцией, так как имеется большое количество команд, предназначенных для выполнения этой задачи. Многие из них хорошо подходят для реализации языков высокого уровня, как уже отмечалось в предыдущих главах. В старших моделях AVR серии 8515 планирование того, как надо хранить данные и производить обмен между РОН и памятью SRAM, очень важно для создания хорошей программы. Ни одна из команд пересылки данных не оказывает влияния на биты регистра состояния. Это означает, что для проверки значения данных после этих команд надо выполнить команду «tst» для соответствующей установки флагов нуля и отрицательного результата в регистре состояния SREG. Первой будет рассмотрена команда «mov» (команда 36.1), которая копирует содержимое одного регистра общего назначения в другой. Команда «ldi» (команда 36.2) используется для загрузки в регистр значения константы. Наряду с командой «mov» эта команда является базовой при создании программ, простых для выполнения. Команда «ldi» загружает в один из 16-ти старших РОН байт, содержащийся в команде. Она служит для записи произвольных констант в регистры общего назначения.


Для прямого обращения к пространству регистров ввода-вывода используются команды «in» и «out» (команда 36.3 и команда 36.4). Эти команды обеспечивают доступ к регистрам, начиная с нулевого адреса в пространстве ввода-вывода, а не с адреса $1F, с которого в пространстве данных AVR определены адреса регистров ввода-вывода.

Перечисленные выше команды — это практически все, что имеется в младших моделях AVR серии 1200 для пересылки данных. Остальные команды позволяют получить доступ к любой ячейке в пределах 64К пространства данных AVR, которое включает в себя РОН, регистры ввода-вывода и память SRAM, или к памяти программ, а не только к отдельным регистрам, как это было в предыдущих командах.

«Lds» и «sts» — четырехбайтовые команды, которые передают данные между РОН и пространством данных, используя прямую адресацию (команды 36.5 и 36.6). Можно также использовать косвенную адресацию, применяя команды «ld(d)» и «st(d)» (команды 36.7, 36.8, 36.9, 36.10, 36.11, 36.12, 36.13, 36.14). В командах 36.10 и 36.14 обращение к данным производится с помощью индексных регистров X, Y или Z.

При использовании команд «ld» и «st» можно увеличивать или уменьшать на единицу содержимое индексных регистров. Возможности такого предекремент и постинкремент позволяют эмулировать стек при помощи этих команд. Команды «ldd» и «std» очень полезны в случаях, когда индекс является указателем на структуру данных. В других главах я рассмотрел более детально, как можно использовать эти команды при работе со структурами данных в программном коде, генерированном компилятором.


Младшие модели AVR используют основные возможности этих команд, чтобы производить доступ к данным в пространстве регистров общего назначения с помощью индексного регистра Z. Это значит, что можно создавать таблицы в РОН, хотя при этом не обеспечиваются все возможности, доступные в старших моделях AVR.

Стек в старших моделях AVR реализуется с помощью команд «push» и «pop», выполняющих операции с регистрами общего назначения (команды 36.15 и 36.16). Вас это может удивить, но я избегаю использования этих команд. Вместо них я предпочитаю применять команды «ld» и «st», реализующие индексную адресацию с предекрементом и постинкрементом, так как с их помощью можно обеспечить более простой доступ к данным. При этом стек микроконтроллеров AVR служит только для сохранения содержимого программного счетчика во время выполнения подпрограмм или обработчиков прерываний.

Последняя из команд пересылки данных - это команда загрузки из памяти программ «lpm» (команда 36.17). Она служит для загрузки данных из таблиц, хранящихся в памяти программ. Хотя ее применение кажется довольно очевидным, есть одна вещь, которую следует опасаться при обращении к памяти программ. В этой команде младший бит индексного регистра Z используется для указания байта, который будет читаться (старший или младший), тогда как оставшиеся 14 бит используются для указания адреса слова (рис. 36.1). Хотя большинство таблиц может создаваться с использованием словарной организации: читаем младший байт, увеличиваем содержимое Z на 1, читаем старший байт и т.д., имеются некоторые случаи, когда это невозможно. Например, если вы имеете таблицу с нечетным числом элементов, следует позаботиться, чтобы следующие команды размещались в памяти, начиная с четных адресов, Иначе в зависимости от программного обеспечения, генерирующего объектный код, эти команды могут быть размещены так, что границы слов окажутся посередине команды.


Команды арифметических и логических операций AVR

Выполнение арифметических и логических команд в AVR, на самом деле, довольно очевидно. Если вы знакомы с программированием на ассемблере для микропроцессоров Intel 8085 или 8086, у вас не будет никаких проблем и с AVR. Во всех командах первый параметр является источником первого операнда, используемого при операции, а также приемником результата (destination). Второй параметр, который не является обязательным, служит источником второго операнда (source).

Основными арифметическими операциями являются сложение и вычитание двух чисел (команды 36.18, 36.19, 36.20 и 36.21). Эти команды, по большей части, очевидны. Сложение и вычитание содержимого двух регистров производится при помощи команд «add» и «sub». Модификаций этих команд, которые учитывают значение флага переноса, позволяют выполнять операции над 8- или 16-разрядными числами, хранящимися в регистрах.

Вычисление выражения А = А - В, где 16-разрядное число А хранится в R0 и R1, а число В - в R2 и R3, может быть реализовано при помощи следующего ассемблерного кода для AVR:

sub R0, R2 ; Вычесть младшие 8 бит


sbc R1, R3 ; Теперь вычесть старшие 8 бит

Используя команды сложения и вычитания с учетом переноса можно легко обрабатывать 24- и 32-разрядные числа со знаком.

Прежде, чем перейти к описанию следующих команд, я хочу пояснить функции флагов отрицательного результата N («negative»), переполнения V («overflow») и знака S («sign»), так как они имеют некоторые особенности и сложны для понимания при первоначальном знакомстве.

Флаг отрицательного результата N просто копирует значение бита 7 результата, который показывает, является результат положительным или отрицательным числом. При выполнении команды:

sub R4, R5.

если содержимое регистра R4 больше или равно содержимому R5, то результат будет положительным, и бит 7 равняется нулю. Если же содержимое R4 меньше, чем содержимое R5, то бит 7 будет установлен в 1, показывая, что результат отрицателен и представлен в дополнительном коде.

Назначение флага переполнения V в регистре SREG может показаться вам не очень понятным. Этот флаг указывает на переполнение во время сложения или вычитания чисел со знаком. Рассмотрим пример:


add R1, R2

Флаг V будет установлен в 1, если в регистрах RI и R2 содержатся положительные числа, а результат их сложения окажется больше 127, или оба числа отрицательны, а результат будет меньше -128. Возможно, это не слишком понятно, но если рассмотреть пример с конкретными значениями, все станет гораздо яснее:

Idi R1, 100 ; Занести 0Ь00110100 в R1 и R2

Idi R2, 100

add R1, R2 ;R1 = R1 + R2

; = 100 + 100

; = 200

; = $С8 = 0b011001000

Десятичное число 200 в двоичной записи имеет значение бита 7 равное 1, что указывает на получение отрицательного результата число. Следовательно, после выполнения операции сложения флаг N будет установлен в 1. Но в данном случае вместе с флагом N будет также установлен в 1 флаг V, указывая, что произошло переполнение при обработке чисел со знаком.


Если содержимое R1 и R2 равно -100, то результатом сложения этих чисел будет -200 или $38, что является положительным числом. При этом флаг N будет сброшен в 0, показывая, что результат положителен, однако будет установлен флаг V, означающий, что на самом деле это не так.

При чтении предыдущего абзаца вы, возможно, заметили, что при помощи флагов N и V можно определить настоящий знак результата. Именно это и делает флаг знака S в регистре состояния. Если вы внимательно изучите описание команд, то увидите, что этот флаг принимает следующее значение:

S = N ^ V.

Использование флага S позволяет рассматривать результат как 9-разрядное число со знаком, где старшим (знаковым) разрядом как раз и является флаг S. Как было отмечено при описании флага V, он устанавливается в 1, когда бит 7 результата имеет неправильное значение, то есть результат не представлен правильным числом со знаком в дополнительном коде. Выполнив операцию «Исключающее ИЛИ» над значениями флага V и бита 7 результата, который хранится в бите N, вы получите реальный знак результата. В первом примере (100 + 100) происходит установка в 1 флагов V и N, в результате флаг S будет равняться нулю (1 ^ 1 = 0). Во втором примере (-100 - 100) флаг N сбрасывается в 0, а флаг V устанавливается в 1, поэтому флаг S будет равняться единице, указывая на то, что результат отрицательный.


Флаг S должен использоваться только со старшим байтом числа. При операциях с 16-, 24- и 32-разрядными числами значение флага S надо проверять только после завершения последней операции со старшим байтом числа. При операциях с младшими байтами используется флаг переноса С, как обычно при выполнении сложения и вычитания.

Возвращаясь к командам сложения и вычитания, надо заметить, что кроме их модификаций, учитывающих флаг переноса, существует еще ряд команд, на которые следует обратить внимание, так как они облегчают жизнь разработчика программ. Первая — это вычитание непосредственно заданного операнда (команды 36.22 и 36.23). Эти команды производят вычитание константы из числа, хранящегося в регистре, и заносят результат обратно в этот регистр (аналогичных команд сложения нет). Важной особенностью команд, использующих непосредственно заданное число в качестве второго операнда, является то, что они могут обращаться только к 16-ти старшим РОН.

Команды «subi» и «sbci» могут использоваться совместно, чтобы произвести вычитание 16-разрядной константы из содержимого пары регистров. Вычитание 16-разрядной константы из содержимого индексного регистра X может быть выполнено при помощи следующей последовательности команд:


subi R26, Constant & $FF ; Вычитание из младшего байта

sbci R27, Constant » 8 ; Вычитание из старшего байта с

; учетом переноса

В начале описания команд «subi» и «sbci» было сказано, что нет аналогичных команд сложения. Но это не совсем так. Вы можете эмулировать сложение при помощи вычитания отрицательной константы, как это делается в следующем макросе:

MACRO addi Register, Value

subi Register, 0 – Value

ENDMACRO

В данном случае «ноль минус значение» дает отрицательное число в дополнительном коде, а вычитание отрицательного значения эквивалентно прибавлению положительного. Такая операция не может быть проделана для сложения непосредственного операнда с учетом флага переноса, так как значение этого флага будет вычитаться из результата.

После предыдущего примера надо указать, что есть простой способ для прибавления числа к содержимому индексных регистров или вычитания числа из него. Этим способом является использование команд «adiw» и «sbiw» (команды 36.24 и 36.25), которые позволяют прибавлять значение константы к содержимому 4-х старших пар РОН (в их число входят индексные регистры X, Y и Z) или вычитать их. Так как эти команды имеют длину в одно слово, значения констант, которые можно использовать, не должны превышать 63. Эти две команды хорошо подходят для программ, где индексные регистры являются указателями на стеки или структуры данных.


Команды инкремента и декремента (команды 36.26 и 36.27) являются еще одной формой явного сложения и вычитания. При этих операциях прибавляется или отнимается единица. Подобно командам инкремента и декремента в большинстве других микроконтроллеров и процессоров, выполнение этих операций не оказывает влияния на флаг переноса (хотя команды «adiw» и «sbiw» изменяют его значение). Но, несмотря на это операцию инкремента 16-разрядного числа можно выполнить довольно легко, как и в других процессорах:

Inc A ; Инкремент младшего байта 16-разрядного числа

Sbic SREG, Z ; Если результат равен 0, то инкремент старшего байта

inc A + 1

Декремент 16-разрядного числа выполняется не так просто, хотя для этого и используется такое же количество команд:

subi A, 1 ; Вычесть единицу из младшего байта

sbic SREG, С ; Если результат меньше нуля, то декремент

; старшего байта dec A + 1


В дальнейшем в реальных программах этот код можно сократить до одной команды «sbiw». Но здесь мне хотелось показать, что при работе с числами, разрядностью больше 8, надо вычитать 1 вместо выполнения операции декремента. Должен также еще раз обратить ваше внимание на то, что приведенный выше код для операции декремента будет работать только, если число находится в 16-ти старших РОН.

Смена знака содержимого регистра производится при помощи команды «neg» (команда 36.28). Она просто вычитает содержимое регистра из нуля и помещает результат обратно в регистр. Смена знака 16-разрядного (и более) числа гораздо более сложная операция, которая требует применения команд вычитания и использования дополнительного регистра.

neg A ; Меняем знак младшего байта

clr Rn ; Выполняем команду «sbc» с нулем

; для старшего байта

sbc Rn, A + 1 ; Здесь Rn - любой РОН

mov A + 1, Rn

Команда дополнения «com» (команда 36.29) инвертирует значения всех битов в заданном РОН. Она не изменяет знак числа, а выполняет те же действия, что и логическая операция Исключающее ИЛИ (XOR) с числом $0FF. Эта команда называется также «дополнение до единицы».


Приятной особенностью набора команд AVR является возможность сравнения содержимого двух регистров или регистра и константы без сохранения результата в каком-либо РОН (команды 36.30, 36.31 и 36.32). Команды сравнения, в сущности, производят вычитание без записи результата на место первого операнда. Команда «ср» сравнивает содержимое двух регистров, «срс» — содержимое двух регистров с учетом переноса, a «cpi» — содержимое регистра и константу.

Команда «tst»(команда 36.33) выполняет логическую операцию ИЛИ с содержимым указанного регистра и нулем, по результатам которой устанавливаются флаги нуля и отрицательного результата в регистре SREG. При рассмотрении команды «tst» вы будете удивлены, обнаружив, что флаг переполнения V сбрасывается в 0. Это сделано для того, чтобы быть уверенным, что флаг S будет установлен правильно. Так как S = N ^ V, то при V=0 флаг знака будет иметь правильное значение S = N.

Последняя арифметическая команда «mul» выполняет операцию умножения (команда 36.34). Она перемножает два 8-разрядных числа, обеспечивая получение 16-разрядного результата. Команда умножения работает только с числами без знака.

Команды логических операций я называю «побитовыми» («bitwise»), так как они изменяют значения отдельных битов. Чтобы было меньше путаницы, я сгруппировал их таким же образом, как это сделана фирма Atmel, но буду рассматривать их не как логические, а как «побитовые» команды.


Выполнение логической операции И с содержимым регистра (команды 36.35 и 36.36) не содержит чего-либо необычного и реализуется точно так, как вы ожидаете. Следует только обратить внимание на команду «cbr». Она выполняется как команда «andi» с инвертированием значения битов заданной константы перед логической операцией И с содержимым РОН, которое является первым операндом. Инвертирование значения константы производится при помощи операции Исключающее ИЛИ с числом $FF. Назначение команды «cbr» — сбросить в нуль значения указанных битов вместо того, чтобы сохранить их неизменными, как это делает обычная команда AND.

Команды логического ИЛИ (комэндб 36.37 и 36.38) в AVR имеют такой же формат записи, что и команды логического И. Это справедливо и для команды «sbr», которая аналогична команде «ori» так же, как «cbr» аналогична «andi». Однако при этом значение константы не инвертируется, как в команде «cbr», так как «sbr» предназначена для установки в 1 определенных битов, а не для сброса их в 0, как команда «cbr».

Команда «еоri» (команда 36.39) выполняет операцию Исключающее ИЛИ над битами содержимого двух регистров. К сожалению, нет команды «eori», которая позволила бы инвертировать значения определенных битов в регистре с помощью одной команды. Команда «еоri» может быть использована для обмена содержимым между двумя регистрами без использования третьего регистра для временного хранения:


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

mov Rn, A mov А, В mov В, Rn

Чтобы быть совершенно честным, скажу, что узнал об этой хитрости при изучении микроконтроллеров Р1С.

Последние две команды «clr» и «ser» (команды 36.40 и 36.41) используются, соответственно, для сброса в 0 и установки в 1 всех битов указанного регистра. С командой «clr» вы, вероятно, уже знакомы и знаете, для чего ее можно использовать, тогда как команда «ser» кажется, на первый взгляд, менее полезной. На самом деле эта команда очень полезна для записи в регистр начального значения -1 ($FF равно -1 в десятичном счислении). Я часто использую начальное значение -1, чтобы показать, что в регистр еще не была записана переменная.

Команды ветвления AVR

Архитектура AVR предоставляет широкие возможности для изменения порядка выполнения программы. Чтобы использовать все преимущества AVR в этой области, вы должны хорошо понимать, какие способы изменения содержимого программного счетчика реализуются в данной архитектуре.


Команды относительного перехода «rjmp» и вызова подпрограммы «rcall» (команды 36.42 и 36.43) являются основными для изменения последовательности выполнения команд в микроконтроллерах AVR. При этом содержимое программного счетчика изменяется на величину смещения, которое задается в 12 младших битах кода команды (рис. 36.2).

Рис. 36.2. Изменение содержимого программного счетчика в AVR при выполнении команд «rjmp» и «rcall»

При таком способе изменения содержимого программного счетчика в случае вызова подпрограммы с помощью команды «rcall» его старое содержимое записывается в стек до того, как в него поступит новый адрес. Это позволяет микроконтроллеру AVR вернуться обратно к месту, где произошел вызов подпрограммы, независимо от текущего состояния выполнения программы. Смещение может производиться в пределах +/-2 К адресов в пространстве памяти программ, что означает, что команды относительных переходов позволяют обратиться к любой позиции памяти программ младших моделей AVR серии 1200. Благодаря этой возможности, описанные далее команды прямых переходов «jmp» и «са11» не требуются для микроконтроллеров серии AVR 1200.

Важной особенностью, о которой я не упоминал ранее, является адресация и организация памяти программ в микроконтроллерах AVR. Когда фирма Atmel указывает объем памяти программ своих контроллеров, то, как правило, приводятся цифры в байтах. Каждая команда занимает два или четыре байта, так что количество хранящихся команд может быть равно половине (или меньше, если используется большое количество 4-байтовых команд) от заявленного объема памяти программ.


Все это может быть знакомо вам, если вы работали ранее с микропроцессорами типа 8086, которые используют 16-битовые слова, или с микроконтроллерами семейства 68НС05, где команды с различными способами адресации содержат разное количество байтов. Во многих микропроцессорах, таких как Intel 8086, каждый байт имеет собственный адрес, и каждое слово начинается с байта, имеющего четный адрес. В микроконтроллерах AVR обращение к каждому слову производится с помощью инкремента адреса. Понимание этого обстоятельства является очень важным, как было показано в предыдущем разделе при рассмотрении команды «lpm».

Вслед за командами «rjmp» и «rcall» рассмотрим команды безусловных переходов «jmp» и «call» (команды 36.44 и 36.45). Эти две команды предназначены для перехода на любой адрес в пределах 4 Мб памяти. Микроконтроллеры серии 8515 имеют память программ EEPROM емкостью 4 Кб, что свидетельствует о том, что фирма Atmel имеет большие планы по расширению возможностей AVR. Хотя я и не вижу необходимости в использовании для микроконтроллеров памяти программ емкостью 4 Мб, все же приятно видеть, как компания готовится к будущему. Я помню, что, когда появились первые компьютеры Apple II с емкостью памяти 64 Кб, многие думали, что это предел желаний для выполнения персональных вычислений.


Команды «jmp» и «call» имеют длину в два слова (четыре байта), что оказывает некоторое воздействие на ход выполнения программы. Во-первых, это влияет на число тактов, необходимых для выполнения команды. Выполнение команд «jmp» и «call» требует на один такт больше, чем команд «rjmp» и «rcall», которые выполняются за два и три такта, соответственно. Как вы увидите дальше, они также оказывают влияние на выполнение других команд.

Две последние команды для выполнения переходов и вызовов подпрограмм, которые следует обсудить — это команды «ijmp» и «icall», использующие индексный регистр Z (команды 36.46 и 36.47). Эти команды индексных переходов и вызовов подпрограмм имеются только в старших моделях AVR, Они модифицируют содержимое программного счетчика, как показано на рис. 36.3.

Рис. 36.3. Изменение содержимого программного счетчика в AVR при выполнении команд «ijmp» и «icall»

С помощью команд индексных переходов и вызовов подпрограмм можно легко реализовать конечный автомат (state machine) или логические структуры, выполняющие обработку таблиц. Эти команды отсутствуют в младших моделях AVR серии 1200, что означает, что они не могут выполнять индексные или табличные переходы и вызовы (в данных моделях не реализуется также команда «lpm»).


Как было упомянуто выше, при выполнении любой команды вызова «call» в AVR происходит сохранение в стеке полного адреса возврата, даже если эта команда осуществляет короткий относительный переход к адресу подпрограммы. Для возврата из подпрограммы используется команда «ret» (команда 36.48). Команда «reti» (команда 36.49) выполняется так же, как и «ret», с той лишь разницей, что после возврата еще разрешаются прерывания. Далее в этом разделе мы еще вернемся к прерываниям, но я хочу обратить внимание на один малоизвестный вариант использования команды «reti» - ее применение в подпрограммах, для которых время является критическим параметром, например, при работе с термодатчиком DS1820. Если вы не хотите, чтобы тратилось время на обслуживание прерывания, то надо замаскировать прерывания при входе в подпрограмму, а при выходе из нее снова их разрешить.

Можно использовать команду «sei» для разрешения прерываний, а затем команду «ret» для возврата, однако обе эти команды заменяются одной - «reti». Микроконтроллеры AVR могут выполнять команды ветвления по значению определенных битов в регистре состояния SREG (команды 36.50 и 36.51). Поскольку номер бита и его значение должны быть указаны в коде команды, то диапазон возможных адресов перехода уменьшается до +/- 63 относительно текущего адреса. Это означает, что применение команд условных ветвлений весьма ограничено, хотя эту проблему можно решить так же, как в микроконтроллерах 8051 и 68НС05 при помощи ветвления к команде, которая затем выполнит необходимый безусловный переход. Например, переход на метку Label при значении флага нуля Z=l может быть реализован следующим образом:


brne Skip ; Пропустить команду перехода на метку Label

rjmp Label

Skip

Таким образом обеспечивается возможность перехода в диапазоне адресов +/- 2 Кб вместо +/- 63 байта, как в командах условного ветвления.

При описании набора команд фирма Atmel рассматривает целый ряд (в общей сложности 18) команд, основанных на «brbc» и «brbs». Я привожу их в виде списка (см. таблицы в описании команд 36.50, 36.51), вместо того, чтобы отводить на каждую по отдельной странице описания.

При рассмотрении команд ветвлений я хочу показать, как команды сравнения и ветвления могут использоваться для реализации оператора «if» при использовании содержимого РОН. Например,

if (А == В) // Сравнить переменные А и В, находящиеся в РОН,

goto Label // В случае равенства перейти на метку Label

может быть скомпилировано в следующий код:

ср А,


В breq Label

что является очень простым преобразованием двух строчек исходного кода, написанного на языке высокого уровня. После недолгих раздумий можно найти решение для проверки условий «меньше, чем» и «больше, чем». Код на ассемблере AVR для операторов:

if (A < В) // Сравнить переменные А и В, находящиеся в РОН,

goto Label // Перейти на метку Label, если А < В

будет иметь простой вид:

ср А, В

brlt Label

Рассмотрим реализацию операторов:

if (A > В) // Сравнить переменные А и В, находящиеся в РОН,

goto Label // Перейти на метку Label, если А > В

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


cр В, А

brlt Label

Его можно легко получить с помощью следующей перестановки переменных в операторе «if»:

if (В < А)

Используя эту методику, можно легко выполнить переходы по условиям «меньше или равно» и «больше или равно»: Например, операторы:

if (А >= В) // Сравнить переменные А и В, находящиеся в РОН,

goto Label // Перейти на метку Label, если А >= В

реализуются с помощью кода:

ср А, В

brge Label

Операторное выражение:

if (А <= В) // Сравнить переменные А и В, находящиеся в РОН,

goto Label // Перейти на метку Label, если А <= В


можно представить в следующем виде:

if (В >= А) // Сравнить переменные А и В, находящиеся в РОН,

goto Label // Перейти на метку Label, если А <= В

что после компиляции дает такой код:

ср В, А

brge Label

Я использую команду «brge» (переход, если больше или равно) вместо «brpl» (переход, если знак плюс), так как эта команда учитывает значение флага S в регистре SREG. Как уже отмечалось в предыдущем разделе, данный флаг учитывает переполнение при сравнении чисел со знаком. Команда «brpl» учитывает только флаг N, который может быть неправильно установлен в случае переполнения.

Последний класс команд ветвления или изменения последовательности выполнения программы — это команды пропуска. После проверки указанного условия, данные команды либо выполняют следующую команду, либо пропускают ее.

При взгляде на описание команд можно увидеть, что команды пропуска могут выполняться за один, два или даже три такта. Впервые увидев это, вы, так же, как и я, можете подумать, что это просто чья-то ошибка. На самом деле это не так. Команды пропуска реализуются следующим образом:


1. Если условие не выполняется, то происходит переход на следующую команду, что занимает один такт.

2. Если условие выполняется и следующая команда не «jmp» или «call», то команда пропускается, а на выполнение команды пропуска требуется два такта.

3. Если условие выполняется, и следующей командой является «jmp» или «call», то пропускаются оба слова этой команды, а команда пропуска выполняется три такта.

Теперь, надо поговорить о командах «sbic» и «sbis» (команды 36.52 и 36.53), которые пропускают следующую команду при определенном значении бита в регистре ввода-вывода. Здесь надо быть аккуратным, так как они работают только с 32-мя первыми адресами в пространстве ввода-вывода. Вы, наверное, думаете, что это не проблема, но, взглянув на регистр SREG, можно увидеть, что его адрес в пространстве ввода-вывода равен $3F.

Данную проблему можно решить при помощи команд условного ветвления «brbc» и «brbs». Использовать их можно следующим образом:

brbs Bit, $ + 2 ; Пропустить следующую команду, если Bit = 1

Instruction


Но в таком случае может возникнуть проблема, если следующей командой будет «jmp», «call», «Ids» или «sts», то есть такая, которая занимает два слова. Переход может произойти на адрес, соответствующий середине команды, и контроллер будет пытаться интерпретировать часть команды так, как если бы это была самостоятельная команда, что может привести к разным неприятностям. Чтобы избежать этого, лучше выполнять переход на метку, а не на относительный адрес.

Вы также можете пропустить следующую команду при определенном значении бита в РОН. Для этого используются команды «srbo» и «sbrs» (команды 36.54 и 36.55).

Последняя команда ветвления «cpse» производит сравнение операндов и пропуск следующей команды в случае их равенства (команда 36.56). Как показано ниже, эта команда лучше всего подходит для проверки условия окончания цикла:

Loop

cpse А, В ; Выход из цикла, если условие выполняется

rjmp Loop

Битовые команды и команды тестирования битов


Когда вы впервые посмотрите на эту группу команд, вы, вероятно, удивитесь, почему фирма Atmel дала им такое название. Здесь есть несколько «настоящих» битовых операций, но в целом эта группа выглядит, как попытка собрать в одну кучу все оставшиеся команды, особенно, если принять во внимание наличие в ней команд сдвигов и циклических сдвигов.

Команды сброса (очистки) и установки битов (команды 36.57, 36.58, 36.59 и 36.60) предназначены для модифицирования содержимого регистров ввода-вывода. Когда вы рассмотрите выполнение команд «bclr», «bset». «cbi» и «sbi» , то увидите, что они могут работать только с частью пространства ввода-вывода: «bclr» и «bset» модифицируют бит в регистре состояния, a «cbi» и «sbi» имеют доступ только к 32-м первым адресам регистров ввода-вывода. Это значит, что для большинства регистров ввода-вывода вы должны сначала переписать их содержимое в РОН, модифицировать, а затем снова сохранить в регистре ввода-вывода. Для выполнения этой процедуры можно написать специальную макрокоманду:

Эту макрокоманду можно также использовать для сброса в 0 битов, находящихся в РОН. Обратите внимание, что регистр общего назначения Temp должен иметь адрес от 16 до 31.

Команды «bset» и «bclr» имеют также ряд «псевдокоманд», которые служат для изменения значений отдельных битов в регистре SREG. Мнемокоды, используемые для «псевдокоманд», позволяют лучше запомнить выполняемую операцию. Эти «псевдокоманды» приведены ниже в описаниях соответствующих команд.


Привлекательными для пользователей являются особенности реализации некоторых команд в AVR. Одной из таких приятных особенностей я считаю реализацию команд «bst» и «bid» (команды 36.61 и 36.62). Они позволяют легко пересылать отдельные биты содержимого регистров, не изменяя содержимого других регистров, которые могут повлиять на ход выполнения программы. Что же замечательного в этих командах?

Я часто сталкиваюсь с ситуациями, когда надо переслать бит из одного регистра или переменной в другой:

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

Команда «swap» (команда 36.63) производит обмен содержимым тетрад в заданном РОН. Это полезно, когда вы храните в регистре две цифры, а не одно 8-битовое число. Чтобы вывести его на индикатор, можно использовать следующий код:


Команды сдвигов и циклических сдвигов «Isl», «Isr», «rol», «ror» и «asr» (команды 36.64, 36.65, 36.66, 36.67 и 36.68) полезны как для выполнения сдвигов данных в процессе их ввода или вывода, так и для проверки значения определенного бита в РОН без необходимости выполнения 8 отдельных операций тестирования битов. С помощью циклического сдвига можно произвести индивидуальную проверку любого бита в заданном месте байта.

Если вы интересуетесь, в чем состоит различие между командами обычного («shift») и циклического («rotate») сдвига, то я советую представить себе операцию «rotate» как вращение колеса, на котором расположена последовательность блоков, содержащих по одному биту. Такое расположение битов показано на рис. 36.4, где также показан флаг переноса, который занимает одну из позиций на колесе. Колесо может повернуться в любую позицию, при этом данные перемещаются, но не теряются Команда циклического сдвига помещает выдвигаемый бит в флаг переноса, а старое значение флага продвигается дальше, Это означает, что флаг переноса является одним из блоков на колесе, содержащем 9 бит.

В командах обычного сдвига «shift» биты можно представить выстроенными в один ряд на уступе (рис. 36.4). Когда вы сдвигаете блоки, один из них падает с уступа и теряется. Вы можете затем сдвигать биты в обратном направлении, но данные уже будут потеряны. В этом состоит основное отличие этих операций от циклического сдвига, при котором не имеет значения, как часто и в каком направлении производятся сдвиги - данные никогда не будут потеряны.


Различные типы сдвигов отличаются между собой тем, как заполняются освобождающиеся биты. В логических сдвигах «lsl», «lsr», заполнение всегда происходит нулями. При арифметическом сдвиге вправо «asr» знаковый разряд (бит 7) остается неизменным, что важно, когда сдвиг используется для деления числа со знаком на числа, являющиеся степенями двойки.

Рис. 36.4. Команды AVR Shift/Rotate

Последние три команды в этой группе скорее относятся к командам управления процессором и должны быть хорошо нам знакомы, так как они есть но всех типах микроконтроллеров и многих микропроцессорах. Первая из них — это команда «пор» (команда 36.69), работа которой стоп, очевидна, что чем меньше мы будем о нем говорить, тем лучше.

Команда «wdr» (команда 36.70) сбрасывает в нулевое состояние сторожевой таймер (watchdog timer) прежде, чем он получит возможность перезапустить микроконтроллер. Далее мы вернемся к рассмотрению работы сторожевого таймера в AVR.

Команда «sleep» (команда 36.71) переводит AVR в состояние ожидания с пониженным 'энергопотреблением, при котором работа микроконтроллера останавливается. Он остается в этом состоянии до поступления сигнала прерывания или запуска, которые снова переводят его в рабочее состояние. Если бит SM и регистре управления процессора MCUCR сброшен в 0. то внешние тактовые сигналы продолжают поступать, так что внутренние запросы прерывания от таймера или сторожевого устройства могут «разбудить» микроконтроллер так же, как и внешний сигнал прерывания. В документации на AVR написано, что команда «sleep» выполняется за три цикла. Эти три цикла тратятся на выполнение самой команды «sleep», а также на загрузку и выполнение следующей команды.


Если бит SM установлен в 1, то при выполнении команды «sleep» генератор тактовых сигналов останавливается. При этом микроконтроллер может вернуться в рабочий режим только после прихода внешнего сигнала прерывания (изменения уровня потенциала на входе прерывания), гак как при остановленном генераторе таймеры не работают В данном случае при возврате в рабочей режим вы должны учитывать задержку в 16 мс, которая необходима для того, чтобы снова запустить генератор тактовых импульсов и дождаться стабилизации его частоты. Такая задержка реализуется встроенной в AVR схемой.

Глава 37

ПРИМЕРЫ ПРИМЕНЕНИЯ AVR

Для проверки работы приведенных ниже программ для микроконтроллеров AVR использовалась младшая модель этого семейства AVR1200. Этот микроконтроллер позволил мне получить достаточно хороший опыт работы с регистрами AVR и его набором команд. Первые программы, написанные мной, не имели прямого практического применения - они разрабатывались с целью получения опыта работы с этими микроконтроллерами.


Проблемы, с которыми я столкнулся при разработке этих приложений, были не очень серьезными. Две первые прикладные программы я написал в один вечер за несколько часов, одновременно изучая основы работы со стартовым комплексом разработчика Atmel AT89/90 Starter Kit. Трудности были связаны с отсутствием у меня опыта работы с архитектурой AVR. Первой ошибкой было то, что я впервые использовал микроконтроллер AVR, который имеет возможность самопроизвольного повторного запуска без какого-либо предупреждения, что привело к проблемам при отладке второй программы. Кроме того, все другие микроконтроллеры, представленные в этой книге, имеют специальный регистр-аккумулятор для хранения промежуточных результатов арифметических операций, поэтому при написании программ для AVR мне пришлось изменить свой стереотип разработки прикладных программ.

Первое приложение

Если вы внимательно ознакомились с первыми тремя семействами микроконтроллеров, то, вероятно, уже стали большим специалистом по написанию приложений для устройств, использующих одну кнопку и два светодиода. Микроконтроллер AVR не доставит вам особых забот в этом приложении. Схема, используемая в данном примере, не содержит никаких сюрпризов (рис. 37.1). Единственное, на что стоит обратить внимание в этой схеме - это включение резистора сопротивлением 10 К на входе Reset. Его использование не является обязательным, то есть вы можете оставить этот вывод неподключенным («плавающим»), но я сделал такое включение просто по привычке. Вы также должны обратить внимание на то. что я использовал внутреннее «подтягивание» к напряжению питания вывода 5 порта D (PD.5) вместо внешнего подключения кнопки к этой шине.


Рис.37.1. Схема первого приложения, использующая AVR

Написание, проверка на симуляторе и тестирование этого приложения заняло у меня чуть меньше часа, хотя это была моя первая программа для AVR. Я был очень доволен таким результатом, потому что данная прикладная программа содержит обработчик прерываний для обслуживания запросов прерывания от таймера и не использует каких-либо РОН. за исключением инициализации регистров ввода-вывода.

Единственной неожиданностью, которую я обнаружил, когда первый раз запустил эту программу, было слишком частое мигание светодиода, управляемого таймером. Он мигал гораздо чаше, чем два раза в секунду, как ожидалось при проектировании. Дело в том, что при вычислении множителя для определения периода срабатывания таймера я по привычке использовал командные циклы, длительностью по 4 такта каждый, а не такты. Когда значение коэффициента для предварительного делителя частоты было увеличено в четыре раза — с 256 до 1024, приложение стало работать без каких-либо проблем.

Как уже говорилось при описании стартового комплекса разработчика Starter Kit AT89/90, плата программатора имеет восемь светодиодов и восемь кнопочных переключателей, которые могут быть подсоединены к программатору при помощи кабеля с разъемом IDC, входящего в состав комплекса. Рассмотренное приложение может быть легко реализовано на данном комплексе, надо только подключить кабели. Хотя тактовая частота в комплексе составляет 4 МГц вместо 1 МГц, как предполагалось при написании программы, это приведет только к тому, что светодиоды будут мигать очень часто.


Часы реального времени и термометр

Как и создание первого приложения, описанного выше, реализация часов с термометром является для вас давно знакомой задачей. Здесь никаких сюрпризов. Единственное, что следует отметить — я не использовал внешний резистор для «подтягивания» к напряжению питания вывода, к которому подключена кнопка установки времени, хотя такой резистор подключен к линии последовательного интерфейса термодатчика DS1820 (рис 37.2). Это сделано для того, чтобы избежать каких-либо неприятностей с внутренними КМОП-схемами, «подтягивающими» выводы к напряжению питания.

Рис. 37.2. Цифровые часы/термометр на основе AVR

Особенностью реализации этого приложения на базе AVR по сравнению с аналогичными приложениями, написанными для других микроконтроллеров, является недостаток возможностей для размещения таблиц в памяти программ. Вместо этого, заголовки «Time:» и «Temp:» должны быть введены в исходный код программы следующим образом:

В данном приложении проявляются некоторые недостатки ассемблера/симулятора AVR. Первый — это отсутствие возможностей определять константы в виде ASCII-символов. Обычно при написании программ я стараюсь использовать наиболее подходящий тип для реализации данных. То обстоятельство, что в AVR нельзя вводить константы в виде символов, иногда вызывает значительные неудобства. Обычно я никогда не пользуюсь таблицей символов ASCII при написании программ. Симулятор AVR также несколько разочаровал меня, так как он не показывает содержимое регистров ввода-вывода, а только содержимое РОН и некоторых других регистров процессора. Честно говоря, данные недостатки не очень значительны, и я никогда не имел проблем с программным обеспечением, которое использовал. При этом я уверен, что в последующих версиях программ все недочеты будут устранены.


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

Однако это не решило проблем с ложными сбросами микроконтроллера. Данная проблема была решена путем замены контроллера на другой образец AVR1200. Образец, который я первоначально использовал, относился к очень ранним партиям выпуска, поэтому не удивительно, что при его использовании возникли некоторые проблемы.


При разработке данного приложения я попутно нашел один интересный способ реализации 16-битовой задержки в AVR:

Здесь Count и Counthi - регистры общего назначения с адресами в диапазоне от $10 до $1F. При помощи этого фрагмента кода можно обеспечить очень широкий диапазон задержек значительно проще, чем это реализуется в микроконтроллерах PIC. Каждый цикл выполняется в течение 5 тактов независимо от того, производится инкремент старшего байта счетчика циклов, или не производится. Чтобы получить необходимую задержку, можно воспользоваться формулой:

Задержка = (Начальное значение счетчика*5)/Тактовая частота

Чтобы определить требуемое начальное значение счетчика при заданной задержке, можно переписать формулу следующим образом:

Начальное значение = (Задержка * Тактовая частота)/5

При реализации задержки по этой формуле следует учесть, какие значения должны быть загружены в регистры Count и Counthi. В регистр Count заносятся младшие восемь бит начального значения, а в регистр Countlii — старшие 8 бит плюс I, для того, чтобы выполнялось требуемое число циклов. Это отражено в комментарии к приведенному выше фрагменту программного кода.


Вывод изображения с возможностью его позиционирования

В начале этой книги был затронут вопрос о работе микроконтроллера с аналоговыми сигналами — как входными, так и выходными. Как было отмечено, для ввода аналогового сигнала можно использовать простой потенциометр с конденсатором, а для реализации аналогового выхода - резисторный делитель напряжения. Мне хотелось написать приложение, которое демонстрировало бы, как все это можно реализовать на практике. Лучшим примером, на мой взгляд, могла бы стать программа, в которой аналоговый вход будет использоваться для перемещения пятна на видеоэкране. Эту программу мне хотелось написать именно для микроконтроллеров AVR которые выполняют большую часть команд за один командный цикл, что является большим преимуществом при работе с изображением (рис. 37.3).

Данная схема выводит на экран полный видеосигнал в системе NTSC с помощью программного обеспечения, написанного для данного приложения. Соответствующая схема оказывается неожиданно простои (рис 37.4).

Макет был реализован на основе набора SimmStick. Схема была подключена к интерфейсной плате с источником питания DT003, а видеосигнал поступал по линии А15 на видеомодулятор, подсоединенный к макетной плате SimmStick. Такой метод макетирования очень прост и эффективен (рис. 37.5).


Как показано на рис. 37.4, я поместил все компоненты схемы на плату SimmStick. Это несколько расходится с моими рассуждениями о том, что интерфейс с периферийными устройствами должен быть реализован отдельно от SimmStick, но я имел возможность подключить выходные резисторы непосредственно к выводам микроконтроллера и соединить их с резистором, «подтягивающим» выходной сигнал к напряжению питания. Конденсатор и потенциометр были смонтированы с обратной стороны платы SimmStick, так, чтобы можно было менять позицию потенциометра, когда перед этой платой включена плата модулятора. Такая компоновка упрощает работу с макетом.

Рис. 37.3. Платы SimmStick, используемые для вывода видеосигналов с помощью микроконтроллера AVR (на рисунке по часовой стрелке, начиная с правого-верхнего угла, показаны: макетная плата с видеомодулятором, интерфейсная плата DT003 с источником питания и плата SimmStick DT104 на основе процессора AVR с резистивным делителем для вывода видеосигнала)

Рис. 37.4. Схема на основе AVR, реализующая позиционирование и вывод видеосигнала

Рис. 37.5. Плата SimmStick DT104 с микроконтроллером AVR и резисторным делителем для вывода полнот видеосигнала


При первом запуске программы я столкнулся с одной проблемой - небольшим «шумом» на выходной линии. С помощью осциллографа я определил, что шум имеет частоту 60 МГц, а его амплитуда равна 200 мВ. При низком уровне сигнала на выходе AVR этот шум мог вызвать некоторые проблемы. Когда я посмотрел на плату SimmStick, то увидел, что развязывающий конденсатор расположен слишком далеко от выводов микроконтроллера AVR. После того, как конденсатор емкостью 0,1 мкФ был включен непосредственно между выводами питания Vcc и "земля" микроконтроллера, шум был уменьшен до приемлемого уровня в 50 мВ.

Аналоговое выходное напряжение формируется при помощи делителя напряжения, в котором верхний резистор имеет сопротивление 470 Ом. При первом взгляде на схему вас, наверное, удивило, где я нашел для нее резисторы с сопротивлением 74 и 66 Ом. Реально эти сопротивления получаются с помощью параллельного соединения резисторов: 74 или 75 Ом - это два резистора по 150 Ом, соединенных параллельно, а 66 Ом реализуется при параллельном соединении трех резисторов по 200 Ом. Для формирования требуемого напряжения определенные выводы подключаются к «земле» (логический 0), в результате чего образуется делитель напряжения из верхнего резистора сопротивлением 470 Ом и параллельного соединения нижних резисторов, соединенных с выводами микроконтроллера.


Правда, это не та схема, которую можно запускать в производство, так как она предполагает, что при включенном питании микроконтроллер всегда активен и правильно выполняет программу. Если все выводы контроллера находятся в режиме ввода, или в режиме вывода с подачей на них высокого уровня потенциала, то на выходе делителя установится потенциал +4,5 В или больше, что может быть проблемой для ТВ-модулятора, к которому подключена схема.

Если бы я собрался снова сделать такую схему, я бы использовал этот делитель для управления другим делителем напряжения, который бы уменьшил уровень выходного сигнала до нужной величины, то есть из 5 В сделал бы 1,5 В в качестве сигнала «белого» поля.

Видеомодулятор был куплен мной за 1,5 доллара в местном магазине уцененных товаров. Для его питания требуется напряжение +12В. Чтобы не усложнять схему подсоединения макета, я подавал на модулятор напряжение + 13В с выхода питания «Wall Wart», подсоединив модулятор к выводу PWR на шине SimmStick. Видеомодулятор должен быть помещен в металлический корпус для уменьшения излучения при работе устройства.

Прежде чем продолжить описание устройства, я должен сделать несколько важных замечаний. Первое — это то, что при написании приложения я не имел полной спецификации видеосигналов NTSC. Я использовал видеокамеру «Tyco VideoCam», купленную в магазине игрушек, которая имеет выход полного видеосигнала, просмотрел на осциллографе выходной видеосигнал и то, что увидел, применил в данном приложении. Это приложение отлично работало на 12-дюймовом черно-белом телевизоре, который был куплен на распродаже за 10 долларов.


Я не советую испытывать это приложение на «домашнем кинотеатре» сто имостью 3000 долларов. Нет каких-либо объективных предпосылок для того, чтобы данная схема могла испортить телевизор или монитор, но я не хочу проверять это на своей аппаратуре. Как и в других приложениях, описанных в этой книге, многие детали брались из магазина уцененных вещей или из моей коробки для старых деталей, так что некоторые спецификации могут быть нарушены, а при неправильном соединении между вашей схемой и телевизором может потечь слишком большой ток.

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

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

Полный видеосигнал устанавливает на выходе четыре различных уровня потенциала. Это можно показать на примере импульса горизонтальной синхронизации (рис. 37.6). Каждый из этих четырех уровней образуется путем подачи на один из выходов микроконтроллера низкого уровня потенциала. При этом образуется делитель напряжения, который может отдавать в нагрузку ток величиной более 100 мкА без существенного изменения уровня выходного потенциала.


Рис. 37.6. Импульс горизонтальной синхронизации видеосигнала AVR

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

Сигнал горизонтальной синхронизации является частью полного строчного сигнала, вид которого представлен на рис. 37.7. После каждого импульса горизонтальной синхронизации идет передача видео данных в течение 53 мкс. На рис. 37.7 показаны различные уровни серого цвета, но в приложении использовались только черный и белый цвета.

Рис. 37.7. Вывод строки видеосигнала с помощью AVR

Вывод данных в течение 53 мкс - это только одна из областей, в которых с успехом может применяться AVR. Большая тактовая частота и возможность выполнения команд за один цикл означает, что за это время можно выполнить до 795 команд. Это особенно важно, так как первоначальной целью этого приложения была реализация видеоигры наподобие настольного тенниса. Использование других микроконтроллеров значительно уменьшило бы количество выполняемых команд, так как они требуют больше циклов для их реализации.


Приложение выводит 268, а затем 267 строк данных (в общей сложности 535 строк) в каждом из двух полей. В конце каждого из полей выводится шесть или семь коротких строк, за которыми следует шесть импульсов вертикальной синхронизации, пять или шесть коротких строк и затем одиннадцать длинных строк, после которых начинаются данные. Это повторяется дважды для каждого полного кадра. Разница в коротких импульсах, содержащих данные должна составлять полстроки для каждого поля, чтобы заполнить экран строками, которые пропущены в предыдущем полукадре.

На рис. 37.8 приведена форма сигнала на потенциометре. Во время начала поля происходит заряд конденсатора, а во время вывода изображения меняется режим работы вывода (с вывода данных на их ввод) и происходит ожидание разряда конденсатора. Суть идеи состоит в том, чтобы вывести белое пятно на экран в точке разряда конденсатора.

Рис. 37.8. Вертикальная синхронизация полного видеосигнала AVR с интегральным чтением положения потенциометра

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


На прилагаемом к книге CD-ROM вы обнаружите три версии программ для этого приложения. Первая предназначена для проверки уровня аналогового выхода до попытки работы с видеосигналом. Вторая программа (Ap3v2.ASM) выводит в центр телевизионного экрана белую полоску, и последняя (Ap3v3.ASM) - обеспечивает вывод полоски в правом нижнем углу экрана, а также вывод светового пятна, которое можно двигать путем вращения потенциометра.

Последняя программа использует 179 слов памяти программ из 512 доступных, так что ее легко можно расширить до игры, более напоминающей теннис. Я не стал до конца реализовывать эту игру из-за аппаратных неудобств - реальный уровень выходного напряжения несколько отличался от того, который хотелось бы иметь, хотя приложение хорошо работало на моем дешевом телевизоре. Другая важная причина связана с работой связки конденсатор-потенциометр, используемой для управления. Надо было бы поменять номиналы компонентов для того, чтобы максимальное время разряда конденсатора было больше времени вывода на экран одного поля. Можно было бы также включить между потенциометром и землей дополнительный резистор сопротивлением 10 К для того, чтобы помочь решить эту проблему Кроме того, это позволило бы немного улучшить форму сигнала при минимальном значении сопротивления потенциометра. Когда я правил эту книгу перед посылкой ее в издательство, то обнаружил, что неправильно включил потенциометр. Контакт потенциометра, подсоединенный к земле, должен оставаться неподключенным.


Должен сказать, что это приложение было единственным из тех, которые я разрабатывал для этой книги, которое заставило меня после его создания расслабиться и почувствовать, что я действительно чего-то достиг. Хотелось бы, конечно, найти хорошую спецификацию полного видеосигнала NTSC, так как было очень трудно анализировать выходной сигнал видеокамеры «TycoVideoCam» и применять все это к моему приложению. На реализацию этого приложения я потратил больше времени, чем проведу, глядя на экран и вращая ручку переменного резистора. Если у меня будет свободное время, я, возможно, займусь улучшением этого приложения, но пока я удовлетворен тем, что могу, показывая на экран, рассказывать детям о том, что сделал их отец.

Глава 38

ЗАКЛЮЧЕНИЕ ПО СЕМЕЙСТВУ AVR

За то короткое время, которое AVR присутствует на рынке, он оказал, огромное влияние на весь мир микроконтроллеров. Как я уже упоминал, к моменту написания этой книги AVR был доступен для пользователей только шесть месяцев, и я был сильно удивлен тем интересом, который он вызвал. Каждый производитель, продукция которого описывается в книге, придерживается своей собственной модели бизнеса. Фирма Atmef ориентируется на выпуск микроконтроллеров, которые имеют только флэш-память для; хранения программ, что является весьма привлекательным и отличает ее от других производителей. Лично мне это очень нравится, так: как я всегда предпочитал контроллеры, которые используют для хранения программного обеспечения флэш-память с возможностью внутрисхемного программирования, а не память EPROM с однократным программированием или масочно-программируемую память ROM.


Я собираюсь продолжить свои опыты с микроконтроллерами' AV-R и создать ряд новых приложений, а также провести эксперименты; с созданием структур данных. Хотя в начале своего описания я, отметил наличие 32- регистров общего назначения как ограничение AVR, при написании- прикладных программ для этой книги увидел, что можно обеспечить баланс между использованием РОН микроконтроллера и памяти RAM.

Оглядываясь назад, я понимаю, что надо было бы уделить больше внимания различиям между архитектурой старших и младших (серия 1200) моделей AVR. Хотя AVR1200 может выполнять большую часть команд из тех, которые реализуют старшие модели, недостаток внешней памяти и наличие стека глубиной всего в 3 элемента оказывают большое влияние на создание приложений.

В 1998 году фирма Atmel планирует выпустить ряд новых моделей из числа тех, которые были анонсированы. Они будут иметь дополнительные периферийные устройства и варианты реализации памяти, что значительно обогатит семейство AVR.

Информационная поддержка AVR

Так как AVR один из самых новых микроконтроллеров, имеющихся на рынке (первые образцы появились в продаже в середине 1997 г.), вполне понятно, что ему посвящено меньшее количество информации по сравнению с другими микроконтроллерами, доступными для пользователя. Я думаю, что ситуация скоро изменится в лучшую сторону, и не удивлюсь, если информация, представленная в этом разделе, устареет уже к концу 1998 г.