» » Програмирование в AVR Studio 5 с самого начала. Часть 3

 
 
 
11

Програмирование в AVR Studio 5 с самого начала. Часть 3

Разместил galrad 1 октября 2011. Просмотров: 28 329


Мы научились включать и выключать светодиоды, а как сделать, чтобы они сами заморгали? Понятно, что после того, как их включили, нужно сделать паузу, затем выключить, снова выждать паузу и снова включить. А как сделать паузу?
Есть конечно, команда NOP, которая сделает паузу равную одному такту, но мы ее никак не увидим.
Такт – это один импульс тактового генератора. Современные контроллеры работают с тактовыми частотами от 1 до 60 мегагерц (от 1 до 60 миллионов импульсов в секунду). Большинство команд AVR выполняется за один такт, где то около 10 команд выполняется за 2 такта.
Поэтому паузу сделанную одной командой NOP, увидеть невозможно, а если нам нужна пауза в полсекунды - тогда нужно минимум написать 500 тысяч команд NOP. Но, это не реально!.
Может, остановить программу?
А остановить мы ее не можем, иначе будет сбой программы. Есть другое решение – можно программу зациклить, чтобы отсчитать какое-то количество тактов, а затем продолжить.
Самый простой вариант зацикливания:
Cycle:       rjmp Cycle

Строка начинается метки Cycle:
Метка обязательно заканчивается двоеточием – в этом ее отличие. Метка может иметь любое сочетание букв и цифр написанное в английской транскрипции (как в предыдущем примере я написал Cicle: и ничего, программа без проблем распознала эту метку).
Кто изучал программы для PIC, видимо заметил, что там после метки, двоеточие не ставится.
Далее стоит команда rjmp Cycle – относительный переход к метке Cycle т.е. на самого себя. Все “бесконечный цикл”.
Из этой программы можно выйти, только если были заданы условия прерывания, или включен сторожевой таймер WDR, иначе никак. Есть программы, основное тело которой состоит только из такой строки, вся остальная часть построена на подпрограммах, вызываемых прерываниями. Но эти случаи мы рассмотрим чуть позже.
Вообще – любая программа - это цикл, имеющий начало и конец
Самый короткий цикл, это тот который мы только, что рассмотрели, состоящий всего из одной команды. Нередко применяется тогда, когда от контроллера не требуется никаких действий, только ожидание.
Программа может представлять из себя огромный цикл, включающий в свою структуру множество мелких циклов – подпрограмм. Пишутся они с помощью команд ветвления и команд вызова подпрограмм.
Рассмотрим некоторые из них:
breq – Перейти (на определенную строку) если результат предыдущей строки =0
Если значение регистров указанных в предыдущей строке не равно 0, то команда игнорируется (как будто ее нет)
brne - Перейти (на определенную строку) если результат предыдущей строки не 0
Если значение регистров указанных в предыдущей строке равно 0, то команда игнорируется (как будто ее нет)

rcall - Относительный вызов подпрограммы
ret – Выход из подпрограммы
Здесь функции команд понятны без комментприев.
Еще рассмотрим пару команд, которые очень часто испоьзуются:
inc – Инкремент, прибавить к регистру единицу
dec – Декремент, вычесть из регистра единицу
Попробуем дописать предыдущую программу:

.def temp=r16; директива .def назначает регистру r16 имя temp
.def temp1=r17; директива .def назначает регистру r17 имя temp1
.def temp2=r18; директива .def назначает регистру r18 имя temp2
.def temp3=r19; директива .def назначает регистру r19 имя temp3
;====================================================
; Начало программы
.cseg; директива .cseg определяет начало сегмента, где будет расположен
   ; основной код программы. В AVR Studio 5 это директива не
   ; обязательна
.org 0; начало первой строки программы
rjmp Start; относительный переход к метке Start (в PIC соответствует 
   ; команде goto)
; ====================================================
Start:
ser temp; устанавливает все биты регистра temp  в 1
out DDRB,temp; переводит все биты 
out DDRD,temp; порта B  и D на вывод
clr temp; обнуляет регистр temp (устанавливает все биты регистра temp  в 0)
out PortB,temp; отключает подтягивающие резисторы 
out PortD,temp; портов B и D 
Cicle: 
ldi temp,0b11001100; включает светодиоды
out PortB, temp; порта B
rcall Pause; вызов подпрограммы задержки
clr temp; выключает светодиоды
out PortB, temp; порта B
rcall Pause; вызов подпрограммы задержки
rjmp Cicle; Возвращаемся к метке Cicle, зацикливаемся
; ====================================================
; Подпрограмма задержки
; ====================================================
Pause:    
ldi Temp1,0; записать в регистр temp1 знчение 0
ldi Temp2,0; записать в регистр temp2 знчение 0
ldi Temp3,2; записать в регистр temp3 знчение 2

Pause1:    
dec Temp1; вычесть из значения  регистра temp1 единицу
brne Pause1; если значение temp1 не равно 0 перейти к метке Pause1

dec Temp2; вычесть из значения  регистра temp2 единицу
brne Pause1; если значение temp2 не равно 0 перейти к метке Pause1

dec Temp3; вычесть из значения  регистра temp3 единицу
brne Pause1; если значение temp1 не равно 0 перейти к метке Pause1
ret; выйти из подпрограммы

Здесь проект для Proteus:
attiny2313_led_1.rar | Файл 27,14 Kb загружен 111 раз.
компилируем, загружаем проект, распаковываем и запускаем:

Смотрим как работает программа в Proteus (как загрузить .hex файл подробно описано во 2-ой части). Что видим? Заморгали светодиоды?

morganie.wmv | Файл 491,56 Kb загружен 105 раз.

Разберем, что мы тут понаписали:
Строка:
clr temp – обнуляет регистр temp    

Строка:
rcall Pause
; вызов подпрограммы задержки
команда rcall вызывает подпрограмму с меткой Pause, которая реализует нужную нам задержку. Выход из подпрограммы происходит по команде - ret
По команде ret происходит возврат в прежнюю точку, откуда была вызвана подпрограмма. Подпрограммы удобно создавать, когда в программе требуется многократно выполнять одно и тоже действие. Достаточно написать одну подпрограмму и обращаться к ней в любой момент, по мере необходимости.
Как работает наша подпрограмма Pause?
Нам нужно правильно рассчитать время задержки. Возьмем во внимание, что внутренняя (без внешнего кварцевого генератора) тактовая частота нашего микроконтроллера равна 8 МГц. По умолчанию, происходит деление этой частоты на 8 т.е. реальная тактовая частота равна 1 МГц, и задержка одного такта составит 1 миллисекунду. Для того, чтобы организовать задержку в 0,5 секунды, нужно пропустить 500 тысяч тактов. Как это сделать?
А для этого мы организуем 3-х байтный счетчик из регистров Temp1, Temp2, Temp3
Почему трехбайтный? Давайте посмотрим, как выглядит число 500000 в двочной и шестнадцатиричной системах.
[b0] 00000111 10100001 00100000;
07 A1 20 [h]
Наглядно видно, что число состоит из трех байт.
Вроде все просто, но если мы запишем эти числа в регистры, то на самом деле задержка окажется значительно больше, чем мы ожидали. Почему?
А ведь кроме регистров есть в подпрограмме команды, которые выполняются за определенное количество тактов, они то и забирают дополнительное время. Чем больше команд, тем большее время будет выполняться задержка. Если грубо прикинуть, то время задержки будет примерно в четыре раза больше ожидаемого! Поэтому я записал в младшие регистры нули, а в старший 2.

Pause:    
ldi Temp1,0; записать в регистр temp1 знчение 0
ldi Temp2,0; записать в регистр temp2 знчение 0

Не будет ошибкой, если мы пропишем clr temp1 и clr temp2
ldi Temp3,2; записать в регистр temp3 знчение 2


После того, как прописали значения регистров переходим к самой задержке:
Строки:
Pause1:    
dec Temp1            
brne Pause1  


команда dec Temp1 – вычитает из регистра temp1, (в который сейчас прописан нуль) единицу, результатом будет число FFh или 255 (чтобы проверить - сделайте обратное действие в восьми битном регистре, произойдет переполнение и обнуление регистра)

команда brne Pause1 – сравнивает значение пред идущего регистра (регистра temp1) с нулем. Если результат не равен нулю, то пересылает к метке Pause1. Цикл повторяется до тех пор, пока значение temp1 не станет равным нулю.
Если значение регистра temp =0, то команда brne игнорируется и выполняется пустой такт (как Nop), а прогамма переходит к строке ниже.
Аналогично происходит и с регистрами temp2 и temp3, пока не будет выполнена команда – ret.

А что делать, если нам надо вычислить задержку с точностью до нескольких микросекунд?
Для этого используем AVR Studio 5
В редакторе пишем текст (можно скопировать и перенести отсюда).

После того, как ввели текст, компилируем программу (F7).
Кликаем (View)

В меню (View) кликаем (Toolbars)

Ставим галочку в подменю (AVR Dbugger)

Выходим из подменю на страницу редактора, устанавливаем курсор на строке в начале подпрограммы задержки и кликаем (F9)
Возникает красный кружек с выделенной строкой (Breakpoint) точка останова.

Точно также выделяем вторую строку (Breakpoint)

1. Кликаем на зеленый треугольник (Start), тем самым запускаем эмуляцию-отладку (Debuger).
2. Кликаем на символ микросхемы, если справа не появилось окно (Processor).
3. Устанавливаем желтую стрелку на верхнем Breakpoint-е, кликая по зеленому треугольнику (Start).
4. Выделяем строку (Cycle Counter) и прописываем 0.
5. Устанавливаем тактовую частоту процессора

Кликаем на зеленый треугольник (Start) и ждем появления желтой стрелки в нижнем красном кружке Breakpoint-а.
Смотрим строку Stop Watch (секундомер).
Это время от начала подпрограммы задержки, до его завершения.

Чтобы убрать Breakpoint-ы, нужно подвести курсор на красный кружек и кликнуть (F9).
Таким образом можно определить длительность выполнения любого отрезка программы, и очень точно выставить временные интервалы.

В нашей программе время отчитывается с момента включения светодиода до момента его отключения. Частота процессора соответствует 1 МГц. Установим Breakpoint на команде включения светодиода, а второй на команде выключения.

Запустим Debug-ер, кликнув зеленый треугольник. Смотрим показания секундомера Stop Watch.

Это реальное время включения светодиодов (394 255,00 микросекунд). Снова обнуляем, и запускем Debug-ер,

теперь в показаниях секундомера смотрим время паузы (394 257,00 микросекунд). Получили разницу в 2 микросекунды. Попробуйте самостоятельно, с помощью команд Nop, сделать одинаковыми время включения и выключения светодиодов.
Изменим программу таким образом,, чтобы получить возможность управлять включением светодиодов с помощью кнопок.

.def temp=r16; дирекива .def назначает регистру r16 имя temp
.def temp1=r17; директива .def назначает регистру r17 имя temp1
.def temp2=r18; директива .def назначает регистру r18 имя temp2
.def temp3=r19; директива .def назначает регистру r19 имя temp3
;====================================================
; Начало программы
.cseg; директива .cseg определяет начало сегмента, где будет расположен
   ; основной код программы. В AVR Studio 5 это директива не
   ; обязательна
.org 0; начало первой строки программы
rjmp Start; относительный переход к метке Start (в PIC соответствует 
   ; команде goto)
; ====================================================
Start:
ser temp; устанавливает все биты регистра temp  в 1
out DDRB,temp; переводит все биты порта B на вывод
clr temp1; обнуляет регистр temp1
out DDRD,temp1; переводит все биты порта D на ввод         
out PortB,temp1; отключает подтягивающие резисторы портов B
out PortD,temp; включает подтягивающие резисторы портов D 
Cicle: 
in temp,PinD; считывает значение порта D и 
out PortB, temp; переводит результат в порт B
rcall Pause; вызов подпрограммы задержки
clr temp; выключает светодиоды
out PortB, temp; порта B
rcall Pause; вызов подпрограммы задержки
rjmp Cicle; Возвращаемся к метке Cicle, зацикливаемся
; Подпрограмма задержки
; ====================================================
Pause:    
clr temp1; обнулить регистр temp1
clr temp2; обнулить регистр temp2
ldi temp3,2; записать в регистр temp3 число 2

Pause1:    
dec temp1; вычесть из значения  регистра temp1 единицу
brne Pause1; если значение temp1 не равно 0 перейти к метке Pause1

dec temp2; вычесть из значения  регистра temp2 единицу
brne Pause1; если значение temp2 не равно 0 перейти к метке Pause1

dec temp3; вычесть из значения  регистра temp3 единицу
brne Pause1; если значение temp1 не равно 0 перейти к метке Pause1
ret; выйти из подпрограммы


Строка:
in temp,PinD

Команда in считывает значение регистра порта D, и записывает в регистр temp.

Небольшое отступление: По поводу правильного введения цифровых значений в программу. Программа AVR Studio 5, как и предыдущие версии не понимает интеловской формы введения шестнадцатеричных чисел, где после значения ставиться маленькая буква h, например A5h. В AVR Studio 5 правильно писать 0хА5. В обычном тексте удобно писать и пояснять именно в интеловской форме, но в тексте программ такая форма недопустима.

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

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

knopki.wmv | Файл 1,73 Mb загружен 102 раз.
Далее мы напишем программу бегущих огней, выясним, что такое стек.
Радик (galrad)
РФ. Республика Башкортостан. г.Уфа
Профиль galrad
1964г.р. Специальность - врач. Ученая степень - кандидат медицинских наук. Радиоэлектроника - увлечение с 15 лет. Приоритетные направления - микроконтроллеры, цифровая электроника, измерения, ремонт компьютеров и сотовых телефонов, и т.п. Второе высшее образование - инженер-электроник.
 

Понравилось? Палец вверх!

  • всего лайков: 12

Поделись с друзьями!

Связанные материалы:


Схема на Датагоре. Новая статья Програмирование в AVR Studio 5 с самого начала. Часть 7... Поговорим о прерываниях. Слово прерывание говорит само за себя, происходит остановка какого —...
Схема на Датагоре. Новая статья Програмирование в AVR Studio 5 с самого начала. Часть 6... Продолжим разбор теоретических основ, без которых невозможно полноценное создание программ....
Схема на Датагоре. Новая статья Програмирование в AVR Studio 5 с самого начала. Часть 4... Сегодня рассмотрим программу “бегущих огней” и “бегущих теней”. Примеры “бегущих огней” можно найти...
Схема на Датагоре. Новая статья Програмирование в AVR Studio 5 с самого начала. Часть 2... Пишем первую программу!Большинство начинают с мигания светодиодов, и мы не исключение. Если...
Схема на Датагоре. Новая статья Програмирование в AVR Studio 5 с самого начала. Часть 1... Каждый человек, который только начинает осваивать программирование микроконтроллеров, да и вообще...
Схема на Датагоре. Новая статья Электронная замена механическому таймеру СВЧ-печи... У знакомого по работе, сломался механический таймер СВЧ печки. Попросил помощи, но через три дня...
Схема на Датагоре. Новая статья Проект DMX512. Микроконтроллер управляет профессиональным шоу. Ч.3... Я думаю, что прочитав теоретическую часть, в которой не всё сразу понятно, лучше сразу потихонечку...
Схема на Датагоре. Новая статья Программа «Timbreblock 4.0.0.0»... Программа «Timbreblock 4.0.0.0» Перед Вами русская версия программы «Timbreblock 4.0.0.0»,...
Схема на Датагоре. Новая статья Программа «Filter for acoustic system 3.0.0.0»... Программа «Filter for acoustic system 3.0.0.0» Перед Вами русская версия программы «Фильтр для...
Схема на Датагоре. Новая статья Применение микроконтроллеров AVR. Схемы, алгоритмы, программы... Какой микроконтроллер выбрать? Где найти его описание? Где взять программу, обеспечивающую...
Схема на Датагоре. Новая статья Анатомия микроконтроллеров ATmega - 3. Прерывания.... Итак, наши светодиоды мигают, но мы не можем никак повлиять на программу, давайте добавим в схему...
Схема на Датагоре. Новая статья Анатомия микроконтроллеров ATmega - 2... Итак, продолжим издевательство над МК. Что же нам ещё такого сделать? Давайте заставим мигать...
<
  • Гражданин
1 октября 2011 01:04

Владимир / vol2008

Цитата
  • С нами с 29.07.2011
  • Ушёл в реал Пользователь offline
  • 43 комментария
  • 7 публикаций
 
  • 0
Написано все очень популярно!

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

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

<
  • Главный редактор
1 октября 2011 01:23

Игорь Петрович Котов / Datagor

Цитата
  • С нами с 25.02.2011
  • Ушёл в реал Пользователь offline
  • 1 680 комментариев
  • 264 публикации
 
  • 0
Цитата: vol2008
Предполагаю, что автор в курсе этого и в дальнейших статьях обязательно осветит этот момент.

Володя, вот именно! Это ТРЕТИЙ урок. smile
Все по порядку: от простого (пусть иногда не оптимального) к сложному и красивому.

Радик, спасибо за продолжение!

<
  • Гражданин
1 октября 2011 13:50

Радик / galrad

Цитата
  • С нами с 23.08.2011
  • Ушёл в реал Пользователь offline
  • 88 комментариев
  • 12 публикаций
 
  • 0
Цитата: vol2008
В тексте есть неточность - время операций не в миллисекундах. а в микросекундах.

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

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

<
  • Гражданин
1 октября 2011 16:49

Андрей Панченко / 120780andrey

Цитата
  • С нами с 8.02.2009
  • Ушёл в реал Пользователь offline
  • 13 комментариев
  • 0 публикаций
 
  • 0
Спасибо за цикл статей. Начал изучать и пробовать моргать светиками в виртуале.
Определенно продолжать стоит.
Спасибо еще раз.

<
  • Гражданин
1 октября 2011 22:47

Николай / Nikom

Цитата
  • С нами с 3.03.2010
  • Ушёл в реал Пользователь offline
  • 16 комментариев
  • 0 публикаций
 
  • 0
Так как цикл статей для начинающих, продолжать стоит.Лучше медленно, но зато понятно.Еще раз спасибо за статьи.

<
  • Гражданин
1 октября 2011 23:54

Анатолий / Anatolyi

Цитата
  • С нами с 15.05.2008
  • Ушёл в реал Пользователь offline
  • 22 комментария
  • 1 публикация
 
  • 0
galrad,
Радик, так держать!!!
Для меня это интересно и , самое главное, примитивно = всё становится понятным.
Дело в том, что раздражения бывалых не должно касаться меня, абсолютно не понимающего азов.
Я с удовольствием слежу за вашими уроками.
Продолжайте, пожалуйста, в этом духе. bye

<
  • Кандидат
2 октября 2011 00:18

Сергей / sergD

Цитата
  • С нами с 28.03.2010
  • Ушёл в реал Пользователь offline
  • 5 комментариев
  • 0 публикаций
 
  • 0
Спасибо за статьи.
интересно, поучительно, полезно для начинающих.
продолжать стоит однозначно.

<
  • Кандидат
2 октября 2011 17:46

Вадим / vadeg

Цитата
  • С нами с 14.01.2012
  • Ушёл в реал Пользователь offline
  • 28 комментариев
  • 0 публикаций
 
  • 0
Отличное продолжение! Радик, спасибо!
На мой взгляд новичка, именно с кнопок и светодиодов и надо начинать! Но в большинстве случаев этим все и заканчивается, далее следует пример более серьезной и полезной программы, а внимания правильного подхода к дребезгу и формированию временных интервалов не уделяется. Есть такой прием, когда от таймера, даже без прерываний, получают временные интервалы для опроса кнопок (антидребезг), развертку динамической индикации и счет секунд, например если это часы.
Будет очень поучительно подобное увидеть, т.к. времена AT90S1200 давно прошли.

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

В общем мое мнение (как новичка) такое:
пусть будет простая "бесполезная" мигалка, но написанная в двух или в трех вариантах (с усложнением), чтобы последняя версия была "красивой и правильной".

<
  • Гражданин
3 октября 2011 23:52

Григорий / faers

Цитата
  • С нами с 20.09.2008
  • Ушёл в реал Пользователь offline
  • 25 комментариев
  • 2 публикации
 
  • 0
Автору ОГРОМНЕЙШЕЕ СПАСИБО. Вы мой Пастух я ваш БАРАН. Я вполне согласен с Anatolyi
ето для меня статья бывалым прозьба не усложнять, ибо и так туплю. У каждого начинающего свой уровень начинаний.

<
  • Прохожий
4 октября 2011 02:49

/ Demiurg

Цитата
  • С нами с --
  • 0 комментариев
  • 0 публикаций
 
  • 0
Небольшая поправка. Директива, а не директория. Почему-то я не увидел директиву .include Вообще, для удобства следует создать шаблон проектов.

<
  • Гражданин
4 октября 2011 10:37

Радик / galrad

Цитата
  • С нами с 23.08.2011
  • Ушёл в реал Пользователь offline
  • 88 комментариев
  • 12 публикаций
 
  • 0
Спасибо, исправил! Аж самому слух режет. Видимо, когда писал - думал о другом (бывает) smile

Цитата: Demiurg
Почему-то я не увидел директиву .include

Директива .include "2313def.inc" в AVR Studio 5 устанавливается по умолчанию, после выбора контроллера.
Пропишите для интереса в редакторе, и...получите ошибку....

Цитата: Demiurg
Вообще, для удобства следует создать шаблон проектов.

Форма шаблона была предложена во второй части.

Добавление комментария


Налетай! Паяльники, станции, жала с доставкой
  • smilelolbyewinkyahoocoollaughing
    crazybadcryingsadirefulsickstraight
    ballooncakegooddrinksmailbombsun
    nightrainstarscolddashguitar-manhandshake
    musicnegativenopardonshoksleepunknown
    wackoyawnblushbullyhashsmokingwhew
Скопируйте текст вашего комментария на случай неверного ответа на контрольный вопрос.