Программирование на микроконтроллеров avr для начинающих. Программирование микроконтроллеров AVR для начинающих. Особенности последовательного низковольтного программирования

Урок 1

Здравствуйте уважаемые читатели!

Сегодня мы вплотную подберемся к программированию микроконтроллеров AVR собрав всё необходимое для начала работы. Итак, приступим.

Существует два пути освоения AVR. Рассмотрим каждый из них.

1.Arduino

Arduino - это электронный конструктор и удобная платформа быстрой разработки электронных устройств. То есть, плата Arduino включает в себя всё необходимое для быстрой разработки технических устройств. Она имеет в своем составе микроконтроллер AVR, его обвязку(необходимые компоненты для работы микроконтроллера), программатор(устройство для «прошивки» микроконтроллера).

Рассмотрим плюсы данного подхода :

  1. Быстрота начала разработки. Купив данный продукт, Вы можете сразу перейти к началу работы с микроконтроллером, без дополнительной подготовки.
  2. Низкий порог вхождения. Вам не нужны какие либо специальные умения и навыки чтобы начать разрабатывать технические устройства.
  3. Широкий спектр подключаемых «шилдов»(то есть плат расширения, включающих в себя готовые к использованию,легко подключаемые внешние устройства.).
  4. Поддержка сообщества. В интернете Вы найдете множество уроков и задач основывающихся на применении платформы Arduino.

Однако существуют минусы, которые перевешивают положительные стороны платформы Arduino :

  1. Купив Arduino, Вы лишаетесь возможности глубже окунутся в мир AVR, узнать что такое программатор, необходимая обвязка и многое другое.
  2. Узкая линейка моделей. Очень часто необходимо выбирать конкретный микроконтроллер для конкретной задачи. К сожалению, Arduino не сможет предоставить Вам спектр моделей под все мыслимые и немыслимые задачи. И рано или поздно Вы столкнетесь с необходимостью использования микроконтроллера которого нет в линейке плат Arduino.
  3. Другой язык программирования. Язык программирования платформ Arduino, значительно отличается от стандартных AVR C, AVR ASM.То есть,возникает необходимость перехода на Arduino IDE и изучения языка Arduino.

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

2.Самостоятельная сборка.

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

Плюсы данного подхода:

  1. Глубина погружения.Вы узнаете намного больше, собрав всё необходимое самостоятельно, получите множество полезных знаний и умений.
  2. Возможность самостоятельного выбора комплектующих для решения поставленной задачи.
  3. Стандартные языки AVR C/AVR ASM.Возможность выбора удобной Вам среды программирования.Огромная база знаний и уроков по данным языкам.
  4. Дешевизна.Зачастую(но не всегда), бывает достаточно выгодно отказаться от готового решения, и собрать всё самостоятельно.

Минусы данного подхода:

  1. Сложность. Собрать всё самому впервые,при отсутствии навыков и знаний, в достаточной степени сложнее, нежели приобрести готовый к эксплуатации продукт.

Но нас не пугают сложности, потому что пройдя их мы узнаем много нового и полезного!

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

1.Микроконтроллер.

2.Программатор.

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


В этом учебном курсе по avr я постарался описать все самое основное для начинающих программировать микроконтроллеры avr . Все примеры построены на микроконтроллере atmega8 . Это значит, что для повторения всех уроков вам понадобится всего один МК. В качестве эмулятора электронных схем используется Proteus - на мой взгляд, - лучший вариант для начинающих. Программы во всех примерах написаны на компиляторе C для avr CodeVision AVR. Почему не на каком-нибудь ассемблере? Потому что начинающий и так загружен информацией, а программа, которая умножает два числа, на ассемблере занимает около ста строк, да и в сложных жирных проектах используют С. Компилятор CodeVision AVR заточен под микроконтроллеры atmel, имеет удобный генератор кода, неплохой интерфейс и прямо с него можно прошить микроконтроллер.

В этом учебном курсе будет рассказано и показано на простых примерах как:

  • Начать программировать микроконтроллеры, с чего начать, что для этого нужно.
  • Какие программы использовать для написания прошивки для avr, для симуляции и отладки кода на ПК,
  • Какие периферийные устройства находятся внутри МК, как ими управлять с помощью вашей программы
  • Как записать готовую прошивку в микроконтроллер и как ее отладить
  • Как сделать печатную плату для вашего устройства
Для того, чтобы сделать первые шаги на пути программирования МК, вам потребуются всего две программы:
  • Proteus - программа-эмулятор (в ней можно разработать схему, не прибегая к реальной пайке и потом на этой схеме протестировать нашу программу). Мы все проекты сначала будем запускать в протеусе, а потом уже можно и паять реальное устройство.
  • CodeVisionAVR - компилятор языка программирования С для AVR. В нем мы будем разрабатывать программы для микроконтроллера, и прямо с него же можно будет прошить реальный МК.
После установки Proteus, запускаем его
Он нам предлагает посмотреть проекты которые идут с ним, мы вежливо отказываемся. Теперь давайте создадим в ней самую простую схему. Для этого кликнем на значок визуально ничего не происходит. Теперь нужно нажать на маленькую букву Р (выбрать из библиотеки) в панели списка компонентов, откроется окно выбора компонентов
в поле маска вводим название компонента, который мы хотим найти в библиотеке. Например, нам нужно добавить микроконтроллер mega8
в списке результатов тыкаем на mega8 и нажимаем кнопку ОК . У нас в списке компонентов появляется микроконтроллер mega8
Таким образом добавляем в список компонентов еще резистор, введя в поле маска слово res и светодиод led

Чтобы разместить детали на схеме, кликаем на деталь, далее кликаем по полю схемы, выбираем место расположения компонента и еще раз кликаем. Для добавления земли или общего минуса на схему слева кликаем "Терминал" и выбираем Ground. Таким образом, добавив все компоненты и соединив их, получаем вот такую простенькую схемку
Все, теперь наша первая схема готова! Но вы, наверное, спросите, а что она может делать? А ничего. Ничего, потому что для того, чтобы микроконтроллер заработал, для него нужно написать программу. Программа - это список команд, которые будет выполнять микроконтроллер. Нам нужно, чтобы микроконтроллер устанавливал на ножке PC0 логический 0 (0 вольт) и логическую 1 (5 вольт).

Написание программы для микроконтроллера

Программу мы будем писать на языке С в компиляторе CodeVisionAVR. После запуска CV, он спрашивает нас, что мы хотим создать: Source или Project Мы выбираем последнее и нажимаем кнопку ОК. Далее нам будет предложено запустить мастер CVAVR CodeWizard (это бесценный инструмент для начинающего, потому как в нем можно генерировать основной скелет программы) выбираем Yes
Мастер запускается с активной вкладкой Chip, здесь мы можем выбрать модель нашего МК - это mega8, и частоту, на которой будет работать МК (по умолчанию mega8 выставлена на частоту 1 мегагерц), поэтому выставляем все, как показано на скриншоте выше. Переходим во вкладку Ports
У микроконтроллера atmega8 3 порта: Port C, Port D, Port B. У каждого порта 8 ножек. Ножки портов могут находиться в двух состояниях:
  • Выход
С помощью регистра DDRx.y мы можем устанавливать ножку входом или выходом. Если в
  • DDRx.y = 0 - вывод работает как ВХОД
  • DDRx.y = 1 вывод работает на ВЫХОД
Когда ножка сконфигурирована как выход, мы можем выставлять на ней лог 1 (+5 вольт) и логический 0 (0 вольт). Это делается записью в регистр PORTx.y. Далее будет подробно рассказано про порты ввода-вывода. А сейчас выставляем все, как показано на скриншоте, и кликаем File->Generate, Save and Exit. Дальше CodeWizard предложит нам сохранить проект, мы его сохраняем и смотрим на код:

#include //библиотека для создания временных задержек void main(void) { PORTB=0x00; DDRB=0x00; PORTC=0x00; DDRC=0x01; // делаем ножку PC0 выходом PORTD=0x00; DDRD=0x00; // Timer/Counter 0 initialization TCCR0=0x00; TCNT0=0x00; // Timer/Counter 1 initialization TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Timer/Counter 2 initialization ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; // External Interrupt(s) initialization MCUCR=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x00; // Analog Comparator initialization ACSR=0x80; SFIOR=0x00; while (1) { }; }


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

#include //библиотека для работы с микроконтроллером mega8 #include //библиотека для создания временных задержек void main(void) { DDRC=0x01; /* делаем ножку PC0 выходом запись 0x01 может показаться вам незнакомой, а это всего лишь число 1 в шестнадцатиричной форме, эта строка будет эквивалентна 0b00000001 в двоичной, далее я буду писать именно так.*/ while (1) { }; }


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

#include //библиотека для работы с микроконтроллером mega8 #include //библиотека для создания временных задержек void main(void) { DDRC=0x01; /* делаем ножку PC0 выходом запись 0x01 может показаться вам незнакомой, а это всего лишь число 1 в шестнадцатиричной форме, эта строка будет эквивалентна 0b00000001 в двоичной, далее я буду писать именно так.*/ while (1)//главный цикл программы {// открывается операторная скобка главного цикла программы PORTC.0=1; //выставляем на ножку 0 порта С 1 delay_ms(500); //делаем задержку в 500 милисекунд PORTC.0=0; //выставляем на ножку 0 порта С 0 delay_ms(500); //делаем задержку в 500 милисекунд };// закрывается операторная скобка главного цикла программы }


Все, теперь код готов. Кликаем на пиктограму Build all Project files, чтобы скомпилировать (перевести в инструкции процессора МК) нашу программу. В папке Exe, которая находится в нашем проекте, должен появиться файл с расширением hex, это и есть наш файл прошивки для МК. Для того, чтобы нашу прошивку скормить виртуальному микроконтроллеру в Proteus, нужно два раза кликнуть на изображении микроконтроллера в протеусе. Появится вот такое окошко
кликаем на пиктограму папки в поле Program File, выбераем hex - файл нашей прошивки и нажимаем кнопку ОК. Теперь можно запустить симуляцию нашей схемы. Для этого нажимаем кнопку "Воспроизвести" в нижнем левом углу окна Протеус.
Киселев Роман, Май 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

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

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

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

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

Первая программа на Си для 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 сварганил плагинчик для файрфокса облегчающий навигацию по моему сайту и форуму.
Обсуждение и скачивание,

Чтобы перенести с компьютера в микроконтроллер нам понадобится USBasp и программа AVRDUDE. Сегодня существует широкий выбор программаторов, предназначенных для программирования микроконтроллеров AVR. Среди них можно найти много самодельных, который даже трудно назвать программаторами, поскольку они с помощью всего лишь нескольких резисторов напрямую подключаются к COM порту. Однако современные компьютеры и ноутбуки уже практически не оборудываются COM портами, поэтому одним из основных критериев при выборе программатора является возможность подключения его к USB порту. Наиболее дешевый, простой и очень распространенный – это программатор USBasp. Его можно приобрести практически в любом радиомагазине по доступной цене. Стоимость его в китайских интернет магазина находится в пределах от 1,5 $ до 3 $.

Программатор USBasp

Связь компьютера с микроконтроллером осуществляется посредством программатора USBasp через USB порт, а данные передаются по интерфейсу SPI S erial P eripheral I nterface (последовательный периферийный интерфейс). Для связи МК с программатором задействуются специальные выводы: MOSI, MISO, SCK, RESET, VCC, GND. Хотя SPI предполагает использование всего трех выводов MOSI, MISO и SCK, но мы будем задействовать все шесть выводов.

При обмене данными по интерфейсу SPI микроконтроллер может одновременно либо принимать (вывод MISO) либо передавать данные (вывод MOSI). Установка режима приема или передачи данных осуществляется путем подачи определенного импульса на вывод SCK.

Разъем программатора, как правило, имеет 10 пинов и подключается к микроконтроллеру с помощью 10 проводного шлейфа. Однако удобней пользоваться шлейфами, которые имеют переходник на 6 пин, так как в таком случае все пины заняты. У десяти пинового разъема одни пин остается не занятым, а четыре пина подключены к общему проводу (GND).

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

Фото подсоединенного программатора к микроконтроллеру ATmega8 приведено ниже.

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

Настройка

Теперь нам осталось выполнить финальный шаг. Запускаем программу AVRDUDE. По умолчанию открывается вкладка Program. В нижней части окна в меню Настройки выбираем тип программатора usbasp . Далее в категории Микроконтроллер выбираем наш микроконтроллер ATmega8. Ниже, в категории Flash кликаем по значку троеточия и в открывшемся меню указываем путь к скомпилированному файлу с расширением hex . Путь к файлу и сам файл будут теми же, что мы ранее задавали в .

Чтобы убедится в том, что программатор определен операционной системой (драйвер программатора корректно установлен) и правильно подключен к микроконтроллеру, кликаем по кнопке Чтение . Если ошибок нет, то появится окно с записью “Калибровочные ячейки генератора считаны!” И в верхнем окошке отобразится шестнадцатеричное число. У каждого МК это число индивидуальное.

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

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

Результат записанной, или, как еще говорят, прошитой программы – это засветившийся светодиод, подключенный к выводу PC0 нашего микроконтроллера.

Вверх