Порядок программирования микроконтроллеров avr. Что нужно для программирования микроконтроллеров? Как прошивать контроллер, и какие дополнительные приборы и акссесуары нужны для удобной работы с ними

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

Ее тут два вида (EEPROM не в счет т.к. она вообщет переферия, а о ней потом):

  • RAM — оперативка
  • ROM — ПЗУ, она же flash, она же память программ

Так как архитектура у нас Гарвардская, то у оперативы своя адресация, а у флеша своя. В даташите можно увидеть структуру адресации ОЗУ.

Сразу обратите внимание на адреса! РОН и регистры периферии, а также ОЗУ находятся в одном адресном пространстве. Т.е. адреса с 0000 по 001F занимают наши регистры, дальше вплоть до адреса 005F идут ячейки ввода-вывода — порты. Через порты происходит конфигурирование всего, что есть на борту контроллера. И только потом, с адреса 0060 идет наше ОЗУ, которое мы можем использовать по назначению.

Причем обратите внимание, что у регистров I/O есть еще своя адресация — адресное пространство регистров ввода-вывода (от 00 до 3F), она указана на левой части рисунка. Блок IO/Register Эта адресация работает ТОЛЬКО в командах OUT и IN Из этого вытекает интересная особенность.

К регистрам периферии можно обратиться двумя разными способами:

  • Через команды IN/OUT по короткому адресу в пространстве адресов ввода-вывода
  • Через группу команд LOAD/STORE по полному адресу в пространстве адресов RAM

Пример. Возьмем входной регистр асинхронного приемопередатчика UDR он имеет адрес 0x0C(0х2С) в скобках указан адрес в общем адресном пространстве.

LDI R18,10 ; Загрузили в регистр R18 число 10. Просто так OUT UDR,R18 ; Вывели первым способом, компилятор сам; Подставит вместо UDR значение 0х0С STS 0x2C,R18 ; Вывели вторым способом. Через команду Store ; Указав адрес напрямую.

Оба метода дают идентичные результаты. НО! Те что работают адресацией в пространстве ввода-вывода (OUT/IN) на два байта короче. Это и понятно — им не нужно хранить двубайтный адрес произвольной ячейки памяти, а короткий адрес пространства ввода—вывода влезает и в двухбайтный код команды.

Правда тут возникает еще один прикол. Дело в том, что с каждым годом появляются все новые и новые камни от AVR и мяса в них все больше и больше. А каждой шкварке нужно свои периферийные регистры ввода-вывода. И вот, дожили, в ATMega88 (что пришла на замену Mega8) периферии уже столько, что ее регистры ввода-вывода уже не умещаются в лимит адресного пространства 3F.

Опаньки, приплыли. И вот тут у тех кто пересаживается с старых камней на новые начинаются недоуменные выражения — с чего это команды OUT/IN на одних периферийных регистрах работают, а на других нет?

А все просто — разрядности не хватило.

А ядро то единое, его уже не переделать. И вот тут ATMELовцы поступили хитро — они ввели так называемые memory mapped регистры. Т.е. все те регистры, что не влезли в лимит 3F доступны теперь только одним способом — через Load/Store.

Вот такой прикол. Если открыть какой нибудь m88def.inc то там можно увидеть какие из регистров ввода-вывода «правильные» а какие memory mapped.

Будет там бодяга вот такого вида:

; ***** I/O REGISTER DEFINITIONS ***************************************** ; NOTE: ; Definitions marked "MEMORY MAPPED"are extended I/O ports ; and cannot be used with IN/OUT instructions .equ UDR0 = 0xc6 ; MEMORY MAPPED .equ UBRR0L = 0xc4 ; MEMORY MAPPED .equ UBRR0H = 0xc5 ; MEMORY MAPPED .equ UCSR0C = 0xc2 ; MEMORY MAPPED .equ UCSR0B = 0xc1 ; MEMORY MAPPED .equ UCSR0A = 0xc0 ; MEMORY MAPPED бла бла бла, и еще много такого.equ OSCCAL = 0x66 ; MEMORY MAPPED .equ PRR = 0x64 ; MEMORY MAPPED .equ CLKPR = 0x61 ; MEMORY MAPPED .equ WDTCSR = 0x60 ; MEMORY MAPPED .equ SREG = 0x3f ;<------ А тут пошли обычные.equ SPL = 0x3d .equ SPH = 0x3e .equ SPMCSR = 0x37 .equ MCUCR = 0x35 .equ MCUSR = 0x34 .equ SMCR = 0x33 .equ ACSR = 0x30

Вот такие пироги.

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

Впрочем есть решение. Макроязык! Не нравится система команд? Придумай свою с блекджеком и шлюхами!
Сварганим свою собственную команду UOUT типо универсальный OUT

Аналогично и для команды IN Вообще, такими вот макросами можно ОЧЕНЬ сильно разнообразить ассемблер, превратив его в мощнейший язык программирования, рвущий как тузик тряпку всякие там Си с Паскалями.

Ну так о чем я… а о ОЗУ.

Итак, с адресацией разобрались. Адреса памяти, откуда начинаются пользовательские ячейки ОЗУ теперь ты знаешь где смотреть — в даташите, раздел Memory Map. Но там для справки, чтобы знать.

А в нашем коде оперативка начинается с директивы.DSEG Помните наш шаблончик?

Include "m16def.inc" ; Используем ATMega16 ;= Start macro.inc =============================== ; Макросы тут;= End macro.inc ================================= ; RAM ============================================= .DSEG ; Сегмент ОЗУ; FLASH =========================================== .CSEG ; Кодовый сегмент; EEPROM ========================================== .ESEG ; Сегмент EEPROM

Вот после.DSEG можно задавать наши переменные. Причем мы тут имеем просто прорву ячеек — занимай любую. Указал адрес и радуйся. Но зачем же вручную считать адреса? Пусть компилятор тут думает.

Поэтому мы возьмем и зададим меточку

0x0060 ## ;Variables 0x0061 ## 0x0062 ## 0x0063 ## ;Variables2 0x0064 ## 0x0065 ## ;Тут могла бы начинаться Variables4

В качестве ## любой байт. По дефолту FF. Разумеется ни о какой типизации переменных, начальной инициализации, контроля за переполнениями и прочих буржуазных радостей говорить не приходится. Это Спарта! В смысле, ассемблер. Все ручками.
Если провести аналогию с Си, то это как работа с памятью через одни лишь void указатели. Сишники поймут. Поймут и ужаснутся. Т.к. мир этот жесток и коварен. Чуть просчитался с индексом — затер другие данные. И хрен ты эту ошибку поймаешь если она сразу не всплывет.

Так что внимание, внимание и еще раз внимание. Все операции с памятью прогоняем через трассировку и ничего у нас не вылезет и не переполнится.

В сегменте данных работает также директива.ORG Работает точно также — переносит адреса, в данном случае меток, от сих и до конца памяти. Одна лишь тонкость — ORG 0000 даст нам самое начало ОЗУ, а это R0 и прочие регистры. А нулевой километр ОЗУ на примере Мега16 даст ORG 0x0060. А в других контроллерах еще какое-нибудь значение. Каждый раз в даташит лазать лениво, поэтому есть такое макроопределение как SRAM_START указывающее на начало ОЗУ для конкретного МК.

Так что если хотим начало ОЗУ, скажем 100 байт оставить под какой нибудь мусорный буффер, то делаем такой прикол.

1 2 3 4 .DSEG .ORG SRAM_START+100 Variables: .byte 3

DSEG .ORG SRAM_START+100 Variables: .byte 3

Готово, расчистили себе буфферную зону от начала до 100.

Ладно, с адресацией разобрались. Как работать с ячейками памяти? А для этих целей существует две группы команд. LOAD и STORE самая многочисленная группа команд.

Дело в том, что с ячейкой ОЗУ ничего нельзя сделать кроме как загрузить в нее байт из РОН, или выгрузить из нее байт в РОН.

Записывают в ОЗУ команды Store (ST**), а считываю команды Load (LD**).

Чтение идет в регистр R16…R31, а адрес ячейки задается либо непосредственно в команде. Вот простой пример. Есть трехбайтная переменная Variables, ее надо увеличить на 1. Т.е. сделать операцию Variables++

DSEG Variables: .byte 3 Variavles2: .byte 1 .CSEG ; Переменная лежит в памяти, сначала надо ее достать. LDS R16, Variables ; Считать первый байт Variables в R16 LDS R17, Variables+1 ; Считать второй байт Variables в R17 LDS R18, Variables+2 ; Ну и третий байт в R18 ; Теперь прибавим к ней 1, т.к. AVR не умеет складывать с константой, только; вычитать, приходиться извращаться. Впрочем, особых проблем не доставляет. SUBI R16,(-1) ; вообще то SUBI это вычитание, но -(- дает + SBCI R17,(-1) ; А тут перенос учитывается. Но об этом потом. SBCI R18,(-1) ; Математика в ассемблере это отдельная история STS Variables,R16 ; Сохраняем все как было. STS Variables+1,R17 STS Variables+2,R18

А можно применить и другой метод. Косвенную запись через индексный регистр.

DSEG Variables: .byte 3 Variavles2: .byte 1 .CSEG ; Берем адрес нашей переменной LDI YL,low(Variables) LDI YH,High(Variables) ; Переменная лежит в памяти, сначала надо ее достать. LD R16, Y+ ; Считать первый байт Variables в R16 LD R17, Y+ ; Считать второй байт Variables в R17 LD R18, Y+ ; Ну и третий байт в R18 ; Теперь прибавим к ней 1, т.к. AVR не умеет складывать с константой, только; вычитать, приходиться извращаться. Впрочем, особых проблем не доставляет. SUBI R16,(-1) ; вообще то SUBI это вычитание, но -(- дает + SBCI R17,(-1) ; А тут перенос учитывается. Но об этом потом. SBCI R18,(-1) ; Математика в ассемблере это отдельная история ST -Y,R18 ; Сохраняем все как было. ST -Y,R17 ; Но в обратном порядке ST -Y,R16

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

Подобными инкрементальными командами удобно перебирать массивы в памяти или таблицы какие.
А там есть еще и косвенная относительная запись/чтение LDD/STD и еще варианты на все три вида индексов (X,Y,Z). В общем, кури даташит и систему команд.

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

Почему люблю? Ну дык, если Си это тупое ремесло, быстро и результативно, то Ассемблер это филигранное искусство. Как маньяки вроде Jim’a из бумаги и только из бумаги клепают шедевры, хотя, казалось бы, купи готовую сборную модель и клей себе в удовольствие. Так и тут — от самого процесса прет нипадецки. В том числе и от затраха с отладкой:))))

Так вот, о стеке. Что это такое? А это область памяти. Работает по принципу стопки. Т.е. какую последнюю положил, ту первой взял.

У стека есть указатель, он показывает на вершину стека. За указатель стека отвечает специальный регистр SP, а точнее это регистровая пара SPL и SPH. Но в микроконтроллерах с малым обьемом ОЗУ, например в Тини2313, есть только SPL

При старте контроллера, обычно, первым делом инициализируют стек, записывая в SP адрес его дна, откуда он будет рости. Обычно это конец ОЗУ, а растет он к началу.

Делается это таким вот образом, в самом начале программы:

1 2 3 4 5 LDI R16,Low(RAMEND) OUT SPL,R16 LDI R16,High(RAMEND) OUT SPH,R16

LDI R16,Low(RAMEND) OUT SPL,R16 LDI R16,High(RAMEND) OUT SPH,R16

Где RAMEND это макроопределение указывающий на конец ОЗУ в текущем МК.

Все, стек готов к работе. Данные кладутся в стек командой PUSH Rn, а достаются через POP Rn.
Rn — это любой из РОН.

Еще со стеком работают команды CALL, RCALL, ICALL, RET, RETI и вызов прерывания, но об этом чуть позже.

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

Вбей в студию такой код:

CSEG ; Кодовый сегмент LDI R16,Low(RAMEND) ; Инициализация стека OUT SPL,R16 LDI R16,High(RAMEND) OUT SPH,R16 LDI R17,0 ; Загрузка значений LDI R18,1 LDI R19,2 LDI R20,3 LDI R21,4 LDI R22,5 LDI R23,6 LDI R24,7 LDI R25,8 LDI R26,9 PUSH R17 ; Укладываем значения в стек PUSH R18 PUSH R19 PUSH R20 PUSH R21 PUSH R22 PUSH R23 PUSH R24 PUSH R25 PUSH R26 POP R0 ; Достаем значения из стека POP R1 POP R2 POP R3 POP R4 POP R5 POP R6 POP R7 POP R8 POP R9

А теперь запускай студию в пошаговое выполнение и следи за тем как будет меняться SP. Stack Pointer можно поглядеть в студии там же, где и Program Counter.

Вначале мы инициализируем стек и загрузим регистры данными. В результате получится следующая картина:

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

PUSH R16 PUSH R17 POP R16 POP R17

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

Проблема решается с помощью макроса. Я назвал его LDIL — LDI low

MACRO LDIL PUSH R17 ; Сохраним значение одного из старших регистров в стек. LDI R17,@1 ; Загрузим в него наше непосредственное значение MOV @0,R17 ; перебросим значение в регистр младшей группы. POP R17 ; восстановим из стека значение старшего регистра. .ENDM

Теперь можно легко применять нашу самодельную команду.

1 LDIL R0,18

Со временем, файл с макросами обрастает такими самодельными командами и работать становится легко и приятно.

Стековые ошибки
Стек растет навстречу данным, а теперь представьте что у нас в памяти есть переменная State и расположена она по адресу, например, 0х0450. В опасной близости от вершины стека. В переменной хранится, например, состояние конечного автомата от которого зависит дальнейшая логика работы программы. Скажем если там 3, то мы идем делать одно, если 4 то другое, если 5 то еще что-то и так до 255 состояний. И по логике работы после 3 должна идти 4ре, но никак не 10

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

Либо обратный пример — стек продавился до переменных, но в этот момент переменные обновились и перезаписали стековые данные. В результате, со стека снялось что-то не то (обычно кривые адреса возврата) и программе сорвало крышу. Вот такой вариант, кстати, куда более безобидный, т.к. в этом случае косяк видно сразу и он не всплывает ВНЕЗАПНО спустя черт знает сколько времени.

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

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

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

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

Стековые извраты
Моя любимая тема. =)))) Несмотря на то, что стековый указатель сам вычисляется при командах PUSH и POP, никто не мешает нам выковырять его из SP, да использовать его значения для ручного вычисления адреса данных лежащих в стеке. Либо подправить стековые данные как нам угодно.
Зачем? Ну применений можно много найти, если напрячь мозг и начать думать нестандартно:))))

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

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

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

Правда это уже напоминает нейрохирургию. Чуть ошибся и пациент труп.

Благодаря стеку и ОЗУ можно обходиться всего двумя-тремя регистрами, не особо испытывая напряг по поводу их нехватки.

Флеш память

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

Записать то мы запишем, а как достать? Для этого сначала надо туда что-либо положить.
Поэтому добавляй в конце программы, в пределах сегмента.CSEG метку, например, data и после нее, используя оператор.db, вписывай свои данные.

Оператор DB означает что мы на каждую константу используем по байту. Есть еще операторы задающий двубайтные константы DW (а также DD и DQ).

1 data: .db 12,34,45,23

data: .db 12,34,45,23

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

Одна тонкость — дело в том, что адрес метки подставляет компилятор, а он считает его адресом перехода для программного счетчика. А он, если ты помнишь, адресует двубайтные слова — ведь длина команды у нас может быть либо 2 либо 4ре байта.

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

Для загрузки данных из памяти программ используется команда из группы Load Program Memory

Например, LPM Rn,Z

Она заносит в регистр Rn число из ячейки на которую указывает регистровая пара Z. Напомню, что Z это два регистра, R30 (ZL) и R31 (ZH). В R30 заносится младший байт адреса, а в R31 старший.

В коде выглядит это так:

LDI ZL,low(data*2) ; заносим младший байт адреса, в регистровую пару Z LDI ZH,high(data*2) ; заносим старший байт адреса, в регистровую пару Z ; умножение на два тут из-за того, что адрес указан в; в двубайтных словах, а нам надо в байтах. ; Поэтому и умножаем на два; После загрузки адреса можно загружать число из памяти LPM R16, Z ; в регистре R16 после этой команды будет число 12, ; взятое из памяти программ. ; где то в конце программы, но в сегменте.CSEG data: .db 12,34,45,23

AVR - это название популярного семейства микроконтроллеров, которое выпускает компания Atmel . Кроме АВР под этим брендом выпускаются и других архитектур, например, ARM и i8051.

Какими бывают AVR микроконтроллеры?

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

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

Микроконтроллеры AVR 8-bit в свою очередь делятся на два популярных семейства:

    Attiny - из названия видно, что младшее (tiny - юный, молодой, младший), в основном имеют от 8 пинов и более. Объём их памяти и функционал обычно скромнее, чем в следующем;

    Atmega - более продвинутые микроконтроллеры, имеют большее количество памяти, выводов и различных функциональных узлов;

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

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

Для чего нужны и на что способны микроконтроллеры?

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

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

В распространенных AVR-микроконтроллерах, например, Atmega328 , который на 2017 году является сердцем многих плат Arduino , но о них позже. Используется 8 канальный АЦП , с разрядностью 10 бит . Это значит вы сможете считать значение с 8 аналоговых датчиков. А к цифровым выводам подключаются цифровые датчики, что может быть очевидным. Однако цифровой сигнал может являться только 1 (единицей) или 0 (нулем), в то время как аналоговый может принимать бесконечное множество значений.

Пояснение:

Разрядность - это величина, которая характеризует качество, точность и чувствительность аналогового входа. Звучит не совсем понятно. Немного практики: 10 битный АЦП, записать аналоговую информацию с порта в 10 битах памяти, иначе говоря плавно изменяющийся цифровой сигнал микроконтроллером распознается как числовое значение от 0 до 1024.

12 битный АЦП видит тот же сигнал, но с более высокой точностью - в виде от 0 до 4096, а это значит, что измеренные значения входного сигнала будут в 4 раза точнее. Чтобы понять откуда взялись 1024 и 4096, просто возведите 2 в степени равную разрядности АЦП (2 в степени 10, для 10 разрядного и т.д.)

Чтобы управлять мощностью нагрузки к вашему распоряжению есть ШИМ-каналы, их можно задействовать, например, для регулировки яркости, температуры, или оборотов двигателя. В том же 328 контроллере их 6.

В общем структура AVR микроконтроллера изображена на схеме:

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

    АЛУ - арифметико-логическое устройство. Нужно для выполнения вычислении.

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

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

    JTAG - интерфейс для внутрисхемного программирования без снятия микроконтроллера с платы.

    Flash, ОЗУ, EEPROM - виды памяти - программ, временных рабочих данных, долгосрочного хранения независимая от подачи питания к микроконтроллеру соответственно порядку в названиях.

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

    A/D (Analog/Digital) - АЦП, его назначение мы уже описали ранее.

    WatchDogTime (Сторожевой таймер) - независимый от микроконтроллера и даже его тактового генератора RC-генератор, который отсчитывает определенный промежуток времени и формирует сигнал сброса МК, если тот работал, и пробуждения - если тот был в режиме сна (энергосбережния). Его работу можно запретить, установив бит WDTE в 0.

Выходы микроконтроллера довольно слабые, имеется в виду то, что ток через них обычно до 20-40 миллиампер, чего хватит для розжига светодиода и LED-индикаторов. Для более мощной нагрузки - необходимы усилители тока или напряжения, например, те же транзисторы.

Что нужно чтобы начать изучение микроконтроллеров?

Для начала нужно приобрести сам микроконтроллер. В роли первого микроконтроллера может быть любой Attiny2313, Attiny85, Atmega328 и другие. Лучше выбирать ту модель, которая описана в уроках, по которым вы будете заниматься.

Следующее что Вам нужно - программатор . Он нужен для загрузки прошивки в память МК, самым дешевым и популярным считается USBASP .

Немногим дороже, но не менее распространенный программатор AVRISP MKII , который можно сделать своими руками - из обычной платы Arduino

Другой вариант - прошивать их через USB-UART переходник, который обычно делается на одном из преобразователей: FT232RL, CH340, PL2303 и CP2102.

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

Одно лишь «но» - в память микроконтроллера предварительно нужно загрузить UART бутлоадер. Разумеется, для этого все равно нужен программатор для AVR-микроконтроллеров.

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

Для работы UART (RS-232) интерфейса в микроконтроллерах AVR выделен целый регистр UDR (UART data register) . UCSRA (настройки битов приемопередатчика RX, TX), UCSRB и UCSRС - набор регистров отвечающие за настройки интерфейса в целом.

В чем можно писать программы?

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

Официальным IDE от Atmel является AVR Studio, которая на 6 версии была переименована в Atmel studio. Она поддерживает все микроконтроллеры AVR (8, 32, xMega), автоматически определяет команды и помогает ввести, подсвечивает правильный синтаксис и многое другое. С её же помощью можно прошивать МК.

Наиболее распространённым является - C AVR, поэтому найдите самоучитель по нему, есть масса русскоязычных вариантов, а один из них - Хартов В.Я. «Микроконтроллеры AVR. Практикум для начинающих».

Смотрите также подробные обучающие видеокурсы по программированию микроконтроллеров для начинающих Максима Селиванова: .

Самый простой способ изучить AVR

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

Самые распространенные - это Arduino Nano и Arduino UNO, они по сути своей идентичны, разве что «Нано» меньше примерно в 3 раза чем «Уно».

Несколько фактов:

    Ардуино может программироваться стандартным языком - «C AVR»;

    своим собственным - wiring;

    стандартная среда для разработки - Arduino IDE;

    для соединения с компьютером достаточно лишь подключить USB шнур к гнезду micro-USB на плате ардуино нано, установить драйвера (скорее всего это произойдет автоматически, кроме случаев, когда преобразователь на CH340, у меня на Win 8.1 драйвера не стали, пришлось скачивать, но это не заняло много времени.) после чего можно заливать ваши «скетчи»;

    «Скетчи» - это название программ для ардуино.

Выводы

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

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

32 регистра общего назначения (РОН). Atmel была первой компанией, далеко
отошедшей от классической модели вычислительного ядра, в которой выполне-
ние команд предусматривает обмен данными между АЛУ и запоминающими
ячейками в общей памяти. Введение РОН в таком количестве (напомним, что в
архитектуре х 86 всего четыре таких регистра, а в x 51 понятие РОН, как таковое,
отсутствует) в ряде случаев позволяет вообще отказаться от расположения гло-
бальных и локальных переменных в ОЗУ и от использования стека, операции с
которым усложняют и загромождают программу. В результате структура ас-
семблерной программы приближается к программам на языках высокого уровня.
Правда, это привело к некоторому усложнению системы команд, номенклатура
которых для AVR больше, чем в других RISC-семействах (хотя значительная
часть инструкций - псевдонимы).

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

Отдельная область энергонезависимой памяти (EEPROM, 100 000 циклов
стирание/запись) для хранения данных, с возможностью записи программным
путем, или внешней загрузки через SPI-интерфейс.

Встроенные устройства для обработки аналоговых сигналов : аналоговый
компаратор и многоканальный 10-разрядный АЦП.

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

Последовательные интерфейсы SPI , TWI (I

C ) и UART (USART ), позволяю-

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

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

Возможность работы при тактовой частоте от 0 Гц до 16–20 МГц.

Диапазон напряжений питания от 2,7 до 5,5 В (в некоторых случаях от 1,8 или
до 6,0 В).

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

Встроенный монитор питания - детектор падения напряжения (Brown-out
Detection).

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

Семейства AVR

В 2002 г. фирма Atmel начала выпуск новых подсемейств 8-разрядных МК на базе
AVR-ядра. С тех пор все МК этого семейства делятся на три группы (подсемейст-
ва): Classic, Tiny и Mega. МК семейства Classic (AT90Sxxxx ) уже не выпускаются;
дольше всего в производстве "задержалась" очень удачная (простая, компактная и
быстродействующая модель) AT90S2313, но и она была в 2005 г. заменена на
ATtiny2313. Все "классические" AVR с первыми цифрами 2 и 8 в наименовании
модели (что означает объем памяти программ в килобайтах) имеют аналоги в се-
мействах Tiny и Mega. Для Mega при программировании возможна установка спе-
циального бита совместимости, который позволяет без каких-либо изменений ис-
пользовать программы, созданные для семейства Classic. Поэтому ряд примеров в
данной книге в целях упрощения изложения приводится в версии для семейства
Classic.
Примеры различных типов корпусов, в которых выпускаются микросхемы AVR,
приведены на рис. 1.1. Более подробную информацию на эту тему можно найти в
приложении 1 (табл. П1.2), а также в технической документации на устройства.
Отметим, что для радиолюбительских нужд и макетирования удобнее всего микро-
схемы в PDIP-корпусах, но не все модели МК в таких корпусах производятся.
Все семейства могут иметь две модификации: буква "L" в обозначении говорит
о расширенном диапазоне питания 2,7–5,5 В, отсутствие такой буквы означает диа-
пазон питания 4,5–5,5 В. При выборе конкретного типа микросхемы нужно быть
внимательным, т. к. L-версии одновременно также и менее быстродействующие, у
большинства из них максимальная тактовая частота ограничена значением 8 МГц.
Для "обычных" версий максимальная частота составляет 16 или 20 МГц. Хотя, как
правило, при запуске L-микросхем с напряжением питания 5 В на частотах до 10–
12 МГц неприятностей ожидать не следует (аналогично версии без буквы L вполне
могут работать при напряжении питания около 3 В, разумеется, не на экстремаль-
ных значениях частот), тем не менее при проектировании высоконадежных уст-
ройств следует учитывать это требование.
Микросхемы Tiny имеют Flash-ПЗУ программ объемом 1–8 кбайт и размещаются в
основном в корпусах с 8–20 выводами (кроме ATtiny28), т. е. они в целом предна-
значены для более простых и дешевых устройств. Это не значит, что их возможно-
сти во всех случаях более ограниченны, чем у семейства Mega. Так, например,
ATtiny26 при цене менее 2 долларов содержит таймер с высокоскоростным ШИМ-
режимом (в других моделях такого нет), а также 11-канальный АЦП с возмож-
ностью работы в дифференциальном режиме, с регулируемым входным усилителем

Часть I. Общие принципы устройства и функционирования Atmel AVR

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

Рис. 1.1. Примеры различных типов корпусов для МК AVR

Подсемейство Mega оснащено Flash-ПЗУ программ объемом 8–256 кбайт и корпу-
сами с 28–100 выводами. В целом МК этой группы более "навороченные", чем
Tiny, имеют более разветвленную систему встроенных устройств с более развитой
функциональностью.
Таблицы с основными характеристиками некоторых моделей Tiny и Mega из числа
самых ходовых приведены в приложении 1 . Там же даны некоторые общие техни-
ческие характеристики семейства AVR. Более подробные сведения можно почерп-
нуть из и фирменной технической документации, которая доступна на сайте
Atmel для каждой модели.
Кроме этих трех семейств, на базе AVR-ядра выпускаются специализированные
микросхемы для работы с USB-интерфейсом (AT90USBxxxx ), промышленным ин-
терфейсом CAN (AT90CANххх ), для управления ЖК-дисплеями (ATmega329 и др.),
с беспроводным интерфейсом IEEE 802.15.4 (ZigBee) для предприятий торговли и
некоторые другие. В последнее время некоторые микроконтроллеры серий Tiny и
Mega стали выпускаться в версиях со сверхмалым потреблением (технология
picoPower с напряжением питания от 1,8 В, в конце наименования МК этой серии
добавлена буква "P") и высокотемпературных для использования в автомобильной
промышленности (версии Automotive). Появилось семейство XMega с напряжением
питания 1,8–3,6 В, повышенным быстродействием (тактовая частота до 32 МГц),

Глава 1. Обзор микроконтроллеров Atmel AVR

12-разрядным 16-канальным АЦП и 2–4 каналами ЦАП (до сих пор в структуре
AVR они отсутствовали), несколькими каналами UART и других последовательных
портов (причем с возможностью работы в автономном режиме, при остановленном
ядре), встроенной поддержкой криптографии, усовершенствованным режимом
picoPower и другими "наворотами". Существует также отдельное семейство 32-раз-
рядных МК AVR32, предназначенное для высокоскоростных приложений, таких
как обработка видеопотока или распознавание образов в реальном времени.

Особенности
практического использования МК AVR

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

О потреблении

МК AVR потребляют в среднем 5–15 мА (без учета потребления внешних уст-
ройств через выводы МК). Потребляемый ток зависит не только от степени "наво-
роченности" модели, но и от тактовой частоты и напряжения питания. На рис. 1.2
приведена типовая диаграмма зависимости тока потребления от напряжения пита-
ния и тактовой частоты для младших моделей семейства Mega.
Из рис. 1.2, в частности, следует, что значительно уменьшить потребление можно,
снижая тактовую частоту в тех случаях, когда время выполнения программы не-
критично. Это позволяет упростить программу, отказавшись от режимов энерго-
сбережения: например, при установке "часового" кварца 32 768 Гц в качестве так-
тирующего потребление МК может составить порядка 200–300 мкА.

З

АМЕТКИ НА ПОЛЯХ

Величину тока потребления 1–2 мА и менее можно условно считать приемлемой для
батарейных устройств, которые рассчитаны на долговременный режим непрерывной
работы. Элементы типоразмера АА (типа alcaline, т. е. щелочные) имеют емкость по-
рядка 2000 мА ч, т. е. устройство с указанным потреблением от этих элементов про-
работает не менее 1000 ч (реально даже несколько больше) или более 40 суток. Вре-
мя работы от батарей типоразмера D с энергоемкостью порядка 15–18 000 мА ч со-
ставит около года, чего для большинства практических применений достаточно.
Выбирать для питания подобных устройств (особенно, включающихся периодически
на короткое время) следует именно щелочные элементы, т. к. они обладают большой
емкостью, не текут при переразряде и, главное, имеют значительно больший срок
хранения (порядка 7 лет) по сравнению с другими типами элементов.

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

Часть I. Общие принципы устройства и функционирования Atmel AVR

низкой тактовой частоты и ограничиваются. Графики на рис. 1.2 линейны, отсюда
следует, что пропорционально снижению тактовой частоты растет время выполне-
ния команд. Таким образом, процедура, выполнение которой при тактовой частоте
4 МГц займет 100 мкс, при тактовой частоте 32 768 Гц будет длиться более 12 мс.
Легко подсчитать, что в том и другом случае количество энергии, потребленной на
выполнение этой процедуры, будет одинаковым.

Рис. 1.2. Диаграмма зависимости тока потребления от напряжения питания

и тактовой частоты для младших моделей семейства Mega

Поэтому можно сделать следующий общий вывод: если вы не желаете вникать в
тонкости режимов энергосбережения и не реализуете их в программе, то для обще-
го снижения потребления нужно выбирать тактовую частоту как можно ниже (на
практике обычно достаточно ограничиться величиной 1 МГц, т. к. дальнейшее
снижение, скорее всего, не даст эффекта из-за дополнительного потребления внеш-
ними цепями, неизбежно присутствующими во всех схемах). Если же у вас преду-
смотрен один из режимов "глубокого" энергосбережения (см. главу 4 ), то тактовая
частота с точки зрения суммарного потребления практически не имеет значения.
Другое дело - выбор напряжения питания, которое желательно сделать как можно
меньше, если это позволяют внешние устройства. Зависимость тока потребления от
напряжения питания, как легко уяснить из графиков на рис. 1.2, нелинейная: с уве-
личением напряжения ток потребления быстро возрастает. Поэтому снижать на-
пряжение питания даже с учетом ограничения на тактовую частоту для большинст-
ва моделей AVR (не более 8 МГц при питании 2,7 В) все равно выгодно. Например,
устройство с питанием 3 В при тактовой частоте 8 МГц, согласно рис. 1.2, будет
потреблять около 3 мА или, в пересчете на единицы мощности, 9 мВт; на процеду-

Глава 1. Обзор микроконтроллеров Atmel AVR

ру длительностью 100 мкс уйдет энергия 0,9 мкДж. При частоте 16 МГц та же про-
цедура займет 50 мкс, но потребление при необходимом напряжении питания 5 В
составит около 14 мА, т. е. 70 мВт; итого на выполнение процедуры уйдет энергия
3,5 мкДж, почти в 4 раза больше.
Для всех внешних цифровых устройств, за редчайшим исключением, можно по-
добрать современный аналог, предназначенный для работы при напряжениях 2,7–
3,0 В (и даже ниже, если модель контроллера это позволяет), так что с этой стороны
ограничений нет; то, что большинство примеров в этой книге ориентировано на
напряжение питания 5 В, есть лишь дань традиции. К тому же примеры эти, как
правило, подразумевают питание от сети, где потребление не имеет большого зна-
чения. Лимитировать снижение напряжения питания могут светодиодные индика-
торы (из-за того, что прямое падение напряжения на светодиодах само по себе со-
ставляет порядка 2 В, а для больших индикаторов даже 5 В для управления недос-
таточно), но в таких устройствах потребление контроллера уже не играет большой
роли: четыре семисегментные цифры сами по себе будут потреблять ток порядка
100 мА и более. Другой случай представляют аналоговые схемы, где повышение
напряжения питания выгодно с точки зрения увеличения отношения "сигнал-шум".
Заметим, что выводы AVR могут в долговременном режиме отдавать значительный
ток (до 20-40 мА), однако не следует забывать об общем суммарном ограничении
на потребление по выводу питания (см. табл. П1.3). Следует также отметить, что
при подаче аналоговых напряжений на входы АЦП входной цифровой КМОП-
элемент (вход соответствующего порта) не отключается, и при значении данного
напряжения вблизи порога срабатывания элемента это может приводить к возрас-
танию потребления за счет протекания сквозного тока через выходные каскады
КМОП (в том числе иногда и при нахождении микросхемы в "спящем" режиме,
см. главу 14 ). Этого недостатка лишены микросхемы с технологией picoPower.

Некоторые особенности применения AVR в схемах

У большинства выводов МК имеется встроенный подключаемый "подтягивающий"
(т. е. подсоединенный к шине питания) резистор, что, казалось бы, решает одну из
обычных схемотехнических проблем, когда наличие такого резистора требуется
для подключения двухвыводных кнопок или выходов с "открытым коллектором".
Однако в критичных случаях необходим внешний резистор сопротивлением 2–
5 кОм (в критичных для потребления случаях до 10–30 кОм).
"Подтягивающий" резистор следует устанавливать не только на выводе /RESET
(о чем пойдет речь в главе 2 ), но и в том случае, когда выводы SCK, MOSI и MISO
соответствующих портов используются для программирования и подключены к
программирующему разъему ISP (см. главу 5 ), а также по выводам внешних преры-
ваний, если они задействованы. Если эти выводы не "подтягивать" к напряжению
питания дополнительными резисторами (хотя это и не оговорено в технической
документации), то не исключены ложные срабатывания внешних прерываний, пе-
резапуск системы, а при очень мощных помехах - даже порча программы в памя-
ти программ. С другой стороны, когда выводы программирования служат и в каче-

Часть I. Общие принципы устройства и функционирования Atmel AVR

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

C (или просто при подсоединении входа МК к

выходу другого устройства с открытым коллектором, например, мониторов пита-
ния, описанных в главе 3 ), при подключении к двухвыводным кнопкам (особенно
при наличии внешнего прерывания, см. главы 4 и 5 ). Сопротивление встроенного
резистора (на самом деле представляющего собой, разумеется, полевой транзистор)
в таких случаях слишком велико для того, чтобы электромагнитные помехи ("на-
водки") на нем эффективно "садились".
Микросхемы AVR, как и всякая КМОП-логика, благодаря высокому порогу сраба-
тывания эффективно защищены от помех по шине "земли". Однако они ведут себя
гораздо хуже при помехах по шине питания. Поэтому не забывайте о развязываю-
щих конденсаторах, которые нужно устанавливать непосредственно у выводов пи-
тания (керамические 0,1–0,5 мкФ), а также про качество сетевых выпрямителей и
стабилизаторов.

Г Л АВ А

Общее устройство,
организация памяти,
тактирование, сброс

Общая структура внутреннего устройства МК AVR приведена на рис. 2.1. На этой
схеме показаны все основные компоненты AVR (за исключением модуля JTAG);
в отдельных моделях некоторые составляющие могут отсутствовать или различать-
ся по характеристикам, неизменным остается только общее 8-разрядное процессор-
ное ядро (GPU, General Processing Unit). Кратко опишем наиболее важные компо-
ненты, большинство из которых мы подробно будем рассматривать в дальнейшем.
Начнем с памяти. В структуре AVR имеются три разновидности памяти: flash-
память программ, ОЗУ (SRAM) для временных данных и энергонезависимая па-
мять (EEPROM) для долговременного хранения констант и данных. Рассмотрим их
по отдельности.

Память программ

Объем встроенной flash-памяти программ в AVR-контроллерах составляет от
1 кбайта у ATtiny11 до 256 кбайт у ATmega2560. Первое число в наименовании мо-
дели соответствует величине этой памяти из ряда: 1, 2, 4, 8, 16, 32, 64, 128 и
256 кбайт. Память программ, как и любая другая flash-память, имеет страничную
организацию (размер страницы, в зависимости от модели, составляет от 64 до
256 байт). Страница может программироваться только целиком. Число циклов пе-
репрограммирования достигает 10 тыс.
С точки зрения программиста память программ можно считать построенной из от-
дельных ячеек - слов по два байта каждое. Устройство памяти программ (и только
этой памяти) по двухбайтовым словам - очень важный момент, который нужно
твердо усвоить. Такая организация обусловлена тем, что любая команда в AVR
имеет длину ровно два байта. Исключение составляют команды

и некото-

рые другие (например,

), которые оперируют с 16-разрядными и более длинны-

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

Часть I. Общие принципы устройства и функционирования Atmel AVR

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

Рис. 2.1. Общая структурная схема микроконтроллеров AVR

З

АМЕТКИ НА ПОЛЯХ

Приведем пример интересного случая адресации, который представляет
команда для чтения констант из памяти LPM (а также ELPM в МК с памятью программ
128

кбайт и более). Эта команда подразумевает чтение по байтовому адресу, указан-

ному в двух старших РОН (образующих т. н. регистр Z, см. далее). Однако чтобы не
нарушать "чистоту" концепции организации памяти программ по словам, разработчики
запутали этот простой вопрос, указав в описании, что при вызове команды LPM стар-
шие 15 разрядов регистра Z адресуют слово в памяти, а младший разряд выбирает
младший или старший байт (при равенстве разряда 0 или 1 соответственно) этого

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

Последний адрес существующего объема памяти программ для конкретной модели
обозначается константой

По умолчанию все контроллеры AVR всегда

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

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

который указывает на процедуру, выполняющуюся при сбросе МК (в том числе и
при включении питания).

П

РИМЕЧАНИЕ

В ассемблере AVR можно обозначать шестнадцатеричные числа в "паскалевском"
стиле, предваряя их знаком $, при этом стиль языка С (0x00) тоже действителен, а вот
"интеловский" способ (00h) не работает. Подробнее об обозначениях чисел различных
систем счисления в AVR-ассемблере см. главу 5 .

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

Память данных (ОЗУ, SRAM)

В отличие от памяти программ, адресное пространство памяти данных адресуется
побайтно (а не пословно). Адресация полностью линейная, без какого-то деления
на страницы, сегменты или банки, как это принято в некоторых других системах.
Младшие МК семейства Tiny (включая Tiny1х и Tiny28) памяти данных, как тако-
вой, не имеют, ограничиваясь лишь регистровым файлом (РОН) и регистрами вво-
да-вывода (РВВ). В других моделях объем встроенной SRAM колеблется от
128 байт в представителях семейства Tiny (например, у ATtiny2313) до 4–8 кбайт
у старших моделей Mega.
Адресное пространство статической памяти данных (SRAM) условно делится на
несколько областей, показанных на рис. 2.2. Темной заливкой выделена часть, от-
носящаяся к собственно встроенной SRAM, до нее по порядку адресов расположе-
но адресное пространство регистров (первые 32 байта занимает РОН, еще 64 -
РВВ). Для старших моделей Mega со сложной структурой (например, ATmega128)
64-х регистров ввода-вывода может оказаться недостаточно, поэтому в них для до-
полнительных РВВ выделяется отдельное адресное пространство (от $60 до макси-
мально возможного в байтовой адресации значения $FF, итого таких регистров мо-
жет быть всего 160).

З

АМЕТКИ НА ПОЛЯХ

В архитектуре МК AVR понятие "ввода-вывода" употребляется в двух смыслах: во-

первых, имеются "порты ввода-вывода" (I/O ports), которые мы рассмотрим в главе 3 .
Во-вторых, "регистрами ввода-вывода" (РВВ) в структуре AVR называются регистры,
которые обеспечивают доступ к дополнительным компонентам, внешним по отноше-

нию к GPU, за исключением ОЗУ (в том числе и к портам ввода-вывода). Такое под-
разделение приближает структуру МК AVR к привычной конфигурации персонального
компьютера, где доступ к любым внешним по отношению к центральному процессору
компонентам, кроме памяти, осуществляется через порты ввода-вывода.

Часть I. Общие принципы устройства и функционирования Atmel AVR

Для некоторых моделей Mega (ATmega8515, ATmega162, ATmega128, ATmega2560
и др.) предусмотрена возможность подключения внешней памяти объемом до
64 кбайт, которая может быть любой статической
разновидностью (SRAM, Flash или EEPROM) с па-
раллельным интерфейсом.
Отметим, что адреса РОН и РВВ не отнимают про-
странство у ОЗУ данных (за исключением подклю-
чаемой внешней памяти у старших моделей Mega,
максимальный адрес которой ограничен значением
$FFFF): так, если в конкретной модели МК имеется
512 байт SRAM, а пространство регистров занимает
первые 96 байт (до адреса $60), то адреса SRAM
займут адресное пространство от $0060 до $025F
(т. е. от 96-й до 607-й ячейки включительно). Конец
встроенной памяти данных обозначается константой

Рис. 2.2. Адресное пространство

статической памяти данных (SRAM)

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

Операции чтения/записи в память одинаково работают с любыми адресами из дос-
тупного пространства, и при работе с SRAM нужно быть внимательным: вместо
записи в память вы легко можете "попасть" в какой-нибудь регистр. Например,
команда загрузки значения регистра

в регистр

) равносильна

записи в SRAM по нулевому адресу (

). Адрес в памяти для РОН сов-

падает с его номером. В то же время для непосредственной записи в РВВ по его
адресу в памяти к номеру регистра следует прибавить $20: так, регистр флагов

который для большинства моделей располагается в конце таблицы РВВ по адресу
$3F, в памяти имеет адрес $5F. Устанавливать РОН и РВВ прямой адресацией па-
мяти неудобно: такая запись всегда отнимает два такта вместо одного, характерно-
го для большинства других команд, хотя иногда это позволяет обойти ограничения
на манипуляции с некоторыми РВВ. Но если имеется готовая программа, работаю-
щая с SRAM, то при замене моделей процессоров на более старшие нужно быть
внимательным из-за того, что в них младшие адреса SRAM могут перекрываться
дополнительными РВВ.

Глава 2. Общее устройство, организация памяти, тактирование, сброс

Энергонезависимая память данных (EEPROM)

Все модели МК AVR (кроме снятого с производства ATtiny11) имеют встроенную
EEPROM для хранения констант и данных при отключении питания.
В разных моделях объем ее варьируется от 64 байт (ATtiny1х) до 4 кбайт (старшие
модели Mega). Конец EEPROM обозначается константой

(это обозначе-

ние введено только для более поздних моделей AVR, потому при использовании
этой константы иногда ее придется определять самому). Число циклов перепро-
граммирования EEPROM может достигать 100 тыс.
Напомним, что EEPROM отличается от Flash возможностью выборочного про-
граммирования побайтно (в принципе даже побитно, но этот способ недоступен
пользователю). Однако в старших моделях семейства EEPROM, как и flash-память
программ, имеет страничную организацию, правда, страницы эти невелики - до
4 байт каждая. На практике, как при программировании EEPROM по последова-
тельному каналу (т. е. через SPI-интерфейс программирования), так и при записи и
чтении EEPROM из программы, эта особенность не имеет значения, и доступ осу-
ществляется побайтно.
Чтение из EEPROM осуществляется в течение одного машинного цикла (правда, на
практике оно растягивается на четыре цикла, но программисту следить за этим спе-
циально не требуется). А вот запись в EEPROM протекает значительно медленнее,
и к тому же с точно не определенной скоростью: цикл записи одного байта может
занимать от 2 до ~ 4 мс и более. Процесс записи регулируется встроенным RC -
генератором, частота которого нестабильна (при более низком напряжении питания
можно ожидать, что время записи будет больше). За такое время при обычных так-
товых частотах МК успевает выполнить несколько тысяч команд, потому програм-
мирование процедуры записи требует аккуратности: например, нужно следить,
чтобы в момент записи не "вклинилось" прерывание (подробнее об этом см. гла-
вы 4
и 9 ).
Главная же сложность при работе с EEPROM - возможность повреждения ее со-
держимого при недостаточно быстром снижении напряжения питания в момент
выключения. Обусловлено это тем, что при уменьшении напряжения питания до
некоторого порога (ниже порога стабильной работы, но недостаточного для полно-
го выключения) из-за колебаний напряжения МК начинает выполнять произволь-
ные команды, в том числе может осуществить процедуру записи в EEPROM. Если
учесть, что типовая команда МК AVR выполняется за десятые доли микросекунды,
то ясно, что никакой реальный источник питания не может обеспечить снижение
напряжения до нуля за нужное время. По опыту автора при питании от обычного
стабилизатора типа LM7805 с рекомендованными значениями емкости конденсато-
ров на входе и на выходе содержимое EEPROM будет неизбежно испорчено при-
мерно в половине случаев.
Этой проблемы не должно существовать, если константы записывают в EEPROM
при программировании МК, а процедура записи в программе отсутствует (о том,
как сформировать файл с данными для EEPROM, см. раздел "Директивы и функ-
ции" главы 5
). Большая сохранность данных в таких случаях подтверждается и эм-

Часть I. Общие принципы устройства и функционирования Atmel AVR

пирическими наблюдениями, и тем, что разрешение записи в EEPROM - процеду-
ра двухступенчатая (см. главу 9 ). Во всех же остальных случаях (а их, очевидно,
абсолютное большинство - в EEPROM чаще всего хранят пользовательские уста-
новки и текущую конфигурацию при выключении питания) приходится принимать
специальные меры. Наиболее кардинальной и универсальной из них является уста-
новка внешнего монитора питания, удерживающего МК в состоянии сброса при
уменьшении напряжения питания ниже пороговой величины. Той же цели служит
встроенный детектор падения напряжения (Brown-out Detection, BOD), имеющийся
практически во всех моделях Tiny и Mega, но техническая документация не исклю-
чает при этом для надежности дублирования его и внешним монитором питания.
Подробнее о схеме BOD и режимах сброса МК см. далее в этой главе , а о програм-
мировании EEPROM и мерах предосторожности при ее использовании см. главу 9 .

Способы тактирования

Канонический способ тактирования МК - подключение кварцевого резонатора к
соответствующим выводам (рис. 2.3, а ). Емкость конденсаторов С1 и С2 в типовом
случае должна составлять 15–22 пФ (может быть увеличена до 33–47 пФ с одно-
временным повышением потребления). В большинстве моделей Tiny и Mega име-
ется специальный конфигурационный бит

Который позволяет регулировать

потребление. При установке этого бита в 1 (незапрограммированное состояние)
размах колебаний генератора уменьшается, однако при этом сужается возможный
диапазон частот и общая помехоустойчивость, поэтому задействовать этот режим
не рекомендуется. Может быть также выбран низкочастотный кварцевый резонатор
(например, "часовой" 32 768 Гц), при этом конденсаторы С1 и С2 могут отсутство-
вать, т. к. при установке

в значение 0 подключаются имеющиеся в составе

МК внутренние конденсаторы емкостью 36 пФ.
Кварцевый резонатор можно заменить керамическим. Автору этих строк удавалось
запускать МК на нестандартных частотах, используя вместо кварца в том же под-
ключении миниатюрную индуктивность (при ее значении 4,7 мкГн и емкостях кон-
денсаторов 91 пФ частота получается около 10 МГц), что заодно позволяет немного
уменьшить габариты схемы.
Естественно, тактировать МК можно и от внешнего генератора (рис. 2.3, б ). Осо-
бенно это удобно, когда требуется либо синхронизировать МК с внешними компо-
нентами, либо получить очень точную частоту тактирования, выбрав соответст-
вующий генератор (например, серии SG-8002 фирмы Epson).
Наоборот, когда точность не требуется, можно подключить внешнюю RC -цепочку
(рис. 2.3, в ). В этой схеме емкость С1 должна быть не менее 22 пФ, а резистор R1
выбирается из диапазона 3,3–100 кОм. Частота при этом определяется по формуле
F = 2/3 RC . С1 можно не устанавливать вообще, если записать лог. 0 в конфигура-
ционную ячейку

Подключив тем самым внутренний конденсатор 36 пФ.

Наконец, можно вообще отказаться от внешних компонентов и обойтись встроен-
ным RC -генератором, который способен работать на четырех приблизительных

Глава 2. Общее устройство, организация памяти, тактирование, сброс

значениях частот (1, 2, 4 и 8 МГц). В ряде моделей предусмотрена возможность
подстройки частоты этого генератора (подробнее см. или техническое описание
конкретных моделей). Эту возможность наиболее целесообразно использовать в
младших моделях Tiny, выпускающихся в 8-контактном корпусе - тогда выводы,
предназначенные для подключения резонатора или внешнего генератора, можно
задействовать для других целей, как обычные порты ввода-вывода.

Рис. 2.3. Способы тактирования МК AVR с использованием: а - кварцевого резонатора;

б - внешнего генератора; в - RC -цепочки

Семейство Classic встроенного RC -генератора не имеет, а специальных конфигура-

ционных ячеек у этих МК значительно меньше, и в общем случае на них можно не

обращать внимания. Для других семейств это не так. По умолчанию МК семейств

Tiny и Mega установлены в состояние для работы со встроенным генератором на
частоте 1 МГц (

0001), поэтому для других режимов нужно соответствую-

щим образом установить конфигурационные ячейки

(см. табл. 2.1). При этом

следует учитывать, что состояние ячеек

0000 (зеркальное по отношению к

наиболее часто употребляемому значению для кварцевого резонатора 1111) пере-

водит МК в режим тактирования от внешнего генератора, и при этом его нельзя

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

ках конфигурационных ячеек и об особенностях их программирования см. также

главу 5 .

Таблица 2.1. Установка конфигурационных ячеек CKSEL

в зависимости от режимов тактирования

CKSEL3...0

Источник тактирования

Частота

Внешняя частота

Встроенный RC -генератор

Встроенный RC -генератор

Встроенный RC -генератор

Встроенный RC -генератор

Внешняя RC -цепочка

Часть I. Общие принципы устройства и функционирования Atmel AVR

Таблица 2.1 (окончание)

CKSEL3...0

Источник тактирования

Частота

Внешняя RC -цепочка

0,9... 3,0 МГц

Внешняя RC -цепочка

3,0... 8,0 МГц

Внешняя RC -цепочка

8,0... 12 МГц

Низкочастотный резонатор

Кварцевый резонатор

0,4... 0,9 МГц

Кварцевый резонатор

0,9... 3,0 МГц

Кварцевый резонатор

3,0... 8,0 МГц

1ххх (CKPOT=0)

Кварцевый резонатор

Сброс

Сбросом (RESET) называется установка начального режима работы МК. При этом
все РВВ устанавливаются в состояние по умолчанию - как правило, это нули во
всех разрядах, за небольшим исключением (а вот РОН могут принимать произ-
вольные значения, поэтому при необходимости начинать с какой-то определенной
величины переменные следует устанавливать в начале программы принудительно).
Программа после сброса начинает выполняться с начального адреса (по умолчанию
это адрес $0000).
Сброс всегда происходит при включении питания. Кроме этого, источниками сбро-
са могут быть следующие события: аппаратный сброс, т. е. подача низкого уровня
напряжения на вход RESET (правильнее его обозначать с инверсией: /RESET, т. к.
активный уровень тут низкий, и мы будем придерживаться этого правила); оконча-
ние отсчета установленного интервала сторожевого таймера; срабатывание схемы
BOD. Значение четырех младших битов регистра состояния

должно сигна-

лизировать о том, от какого источника производился сброс предыдущий раз (уста-
новка в 1 бита 0 - сброс при включении, бита 1 - аппаратный сброс, бита 2 - от
схемы BOD, бита 3 - от сторожевого таймера). На практике, по опыту автора, по
состояниям этого регистра надежно различаются от всех остальных лишь состоя-
ния сброса по таймеру (прочие флаги могут оказаться установленными все одно-
временно). Тем не менее эта информация может быть полезной, например, при ана-
лизе причин перерывов в работе круглосуточно работающих устройств (см. главу 12 ).
В младших МК семейства Tiny (кроме ATtiny28) нет встроенного "подтягивающе-
го" резистора на выводе /RESET, поэтому для надежной работы следует преду-
смотреть подключение внешнего резистора величиной 2–5 кОм от этого вывода к
напряжению питания. Автор также настоятельно рекомендует устанавливать по-
добный резистор для любых моделей AVR, т. к. встроенный резистор имеет боль-
шой номинал (100–500 кОм) и на нем могут наводиться помехи, способные привес-
ти к непредсказуемому сбросу. Также (хотя в технических описаниях такой реко-

Глава 2. Общее устройство, организация памяти, тактирование, сброс

мендации и не содержится) не помешает установка конденсатора 0,1–0,5 мкФ от
вывода /RESET на "землю" - это сглаживает неизбежный дребезг напряжения и
немного затягивает фронт нарастания напряжения на выводе /RESET по сравнению
с увеличением напряжения питания: когда наступит порог срабатывания схемы
сброса, напряжение питания всего МК уже установится.
В моделях Tiny, выпускающихся в 8-контактном корпусе (ATtiny11–ATtiny15), ес-
ли не требуется внешний сброс, вывод /RESET может выполнять функции обычно-
го порта ввода-вывода. С одним только нюансом: при конфигурировании этого
контакта на выход он работает, как вывод с открытым коллектором, а не как обыч-
ный логический элемент (о конфигурации выводов портов см. главу 3 ).
Самый предпочтительный способ организации сброса при включении питания, как
уже говорилось ранее, - установка внешнего монитора питания. Например, при
5-вольтовом питании подойдет популярная микросхема MC34064 с порогом сраба-
тывания 4,6 В и типовым потреблением около 300 мкА или ее более современный
аналог (например, MAX803L с потреблением 12 мкА). Для трехвольтового питания
пригодна схема MAX803R (2,6 В) или подходящая версия DS1816 с соответствую-
щим напряжением. Все перечисленные микросхемы трехвыводные (питание, "зем-
ля", вывод управления сбросом) и имеют выход с открытым коллектором, т. е. пре-
дусматривают установку "подтягивающего" резистора. Типовое время срабатыва-
ния этих микросхем при снижении напряжения - микросекунды, что обеспечивает
сохранность данных в EEPROM. При повышении напряжения они обеспечивают
большую временную задержку (порядка долей секунды), что позволяет надежно
осуществлять сброс МК без дребезга.
Встроенная схема BOD обеспечивает время срабатывания порядка микросекунд с
задержкой на возврат в рабочее состояние после восстановления напряжения, оп-
ределяющейся теми же установками, что и задержка сброса (ячейки

тактовой частоте 4 МГц) и даже максимально возможное ее значение ~68 мс могут
оказаться недостаточными для обхода дребезга, возникающего при снижении на-
пряжения питания автономного источника. Для выбора режима работы BOD слу-
жат три конфигурационные ячейки

имеющие следующие состояния:

111 (установка по умолчанию) - схема BOD выключена;

101 - включает BOD при пороге срабатывания 2,7 В;

100 - соответствует порогу 4,0 В.

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

Я категорически против такого подхода. Обычно это все заканчивается - либо ничем, либо забитые форумы с мольбами помочь. Даже если кому то помогают, то в 90% он больше никогда не всплывет на сайтах по электронике. В остальных 10% он так и продолжает заливать форумы мольбами, его будут сначала пинать, затем поливать грязью. Из этих 10% отсеивается еще 9%. Далее два варианта: либо таки до глупой головы доходит и все же происходит goto к началу, либо в особо запущенных вариантах, его удел копировать чужие конструкции, без единой мысли о том как это работает. Из последних зачастую рождаются ардуинщики.

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

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

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

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

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

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

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

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

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

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

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

5. Изучение ассемблера? Бояться его не нужно, равно как и боготворить. Не нужно думать, что умея написать программу на ассемблере, вы сразу станете гуру микроконтроллеров, почему то это частое заблуждение. В первую очередь это инструмент. Даже если вы не планируете использовать его, то все равно я бы настоятельно рекомендовал написать хотя бы пару программ. Это сильно упростит понимание работы микроконтроллера и внутреннего устройства программ.

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

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

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

Мною был проведен эксперимент: в наличии был студент, даташит и гугл переводчик. Эксперимент №1: студенту вручен даташит и дано задание самостоятельно найти нужные значения, результат - «да как я смогу», «да я не знаю английский», «я ничего не нашел/я не понял» типичные фразы, говорящие о том, что он даже не пытался. Эксперимент №2: тому же студенту, вручен все тот же даташит и тоже задание, с той разницей, что я сел рядом. Результат - через 5 минут он сам нашел все нужные значения, абсолютно без моего участия, без знания английского.

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

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

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

9. А как бы я сделал это, если бы находился на месте разработчиков? Могу ли я сделать лучше? Каждый раз задавайте себе эти вопросы, это очень хорошо помогает продвигаться в обучении. Например, изучите интерфейсы 1wire, i2c, spi, uart, а потом подумайте чем они отличаются, можно ли было сделать лучше, это поможет осознать почему все именно так, а не иначе. Так же вы будете осознавать, когда и какой лучше применить.

10. Не ограничивайтесь в технологиях. Важно что этот совет имеет очень тонкую грань. Был этап в жизни, когда из каждой подворотни доносилось «надо бы знать ПЛИС», «а вот на ПЛИС то можно сделать». Формально у меня не было целей изучать ПЛИСины, но и пройти мимо было никак нельзя. Этому вопросу было выделено немного времени на ознакомление. Время не прошло зря, у меня был целый ряд вопросов, касаемых внутреннего устройства микроконтроллеров, именно после общения с плисинами я получил ответы на них. Подобных примеров много, все знания, которые я приобретал в том или ином виде, рано или поздно пригодились. У меня нет ни единого бесполезного примера.

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

11. Если спросить начинающего радиолюбителя, что ему больше нравится программирование или схемотехника, то с вероятностью 99% ответ будет программирование. При этом большую часть времени эти программисты тратят на изготовление плат ЛУТом/фоторезистом. Причины в общем то понятны, но довольно часто это переходит в некий маразм, который состоит в изготовлении плат ради изготовления плат.

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

12. Следующий совет, особенно болезненный, мне очень не хочется его обсуждать, но надо. Часто мне пишут, мол ххх руб за ууу дорого, где бы подешевле достать. Вроде бы обычный вопрос, но обычно я сразу напрягаюсь от него, так как зачастую он переходит в бесконечные жалобы на отсутствие денег. У меня всегда возникает вопрос: почему бы не оторвать пятую точку и не пойти работать? Хоть в тот же макдак, хоть на стройку, потерпеть месяц, зато потом можно приобрести парочку плат, которых хватит на ближайший год. Да я знаю, что маленьких городах и селах сложно найти работу, переезжайте в большой город. Работайте на удаленке, в общем нужно крутиться. Просто жаловаться нет смысла, выход из ситуации есть, кто ищет его тот находит.

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

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

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

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

Еще в самом начале, когда микроконтроллеры были для меня хобби, я много помогал с курсовыми и дипломами разных вузов, просто чтобы оценить свой уровень. Могу сказать уверенно, что уровень в целом невысок вне зависимости от имени вуза. Учиться несколько лет, для того чтобы написать такой диплом, совершенно необязательно. Достигнуть этого можно самостоятельно за весьма короткий срок. И все же зачастую бывали моменты, когда студенты знали какой то предмет, который они проходили на 2-3 курсе, а я этого не знал. Хоть все эти знания и компенсировались самообразованием, но все же лучше было бы не тратить на это время.

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

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

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

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

16. Поздно ли начинать программировать в 20, 30, 40, 50 лет? Практика других людей показывает, что возраст вообще не помеха. Многие почему то не учитывают то, что есть целый пласт работы, которую молодые в силу своих амбиций не хотят делать. Поэтому работодатели предпочитают брать тех, кто будет ее тащить. Это ваш шанс зацепиться, а дальше все зависит только от вас.

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

Киселев Роман, Май 2007 Статья обновлена 26 Мая 2014

Итак, что вообще такое микроконтроллер (далее МК)? Это, условно говоря, маленький компьютер, размещенный в одной интегральной микросхеме. У него есть процессор (арифметическо-логическое устройство, или АЛУ), flash-память, EEPROM-память, множество регистров, порты ввода-вывода, а также дополнительные «навороты», такие как таймеры, счетчики, компараторы, USARTы и т. п. Микроконтроллер после подачи питания загружается и начинает выполнять программу, записанную в его flash-памяти. При этом он может через порты ввода/вывода управлять самыми разнообразными внешними устройствами.

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

AVR – это 8-битные микроконтроллеры, т. е. их АЛУ может за один такт выполнять простейшие операции только с 8-ми битными числами. Теперь пора поговорить о том, какой МК мы будем использовать. Я работаю с МК ATMega16. Он очень распространенный и приобрести его можно практически в любом магазине радиодеталей где-то за 100 руб. Если вы его не найдете – тогда можно купить любой другой МК серии MEGA, но в этом случае придется искать к нему документацию, т. к. одни и те же «ножки» разных МК могут выполнять разные функции, и, подключив, казалось бы, правильно все выводы, вы, может быть, получите рабочее устройство, а, может быть, лишь облако вонючего дыма. При покупке ATMega16 проверьте, чтобы он был в большом 40-ножечном DIP-корпусе, а также купите к нему панельку, в которую его можно будет вставить. Для работы с ним потребуются также дополнительные устройства: светодиоды, кнопки, разъемы и т. п..

ATMega16 обладает очень большим количеством самых разнообразных функций. Вот некоторые его характеристики:

  • Максимальная тактовая частота – 16 МГц (8 МГц для ATMega16L)
  • Большинство команд выполняются за один такт
  • 32 8-битных рабочих регистра
  • 4 полноценных 8-битных порта ввода/вывода
  • два 8-битных таймера/счетчика и один 16-битный
  • 10-разрядный аналогово-цифровой преобразователь (АЦП)
  • внутренний тактовый генератор на 1 МГц
  • аналоговый компаратор
  • интерфейсы SPI, I2C, TWI, RS-232, JTAG
  • внутрисхемное программирование и самопрограммирование
  • модуль широтно-импульсной модуляции (ШИМ)

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

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

Что для этого понадобится?

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

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

Поясним, какие ножки нас сейчас интересуют.

  • VCC – сюда подается питание (4,5 – 5,5 В) от стабилизированного источника
  • GND – земля
  • RESET – сброс (при низком уровне напряжения)
  • XTAL1, XTAL2 – сюда подключается кварцевый резонатор
  • PA, PB, PC, PD – порты ввода/вывода (A, B, C и D соответственно).

В качестве источника питания можно использовать все, что выдает 7-11 В постоянного тока. Для стабильной работы МК нужно стабилизированное питание. В качестве стабилизатора можно использовать микросхемы серии 7805. Это линейные интегральные стабилизаторы, на вход которых подают 7-11 В постоянного нестабилизированного тока, а на выходе получают 5 В стабилизированного. Перед 7805 и после него нужно поставить фильтрующие конденсаторы (электролитические для фильтрации помех низких частот и керамические для высоких). Если не удается найти стабилизатор, то можно в качестве источника питания использовать батарейку на 4,5 В. От нее МК нужно питать напрямую.

Ниже приведу схему подключения МК:

Давайте теперь разберемся, что здесь для чего.

BQ1 – это кварцевый резонатор, задающий рабочую частоту МК. Можно поставить любой до 16 МГц, но, поскольку мы планируем работать в будущем и с COM-портом, то рекомендую использовать резонаторы на следующие частоты: 14,7456 МГц, 11,0592 МГц, 7,3725 МГц, 3,6864 МГц или 1,8432 МГц (позже станет ясно, почему). Я использовал 11,0592 МГц. Понятное дело, что чем больше частота, тем выше и скорость работы устройства.

R1 – подтягивающий резистор, который поддерживает напряжение 5 В на входе RESET. Низкий уровень напряжения на этом входе означает сброс. После сброса МК загружается (10 – 15 мс) и начинает выполнять программу заново. Поскольку это высокоомный вход, то нельзя оставлять его «болтающимся в воздухе» - небольшая наводка на нем приведет к непредвиденному сбросу МК. Именно для этого и нужен R1. Для надежности рекомендую также установить конденсатор С6 (не более 20 мкФ).

SB1 – кнопка сброса.

Кварцевый резонатор и фильтрующий конденсатор C3 должны располагаться как можно ближе к МК (не далее 5-7 см), т. к. иначе могут возникать наводки в проводах, приводящие к сбоям в работе МК.

Синим прямоугольником на схеме обведен собственно программатор. Его удобно выполнить в виде провода, один конец которого втыкается в LPT порт, а другой – в некий разъем рядом с МК. Провод не должен быть чрезмерно длинным. Если возникнут проблемы с этим кабелем (обычно не возникают, но всякое бывает) то придется спаять адаптер Altera ByteBlaster. О том, как это сделать, написано в описании к программатору AVReal.

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

Для программирования AVR есть несколько сред разработки. Во-первых, это AVR Studio – официальная система программирования от Atmel. Она позволяет писать на ассемблере и отлаживать программы, написанные на ассемблере, С и С++. IAR – это коммерческая система программирования на C, С++ и ассемблере. WinAVR – компилятор с открытыми исходниками. AtmanAVR – система программирования для AVR с интерфейсом, почти «один в один» таким же, как у Visual C++ 6. AtmanAVR также позволяет отлаживать программы и содержит множество вспомогательных функций, облегчающих написание кода. Эта система программирования коммерческая, но, согласно лицензии, ее можно в течение месяца использовать «нахаляву».

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

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

Запустив IAR, выбираем file / new / workspace , выбираем путь к нашему проекту и создаем для него папку и даем имя, например, «Prog1». Теперь создаем проект: Project / Create new project… Назовем его также – «Prog1». Щелкаем правой кнопкой мыши на заголовке проекта в дереве проектов и выбираем «Options»

Здесь будем настраивать компилятор под конкретный МК. Во-первых, нужно выбрать на вкладке Target тип процессора ATMega16, на вкладке Library Configuration установить галочку Enable bit definitions in I/O-include files (чтобы можно было использовать в коде программы имена битов различных регистров МК), там же выбрать тип библиотеки С/ЕС++. В категории ICCAVR нужно на вкладке Language установить галочку Enable multibyte support, а на вкладке Optimization выключить оптимизацию (иначе она испортит нашу первую программу).

Далее выбираем категорию XLINK. Здесь нужно определить формат откомпилированного файла. Поскольку сейчас мы задаем опции для режима отладки (Debug), о чем написано в заголовке, то на выходе нужно получить отладочный файл. Позже мы его откроем в AVR Studio. Для этого нужно выбрать расширение.cof, а тип файла – ubrof 7.

Теперь нажимаем ОК, после чего меняем Debug на Release.

Снова заходим в Options, где все параметры, кроме XLINK, выставляем те же. В XLINK меняем расширение на.hex, а формат файла на intel-standart.

Вот и все. Теперь можно приступать к написанию первой программы. Создаем новый Source/text и набираем в нем следующий код:

#include "iom16.h" short unsigned int i; void main (void ) { DDRB = 255; PORTB = 0; while (1) { if (PORTB == 255) PORTB = 0; else PORTB++; for (i=0; i

Файл «iom16.h» находится в папке (C:\Program Files)\IAR Systems\Embedded Workbench 3.2\avr\inc . Если вы используете другой МК, например, ATMega64, то выбирайте файл «iom64.h». В этих заголовочных файлах хранится информация о МК: имена регистров, битов в регистрах, определены имена прерываний. Каждая отдельная «ножка» порта A, B, C или D может работать либо как вход, либо как выход. Это определяется регистрами Data Direction Register (DDR). 1 делает «ножку» выходом, 0 – входом. Таким образом, выставив, например, DDRA = 13, мы делаем выходами «ножки» PB0, PB2, PB3, остальные – входы, т.к. 13 в двоичном коде будет 00001101.

PORTB – это регистр, в котором определяется состояние «ножек» порта. Записав туда 0, мы выставляем на всех выходах напряжение 0 В. Далее идет бесконечный цикл. При программировании МК всегда делают бесконечный цикл, в котором МК выполняет какое-либо действие, пока его не сбросят или пока не произойдет прерывание. В этом цикле пишут как бы «фоновый код», который МК выполняет в самую последнюю очередь. Это может быть, например, вывод информации на дисплей. В нашем же случае увеличивается содержимое регистра PORTB до тех пор, пока он не заполнится. После этого все начинается сначала. Наконец, цикл for на десять тысяч тактов. Он нужен для формирования видимой задержки в переключении состояния порта В.



Теперь сохраняем этот файл в папке с проектом как Prog1.c, копируем в папку с проектом файл iom16.h, выбираем Project/Add Files и добавляем «iom16.h» и «Prog1.c». Выбираем Release, нажимаем F7, программа компилируется и должно появиться сообщение:


Total number of errors: 0
Total number of warnings: 0

Приведу фотографию своего программатора:

Скачиваем программатор AVReal. Копируем его (AVReal32.exe) в папку Release/exe, где должен лежать файл Prog1.hex. Подаем питание на МК, подключаем кабель-программатор. Открываем Far Manager (в нем наиболее удобно прошивать МК), заходим в эту папку, нажимаем Ctrl+O. Поскольку у нас совершенно новый МК, то набиваем

avreal32.exe +MEGA16 -o11.0592MHZ -p1 -fblev=0,jtagen=1,cksel=F,sut=1 –w

Не забудьте правильно указать частоту, если используете не 11059200 Гц! При этом в МК прошиваются т.н. fuses – регистры, управляющие его работой (использование внутреннего генератора, Jtag и т.п.). После этого он готов к приему первой программы. Программатору в качестве параметров передают используемый LPT-порт, частоту, имя файла и другие (все они перечислены в описании к AVReal). Набираем:

Avreal32.exe +Mega16 -o11.0592MHz -p1 -e -w -az -% Prog1.hex

В случае правильного подключения программатор сообщит об успешном программировании. Нет гарантии, что это получится с первого раза (при первом вызове программы). У меня самого бывает программируется со второго раза. Возможно, LPT-порт глючный или возникают наводки в кабеле. При возникновении проблем тщательно проверьте свой кабель. По своему опыту знаю, что 60% неисправностей связаны с отсутствием контакта в нужном месте, 20% - с наличием в ненужном и еще 15% - с ошибочной пайкой не того не к тому. Если ничего не получится, читайте описание к программатору, попробуйте собрать Byte Blaster.

Предположим, у вас все работает. Если теперь подключить к порту В МК восемь светодиодов (делайте это в выключенном состоянии МК, и желательно последовательно со светодиодами включить резисторы в 300-400 Ом) и подать питание, то произойдет маленькое чудо – по ним побежит «волна»!

© Киселев Роман
Май 2007