Avr studio 5 описание на русском. Интегрированная отладочная среда AVR Studio фирмы Atmel

IDE – это интегрированная среда разработки, в состав которой включены разные шаблоны, библиотеки и функции отладчика. Если говорить о , с 2004 для них разрабатывался мощный программный пакет AVR studio.

Первые версии

В первых версиях студии присутствовал ассемблер для , вы можете его извлечь из первых сборок, однако позже этот проект был заброшен, а в качестве основного языка избран C AVR. Компилятором был платный и очень серьезный продукт IAR. Вы можете скачать бесплатный WINAVR, для этого после установки студии нужно проинсталлировать его.

Обратите внимание! Лучше это делать только после установки AVR studio 4 и других версий.

Долгое время фигурировала AVR studio 4 (на фото выше). Многие разработчики микроконтроллеров сталкивались с ней. Позже IDE модернизировали до AVR studio 5. Кроме интерфейса, особых изменений не было, а уже потом компания разработчик сделала ребрендинг продукта и изменила название на Atmel studio 6.

Среда AVR studio 5 поддерживала следующие микроконтроллеры:

  • AVR32;
  • XMEGA.

Atmel studio 6 отличалась от AVR studio 5 значительно, самые заметные нововведения версии:

  1. Microsoft Visual Studio 2010 стал работать с семейством AVR.
  2. Улучшенная, по сравнению с AVR studio 5, подсветка синтаксиса.
  3. Добавлены подсказки и автозавершение набора команд, что ускоряет процесс разработки.
  4. В целом, вся работа среды стала надежнее.
  5. Добавлена поддержка ARM Cortex-M.
  6. WinAVR не нужно больше устанавливать отдельно, GCC теперь устанавливается в процессе инсталляции, в отличие от младших версий.

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

Актуальная версия – Atmel studio 7

Среду разработки кардинально использовал Visual Studio Isolated Shell 2015; с одной стороны, это решение не поддерживается на Windows XP, с другой – эти меры были предприняты для улучшения как внешнего вида программы, так и функционального.

Пожалуй, самым знаменательным стало добавление поддержки Arduino в Atmel studio 7. Это значит, что вы можете перейти от набора простейших скетчей к использованию всех функций C, отладки, симулятора МК и прочим функциям. Совмещение Arduino и Atmel studio 7 дало новый виток в развитии этой простой обучающей платформы.

Изучение Atmel studio с Arduino даст возможность перейти к полному и продуктивному освоению и более глубокому знакомству с сердцем ардуины – микроконтроллером Atmega.

Дополнительно с сайта Atmel можно скачать пакет для работы и подключения LCD. В качестве примера для освоения можно использовать LCD 1602, в интернете по нему много уроков, а разработчику на дисплее доступно 16 символов и 2 строки.

С чего начать освоение?

Начинать стоит, конечно же, с покупки программатора; самый бюджетный – это – USBASP. Программатор USBASP не поддерживается в Atmel Studio 7.


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

«avrdude -c usbasp -p atmega32 -U flash:w:название файла с прошивкой. hex -U lfuse:w:0x6a:m -U hfuse:w:0xff:m»

и подключить его поддержку, создав профиль в atmel studio 7 (title – external tools), а в пункт Arguments ввести «-c usbasp -p atmega32 -U flash:w:$(TargetName).hex» и так для каждого типа используемых вами микроконтроллеров.

Только таким образом можно связать студио и программатор USBASP. Будьте внимательны при перепрошивке – вы можете повредить сигнатуру микроконтроллера, а восстановить её можно будет только 12 В (высоковольтным) программатором.

Какую литературу использовать для обучения?

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

Для программирования AVR-микроконтроллеров существует немало средств разработки, однако, наиболее популярным, несомненно, следует признать пакет AVR Studio . Есть ряд причин такой популярности – это бесплатный пакет, разработанный фирмой ATMEL , он объединяет в себе текстовый редактор, ассемблер и симулятор. Пакет AVR Studio также используется совместно с аппаратными средствами отладки. В предлагаемой статье на примерах рассматриваются приемы работы с пакетом, что поможет начинающим программистам быстрее понять взаимодействие отдельных компонентов AVR Studio.

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

Пакет AVR Studio имеет солидную историю развития, что отражается в количестве существующих версий. В конце 2003 г. выпущена версия 4.08, которая имеет ряд полезных дополнений, а в начале 2004 г. вышло обновление (Service Pack 1), добавляющее поддержку AVR-контроллеров третьего поколения семейства ATmega48. Производство микросхем этого семейства намечено на вторую половину 2004 г.

Дистрибутив пакета и Service Pack можно загрузить с сайта www.atmel.com или получить компакт-диск с этим дистрибутивом у российского дистрибьютора фирмы ATMEL.

Работу пакета AVR Studio удобно рассматривать на какой-либо конкретной программе. В качестве илюстрации мы рассмотрим создание проекта для простейшей программы, которая будет по очереди зажигать два светодиода. Для определенности возьмем микросхему Atmega128 и подключим два светодиода в выводам 31 и 32 (это биты 6 и 7 порта D микросхемы ATmega128). AVR-контроллеры имеют мощные выходные каскады, типовой ток каждого вывода составляет 20 мА, максимальный ток вывода – 40 мА, причем это относится как к втекающему, так и к вытекающему току. В нашем примере светодиоды подключены анодами к выводам контроллера, а катоды через гасящие резисторы соединены с землей. Это означает, что светодиод зажигается подачей «1» на соответствующий вывод порта. Принципиальная схема приведена на рисунке. На схеме также показаны две кнопки, которые будут использованы в одной из программ.

Здесь уместно сделать небольшое отступление о выборе типа микросхемы для простейшего примера. Действительно, с первого взгляда может показаться странным, зачем нужен такой мощный кристалл в 64-выводном корпусе там, где хватит и 8-выводной микросхемы ATtiny12 ? Однако, в таком подходе есть логика. Известно, что в основе практически любого AVR-контроллера лежит одинаковое ядро. По большому счету, контроллеры различаются объемом памяти, количеством портов ввода/вывода и набором периферийных модулей. Особенности каждого конкретного контроллера – привязка логических имен регистров ввода/вывода к физическим адресам, адреса векторов прерываний, определения битов портов и т.д. описаны в файлах с расширением.inc, которые входят в состав пакета AVR Studio. Следовательно, используя конкретный тип кристалла, можно отлаживать программу как собственно для него, так и для любого младшего кристалла. Далее, если использовать в качестве отладочного самый старший кристалл, на сегодня это ATmega128, можно отлаживать программу практически для любого AVR-контроллера, надо просто не использовать аппаратные ресурсы, которые отсутствуют у целевого микроконтроллера. Таким образом, например, можно отлаживать на ATmega128 программу, которая будет выполняться на ATtiny13 . При этом исходный код останется практически тем же, изменится лишь имя подключаемого файла с 128def.inc на tn13def.inc. У такого подхода также есть свои преимущества. Например, «лишние» порты ввода/вывода можно использовать для подключения ЖК-индикатора , на который можно выводить отладочную информацию. Или, воспользоваться внутрисхемным эмулятором, который подключается к JTAG-порту микросхемы ATmega128 (контроллер ATtiny13 такой порт не имеет). Таким образом, можно использовать единственную отладочную плату, на которой установлен «старший» AVR-контроллер, для отладки любых вновь разрабатываемых систем, естественно, базирующихся также на AVR-микроконтроллерах. Одна из таких плат называется AS-megaM. Именно она использовалась для создания примеров программ, приводимых в статье. Это универсальный одноплатный контроллер на базе микросхемы ATmega128, который содержит внешнее ОЗУ, два порта RS-232 , порт для подключения ЖК-индикатора, внутрисхемного программатора и эмулятора AT JTAG ICE . На плате также есть место для распайки микросхемы FLASH-ПЗУ серии АТ45 в корпусах TSOP32/40/48 и двухканального ЦАП серии AD5302/ AD5312/ AD5322 . Теперь, после объяснения причин использования AVR-монстра для зажигания пары сватодиодов, можно идти дальше.

При программировании в среде AVR Studio надо выполнить стандартную последовательность действий:

  • компиляция
  • Создание проекта начинается с выбора строки меню Project\New Project. В открывшемся окне “Create new Project” надо указать имя проекта, (в нашем случае – sample1) и имя файла инициализации. После нажатия кнопки “Next” открывается окно “Select debug platform and device”, где выбирается отладочная платформа (симулятор или эмулятор) и тип микроконтроллера.

    Можно выбрать один из предлагаемых внутрисхемных эмуляторов, заметим, что у каждого эмулятора свой список поддерживаемых микросхем. Для рассматриваемого примера мы выбираем в качестве отладочной платформы AVR Simulator и микросхему ATmega128. После нажатия кнопки “Finish” нашему взору предстают собственно рабочие окна пакета AVR Studio, пока пустые. Следует в правое окно поместить исходный текст программы. Это можно сделать двумя способами, либо набрать весь текст непосредственно в окне редактора, либо загрузить уже существующий файл. Ниже приведен полный текст простейшей программы с комментариями.

    ; Пример «Управление светодиодами» ; написан для отладочной платы AS-MegaM ; Частота задающего генератора 7,37 МГц; светодиоды подключены к выводам PD6 и PD7 и через резисторы - на общий провод. ; подключение файла описания ввода-вывода микросхемы ATmega128 .include "m128def.inc" ; начало программы begin: ; первая операция - инициализация стека; если этого не сделать, то вызов подпрограммы или прерывания; не вернет управление обратно; указатель на конец стека устанавливается на последний адрес внутреннего ОЗУ - RAMEND ldi r16,low(RAMEND) out spl,r16 ldi r16,high(RAMEND) out sph,r16 ; для того, чтобы управлять светодиодами, подключенными к выводам PD6 и PD7, ; необходимо объявить эти выводы выходными. ; для этого нужно записать "1" в соответствующие биты регистра DDRD (DataDiRection) ldi r16,(1<<6) | (1<<7) out DDRD,r16 ; основной цикл программы loop: ldi r16,(1<<6) ; светится один светодиод out PORTD,r16 rcall delay ; задержка ldi r16,(1<<7) ; светится второй светодиод out PORTD,r16 rcall delay ; задержка rjmp loop ; повторение цикла; процедура задержки; примерно полсекунды при частоте 7,37 МГц; три пустых вложенных цикла соответственно delay: ldi r16,30 ; 30 delay1: ldi r17,200 ; 200 delay2: ldi r18,200 ; и еще 200 итераций delay3: dec r18 brne delay3 dec r17 brne delay2 dec r16 brne delay1 ret ; возврат в главную программу

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

    Компиляция проекта производится командой \Project\Build или нажатием кнопки F7. Процесс компиляции отображается в окне “Output”. Это окно можно «вытащить» командой \View\Output.

    В принципе, мы уже получили выходной файл в формате.hex, который уже можно загружать в микросхему и наблюдать перемигивание светодиодов. Однако, цель статьи – показать полный цикл работы в среде AVR Studio, поэтому мы переходим к стадии отладки. Это делается командой \Debug\Start Debugging.

    Теперь устанавливаем в окне “Simulator Options” частоту кварца 7,3728 МГц для точного измерения времени выполнения программы.

    Остальные опции следует оставить без изменения. Теперь можно выполнять программу в пошаговом режиме при помощи мыши или кнопки F11.

    Пакет AVR Studio содержит мощные средства для просмотра и редактирования состояния внутренних регистров и портов ввода/вывода отлаживаемого микроконтроллера, а также время, выполнения программы. Доступ к ним осуществляется через окно “I/O”.

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

    Для отладки нашего примера, чтобы получить доступ к битам порта D, надо раскрыть строку I/O ATMEGA128 и затем строку PORTD. Теперь видны все три регистра этого порта, PORTD, DDRD и PIND. Чтобы увидеть поля Value, Bits и Address, придется расширить правую границу окна, потеснив при этом окно с исходным текстом программы.

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

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

    ; Пример «Управление светодиодами от кнопок» ; написан для отладочной платы AS-MegaM ; светодиоды подключены к выводам PD6 и PD7 и через резисторы - на общий провод. ; кнопки - на PE4 и PE5 .include "m128def.inc" ; основная программа begin: ; инициализация стека ldi r16,low(RAMEND) out spl,r16 ldi r16,high(RAMEND) out sph,r16 ; инициализация светодиодов ldi r16,(1<<6) | (1<<7) out DDRD,r16 ; инициализация выводов, к которым подключены кнопки (на вход) ; внутренние подтягивающие резисторы подключены; для этого в PORTE нужно установить соответствующие биты в единицы ldi r16,(1<<4) | (1<<5) out PORTE,r16 ; а в DDRE - в нули ldi r16,0 out DDRE,r16 ; бесконечный цикл forever: in r16,PINE ; теперь в r16 находится текущее "состояние" кнопок com r16 ; кнопка "нажимается" нулем, поэтому инвертируем регистр lsl r16 ; переносим биты 4,5 в позиции 6,7 lsl r16 ; и обновляем "показания" светодиодов andi r16,(1<<6) | (1<<7) out PORTD,r16 rjmp forever ; цикл выполняется бесконечно

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

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

    В меню Tools главного окна AVR Studio надо выбрать пункт Customize;

    В окне Customize выбрать пункт Tools;

    Двойным нажатием кнопки мыши или нажав Insert на клавиатуре, добавить новую команду в список и назвать ее "Программатор AS2";

    Указать путь к исполняемому файлу программатора, введя его непосредственно в поле для ввода "Command", или нажав на кнопку "…" справа от этого поля;

    Теперь в меню Tools появился пункт "Программатор AS2".

    Средства пакета AVR Studio 4.08 позволяют подключать вспомогательные программы – plugins. Первый plugin для AVR Studio – это программа графического редактора, упрощающая процесс инициализации ЖК-индикатора, которым может непосредственно управлять AVR-контроллер ATmega169. Максимальный логический размер ЖК-индикатора составляет 100 сегментов, каждому элементу индикатора ставится в соответствие бит в специальном регистре контроллера. Чтобы упростить рутинную процедуру привязки определенных битов к каждому сегменту, можно использовать вышеупомянутую программу.

    Во время посещения «родины AVR» - норвежского офиса фирмы ATMEL, один из авторов статьи беседовал с Ларсом Квенилдом, руководителем группы программистов, которая создала и поддерживает пакет AVR Studio. Этот человек, классический программист, с бородой, в свитере и обутый в сандали на носки, рассказал о перспективах развития пакета. В следующую версию (4.09) - будет включен интерфейс для нового внутрисхемного эмулятора – JTAGICE mkII (он называется также AT JTAGICE2), который во второй половине года придет на смену AT JTAGICE. У этого эмулятора есть два существенных отличия. С одной стороны, добавлена поддержка нового однопроводного отладочного интерфейса для младших AVR-контроллеров, debugWIRE. Этот интерфейс интересен тем, что он не занимает для своей работы дополнительные выводы микроконтроллера, так как использует для обмена вывод Reset микроконтроллера! С другой стороны (можно понимать это выражение буквально), у эмулятора AT JTAGICE2 появится, наконец, интерфейс USB для связи с компьютером.

    Литература

    1. Материалы технического семинара AVR Technical Training. Atmel. Norway. December 2003.
    2. Николай Королев, Дмитрий Королев AVR-микроконтроллеры второго поколения: средcтва разработчика. // Компоненты и технологии, 2003 № 7
    3. AVR-микроконтроллеры второго поколения: новые аппаратные возможности // Компоненты и технологии. 2003. № 4 .
    4. Николай Королев, Дмитрий Королев. AVR-микроконтроллеры: большое в малом. //Схемотехника», 2001, №5
    5. Николай Королев, Дмитрий Королев. AVR-микроконтроллеры: программные средства // Компоненты и технологии, 2000. № 4 .
    6. Николай Королев. AVR: аппаратные средства разработчика // Компоненты и технологии, 1999 № 1
    7. Николай Королев. RISC- микроконтроллеры фирмы ATMEL //Chip-News 1998, №2
    8. Николай Королев, Дмитрий Королев AVR: новые 8-разрядные RISC-микроконтроллеры фирмы ATMEL //Микропроцессор Ревю, 1998, №1

    Для работы с AVR Studio 4 необходимо само собой её установить. Если она уже установлена, то можете пропустить этот шаг.

    Установка:
    создаешь каталог c:/avr/ – тут будут лежать рабочие программы.
    создаешь каталог например c:/works/ – тут будут лежать твои работы.
    надо что бы были короткие пути, что бы не было проблем с ними.

    Есть вообще AVRStudio5 но и AVRStudio4 пока вполне хватает.

    Вся работа будет проходить в AVRStudio4, WinAVR нужна только из-за библиотеки AVR-GCC (Для того, что бы можно было писать на Си)
    НО! первым надо установить именно WinAVR , иначе библиотека AVR-GCC не подцепится.

    Тут думаю разберешься.
    AVR-GCC для того, что бы писать на Си
    Atmel Avr Assembler соответственно для ассемблера.

    Начинать разбираться с МК лучше с нуля. А это значит с Ассемблера, значит создаешь тот, который Atmel AVR Assembler.

    Потом выбирай микроконтроллер Atmega8.

    когда создастся проект, будет большой, белый, чистый лист. тут будет код.

    немного про содержимое этого листа

    “комментарии” – это текст, пропускаемый компилятором, при компиляции.
    перед началом комментария должен стоять спец символ, пользуюсь символом; “точка с запятой”, есть еще “дабл сшеш” (//),
    вот примеры комментариев

    /* * Комментарий такого види(многострочный), * обычно используется для * сопроводительной информции * об исходном коде, т.е. * название, разработчик и т.д. */ NOP // Такой комментарий в основном используется для пояснения назначения команды, или куска кода SLEEP ; такой комментарий тоже как и предыдущий, можно использовать для пояснения (для заметок) в коде

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

    MOV R16, R17 ; два параметра INC R16 ; один параметр SEI ; без параметров

    MOV R16, R17 ; три байта INC R16 ; два байта SEI ; один байт

    Видите связь размера команды с параметрами?

    У каждого микроконтроллера свой ассемблер, хотя мнимоника у них похожа, т.е. команда MOV у мк одной серии будет выглядеть в машинном коде допустим 0x12 а у другого 0x55.
    что бы при компиляции, скомпилировалось в нужном нам коде мы должны сказать компилятору, для какого мк у нас пишется программа.
    это вообще выбирается при создании проекта.
    По этому мы выбрали микроконтроллер Atmega8.

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

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

    Include "m8def.inc" // командой.include, мы подгрузили файл m8def.inc ;и теперь нам станет легче;)

    в самом начале кода, ставится таблица прерываний. Что это такое и как это работает, объясню в другой заметке. Но а пока, будем писать её так:

    RJMP RESET ; Reset Handler RETI; RJMP EXT_INT0 ; IRQ0 Handler RETI; RJMP EXT_INT1 ; IRQ1 Handler RETI; RJMP TIM2_COMP ; Timer2 Compare Handler RETI; RJMP TIM2_OVF ; Timer2 Overflow Handler RETI; RJMP TIM1_CAPT ; Timer1 Capture Handler RETI; RJMP TIM1_COMPA ; Timer1 CompareA Handler RETI; RJMP TIM1_COMPB ; Timer1 CompareB Handler RETI; RJMP TIM1_OVF ; Timer1 Overflow Handler RETI; RJMP TIM0_OVF ; Timer0 Overflow Handler RETI; RJMP SPI_STC ; SPI Transfer Complete Handler RETI; RJMP USART_RXC ; USART RX Complete Handler RETI; RJMP USART_UDRE ; UDR Empty Handler RETI; RJMP USART_TXC ; USART TX Complete Handler RETI; RJMP ADC ; ADC Conversion Complete Handler RETI; RJMP EE_RDY ; EEPROM Ready Handler RETI; RJMP ANA_COMP ; Analog Comparator Handler RETI; RJMP TWSI ; Two-wire Serial Interface Handler RETI; RJMP SPM_RDY ; Store Program Memory Ready Handler

    После этого идет уже сам код

    RESTART: ; маркер инициализации MAIN: NOP ; маркер главного цикла RJMP MAIN

    Но тут есть одна (точнее не одна, а много) особенностей.

    Для удобства написания кода, для его понятности и для облегчения относительных переходов, нам подарили маркеры, как они выглядят? “RESET:” и “MAIN:” это маркеры, в их именах могут содержаться почти любые символы латинского алфавита и цифры. Маркеры не могут иметь имена функций и команд, допустим “NOP”.
    Как к ним переходит? Допустим командой RJMP.

    Так же, из Маркеров, можно сделать подпрограмму(процедуру), по завершению которой, мы вернемся туда, от куда её вызывали. Для вызова её, используем команду “RCALL (подпрограмма)”, а что бы вернуться из Подпрограммы(процедуры), нужно закончить её командой “RET”. У нас должен получиться такой код:

    RESTART: MAIN: NOP RCALL PPP1 ; вызываем подпрограмму RJMP MAIN PPP1: NOP RET ; выходим из подпрограммы

    Как работает команда “RCALL”, при её вызове, адрес из какого места её вызвали, помещается в СТЕК, а по вызове команды “RET”, извлекается из регистра “стек”. СТЕК нужно инициализировать.

    Что бы нам работать с нашим мк, нужно его инициализировать. т.к. мк, это устройство универсальное, в нем есть много портов ввода/вывода, и периферийных устройств. таких как УСАПП, ШИМ, ЦАП, АЦП и т.д. Первым делом в инициализации мк нужно указать начало “стека”. Инициализацию мы проводим после маркера “RESET:”.

    LDI R16,HIGH(RAMEND) OUT SPH,R16 LDI R16,LOW(RAMEND) OUT SPL,R16

    Если бы мы не вводили команду.include “m8def.inc” в начале кода, то нам пришлось бы писать так:

    LDI R16,0x04 OUT SPH,R16 LDI R16,0x5f OUT SPL,R16

    Разница существенная, на мой взгляд.

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

    Таким образом у нас получился такой код:

    Include "m8def.inc" RJMP RESET ; Reset Handler RETI; RJMP EXT_INT0 ; IRQ0 Handler RETI; RJMP EXT_INT1 ; IRQ1 Handler RETI; RJMP TIM2_COMP ; Timer2 Compare Handler RETI; RJMP TIM2_OVF ; Timer2 Overflow Handler RETI; RJMP TIM1_CAPT ; Timer1 Capture Handler RETI; RJMP TIM1_COMPA ; Timer1 CompareA Handler RETI; RJMP TIM1_COMPB ; Timer1 CompareB Handler RETI; RJMP TIM1_OVF ; Timer1 Overflow Handler RETI; RJMP TIM0_OVF ; Timer0 Overflow Handler RETI; RJMP SPI_STC ; SPI Transfer Complete Handler RETI; RJMP USART_RXC ; USART RX Complete Handler RETI; RJMP USART_UDRE ; UDR Empty Handler RETI; RJMP USART_TXC ; USART TX Complete Handler RETI; RJMP ADC ; ADC Conversion Complete Handler RETI; RJMP EE_RDY ; EEPROM Ready Handler RETI; RJMP ANA_COMP ; Analog Comparator Handler RETI; RJMP TWSI ; Two-wire Serial Interface Handler RETI; RJMP SPM_RDY ; Store Program Memory Ready Handler RESET: LDI R16,HIGH(RAMEND) OUT SPH,R16 LDI R16,LOW(RAMEND) OUT SPL,R16 RGMP RESET MAIN: NOP ; маркер главного цикла RJMP MAIN

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

    Для правильного процесса отладки, необходимо задать эмулятору частоту, с которой будет работать МК, это делается только после компиляции и запуска отладки,
    значит находим в панели меню “Build”, раскрываем её и видим “Build and Run”, после чего, мы увидим желтую стрелочку на против первой команды в нашем листинге кода. Теперь мы ищем в панели меню “Debug” и нажимаем “AVR Simulator Options”, открывается такое окно:

    В котором мы можем поменять МК и его частоту, так же, на панели с права, мы видим некоторую информацию о нашем МК: его максимальную частоту, объемы памяти(EEPROM, RAM, FLASH). Теперь открываем даташит на Atmega8, на странице 203 (общий список регистров) и 205 (общий список команд) и приступай к написанию своей программы.
    И запомни, не бойся экспериментировать с симулятором, он от этого не сломается!

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

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

    С другой стороны у Си сильная сторона это переносимость кода. Если, конечно, писать все правильно. Разделяя алгоритмы работы и их железные реализации в разные части проекта. Тогда для переноса алгоритма в другой МК достаточно будет переписать только интерфейсный слой, где прописано все обращение к железу, а весь рабочий код оставить как есть. И, конечно же, читаемость. Сишный исходник проще понять с первого взгляда (хотя.. мне, например, уже пофигу на что фтыкать — хоть си, хоть асм:)), но, опять же, если правильно все написать. Этим моментам я тоже буду уделять внимание.

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

    Первая программа на Си для AVR

    Выбор компилятора и установка среды
    Для AVR существует множество разных компиляторов Си:
    В первую очередь это IAR AVR C — почти однозначно признается лучшим компилятором для AVR, т.к. сам контроллер создавался тесном сотрудничистве Atmel и спецов из IAR. Но за все приходится платить. И этот компилятор мало того, что является дорогущим коммерческим софтом, так еще обладает такой прорвой настроек, что просто взять и скомпилить в нем это надо постраться. У меня с ним правда не срослось дружбы, проект загнивал на странных ошибках на этапе линковки (позже выяснил, что это был кривой кряк).

    Вторым идет WinAVR GCC — мощный оптимизирующий компилятор. Полный опенсорц, кроссплатформенный, в общем, все радости жизни. Еще он отлично интегрируется в AVR Studio позволяя вести отладку прямо там, что адски удобно. В общем, я выбрал его.

    Также есть CodeVision AVR C — очень популярный компилятор. Стал популярен в связи со своей простотой. Рабочую программу в нем получить можно уже через несколько минут — мастер стартового кода этом сильно способствует, штампуя стандартыне инициализации всяких уартов. Честно говоря, я как то с подозрением к нему отношусь — как то раз приходилось дизасмить прогу написаную этим компилером, каша какая то а не код получалась. Жуткое количество ненужных телодвижений и операций, что выливалось в неслабый обьем кода и медленное быстродействие. Впрочем, возможно тут была ошибка в ДНК писавшего исходную прошивку. Плюс он хочет денег. Не так много как IAR, но ощутимо. А в деморежиме дает писать не более чем 2кб кода.
    Кряк конечно есть, но если уж воровать, так миллион, в смысле IAR:)

    Еще есть Image Craft AVR C и MicroC от микроэлектроники. Ни тем ни другим пользоваться не приходилось, но вот SWG очень уж нахваливает MicroPascal , мол жутко удобная среда программирования и библиотеки. Думаю MicroC не хуже будет, но тоже платный.

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

    Так что качай себе инсталяху WinAVR с и AVR Studio. Далее вначале ставится студия, потом, сверху, накатывается WinAVR и цепляется к студии в виде плагина. Настоятельно рекомендую ставить WinAVR по короткому пути, что то вроде C:\WinAVR тем самым ты избежишь кучи проблем с путями.

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

    Открывается рабочее поле с пустым *.c файлом.

    Теперь не помешает настроить отображение путей в закладках студии. Для этого слазь по адресу:
    Меню Tools — Options — General — FileTabs и выбираем в выпадающем списке «Filename Only». Иначе работать будет невозможно — на вкладке будет полный путь файла и на экране будет не более двух трех вкладок.

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

    Тыкай в кнопку с шестеренкой.


    Это настройки твоего проекта, а точнее настройки автоматической генерации make файла. На первой странице надо всего лишь вписать частоту на которой будет работать твой МК. Это зависит от фьюз битов, так что считаем что частота у нас 8000000Гц.
    Также обрати внимание на строку оптимизации. Сейчас там стоит -Os это оптимизация по размеру. Пока оставь как есть, потом можешь попробовать поиграться с этим параметром. -O0 это отстутсвие оптимизации вообще.

    Следующим шагом будет настройка путей. Первым делом добавь туда директорию твоего проекта — будешь туда подкладывать сторонние библиотеки. В списке появится путь «.\»

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


    На этом пока все. Жми везде ОК и переходи в исходник.

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

    Работать будет так:
    При приходе по COM порту единички (код 0х31) будем зажигать диодик, а при приходе нуля (код 0х30) гасить. Причем сделано будет все на прерываниях, а фоновой задачей будет мигание другого диода. Простенько и со смыслом.

    Собираем схему
    Нам надо соединить модуль USB-USART конвертера с выводами USART микроконтроллера. Для этого берем перемычку из двух проводков и накидывам на штырьки крест накрест. То есть Rx контроллера соединяем с Tx конвертера, а Tx конвертера с Rx контроллера.

    Получится, в итоге вот такая схема:


    Подключение остальных выводов, питания, сброса не рассматриваю, оно стандартное

    Пишем код

    Сразу оговорюсь, что я не буду углубляться конкретно в описание самого языка Си. Для этого существует просто колоссальное количество материала, начиная от классики «Язык программирования Си» от K&R и заканчивая разными методичками.

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

    Там правда еще не все главы перенесены, но, думаю, это ненадолго.

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

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

    1 #include

    #include

    Этот файл находится в папке WinAVR и в нем содержится описание всех регистров и портов контроллера. Причем там все хитро, с привязкой к конкретному контроллеру, который передается компилятором через make файл в параметре MCU и на основании этой переменной в твой проект подключается заголовочный файл с описанием адресов всех портов и регистров именно на этот контроллер. Во как! Без него тоже можно, но тогда ты не сможешь использовать символические имена регистров вроде SREG или UDR и придется помнить адрес каждого вроде «0xC1», а это голову сломать.

    Сама же команда #include <имя файла> позволяет добавить в твой проект содержимое любого текстового файла, например, файл с описанием функций или кусок другого кода. А чтобы директива могла этот файл найти мы и указывали пути к нашему проекту (директория WinAVR там уже по дефолту прописана).

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

    • Возвращаемое значение, например, sin(x) возвращает значение синуса икс. Как в математике, короче.
    • Передаваемые параметры, тот самый икс.
    • Тело функции.

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

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

    1 2 3 4 5 int main(void ) { return 0 ; }

    int main(void) { return 0; }

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

    Разберем что же мы сделали.
    int это тип данных которая функция main возвращает.

    Конечно, в микроконтроллере main ничего вернуть в принципе не может и по идее должна быть void main(void) , но GCC изначально заточен на PC и там программа может вернуть значение операционной системе по завершении. Поэтому GCC на void main(void) ругается Warning’ом.

    Это не ошибка, работать будет, но я не люблю варнинги.

    void это тип данных которые мы передаем в функцию, в данном случае main также не может ничего принять извне, поэтом void — пустышка. Заглушка, применяется тогда когда не надо ничего передавать или возвращать.

    Вот такие вот { } фигурные скобочки это программный блок, в данном случае тело функции main , там будет распологаться код.

    return — это возвращаемое значение, которое функция main отдаст при завершении, поскольку у нас int, то есть число то вернуть мы должны число. Хотя это все равно не имеет смысла, т.к. на микроконтроллере из main нам выходить разве что в никуда. Я возвращаю нуль. Ибо нефиг. А компилятор обычно умный и на этот случай код не генерит.
    Хотя, если извратиться, то из main на МК выйти можно — например вывалиться в секцию бутлоадера и исполнить ее, но тут уже потребуется низкоуровневое ковыряние прошивки, чтобы подправить адреса перехода. Ниже ты сам увидишь и поймешь как это сделать. Зачем? Вот это уже другой вопрос, в 99.999% случаев это нафиг не надо:)

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

    1 2 3 4 5 6 int main(void ) { unsigned char i; return 0 ; }

    int main(void) { unsigned char i; return 0; }

    unsigned значит беззнаковый. Дело в том, что в двоичном представлении у нас старший бит отводится под знак, а значит в один байт (char) влазит число +127/-128, но если знак отбросить то влезет уже от 0 до 255. Обычно знак не нужен. Так что unsigned .
    i — это всего лишь имя переменной. Не более того.

    Теперь надо проинициализировать порты и UART . Конечно, можно взять и подключить библиотеку и вызвать какой нибудь UartInit(9600); но тогда ты не узнаешь что же произошло на самом деле.

    Делаем так:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int main(void ) { unsigned char i; #define XTAL 8000000L #define baudrate 9600L #define bauddivider (XTAL/(16*baudrate)-1) #define HI(x) ((x)>>8) #define LO(x) ((x)& 0xFF) UBRRL = LO(bauddivider) ; UBRRH = HI(bauddivider) ; UCSRA = 0 ; UCSRB = 1 << RXEN| 1 << TXEN| 1 << RXCIE| 0 << TXCIE; UCSRC = 1 << URSEL| 1 << UCSZ0| 1 << UCSZ1; }

    int main(void) { unsigned char i; #define XTAL 8000000L #define baudrate 9600L #define bauddivider (XTAL/(16*baudrate)-1) #define HI(x) ((x)>>8) #define LO(x) ((x)& 0xFF) UBRRL = LO(bauddivider); UBRRH = HI(bauddivider); UCSRA = 0; UCSRB = 1<

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

    Они облегчат твои рутинные операции по вычислении нужных коэффициентов. В первой строке мы говорим что вместо XTAL можно смело подставлять 8000000, а L — указание типа, мол long — это тактовая частота процессора. То же самое baudrate — частота передачи данных по UART.

    bauddivider уже сложней, вместо него будет подставлятся выражение вычисленное по формуле из двух предыдущих.
    Ну, а LO и HI из этого результата возьмут младший и старший байты, т.к. в один байт оно явно может не влезть. В HI делается сдвиг икса (входной параметр макроса) восемь раз в вправо, в результате от него останется только старший байт. А в LO мы делаем побитовое И с числом 00FF, в результате останется только младший байт.

    Так что все что сделано как #define можно смело выкинуть, а нужные числа подсчитать на калькуляторе и сразу же вписать их в строки UBBRL = …. и UBBRH = …..

    Можно. Но! Делать этого КАТЕГОРИЧЕСКИ НЕЛЬЗЯ !

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

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

    Запись вида 1< Означает следующее: взять 1 и поставить ее на место RXEN в байте. RXEN это 4й бит регистра UCSRB , так что 1< образует двоичное число 00010000, TXEN — это 3й бит, а 1< даст 00001000. Одиночная «|» это побитовое ИЛИ , так что 00010000 | 00001000 = 00011000. Таким же образом выставляются и добавляются в общуюу кучу остальные необходимые биты конфигурации. В итоге, собраное число записывается в UCSRB. Подробней расписано в даташите на МК в разделе USART. Так что не отвлекаемся на технические детали.

    Готово, пора бы посмотреть что получилось. Жми на компиляцию и запуск эмуляции (Ctrl+F7).

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

    Дело в том, что изначально, на самом деле, она стояла на строке UBRRL = LO(bauddivider); Ведь то что у нас в define это не код, а просто предварительные вычисления, вот симулятор немного и затупил. Но теперь он осознал, первая инструкция выполнена и если ты залезешь в дерево I/O View , в раздел USART и поглядишь там на байт UBBRL то увидишь, что там значение то уже есть! 0х33.

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

    Вскрытие
    Теперь сбрось симуляцию в ноль. Нажми там Reset (Shift+F5) . Открывай дизассемблированный листинг, сейчас ты увидишь что происходит в контроллере в самом деле. View -> Disassembler . И не ЫЫАААА!!! Ассемблер!!! УЖОС!!! А НАДО. Чтобы потом, когда что то пойдет не так, не тупил в код и не задавал ламерских вопросах на форумах, а сразу же лез в потроха и смотрел где у тебя затык. Ничего там страшного нет.

    Вначале будет ботва из серии:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 +00000000: 940C002A JMP 0x0000002A Jump +00000002: 940C0034 JMP 0x00000034 Jump +00000004: 940C0034 JMP 0x00000034 Jump +00000006: 940C0034 JMP 0x00000034 Jump +00000008: 940C0034 JMP 0x00000034 Jump +0000000A: 940C0034 JMP 0x00000034 Jump +0000000C: 940C0034 JMP 0x00000034 Jump +0000000E: 940C0034 JMP 0x00000034 Jump +00000010: 940C0034 JMP 0x00000034 Jump +00000012: 940C0034 JMP 0x00000034 Jump +00000014: 940C0034 JMP 0x00000034 Jump +00000016: 940C0034 JMP 0x00000034 Jump +00000018: 940C0034 JMP 0x00000034 Jump +0000001A: 940C0034 JMP 0x00000034 Jump +0000001C: 940C0034 JMP 0x00000034 Jump +0000001E: 940C0034 JMP 0x00000034 Jump +00000020: 940C0034 JMP 0x00000034 Jump +00000022: 940C0034 JMP 0x00000034 Jump +00000024: 940C0034 JMP 0x00000034 Jump +00000026: 940C0034 JMP 0x00000034 Jump +00000028: 940C0034 JMP 0x00000034 Jump

    00000000: 940C002A JMP 0x0000002A Jump +00000002: 940C0034 JMP 0x00000034 Jump +00000004: 940C0034 JMP 0x00000034 Jump +00000006: 940C0034 JMP 0x00000034 Jump +00000008: 940C0034 JMP 0x00000034 Jump +0000000A: 940C0034 JMP 0x00000034 Jump +0000000C: 940C0034 JMP 0x00000034 Jump +0000000E: 940C0034 JMP 0x00000034 Jump +00000010: 940C0034 JMP 0x00000034 Jump +00000012: 940C0034 JMP 0x00000034 Jump +00000014: 940C0034 JMP 0x00000034 Jump +00000016: 940C0034 JMP 0x00000034 Jump +00000018: 940C0034 JMP 0x00000034 Jump +0000001A: 940C0034 JMP 0x00000034 Jump +0000001C: 940C0034 JMP 0x00000034 Jump +0000001E: 940C0034 JMP 0x00000034 Jump +00000020: 940C0034 JMP 0x00000034 Jump +00000022: 940C0034 JMP 0x00000034 Jump +00000024: 940C0034 JMP 0x00000034 Jump +00000026: 940C0034 JMP 0x00000034 Jump +00000028: 940C0034 JMP 0x00000034 Jump

    Это таблица векторов прерываний. К ней мы еще вернемся, пока же просто посмотри и запомни, что она есть. Первая колонка — адрес ячейки флеша в которой лежит команда, вторая код команды третья мнемоника команды, та самая ассемблерная инструкция, третья операнды команды. Ну и автоматический коммент.
    Так вот, если ты посмотришь, то тут сплошные переходы. А код команды JMP четырех байтный, в нем содержится адрес перехода, записанный задом наперед — младший байт по младшему адресу и код команды перехода 940C

    0000002B: BE1F OUT 0x3F,R1 Out to I/O location

    Запись этого нуля по адресу 0x3F, Если ты поглядишь в колонку I/O view, то ты увидишь что адрес 0x3F это адрес регистра SREG — флагового регистра контроллера. Т.е. мы обнуляем SREG, чтобы запустить программу на нулевых условиях.

    1 2 3 4 +0000002C: E5CF LDI R28,0x5F Load immediate +0000002D: E0D4 LDI R29,0x04 Load immediate +0000002E: BFDE OUT 0x3E,R29 Out to I/O location +0000002F: BFCD OUT 0x3D,R28 Out to I/O location

    0000002C: E5CF LDI R28,0x5F Load immediate +0000002D: E0D4 LDI R29,0x04 Load immediate +0000002E: BFDE OUT 0x3E,R29 Out to I/O location +0000002F: BFCD OUT 0x3D,R28 Out to I/O location

    Это загрузка указателя стека. Напрямую грузить в I/O регистры нельзя, только через промежуточный регистр. Поэтому сначала LDI в промежуточный, а потом оттуда OUT в I/O. О стеке я тоже еще расскажу подробней. Пока же знай, что это такая динамическая область памяти, висит в конце ОЗУ и хранит в себе адреса и промежуточные переменные. Вот сейчас мы указали на то, откуда у нас будет начинаться стек.

    00000032: 940C0041 JMP 0x00000041 Jump

    Прыжок в сааааамый конец программы, а там у нас запрет прерываний и зацикливание наглухо само на себя:

    1 2 +00000041: 94F8 CLI Global Interrupt Disable +00000042: CFFF RJMP PC-0x0000 Relative jump

    00000041: 94F8 CLI Global Interrupt Disable +00000042: CFFF RJMP PC-0x0000 Relative jump

    Это на случай непредвиденых обстоятельств, например выхода из функции main. Из такого зацикливания контроллер можно вывести либо аппаратным сбросом, либо, что вероятней, сбросом от сторожевой собаки — watchdog. Ну или, как я говорил выше, подправить это мест в хекс редакторе и ускакать куда нам душе угодно. Также обрати внимание на то, что бывает два типа переходов JMP и RJMP первый это прямой переход по адресу. Он занимает четыре байта и может сделать прямой переход по всей области памяти. Второй тип перехода — RJMP — относительный. Его команда занимает два байта, но переход он делает от текущего положения (адреса) на 1024 шага вперед или назад. И в его параметрах указывается смещение от текущей точки. Используется чаще, т.к. занимает в два раза меньше места во флеше, а длинные прееходы нужны редко.

    1 +00000034: 940C0000 JMP 0x00000000 Jump

    00000034: 940C0000 JMP 0x00000000 Jump

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

    Функция main. Все аналогично, даже можно и не описывать. Посмотри только что в регистры заносится уже вычисленное число. Препроцессор компилятора рулит!!! Так что никаких «магических» чисел!

    1 2 3 4 5 6 7 8 9 10 11 12 <

    00000036: E383 LDI R24,0x33 Load immediate +00000037: B989 OUT 0x09,R24 Out to I/O location 15: UBRRH = HI(bauddivider); +00000038: BC10 OUT 0x20,R1 Out to I/O location 16: UCSRA = 0; +00000039: B81B OUT 0x0B,R1 Out to I/O location 17: UCSRB = 1<

    А вот тут косяк:

    1 2 3 +0000003E: E080 LDI R24,0x00 Load immediate +0000003F: E090 LDI R25,0x00 Load immediate +00000040: 9508 RET Subroutine return

    0000003E: E080 LDI R24,0x00 Load immediate +0000003F: E090 LDI R25,0x00 Load immediate +00000040: 9508 RET Subroutine return

    Спрашивается, для чего это компилятор добавляет такую ботву? А это не что иное, как Return 0, функцию то мы определили как int main(void) вот и просрали еще целых четыре байта не пойми на что:) А если сделать void main(void) то останется только RET, но появится варнинг, что мол у нас функция main ничего не возвращает. В общем, поступай как хошь:)

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

    Продолжение следует через пару дней …

    Offtop:
    Alexei78 сварганил плагинчик для файрфокса облегчающий навигацию по моему сайту и форуму.
    Обсуждение и скачивание,



    В продолжение темы:
    Android

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