Программирование микропроцессорных систем

  • Вид работы:
    Методичка
  • Предмет:
    Информационное обеспечение, программирование
  • Язык:
    Русский
    ,
    Формат файла:
    MS Word
    2,14 Mb
  • Опубликовано:
    2011-11-27
Вы можете узнать стоимость помощи в написании студенческой работы.
Помощь в написании работы, которую точно примут!

Программирование микропроцессорных систем

           

        

        

        

        

        

        



МЕТОДИЧЕСКИЕ УКАЗАНИЯ

к лабораторным работам

по дисциплине

«Программирование микропроцессорных систем»

Содержание

         Введение. Микропроцессор

1. Лабораторная № 1

.1 Устройство и работа D-триггера

.2 Параллельный регистр

1.3 Параллельный регистр с расширенными возможностями

1.4 Работа делителя частоты

1.5 Счетчики прямого счета

1.6 Счетчики с обратным отсчетом

1.7 Делители с переменным коэффициентом деления

1.8 Таймеры

1.9 Дешифраторы

2. Лабораторная № 2

.1 Общие положения

.2 Простейшая программа

.3 Принципиальная электрическая схема

.4 Алгоритм

.5 Программа на Ассемблере

2.6 Директивы

2.7 Операторы

2.8 Описание программы

3. Лабораторная №3

3.1 Переключающийся светодиод

3.2 Принципиальная схема

3.3 Алгоритм

4. Лабораторная № 4

4.1 Бегущие огни

4.2 Схема

4.3 Алгоритм

5. Лабораторная № 5

5.1 Использование таймера

5.2 Схема

5.3 Алгоритм

5.4 Использование прерываний по таймеру

5.5 Схема

6. Лабораторная № 6

6.1 Формирование звука

6.2 Схема

6.3 Алгоритм

7. Лабораторная №7

7.1 Программная среда AVR Studio

7.2 Программный отладчик

        

        
Введение.
Микропроцессор


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

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

Где же применяются микропроцессоры? Да просто везде! Посмотрите вокруг себя. У вас в квартире стоит современный телевизор? Не сомневайтесь: в нем есть, как минимум, один процессор. У вас есть на руке электронные часы? Современные часы строятся на основе специализированного микропроцессора. Ну, а мобильные телефоны - это вообще миниатюрные компьютеры!

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

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

Что же это за сопутствующие элементы? Это очень важные составные части микропроцессорной системы. Без них не может обходиться ни один микропроцессор. Итак, мы подходим к первому важному вопросу - составу типовой микропроцессорной системы. Любая микропроцессорная система (рис. 1) состоит из следующих основных элементов: процессор, модуль памяти, порты ввода-вывода. Рассмотрим каждую из этих составляющих подробнее.

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

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

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

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

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

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

А также и в обратном направлении: от портов ввода вывода и памяти к процессору.


Рис. 1 Основные составляющие компьютерной системы

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

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

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

Процессор считывает их в виде чисел и обрабатывает полученные числа в соответствии с алгоритмом управления.

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

Эти сигналы используются для управления. Управлять можно любым устройством, которое допускает электрическое управление, это: индикаторы; дисплеи; электромагнитные реле; электромоторы; электропневмоклапаны; электрические нагреватели и т. д.

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

1. Лабораторная № 1

Триггерные схемы

Триггер - логическое устройство, способное хранить 1 бит данных. (Название единицы информации 1 бит происходит от слов binary digit, т. е. двоичный разряд). К триггерам принято относить все устройства, имеющие два устойчивых состояния. В основе любого триггера находится кольцо из двух инверторов, показанное на рис. 1.1, а. Общепринято это кольцо изображать в виде так называемой защелки, которая показана на рис. 1.1,б. Принципиальная схема простейшего триггера-защелки, выполненного на двух инверторах резисторно-транзисторной логики, дана на рис. 1.1, в. Цепи входного управления у этой защелки нет.


После подачи на триггер напряжения питания состояния его транзисторов могут быть равновероятны: либо насыщен транзистор VT1, а VT2 находится в состоянии отсечки, либо наоборот. Эти состояния устойчивы. Защелка не может работать как мультивибратор. Пусть по каким-то причинам при включении питания на коллекторе одного из транзисторов, например VT1, коллекторное напряжение снижается, тем самым уменьшается базовый ток IБ2 транзистора VT2, следовательно, падает и сила его коллекторного тока IК2. Из-за этого на коллекторе VT2 напряжение Uи.п - I К2R К2 должно повыситься. Если это так, то должен еще быстрее возрастать базовый ток IБ1 транзистора VT1, ускоряя его переход к состоянию насыщения. Этот процесс идет быстро, лавинообразно. Он называется регенеративным. Процесс окончится, когда перестанет изменяться коллекторный ток транзистора VT1 и он перейдет в состояние насыщения. Транзистор VT2 окажется в состоянии отсечки.

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

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

Для формирования сигналов управления триггерами используются часто логические элементы со свойствами триггера Шмита.

На рис. 1.2, а показана принципиальная схема RS-триггера, которая содержит защелку (транзисторы VT1 и VT2), а также два раздельных статических входа управления (транзисторы VT3 и VT4). Эти входы управления называются R (reset - сброс) и S (set - установка). Иногда входы R и S называют по-другому: clear - очистка (сброс) и preset - предварительная установка соответственно. К входам раздельного статического запуска, триггера R и S присоединены управляющие переключатели S1 и S2. Поскольку от каждого из них на входы можно подать напряжение низкого Н или высокого В уровней, то имеется четыре комбинации этих управляющих сигналов.

Рис. 1.2. RS-триггер

Они перечислены в колонках R и S таблицы состояний RS-триггера (рис. 1.2,б). Если от S1 и S2 подать на оба входа R и S напряжение низкого уровня (Н, Н), то транзисторы VT3 и VT4 открывающих токов не получат, будут разомкнуты и поэтому не смогут повлиять на состояние транзисторов защелки VT1 и VT2. Напряжения на выходах триггера Q и Q останутся без изменения. Это значит, что в триггере осталась информация, записанная ранее.

Переведем движок переключателя S2 в положение В (высокое входное напряжение), оставив S1 в Н (низкое). Теперь транзистор VT4 будет насыщен, он замкнется и окажется низким напряжением на коллекторе присоединенного в параллель ему транзистора VT2. На входе Q будет также напряжение низкого уровня. Транзистор VT1 больше не получит от выхода Q открывающий базовый ток, поэтому он перейдет в состояние отсечки. По этой причине на выходе Q появляется напряжение высокого уровня (транзистор VT3 от переключателя S1 ток смещения не получает и на этот процесс в триггере не влияет). Данное состояние транзисторов VT1 и VT2 будет зафиксировано, защелкнуто.

Поменять напряжения на выходах Q и Q можно, если перевести движки переключателей S1 и S2 в положения В и Н соответственно (см. третью строку таблицы на рис. 1.2,б). Наконец, возможно четвертое состояние переключателей S1 и S2: оба их движка переводятся в состояние В. Такой входной сигнал RS-триггер зафиксировать не может. Действительно, в этом случае, когда S1 = S2 = B, на обоих выходах Q и Q должно появиться напряжение низкого уровня. Но если S1 и S2 строго одновременно отсоединить от входов, триггер переключится в неопределенное состояние. Иначе, после исчезновения входного состояния В, В защелка не переключается однозначно. Таким образом, два логических уровня В, В одновременно на входы R и S подавать нельзя.

На рис. 1.2, в показано функциональное обозначение RS-триггера, составленного из двух двухвходовых инверторов. Такой триггер можно строить на элементах И и на элементах ИЛИ. На рис. 1.2, г дана таблица логических состояний для RS-триггеров, построенных на элементах И и ИЛИ. Строки состояний «Без изменений» и «Неопределенность» здесь меняются местами в зависимости от выбранного соответствия 1 и 0 напряжениям высокого и низкого уровня.

Таким образом, RS-триггер имеет два раздельных статических входа управления, чтобы можно было записывать и хранить 1 бит информации. Вместе с тем, известно, что триггерные ячейки - это основа многих динамических устройств, главные из которых: делители частоты, счетчики и регистры. В этих устройствах записанную ранее информацию по специальному сигналу, называемому тактовым, следует передать на выход и переписать в следующую ячейку. Для осуществления такого режима RS-триггер необходимо снабдить тактовым входом С (clock).

Предварительно рассмотрим принципиальную схему так называемого Т-триггера (toggle - переключатель), выполняющего лишь одну функцию: он может делить частоту тактовой последовательности, подаваемой на вход С в 2 раза. Принципиальная схема Т-триггера, содержащего два инвертора DD1.1 и DD1.2 популярной в 50-60 годы резистивно-емкостной логики (РЕТЛ), показана на рис. 1.3, а. Схему тактового запуска здесь образуют два резисторно-диодных логических элемента И без инверсии (DD1.3 и DD1.4). Функциональная схема этого Т-триггера показана на рис. 1.3,б.


Для начала анализа работы Т-триггера положим, что в интервале времени от 0 до t1 (рис. 1.3, в) транзистор VT1 насыщен, его база получает избыточный ток от положительного полюса Uи.п через резисторы Rб1 и Rk2; транзистор VT2 разомкнут. Тогда на выходе Q напряжение низкого уровня не должно превышать 0,3 В. На выходе будет напряжение высокого уровня U = Uи.п. Следовательно, диод VD2 надежно закрыт, поскольку на его катоде присутствует большой положительный потенциал. Диод VD1 не закрыт. Обратим внимание также на то, что форсирующий конденсатор Сф1 заряжен до напряжения, существенно превышающего напряжение на втором таком же конденсаторе Сф2.

Таким образом, зная эти начальные условия, ждем прихода первого отрицательного перепада тактового импульса С в момент t1. Вызванный им отрицательный перепад тока выведет транзистор VT1 из состояния насыщения, поскольку скачок отрицательного (закрывающего) базового тока пройдет через незакрытый диод VD1 и конденсатор С1. Отметим, что через закрытый диод VD2 никакой скачок тока пройти не может. Поскольку скачок закрывающего базового тока транзистору VT1 был дан, должен уменьшиться и его коллекторный ток, что вызовет положительный перепад напряжения на коллекторе, т. е. на выходе Q. Далее, уже без влияния цепи запуска в RS-защелке происходит регенеративный процесс переброса, т. е. смены состояний транзисторов. Этот процесс идет однонаправлено и не останавливается с окончанием отрицательного перепада входного запускающего импульса С, что гарантируется неравенством начальных зарядов конденсаторов Сф1 и Сф2- Эти заряды мгновенно измениться не могут, поэтому конденсаторы Сф1 и Сф2 выполняют роль памяти предыдущего состояния. Но, как показал опыт, емкость форсирующих конденсаторов не должна превышать 30... 50 пФ, чтобы процесс не гасился избыточным током запуска.



Таким образом, по окончании регенерации в RS-защелке на выходе Q напряжение будет высоким, а на Q - низким (отрезок времени от t1 до t2). В этот период изменилось состояние диодов, распределяющих тактовые перепады: VD1 теперь заперт, a VD2 открыт, т. е. именно он готов передать RS-защелке очередной отрицательный перепад тактовой последовательности импульсов С. После прихода в момент t2 второго отрицательного перепада состояния выходов Q и Q вновь изменятся и закроется диод VD2, третий отрицательный перепад тактовой последовательности пройдет через диод VD1. Цикл работы Т-триггера на этом закончится.

Сигналы на выходах Q и Q имеют частоту повторения, в 2 раза меньшую, чем исходная тактовая последовательность С (сравните частоты повторения отрицательных фронтов на графиках UC, UQ и UQ (рис. 1.3, в). Таким образом, Т-триггер делит частоту входного сигнала в 2 раза, переключается отрицательным перепадом тактового импульса. Запуск отрицательным перепадом отмечен знаком инверсии С.

Рассмотренный Т-триггер несложно превратить в так называемый RST-триггер (рис. 1.4, а). Для этого разомкнем его внешние цепи обратных связей от выходов на цепь запуска Q - R и Q - S.



Ко входам R и S присоединим управляющие переключатели S1 и S2 (см. также рис. 1.3,б). Теперь еще до подачи перепада тактового импульса С в триггер можно записать две комбинации напряжений высоких и низких уровней, как и для RS-триггера (рис. 1.2,б). Записанная информация будет храниться в защелке до прихода тактового перепада С, и после прихода его триггер переключится. Полученный импульсный перепад выходных сигналов Q и Q будет однозначным. Бит информации в момент перепада появится на выходах RS-защелки. В данном случае его можно использовать для переключения последующего триггера.

Таблица состояний RST-триггера (рис. 1.4,б) показывает, что если на R и S входы поданы напряжения низких уровней, в триггере сохранится предыдущая информация. Она изменится на выходах на противоположное значение после прихода тактового импульса С. Подавать одновременно на статические входы два напряжения высоких уровней нельзя, поскольку аналогично RS-защелке выходной отклик окажется неопределенным. Этот основной недостаток RST-триггера послужил в свое время отправной точкой дальнейшего совершенствования методов запуска RS-защелки.

Заменим в схеме (рис. 1.4, а) элементы И (DD1.3 и DD1-.4) на двух-входовые инверторы. Получается принципиальная схема RST-триггера на элементах РТЛ (рис. 1.5, а). Функциональная схема его приведена на рис. 1.5,б, а таблица состояний на рис. 1.5, в. При напряжении высокого уровня на входе С (на входах R и S могут быть любые уровни) в промежуточных точках R' н S' появляются напряжения низкого уровня поскольку насыщаются транзисторы VT6 и VT7. На RS-защелку (элементы DD1.3 и DD1.4) прохождение управляющих сигналов R и S запрещено. В защелке хранится предыдущее ее состояние.

Если одновременно на входы R и S подать напряжение высокого уровня то в точках S' и R' будет напряжение низкого уровня, и действие тактового входа С будет запрещено. На выходах отобразится предыдущее состояние защелки. Когда на входах R и S зафиксировано напряжение низкого уровня и такое же напряжение поступит на вход С, в точках S' и R' появятся одновременно два напряжения высокого уровня. Такую логическую информацию RS-защелка не примет (неопределенность). Присутствующие на входах R и S взаимно противоположные уровни позволяют после прихода тактового импульса С установить на выходах Q и Q наперед заданную комбинацию уровней: Q=H, Q = B, и наоборот.

1.1 Устройство и работа D-триггера

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

Главным атрибутом D-триггера являются два новых входа: D-вход и С-вход. Входы R и S имеют то же самое назначение, что и у RS-триггера (для сброса и установки). Как у любого другого триггера, у D-триггера имеются два выхода: прямой и инверсный. Следует заметить, что наличие RS-входов, так же как и инверсного выхода, необязательно. Рассмотрим логику работы D-триггера. Для начала разберемся с новыми для нас входами.

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

Вход С называется тактовым. На него поступает тактовый импульс, синхронизирующий запись данных.

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

Импульсный вход не чувствителен к уровню сигнала. Такой вход срабатывает в момент перехода от одного уровня к другому. Про такие входы говорят: срабатывает по переднему фронту (то есть при переходе с нуля на единицу) или срабатывает по заднему фронту (то есть при переходе от единицы к нулю). Иногда применяют другие технические термины для описания работы импульсного входа. В литературе можно прочитать: «вход срабатывает по фронту сигнала» или «вход срабатывает по спаду сигнала».

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

1.2 Параллельный регистр

Для хранения двоичного числа, состоящего из большего количества разрядов, используют несколько параллельно соединенных D-триггеров. На рис. 2.1 показана схема, предназначенная для хранения четырехразрядного двоичного числа.

Такая схема называется параллельным регистром. Для того, чтобы сохранить какое-либо число в таком регистре, нужно подать это число поразрядно на входы D0-D3. Затем на вход С схемы подается импульс записи. По заднему фронту этого импульса число записывается в регистр. Причем каждый разряд числа записывается в свой отдельный D-триггер. Записанное в регистр число можно считывать с выходов Q0-Q3.

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

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

1.3 Параллельный регистр с расширенными возможностями

Более сложный регистр изображен на рис. 1.4. Это регистр приспособлен для работы с параллельной шиной данных. Для этого в регистр введены два новых входа:

·       вход выбора микросхемы (CS);

·       вход перевода выходов в высокоимпедансное состояние (ОЕ).

Разберемся подробнее c этими новыми входами и режимами работы. Вход выбора микросхемы CS (Chip Select) предназначен для ее включения и выключения в разные моменты времени. Такие входы можно часто встретить у микросхем, предназначенных для микропроцессорной техники. Особенно в больших многофункциональных микросхемах. Наличие таких входов позволяет соединять несколько подобных микросхем параллельно по входам, но работать с каждой микросхемой по отдельности. В случае параллельного соединения одноименных входов данные будут записаны только в тот из регистров, на входе CS которого в момент записи будет присутствовать низкий логический уровень. Состояние остальных регистров останется неизменным.

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

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

1.4 Работа делителя частоты

Счетчиками в цифровой технике называются специальные элементы, позволяющие подсчитывать число поступивших на вход импульсов. Понятие «счетчик импульсов» тесно связано с понятием «делитель частоты». По сути дела, это одно и то же устройство. Но рассмотрим все по порядку.

В качестве простейшего делителя частоты может JK-триггер. Для того, чтобы этот триггер работал как делитель, нужно на оба входа J и К подать высокий логический уровень. Теперь, если на вход С подать импульсный сигнал некоторой постоянной частоты, то по спаду каждого входного импульса триггер будет переключаться в противоположное состояние.

В результате на выходе 3.1. JK-триггера мы получим другой сигнал с частотой следования импульсов в два раза меньшей, чем частота импульсов на его входе. Этот процесс наглядно показан на рис. 3.1. Как видно из рисунка, период сигнала на выходе делителя ровно в два раза больше периода входного сигнала. А частота выходного сигнала, соответственно, в два раза ниже входного.

Второй вариант делителя частоты приведен на рис. 3.2. Он построен на основе D-триггера. Для того, чтобы перевести D-триггер в счетный режим, нужно соединить инверсный выход триггера Q с его D-входом так, как это показано на рис. 3.2. Теперь, если подать сигнал на вход С, такая схема тоже будет работать как делитель. Выходной сигнал такого делителя снимается с выхода Q триггера.

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

По спаду первого входного импульса D-триггер перейдет в нулевое состояние, так как на его D-входе сигнал логического нуля. После этого на инверсном выходе триггера устанавливается логическая единица. Поэтому по спаду следующего входного импульса триггер переключится в единичное состояние. И так далее. Результат работы делителя на D-триггере точно такой же, как и делителя на JK-триггере, и выходной сигнал нового варианта так же полностью соответствует рис. 3.1. Следует заметить, что в настоящее время JK-триггеры применяются довольно редко. Гораздо большее распространение благодаря своей простоте и универсальности получили D-триггеры.

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

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

На рис. 3.3. изображена схема четырехкаскадного делителя частоты на D-триггерах. Импульсы тактового генератора поступают на вход первого каскада деления. Если частота сигнала на входе равна f, то на выходах делителя мы получим сигналы со следующими частотами:

Рис. 3.3. Четырехкаскадный делитель частоты.

1.5 Счетчики прямого счета

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

Предположим, что перед началом счета все четыре триггера установлены в нулевое состояние. На вход схемы поступает некоторое количество импульсов. Входящие в схему триггеры будут переключаться согласно описанному выше алгоритму. Состояние триггеров в процессе счета показано в табл. 4.1. Как видно из таблицы, после прихода первого входного импульса триггер DO переходит в единичное состояние. После прихода второго импульса DO возвращается в ноль, зато в единичное состояние переходит D1.

Дальнейшее поведение всех четырех триггеров хорошо видно из таблицы. А теперь внимательно посмотрите, что у нас получилось. Если воспринимать совокупность цифровых сигналов на выходах счетчика как четырехразрядное двоичное число, то мы видим перед собой последовательность чисел от 0000 до 1111. Десятичный эквивалент этих чисел показан в правой крайней колонке таблицы.

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

Таблица 4.1.


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

1.6 Счетчики с обратным отсчетом

Кроме счетчиков прямого отсчета, к которым относится схема, изображенная на рис. 3.3., существуют счетчики с обратным отсчетом (иногда такой счетчик называют инверсным). В таком счетчике при поступлении каждого входного импульса содержимое уменьшается на единицу. Кроме того, бывают задачи, для которых требуются универсальные счетчики, которые могут считать как в прямом, так и в инверсном направлении. Если задаваться задачей построения таких счетчиков на отдельных триггерах и логических элементах, то мы получим довольно сложную схему. На практике используют специальные микросхемы - счетчики импульсов. Современная промышленность предлагает большой ассортимент таких микросхем. На рис. 5.1 изображена микросхема К555ИЕ7. Это одна из микросхем 555 серии, которая широко выпускалась в свое время в СССР, и сейчас ее можно свободно найти в продаже на радиорынках стран СНГ.

Микросхема 555ИЕ7 - это реверсивный четырехразрядный счетчик/делитель с возможностью предустановки. Он имеет два счетных входа, обозначенных как « + 1» и «-1». По спаду каждого импульса на входе «+1» содержимое счетчика увеличивается на единицу. По спаду каждого импульса на входе «-1» содержимое счетчика уменьшается на единицу. Счетчик имеет прямые выходы всех своих разрядов: Q0-Q3. Вход сброса R служит для установки всех разрядов счетчика в нулевое состояние.

Еще одно полезное свойство описываемого счетчика - это наличие режима предустановки. Используя этот режим, можно в любой момент записать во все разряды счетчика любое четырехразрядное двоичное число. Для этого счетчик имеет несколько дополнительных входов. Во-первых, это входы данных D0-D3. А, во вторых, это вход предустановки РЕ. Предустановка счетчика осуществляется следующим образом. Сначала на входы D0 - D3 подается код, который требуется записать в разряды счетчика. Затем на вход РЕ подается сигнал низкого логического уровня. По этому сигналу код, установленный на входах D0-DЗ, запишется в счетчик и тут же появится на его выходах Q0 - Q3. Дальнейший счет импульсов будет производиться уже от этого нового значения.

Выходы «>15» и «<0» - это выходы переполнения. Они используются при последовательном соединении нескольких таких счетчиков. В процессе счета уровень сигнала на обоих этих выходах равен единице. На выходе «>15» логический ноль появляется в том случае, если в процессе прямого счета содержимое счетчика достигнет своего максимального значения 11112, и на вход«+1» поступит очередной счетный импульс. Выход «<0» работает аналогично, но при обратном счете. Сигнал логического нуля появляется на этом выходе в тот момент, когда счетчик досчитает до своего нижнего предела - 00002, и на вход «-1» поступит очередной счетный импульс. При последовательном соединении двух счетчиков выходы «>15» и «<0» первого счетчика соединяется соответственно с входами «+1» и «-1» второго. В результате, соединив последовательно два таких счетчика, мы получим восьмиразрядный реверсивный счетчик, который также будет иметь возможность предустановки. Таким способом можно соединять последовательно любое количество счетчиков 555ИЕ7.

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

.7 Делители с переменным коэффициентом деления

В цифровой и микропроцессорной технике часто требуются делители с произвольным коэффициентом деления. При этом желательно, чтобы коэффициент деления можно было оперативно менять. На рис. 1.24 изображена схема делителя с программируемым коэффициентом деления на основе реверсивного счетчика К555ИЕ7. Для хранения-коэффициента деления используется специальный четырехразрядный параллельный регистр, обозначенный на схеме как DD1. Коэффициент деления такого делителя может изменяться от 1 до 15.


Работа счетчика начинается с установки всех его разрядов в ноль при помощи входа R. Обратите внимание на то, что в микросхеме К555ИЕ7 используется прямой, а не инверсный вход сброса. Поэтому сброс происходит при подаче на этот вход сигнала логической единицы. После того, как счетчик сброшен, для нормальной работы счетчика на вход R должен быть подан нулевой уровень.

Входной сигнал поступает на вход «-1». Поэтому счетчик работает в режиме обратного счета. Поэтому первый же входной импульс после сброса счетчика вызовет сигнал переполнения на выходе «<0». Этот импульс поступит на вход РЕ. В результате в счетчик будет записано двоичное число с выхода регистра DD1. Это число соответствует выбранному коэффициенту деления. Допустим, что в регистр DD1 мы записали число 10 (10102). Тогда именно это число будет записано в разряды счетчика DD2.

Каждый последующий входной импульс будет уменьшать содержимое счетчика на единицу. Так будет продолжаться до тех пор, пока содержимое счетчика снова не уменьшится до нуля. Для этого потребуется как раз 10 тактовых импульсов. По приходу одиннадцатого импульса на выходе «<0» снова появится сигнал переполнения, и в счетчик будет опять записано число десять из регистра DD1.

Описанный процесс будет повторяться все время, пока приходят входные импульсы. Период следования импульсов на выходе «<0», а, значит, и на выходе всей схемы в нашем случае будет в 11 раз больше периода входных сигналов. А частота выходных импульсов будет, соответственно, в 11 раз меньше. То есть наш счетчик будет делить на 11. Записывая в регистр DD1 различные значения, можно легко менять коэффициент деления описанной схемы. Забегая вперед скажу, что запись числа в регистр коэффициента деления может производить микропроцессор. В этом случае мы можем создать делитель, управляемый от микропроцессора.

1.8 Таймеры

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

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

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

Современные микроконтроллеры, или, как их еще называют, однокристальные микроЭВМ, обычно всегда содержат в своем составе один или несколько встроенных таймеров-счетчиков.

Пример. Микроконтроллеры серии AVR имеют от одного (в микросхеме AT90S1200) до четырех (в микросхеме ATmegal28) встроенных таймеров/счетчиков. Это позволяет при формировании временных интервалов обойтись без внешних таймеров.

1.9 Дешифраторы

Устройство и принцип действия дешифратора

Еще один элемент, без которого не обойтись при изучении микропроцессорной техники, - это дешифратор цифровых сигналов. Существует много разных типов дешифраторов. В общем случае дешифратор - это устройство, преобразующее цифровой сигнал, представленный в какой-либо одной из кодировок, в другую, незакодированную форму. Нас в данном случае будет интересовать классический линейный дешифратор. Схемное обозначение одного из вариантов такого дешифратора приведено на рис. 8.1. Описываемый дешифратор имеет три входа данных DO, D1 и D2, вход выбора микросхемы CS, а также восемь выходов, обозначенных цифрами от 0 до 7.

Логика работы микросхемы такова: на входы данных микросхемы подается цифровой код. В данном случае - это любое трехразрядное двоичное число. Смысл работы такого дешифратора - выдать активный сигнал только на одном из своих выходов. На том выходе, номер которого соответствует двоичному коду, присутствующему на его входах D0-D2.

В большинстве современных дешифраторов активным сигналом на выходе считается низкий логический уровень. Это значит, что при поступлении на входы D0-D1 сигнала 0002, на выходе «0» будет логический ноль, а на всех остальных выходах - единица.



2. Лабораторная № 2

.1 Общие положения

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

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

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

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

В качестве слов в языке программирования выступают:

·       команды (операторы);

·       специальные управляющие слова;

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

·       числовые выражения.

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

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

Определение. Транслятор - это специальная программа, которая переводит текст, написанный программистом, в машинные коды, то есть в форму, понятную для микроконтроллера.

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

Все языки программирования делятся на две группы: языки низкого уровня (машиноориентированные); языки высокого уровня.

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

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

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

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

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

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

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

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

Программа-транслятор выбирает все это сама. Поэтому задача эффективности алгоритма полученной в результате трансляции программы целиком ложится на программу-транслятор. В целом, программы, написанные на языках высокого уровня, занимают в памяти микроконтроллера объем на 30-40 % больший, чем аналогичные программы, написанные на языке Ассемблер.

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

Изучение приемов программирования мы будем осуществлять на ряде конкретных примеров:

·   каждый пример будет начинаться с постановки задачи;

·   затем мы научимся выбирать схемное решение;

·       лишь после этого будут представлены примеры программ.

Для каждой задачи в книге приводятся два варианта программы. Одна на языке Ассемблер, вторая на языке СИ. В результате вы сможете не только научиться азам программирования на двух языках, но и понять все достоинства и недостатки каждого из языков программирования.

2.2 Простейшая программа

Постановка задачи

Самая простая задача, которую можно придумать для микроконтроллера, может звучать следующим образом:

«Разработать устройство управления одним светодиодным индикатором при помощи одной кнопки. При нажатии кнопки светодиод должен зажечься, при отпускании - погаснуть».

С практической точки зрения это совершенно бессмысленная задача, так как для ее решения проще обойтись без микропроцессора. Но в качестве примера для обучения подойдет прекрасно.

2.3 Принципиальная электрическая схема

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

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

Очевидно, что нам нужен микроконтроллер, который имеет не менее двух портов. Данным условиям удовлетворяют многие микроконтроллеры AVR. Я предлагаю остановить свой выбор на довольно интересной микросхеме ATtiny2313. Эта микросхема, хотя и относится к семейству «Ttiny», на самом деле занимает некое промежуточное место между семейством «Ttiny» и семейством «Mega». Она не так перегружена внутренней периферией и не столь сложна, как микросхемы семейства «Mega». Но и не настолько примитивна, как все остальные контроллеры семейства «Ttiny».

Эта микросхема содержит два основных и один дополнительный порт ввода-вывода, имеет не только восьмиразрядный, но и шестнадцатиразрядный таймер/счетчик. Имеет оптимальные размеры (20-выводной корпус). И идеально подходит в качестве примера для изучения основ программирования

Итак, если не считать порта А, который включается только в особом режиме, который мы пока рассматривать не будем, микроконтроллер имеет два основных порта ввода-вывода (порт В и порт D). Договоримся, что для управления светодиодом мы будем использовать младший разряд порта В (линия РВ.0), а для считывания информации с кнопки управления используем младший разряд порта D (линия PD.0). Полная схема устройства, позволяющего решить поставленную выше задачу, приведена на рис. 2.1.

Для подключения кнопки S1 использована классическая схема. В исходном состоянии контакты кнопки разомкнуты. Через резистор R1 на вход PD.0 микроконтроллера подается «плюс» напряжения питания, что соответствует сигналу логической единицы.

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

Подключение светодиода также выполнено по классической схеме. Это непосредственное подключение к выходу порта. Каждый выход микроконтроллера рассчитан на непосредственное управление светодиодом среднего размера с током потребления до 20 мА. В цепь светодиода включен токоограничивающий резистор R3.

Для того, чтобы зажечь светодиод, микроконтроллер должен подать на вывод РВ.0 сигнал логического нуля. В этом случае напряжение, приложенное к цепочке R2, VD1, окажется равным напряжению питания, что вызовет ток через светодиод, и он загорится. Если же на вывод PD.0 подать сигнал логической единицы, падение напряжения на светодиоде и резисторе окажется равным нулю, и светодиод погаснет.

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

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

Большинство микроконтроллеров AVR, кроме тактового генератора с внешним кварцевым резонатором, содержат внутренний RC-генератор, не требующий никаких внешних цепей. Если вы не предъявляете высоких требований к точности и стабильности частоты задающего генератора, то микросхему можно перевести в режим внутреннего RC-генератора и отказаться как от внешнего кварца (Q1), так и от согласующих конденсаторов (С2 и СЗ).

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

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


Упростим схему, показанную на рис. 2.1, с учетом описанных выше возможностей. От внешнего кварца пока отказываться не будем. Он нам пригодиться чуть позже, когда мы начнем формировать временные интервалы. Доработанная схема изображена на рис. 2.2.

2.4 Алгоритм

Итак, схема у нас есть. Теперь нужно приступать к разработке программы. Разработка любой программы начинается с разработки алгоритма.

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

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

Операции начальной настройки:

· установить начальное значение для вершины стека микроконтроллера;

·       настроить порт В на вывод информации;

·       подать на выход РВ.0 сигнал логической единицы (потушить светодиод);

·       сконфигурировать порт D на ввод;

·       включить внутренние нагрузочные резисторы порта D.

Операции, составляющее тело цикла:

· прочитать состояние младшего разряда порта PD (PD.0);

·       если значение этого разряда равно единице, выключить светодиод;

·       если значение разряда PD.0 равно нулю, включить светодиод;

·       перейти на начало цикла.

2.5 Программа на Ассемблере

Для создания программ мы используем версию Ассемблера, предложенную разработчиком микроконтроллеров AVR - фирмой Atmel. А также воспользуемся программным комплексом «AVR Studio», разработанным той же фирмой и предназначенным для создания, редактирования, трансляции и отладки программ для AVR на Ассемблере.

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

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

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

Некоторые команды состоят только из одного оператора. Другие же команды имеют один или два операнда (параметра). Операнды записываются в той же строке сразу после оператора, через пробел. Если операнда два, их записывают через запятую. Так, в строке 6 нашей программы записана команда загрузки константы в регистр общего назначения. Она состоит из оператора ldi и двух операндов temp и RAMEND.

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

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

· имя должно состоять из одного слова, содержащего только латинские буквы и цифры;

·       допускается также применять символ подчеркивания;

·       первым символом метки обязательно должна быть буква или символ подчеркивания.

Строка 16 нашей программы содержит метку с именем main. Метка не обязательно должна стоять в строке с оператором. Допускается ставить метку в любой строке программы. Кроме команд и меток, программа содержит комментарии.

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

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

Кроме операторов, в языке Ассемблер применяются псевдооператоры или директивы. Если оператор - это некий эквивалент реальной команды микроконтроллера и в процессе трансляции заменяется соответствующим машинным кодом, который помещается в файл результата трансляции, то директива, хотя но форме и напоминает оператор, но не является командой процессора.

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

Далее из конкретных примеров вы поймете, о чем идет речь. В данной конкретной версии Ассемблера директивы выделяются особым образом. Имя каждой директивы начинается с точки. Смотри листинг 2.1, строки с 1 по 5.

При написании программ на Ассемблере принято соблюдать особую форму записи:

· программа записывается в несколько колонок (см. листинг 2.1);

·       аналогичные элементы разных команд принято размещать друг под другом;

·       самая первая (левая) колонка зарезервирована для меток;

·       если метка отсутствует, место в колонке пустует;

·       следующая колонка предназначена для записи операторов;

·       затем идет колонка для операндов;

·       оставшееся пространство (крайняя колонка справа) предназначено для комментариев.

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

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

.6 Директивы

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

В языке Ассемблер для присоединения фрагмента к программе используется псевдооператор include. В качестве параметра для этой директивы должно быть указано имя присоединяемого файла. Если такой оператор поставить в любом месте программы, то содержащийся в присоединяемом файле фрагмент в процессе трансляции как бы вставляется в то самое место, где находится оператор. Например, в программе на листинге 2.1 в строке 1 в основной текст программы вставляется текст из файла tn2313def. inc.

Кстати, подробнее об этом файле. Файл tn2313def. inc - это файл описаний. Он содержит описание всех регистров и некоторых других параметров микроконтроллера ATtiny2313. Это описание понадобится нам для того, чтобы в программе мы могли обращаться к каждому регистру по его имени. О том, как делаются такие описания, мы поговорим при рассмотрении конкретных программ.

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

.def - Макроопределение. Эта команда позволяет присваивать различным регистрам микроконтроллера любые осмысленные имена, упрощающие чтение и понимание текста программы. В нашем случае нам понадобится один регистр для временного хранения различных величин. Выберем для этой цели регистр r16 и присвоим ему наименование temp от английского слова temporary - временный.

Данная команда выполняется в строке 3 (см. листинг 4.1). Теперь в любом месте программы вместо имени r16 можно применять имя temp. Вы спросите: а зачем это нужно? Да для наглядности и читаемости программы. В данной программе мы будем использовать лишь один регистр, и преимущества такого переименования здесь не очень видны. Но представьте, что вы используете множество разных регистров для хранения самых разных величин. В этом случае присвоение осмысленного имени очень облегчает программирование. Скоро вы сами в этом убедитесь. Кстати, именно таким образом определены имена всех стандартных регистров в файле tn2313def. inc.

.cseg- Псевдооператор выбора программного сегмента памяти. О чем идет речь? Как уже говорилось, микроконтроллер для хранения данных имеет три вида памяти: память программ (Flash), оперативную память (SRAM) и энергонезависимую память данных (EEPROM). Программа на Ассемблере должна работать с любым из этих трех видов памяти. Для этого в Ассемблере существует понятие «сегмент памяти». Существуют директивы, объявляющие каждый за кой сегмент:

· сегмент кода (памяти программ).cseg;

· сегмент данных (ОЗУ)dseg;

· сегмент EEPROMeseg.

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

Только в сегменте кода Ассемблер описывает команды, которые затем в виде кодов будут записаны в память программ. В остальных двух сегментах используются директивы распределения памяти и директивы описания данных. Ну, к сегментам dseg и eseg мы еще вернемся. Сейчас же подробнее рассмотрим сегмент cseg.

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

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

Она позволяет принудительно изменить значение указателя текущего адреса. Оператор org имеет всего один параметр - новое значение указателя адреса. К примеру, команда.org 0x10 установит указатель на адрес 0x10. Транслятор автоматически следит, чтобы при перемещении указателя ваши фрагмент программы не налезали друг на друга. В случае несоблюдения этого условия транслятор выдает сообщение об ошибке.

В нашей программе команда позиционирования указателя применяется всего один раз. В строке 5 указатель устанавливается на нулевой адрес. В данном случае директива org имеет чисто декларативное значение, так как и начале программы, значение указателя и так равно нулю.

2.7 Операторы

Idi- Загрузка в РОН числовой константы. В строке 6 программы (листинг 4.1) при помощи этой команды в регистр temp (rl6) записывается числовая константа, равная максимальному адресу ОЗУ. Эта константа имеет имя RAMEND. Ее значение описано в файле tn2313def. inc. В нашем случае (для микроконтроллера ATtiny2313) значение RAMEND равно $7F.

Как можно видеть из листинга 4.1, оператор Idi имеет два параметра:

· первый параметр - это имя РОН, куда помещается наша константа;

·       второй параметр - значение этой константы.

Обратите внимание, что в команде сначала записывается приемник информации, затем ее источник. Такой же порядок вы увидите в любой другой команде, имеющей два операнда. Это общее правило для языка Ассемблер.

Out- Вывод содержимого РОН в регистр ввода-вывода. Команда также имеет два параметра:

· первый параметр - имя РВВ, являющегося приемником информации;

·       второй параметр - имя РОН, являющегося источником.

В строке 7 программы содержимое регистра temp выводится в РВВ с именем SPL.

In - Ввод информации из регистра ввода-вывода. Имеет два параметра. Параметры те же, что и в предыдущем случае, но источник и приемник меняются местами. В строке 19 программы содержимое регистра PORTD помещается в регистр temp.

rjmp - Команда безусловного перехода. Команда имеет всего один параметр - адрес и перехода. В строке 21 программы оператор безусловного перехода передает давление на строку, помеченную меткой main. To есть на строку 19. Данная строка демонстрирует использование метки.

На самом деле в качестве параметра оператора rjmp должен выступать так называемый относительный адрес перехода. То есть число байт, на которое нужно сместиться вверх или вниз от текущего адреса. Направление смещения (вверх или вниз) - это знак числа. Он определяется старшим битом. Язык Ассемблера избавляет программиста от необходимости подсчета величины смещения. Достаточно в нужной строке программы поставить метку, а в качестве адреса перехода указать ее имя, и транслятор сам вычислит значение этого параметра.

При использовании команды rjmp существует одно ограничение. Соответствующая команда микроконтроллера кодируется при помощи смещения она использует всего двенадцать разрядов. Поэтому такая команда может вызвать переход в пределах ±2 Кбайт. Если вы расположите метку слишком далеко от оператора rjmp, то при трансляции программы это вызовет сообщение об ошибке.

2.8 Описание программы

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

Самая первая команда программы - это псевдокоманда include, которая присоединяет к основному тексту программы файл описаний (см. листинг 4.1 строка 1). В стандартном пакете AVR-Studio имеется целый набор подобных файлов описаний. Для каждого микроконтроллера серии AVR - свой отдельный файл. Все стандартные файлы описаний находятся в директории «C:\Program FilesVAtmel\AVR Tools\AvrAssembler\Appnotes\». Программисту нужно лишь выбрать нужный файл и включить подобную строку в свою программу. Учтите, что без присоединения файла описаний дальнейшая программа работать не будет.

###################################

;# Программа 1 #

;# Программа управлением светодиодом #

;###################################

Для микроконтроллера ATtiny2313 файл описаний имеет название tn2313def. inc. Если файл описаний находится в указанной выше директории, то в команде include достаточно лишь указать его полное имя (с расширением). Указывать полный путь необязательно.

Назначение команды.list (строка 2), надеюсь, у вас уже не вызывает вопросов. Остановимся на команде макроопределения (строка 3). Эта команда, как уже говорилось, присваивает регистру r16 имя temp. Дальше в программе регистр temp используется для временного хранения промежуточных величин. Уместно задаться вопросом: почему выбран именно r16, а, к примеру, не г0? Это становится понятно, если вспомнить, что регистры, начиная с r0 и заканчивая r15, имеют меньше возможностей. Например, в строке 14 программы регистр temp используется в команде ldi. Однако команда ldi не работает с регистрами r0-r15. Именно по этой причине мы и выбрали r16.

Следующие две команды (строки 4, 5) подробно описаны в начале этого раздела. Они служат для выбора программного сегмента памяти и установки начального значения указателя.

В строках 6 и 7 производится инициализация стека. В регистр стека SPL записывается адрес его вершины. В качестве адреса выбран самый верхний адрес ОЗУ. Для обозначения этого адреса в данной версии Ассемблера существует специальная константа с именем RAMEND. Значение этой константы определяется в файле описаний (в нашем случае в файле tn2313def. inc). Для кроконтроллера ATtiny2313 константа RAMEND равна OxDF.

Одной строкой записать константу в регистр стека невозможно, так как в системе команд микроконтроллеров AVR отсутствует подобная команда. Отсутствующую команду мы заменяем двумя другими. И тут нам пригодится регистр temp. Он послужит в данном случае передаточным звеном. Сначала константа RAMEND помещается в регистр temp (строка 6), а затем уже содержимое temp помещается в регистр SPL (строка 7).

В строках 8-12 производится настройка портов ввода-вывода. Ранее мы уже договорились, что порт PD у нас будет работать на ввод, а порт РВ - на вывод. Для выбора нужного направления передачи информации запишем управляющие коды в соответствующие регистры DDRx. Во все разряды регистра DDRD запишем нули (настройка порта PD на ввод), а во все разряды регистра DDRB запишем единицы (настройка порта РВ на вывод). Кроме того, нам нужно включить внутренние нагрузочные резисторы порта PD. Для этого мы запишем единицы (то есть число 0xFF) во все разряды регистра PORTD. И, наконец, в момент старта программы желательно погасить светодиод. Для этого мы запишем единицы в разряды порта РВ.

Все описанные выше действия по настройке порта также выполняются с использованием промежуточного регистра temp. Сначала в него помещается ноль (строка 8). Ноль записывается только в регистр DDRD (строка 9). Затем в регистр temp помещается число OxFF (строка 10). Это число по очереди записывается в регистры DDRB, PORTB, PORTD (строки 11,12,13).

Строки 14 и 15 включены в программу для перестраховки. Дело в том, что встроенный компаратор микроконтроллера после системного сброса остается включен. И хотя прерывания при этом отключены и срабатывание компаратора не может повлиять на работу нашей программы, мы все же отключим компаратор. Именно это и делается в строках 14 и 15.

Здесь уже знакомым нам способом с использованием регистра temp производится запись константы 0x80 в регистр ACSR. Регистр ACSR предназначен для управления режимами работы компаратора, а константа 0x80, записанная в этот регистр, отключает компаратор.

Настройкой компаратора заканчивается подготовительная часть программы. Подготовительная часть занимает строки 1-15 и выполняется всего один раз после включения питания или после системного Сброса. Строки 16-18 составляет основной цикл программы.

Определение. Основной цикл - это часть программы, которая повторяется многократно и выполняет все основные действия.

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

Первый из них читает содержимое порта PD и запоминает это содержимое в регистре temp (строка 16). Следующий оператор записывает это число в порт РВ (строка 17). Завершает основной цикл программы оператор безусловного перехода (строка 18). Он передает управление по метке main.

В результате три оператора, составляющие тело цикла, повторяются бесконечно. Благодаря этому бесконечному циклу все изменения порта PD тут же попадают и порт РB. По этой причине, если кнопка SI не нажата, логическая единица со входа PD0 за один проход цикла передается на выход PB0. И светодиод не светится. При нажатии кнопки S1 логический ноль со входа PD0 поступает на выход PB0, и светодиод загорается.

Эта же самая программа без каких-либо изменений может обслуживать до семи кнопок и такое же количество светодиодов. Дополнительные кнопки подключаются к линиям PD1-PD6, а дополнительные светодиоды (каждый со своим токоограничивающим резистором) - к выходам РВ 1 - РВ7. При этом каждая кнопка будет управлять своим собственным светодиодом. Такое стало возможным потому, что все выводы каждого из двух портов мы настроили одинаково (смотри строки 8-13).

3. Лабораторная №3

3.1 Переключающийся светодиод

Постановка задачи

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

Новая задача может звучать так:

«Разработать устройство управления одним светодиодным индикатором при помощи одной кнопки. При каждом нажатии кнопки светодиод должен поочередно включаться и отключаться. При первом нажатии кнопки светодиод должен включиться, при следующем отключиться и т. д.». Вы можете сказать, что и эта новая задача легко решаема при помощи простейшего D-триггера. Однако все же рассмотрим, как ее можно решить при помощи микроконтроллера.

3.2 Принципиальная схема

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

3.3 Алгоритм

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

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

1.Прочитать состояние младшего разряда порта PD (PD.0).

2.Если значение этого разряда равно единице, перейти к началу цикла.

3. Если значение разряда PD.0 равно нулю, изменить состояние выхода РВ.0 на противоположное.

3.Перейти к началу цикла.

4.Итак, мы описали алгоритм словами. Причем это довольно общее описание. Реальным алгоритм немного сложнее. Словесное описание алгоритма не всегда удобно. Гораздо нагляднее графический способ описания алгоритма. На рис. 3.3 алгоритм нашей работы будущей программы изображен в графическом виде.

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

Допускается объединять несколько операций в один блок и обозначать одним прямоугольником. Последовательность выполнения действий показывается стрелками. Ромбик реализует разветвление программы. Он представляет собой операцию выбора. Условие выбора записывается внутри ромбика. Если условие истинно, то дальнейшее выполнение программы продолжится по пути, обозначенному словом «Да».

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

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



Первой операцией цикла является проверка состояния младшего разряда порта PD (PD0). Программа сначала читает состояние этой линии, а затем выполняет операцию сравнения. В процессе сравнения значение разряда PD0 проверяется на равенство единице. Если условие выполняется, программа переходит к началу цикла (по стрелке «Да»).




Если условие не выполняется (PD0 не равен единице), выполнение программы продолжается по стрелке «Нет», где выполняется еще одна операции сравнения. Это сравнение является частью процедуры переключения светодиода. Для того, чтобы переключить светодиод, мы должны проверить его текущее состояние и перевести его в противоположное.

Как вы помните, светодиодом управляет младший разряд порта РВ (РВ0). Поэтому именно его мы будем промерять и изменять. Работа алгоритма переключения светодиода предельно проста. Сначала оператор сравнения проверяет разряд РВ0 на равенство единице. Если результат проверки - истина (РВ0=1), то разряд сбрасывается в ноль (0 => РВ0). Если ложно, устанавливается в единицу (1 => РВ0). Сочетание символов «=>» означает операцию присвоения. Такое обозначение иногда используется в программировании при написании алгоритмов. После переключения светодиода управление передается на начало главного цикла.

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

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

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

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

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

Новый, доработанный алгоритм приведен на рис. 4.9. Как видно из рисунка, новый алгоритм дополнен всего двумя новыми операциями, которые и реализуют цикл ожидания. Цикл ожидания добавлен после процедуры переключения светодиода. Выполняя цикл ожидания, программа сначала читает значение бита PD0, а затем проверяет его на равенство единице. Если PD0 не равно единице (кнопка нажата), то цикл ожидания повторяется. Если PD0 равно единице (кнопка отпущена) то цикл ожидания прерывается, управление перейдет на начало основного цикла.

4. Лабораторная № 4

.1 Бегущие огни

Постановка задачи

«Разработать автомат «Бегущие огни» для управления составной гирляндой из восьми отдельных гирлянд. Устройство должно обеспечивать «движение» огня в двух разных направлениях. Переключение направления «движения» должно осуществляться при помощи переключателя».

4.2 Схема

В соответствии с поставленной задачей наше устройство должно управлять восемью световыми гирляндами. Удобно задействовать для этого все восемь выходов одного из портов. Кроме того, нам придется подключать переключатель направления. Для этого нам понадобится еще один порт. Очевидно, что для такой задачи вполне подойдет уже знакомый нам микроконтроллерATtiny2313.

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

4.3 Алгоритм

Для создания эффекта «бегущих огней» удобнее всего воспользоваться операторами сдвига, которые имеются в системе команд любого микроконтроллера. Такие операторы сдвигают содержимое одного из регистров микроконтроллера на один разряд влево или вправо. Если сдвигать содержимое регистра и после каждого сдвига выводить новое содержимое в порт РВ, подключенные к нему светодиоды будут загораться поочередно, имитируя бегущий огонь. Алгоритм работы бегущих огней может разный. Один из возможных алгоритмов в самых общих чертах будет выглядеть следующим образом:

2.Если контакты переключателя разомкнуты, перейти к процедуре сдвига вправо.

3.Если контакты замкнуты, перейти к процедуре сдвига влево.

4.После окончания полного цикла сдвига (восемь последовательных сдвигов) перейти к началу алгоритма, то есть к пункту 1.

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

Выполнение алгоритма сдвига

Рис. 1. Схема автомата «Бегущих огней»

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

1.Записать в рабочий регистр начальное значение. В качестве начального значения используется двоичное число, у которого один из разрядов равен единице, а остальные разряды равны нулю. Для сдвига вправо нам нужно число с единицей в самом старшем разряде (0b10000000)Для сдвига влево в единицу устанавливается младший разряд(0 b 0 0 0 0 0 0 0 l).

2.Вывести значение рабочего регистра в порт РВ.

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

4.Сдвинуть содержимое рабочего регистра вправо (влево) на один разряд.

5.Проверить, не окончился ли полный цикл сдвига (8 шагов).

6.Если полный цикл сдвига не закончен, перейти к пункту 2 данного алгоритма. Это приведет к тому, что пункты 2, 3, 4, 5 и 6 повторятся 8 раз, и лишь затем завершится полный цикл сдвига.

5. Лабораторная № 5

.1 Использование таймера

Постановка задачи

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

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

Итак, заново сформулируем нашу задачу:

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

5.2 Схема

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

5.3 Алгоритм

Как известно, в микроконтроллере ATtiny2313 имеются два встроенных таймера-счетчика. Поэтому сначала нам нужно выбрать, какой из них мы будем использовать. Исходить будем из заданного времени задержки 200 мс. Как известно, для формирования временных интервалов таймер/счетчик просто подсчитывает тактовые импульсы от системного генератора.

Частота сигнала этого генератора в нашем случае равна 4 МГц. А период импульсов 1/4 = 0,25 мкс. Для того, чтобы получить на выходе 200 мс, необходимо иметь коэффициент деления, равный 200*103/0,25*106=800*103 (восемьсот тысяч раз).

Микросхема ATtiny2313 содержит два таймера. Один восьмиразрядный и один шестнадцатиразрядный. Восьмиразрядный таймер имеет максимальный коэффициент пересчета 28=256, а шестнадцатиразрядный - 216=65536. То есть даже шестнадцатиразрядного таймера нам не хватит для формирования требуемой задержки. Придется воспользоваться предварительным делителем. Этот делитель производит предварительное деление тактового сигнала перед тем, как тот поступит на вход таймера/счетчика.

Программным путем можно выбрать один из четырех фиксированных коэффициентов деления (см. приложение). Выберем самый большой возможный коэффициент деления предделителя (1024). Тогда на его выходе мы получим сигнал с частотой 4-106/1024 = 3906 Гц. Период такого сигнала будет равен 1/3906 = 0,256-10"3 с или 0,256 мс. Именно этот сигнал поступает на вход нашего таймера, который обеспечивает окончательное деление. Посчитаем коэффициент деления, который наш таймер должен нам обеспечить: 200/0,256 ~ 780. Такой коэффициент пересчета нам может обеспечить только таймер Т1.

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

1.Записать в счетный регистр таймера Т1 нулевое значение.

2.Начать цикл проверки содержимого счетного регистра. В теле цикла программа должна многократно считывать содержимое счетного регистра таймера и проверять, не достигло ли оно своего конечного значения (то есть значения 780).

3.При достижении счетным регистром конечного значения, завершить цикл проверки.

4.Выйти из подпрограммы задержки.

5.4 Использование прерываний по таймеру

Постановка задачи

В предыдущем примере мы использовали таймер для формирования задержки) но не использовали его главного преимущества: способности вызывать прерывания. На практике подобным образом почти никогда не поступают. Чаще всею в подобных случаях применяют прерывания по таймеру. Это позволяет более точно формировать интервалы времени, но главное - позволяет разгрузить центральный процессор.

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

Создать новую программу «бегущих огней» с использованием прерываний по таймеру.

5.5 Схема

Схему оставим без изменений.

Алгоритм

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

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

Все функции управления «движением огней» выполняет процедура обработки прерывания. При каждом вызове прерывания процедура производит сдвиг «огней» на один шаг в нужном направлении.

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

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

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

Алгоритм основной программы:

1.Настроить стек и порты ввода-вывода микроконтроллера.

2.Настроить таймер и систему прерываний.

3.Записать в рабочий регистр исходное значение.

4.Разрешить работу таймера.

5.Разрешить прерывания.

6.Перейти к выполнению основного цикла.

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

Алгоритм процедуры обработки прерывания:

1.Проверить состояние переключателя режимов.

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

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

4.Вывести содержимое рабочего регистра в порт РВ, предварительно проинвертировав его.

5.Закончить процедуру обработки прерывания. Перейти к выполнению основного алгоритма.

6. Лабораторная №6

.1 Формирование звука

Постановка задачи

В общем случае задача формирования звука не составляет большого труда. Достаточно взять за основу схему с мигающим светодиодом (см. раздел 4.5), подключить вместо светодиода звуковой излучатель (например, телефонный капсюль), а в соответствующей программе (листинг4.7) поменять константу задержки таким образом, чтобы частота «мигания» повысилась и достигла звукового диапазона.

Диапазон частот, которые может услышать человек, лежит в пределах примерно от 50 Гц до 15 кГц. Светодиод в упомянутой выше программе мигает с частотой 4 Гц. Если уменьшить время задержки в 1000 раз, то можно получить частоту сигнала на выходе, равную 4 кГц. Эта частота как раз входит в звуковой диапазон.

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

Допустим, мы имеем семь кнопок (датчиков). Сформулируем задачу следующим образом:

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

6.2 Схема

Поставленная выше задача прекрасно решается при помощи уже известного нам микроконтроллера ATtiny2313. Выберем его и на этот раз. Микроконтроллер имеет два встроенных таймера/счетчика. Какой же из таймеров использовать нам? Для формирования звука лучше подходит шестнадцатиразрядный таймер. Чем больше разрядов, тем с большей точностью можно выбирать его коэффициент деления.

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

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

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

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


Как видно из рисунка, мы снова применили внешний кварцевый резонатор (Q1), естественно, не забыв при этом цепи согласования (Cl, С2). При подключении датчиков используется та же схема, что использовалась до сих пор для подключения контактов переключателя. Датчики подключаются ко всем разрядам порта PD. При этом для правильной работы датчиков для каждого разряда порта PD должны быть активизированы встроенные резисторы нагрузки.

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

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

6.3 Алгоритм

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

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

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

Договоримся, что датчику, подключенному к входу PD.0, будет соответствовать нота «До». Следующему датчику - нота «Ре», и так далее до ноты, «Си». Коэффициенты деления для каждой из нот выбираются по законам музыкального ряда.

7. Лабораторная №7

.1 Программная среда AVR Studio

компьютер микропроцессор программа отладчик

Общие сведения

Отладка программы

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

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

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

В процессе выполнения программы под управлением отладчика программист может на экране компьютера:

· видеть содержимое любого регистра микроконтроллера;

·       видеть содержимое ОЗУ и EEPROM;

·       наблюдать за последовательностью выполнения команд, контролируя правильность отработки условных и безусловных переходов;

·       наблюдать за работой таймеров, отработкой прерываний.

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

Существует три основных вида отладчиков:

· программные;

·       аппаратные;

·       комбинированные программно-аппаратные.

7.2 Программный отладчик

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

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

Аппаратный отладчик

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

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

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

· наблюдать содержимое регистров, ОЗУ, портов ввода-вывода;

· контролировать ход выполнения программы.

В аппаратном отладчике мы можем так же, как и в программном, выполнять программу в пошаговом режиме и применять точки останова. Недостатком аппаратного отладчика является его высокая стоимость.

Полнофункциональные программные имитаторы электронных устройств

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

· транзисторы;

·       резисторы;

·       конденсаторы;

·       операционные усилители;

·       логические и цифровые микросхемы, в том числе и микроконтроллеры.

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

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

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

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

Внутренний отладчик микроконтроллеров AVR

Еще один аппаратный способ отладки заложен конструктивно в некоторые модели микроконтроллеров AVR. В частности, микроконтроллер ATtiny2313 поддерживает такой способ отладки.

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

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

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

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

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

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

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

Недостаток - частое «перешивание» программной памяти микроконтроллера. Изменять содержимое этой памяти приходится каждый раз при установке новых или снятии старых точек останова. Если учесть, что допустимое количество перезаписи программной памяти составляет 10000 циклов, то при длительном процессе отладки это количество может исчерпаться, и микросхема выйдет из строя.

Программная среда «AVR Studio»

Фирма Atmel, разработчик микроконтроллеров AVR, очень хорошо позаботилась о сопровождении своей продукции. Для написания программ, их отладки, трансляции и прошивки в память микроконтроллера фирма разработала и бесплатно распространяет специализированную среду разработчика под названием «AVR Studio». Инсталляционный пакет этой инструментальной программы можно свободно скачать с сайта фирмы. Адрес страницы для скачивания программ: #"536117.files/image017.gif">

Для управления всеми этими возможностями используется стандартный интерфейс, знакомый вам по многим текстовым редакторам, в частности, по популярному редактору Microsoft Word. Набранный тест программы не забудьте записать на диск при помощи команды «Save» меню «File» или при помощи соответствующей кнопки на панели инструментов ( ). Кнопка позволяет записать сразу все открытые текстовые файлы.

Для программ, приведенных в этой книге, проекты создавать не обязательно. Достаточно скачать файл с электронными версиями программ с сайта #"536117.files/image019.gif">

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

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

·       ошибки синтаксиса (неправильное написание имени команды);

·       неверное количество параметров у оператора;

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

Например, сообщение «Unknown instruction or macro» означает, что найдена «Неизвестная инструкция или макрокоманда».

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

Все сообщения во вкладке «Build» появляются по мере их поступления. Для наглядности каждое сообщение помечено цветным кружочком в начале строки:

·   сообщения об ошибках помечаются кружочком красного цвета;

·       предупреждения - желтым кружочком;

·       сообщения об успешном выполнении каждого очередного этапа трансляции помечаются зеленым кружочком.

Если сообщения не вмещаются в окно, то они скрываются в верхней его части. Однако, используя полосу прокрутки, их всегда можно просмотреть. В случае успешного завершения процесса трансляции в качестве последнего сообщения выводится статистическая информация (см. раздел 9.1.2). Каждое сообщение об ошибке во вкладке «Build» содержит точное указание места в программе, где произошла эта ошибка. При этом указывается:

·       имя файла;

·       номер строки;

·       фрагмент текста программы, содержащий ошибку;

·       ее расшифровка.

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

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

Отладка программы

Ошибки алгоритма и его реализации

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

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

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

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

С большим юмором подошли к этому вопросу англичане. По-английски процесс отладки называется Debug (Дебаг). Слово «Bug» - означает блоха. A «Debug» - это процесс избавления от ошибок или процесс ловли блох. Именно этим вам и придется заняться.

Этапы процесса отладки

Процесс отладки начинается с перевода программы в соответствующий режим. Если проект открыт, а все его программы записаны и оттранслированы, то для перехода в режим отладки выберите пункт «Start Debugging» в меню «Debug» или нажмите кнопку ( ) на панели задач.

Программа начнет процесс подготовки. Процесс длительный. Пока идет подготовка, в нижней части основной панели будет двигаться полоса, показывающая процент выполнения операции. По окончании процесса подготовки программа переходит в новый режим. В окне 1 на передний план выходит вкладка «I/O View» (см. рис. 4), которая теперь будет использоваться для просмотра содержимого всех регистров. Причем внешний вид этой вкладки немного изменяется. Для каждого элемента в дереве ресурсов появляется поле, отображающее его содержимое.

В окне 2 на передний план выходит вкладка «Breakpoints and Tracepoints», где теперь будут отображаться все точки останова. В панели инструментов активизируются все инструменты, относящиеся к режиму отладки (до этого они были неактивны). В окне 3 на первый план выходит текст главного программного файла. На левой границе окна этого файла появляется желтая стрелка - указатель текущей выполняемой команды. Указатель установится в начало программы (напротив первой исполняемой команды). Теперь все готово для отладки.

Отладка может выполняться разными методами. Самый простой метод - пошаговое выполнение. Для того, чтобы сделать один шаг, выберите в меню «Debug» пункт «Step into» («Шаг в») либо нажмите кнопку на панели инструментов.

Можно также просто нажать кнопку «F11». В результате программа выполнит одну текущую команду. Указатель текущей команды (желтая стрелка) переместится в следующую позицию. Содержимое регистров изменится в соответствии с выполненной операцией.

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

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

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

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

Кроме директивы «Шаг в», имеется еще несколько ее модификаций. Их назначение и способы вызова приведены в табл. 1.

Таблица 1.


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

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

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

Применение точек останова

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

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

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

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

Для управления точками останова программа имеет несколько встроенных директив, которые показаны в таблице 2.

Таблица 2.


Директивы управления точками останова

Для того, чтобы поставить точку останова в какой-либо строке программы, нужно сначала поместить в эту строку текстовый курсор. Затем выбрать директиву «Поставить точку останова» (см. табл. 2). Точка останова выглядит как коричневый кружочек напротив выбранной строки программы на левой границе текстового окна.

Если поместить курсор в строку, где уже есть точка останова, и выполнить еще раз директиву «Поставить точку останова», то точка убирается. Убрать сразу все поставленные точки останова можно при помощи директивы «Убрать все точки останова».

Второй способ простановки точек останова - задание их через меню. Предназначенный для этого пункт «New Breakpoints» меню «Debug» имеет два подпункта. При помощи подпункта «Program Breakpoint» можно устанавливать программные точки останова. То есть точно такие, какие мы ставили предыдущим способом.

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

Для этого вам необходимо заполнить поле «Break execution after: - hits» («Остановить выполнение после: - проходов»). Если число в этом поле не равно нулю, то программа остановится в данной точке останова не с первого раза, а лишь тогда, когда пройдет через нее указанное количество раз.

Если вы установили вашу точку останова не через меню, а напрямую в тексте программы, вы все равно можете вызвать описанный выше диалог и изменить в нем количество проходов, щелкнув мышью по строке с описанием нужной точки останова во вкладке «Breakpoints and Tracepoints».

При помощи подпункта «Data Breakpoint» пункта «New Breakpoints» меню «Debug» можно задавать точки останова по данным. При выборе этого пункта меню открывается диалог, в котором вы можете выбрать любую из переменных вашей программы или любой ресурс микроконтроллера (из открывающегося списка) и поставить точку останова по обращению к этой переменной (ресурсу).

Программа позволяет выбрать целый ряд условий, при которых наступит останов программы. По умолчанию останов происходит при любом обращении к этой переменной как в режиме чтения, так и в режиме записи. Вы можете выбрать другое условие. Например, при равенстве переменной определенному значению. Выбор условия производится при помощи поля «Break when:» («Остановиться если:») и поля «Access type» («Тип доступа»). Имя переменной выбирается при помощи поля «Location».

Диалог простановки точек останова обоих видов можно вызывать не только через меню. В верхней левой части вкладки «Breakpoints and Tracepoints» для этого имеется специальная кнопка.

После того, как вы проставили все точки останова, вы можете запускать программу в режиме автоматического выполнения. Для управления отладчиком в этом режиме программа AVR Studio также имеет несколько специальных директив (см. табл. 3). Запуск автоматического выполнения программы производится при помощи директивы «Пуск».

Пока программа находится в режиме автоматического выполнения, новое состояние регистров не отображается. Указатель текущей команды также отсутствует. В нижней строке главной панели программы в правой ее стороне находится индикатор состояния. В режиме останова это желтый кружочек с минусом посередине. Слева от него находится слово «Stopped» (Остановлено). В режиме автоматического выполнения программы желтый кружочек превращается в зеленый с плюсом внутри. Вместо слова «Stopped» появляется слово «Running» (Запущено).

Если вы неправильно поставили точку останови либо и вовсе забыли ее поставить, программа будет находиться в режиме автоматического выполнения бесконечно долго. Для досрочной остановки программы используется директива «Остановить». Если в процессе отладки программы понадобится начать все сначала (сымитировать сброс микроконтроллера), это можно сделать при помощи директивы «Сброс». По окончании отладки программы необходимо перейти в режим редактирования. Для этого служит директива «Закончить отладку».

Таблица 3.


Просмотр и изменение содержимого введенных переменных

Для оперативного просмотра и изменения содержимого введенных вами переменных в процессе отладки можно открыть специальное окно. Для этого достаточно выбрать пункт «Watch» в меню «View». Окно имеет четыре вкладки. Поэтому можно иметь четыре разных набора переменных.

Для того чтобы включить какую-либо переменную в текущее окно «Watch», необходимо установить курсор мыши на имя этой переменной в тексте программы и нажать правую кнопку мыши. Допустим, вы установили курсор на переменную temp. Тогда в открывшемся меню вы увидите пункт «Add Watch»: «temp». Выберите этот пункт, и переменная будет включена в список «Watch.

Точно так же можно оперативно просматривать содержимое любого вида памяти. Для этого выберите пункт «Memory» в меню «View». Откроется новое окно под названием «Memory». По умолчанию в этом окне в виде дампа будет представлено содержимое программной памяти. При помощи выпадающего списка в левой верхней части этого окна можно выбрать другой вид памяти. Память данных (Data), EEPROM или даже содержимое РОН или портов вода/вывода. В процессе отладки вы всегда будете видеть в этом окне все изменения выбранной части памяти. Если вы желаете видеть одновременно содержимое сразу нескольких видов памяти, то вы можете открыть второе и даже третье подобное окно. Для этого выберите пункт «Memory2» или «МетогуЗ» в меню «View».

Исправление ошибок

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

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

Таблица 4.

Похожие работы на - Программирование микропроцессорных систем

 

Не нашли материал для своей работы?
Поможем написать уникальную работу
Без плагиата!