AVR для детей и домохозяе. Потрошим Arduino

Артемий «Di Halt» Исламов (di_halt@mail.ru)


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

Странный зверь

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

В самом деле, игрушка занятная. Подключается через USB к любому PC-совместимому компу, используя для питания обычный 9-вольтовый адаптер от свитча. Прошивается одним нажатием кнопки в редакторе, после чего работает по программе. При этом имеет очень простую среду программирования, с Си-совместимым языком, но своим – узко заточенным под нее набором библиотек. Что еще нужно для офисного айтишника, который паяльник видел только на картинке? Идиллия! Немудрено, что этот робокирпичек стал так популярен. Цена же за него вполне доступна, по сравнению, конечно, с другими робоконструкторами, вроде того же Lego Mindstorm – всего 30 баксов.

Вскрытие пациента

Еще по фотографиям, бегло осмотрев платку со всех сторон, я понял, что это такое и с чем его можно сожрать. Модуль Arduino представляет собой самый обыкновенный AVR контроллер, причем не самый мощный – Mega8 или Mega168, в более поздней версии. Кроме самого контроллера на плате находится немного обвязки:

  1. Диод на входе, защищающий от дурака – не даст сгореть модулю при неправильной подаче питания. Хотя, на месте разработчиков, я бы сразу вкорячил туда диодный мост. Стало бы на пару копеек дороже, зато можно вообще не думать о том, какой стороной совать блок питания.
  2. Стабилизатор напряжения на базе LM7805 ака КР142ЕН5А, понижающий входную напругу с указанных девяти вольт, до положенных Меге по даташиту пяти вольт. Из этого следует, что на вход можно смело гнать напряжение от 6 до 12 вольт. При крошечном потреблении микроконтроллера линейный стабилизатор легко сбросит напряжение до положенных пяти вольт без критического перегрева. Правда, для батарейного питания лучше все же подавать напряжение пониже – меньше будет зря расходоваться. Там же на плате присутствует традиционная обвязка для микроконтроллера – стабилизирующие конденсаторы, цепь сброса, кнопка RESET и светодиодик.
  3. Интерфейсная микросхема FT232 с необходимой обвязкой, организующая связь с компом. Работает она просто: вход обычный UART, а на выходе – USB-стэк и драйвер в компе, который организует виртуальный COM-порт. Кстати, именно FT232 составляет львиную долю стоимости платы, и без нее обошлось бы гораздо дешевле. В старых версиях Arduino стоял обычный MAX232 и подключалась она к COM-порту. Также есть BlueTooth-версия модуля; как понятно из названия, она цепляется к компу через синий зуб. Разница лишь в том, что вместо FT232 впаян BT блок, работающий точно по такому же принципу – конвертит UART в виртуальный COM-порт, но уже без проводов. Разумеется, стоит он значительно дороже.
  4. Обвязка контроллера, состоящая из кварца с конденсаторами, токоограничивающих резисторов и фильтрующего дросселя на питании АЦП блока, которые сглаживает пульсации основного питающего напряжения. Нужно это, чтобы аналоговые входы могли точнее замерить входной сигнал, ведь точность напрямую зависит от эталонного напряжения, которое подается на АЦП через сглаживающую индуктивность. Если помнишь мои статьи про основы электроники, – она без проблем пропускает только постоянный ток, а всякие колебания и помехи подавляет.

Интерфейсы

На плате модуля находятся гнездовые разъемы, на которые выведены практически все выводы микроконтроллера. Поэтому здесь у нас полное раздолье – и АЦП, и ШИМ, и UART. Есть также SPI и I2C – полный фарш, короче. А как же USB и BlueTooth, который есть в некоторых модулях? С одной стороны, USB тут не полноценный, а всего лишь эмуляция COM-порта: ничего путного, кроме таскания байтов через UART в виртуальный COM-порт и обратно, ты с ним не сделаешь. А с другой стороны, тебе не надо заморачиваться с протоколом обмена – все уже готово аппаратно. Та же история и с BT.

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

Оболочка

Среда компиляции представляет собой надстройку над классическим AVR GCC, написанным на Java. Куски кода из GCC для AVR можно подключить на ура (благо, их уже понаписали гигабайтами). Плюс ко всему, тут есть еще свои языковые конструкции, аппаратно привязанные к Arduino. В самом деле, ведь блок везде одинаковый и за совместимость можно ручаться. А если кто что сделал не так, – то сам себе злой Буратино.

Интерфейс прост, как мычание – окно ввода кода, кнопка компиляции и заливки прошивки в кристалл да стандартные «сохранить/открыть». Кусок кода называется скетчем.

Можно открыть кучу файлов, – они все разместятся в виде табов-закладок. Это удобно, когда работаешь с большой программой, составленной из многих модулей.
Там же есть простенькая терминалка, с помощью которой можно заглянуть в сеанс обмена данными между оболочкой и модулем. Хотя лучше забыть про нее сразу и использовать Terminal v1.9b – мега вещь! Если полазить по менюшкам, то легко находится библиотека примеров, а также возможность залить новый BootLoader. Про Bootloader я расскажу чуть позже.

Язык программирования

Чем подкупает Arduino, так это своим языком. Настолько все просто, что даже мозг не нужен. Была в свое время такая убойная игрушка – «Операция Колобот», где надо было программировать поведение разведывательных роботов в глубоком космосе, практически на чистом Си. Тут примерно то же самое, только в железе. Чтобы зря не пудрить мозги, покажу на примере. Сделаем себе аппаратный пиксель – светодиод, который мы сможем зажигать по команде с компа.
Для начала зададим параметры выводов и переменные:

int outputPin = 13;
int val;

Это всего лишь название, главное, что переменные типа integer – целое беззнаковое, от нуля до 255.

Причем outputPin еще в самом начале равен 13.
Дальше идет первая обязательная процедура – инициализация портов ввода вывода:

void setup()
{
Serial.begin(9600);
pinMode(outputPin, OUTPUT);
}

Сразу говорим, что работа с портом у нас будет на скорости 9600бод. А наш outputPin настраиваем на выход. Собственно, к нему будет подключен светодиод.
Вторая процедура, собственно, сама программа. Аналог функции main() в Си.

void loop()
{
if (Serial.available())
{
val = Serial.read();
if (val == 'H')
{
digitalWrite(outputPin, HIGH);
}
if (val == 'L')
{
digitalWrite(outputPin, LOW);
}
}
}

Как видишь, синтаксис тут сишный, а функции свои, ардуиновские. В этом примере все функции библиотечные; кратко расскажу о тех, что используются. Serial.xxx – означает, что идет обращение к последовательному порту aka UART. Дальше мы проверяем его наличие подфункцией available – если возвращает не ноль, значит, все у нас путем. Serial.read – считывает байт из порта и, если он будет равен коду H, то зажигает светодиод, а если L, то гасит. Все просто! Выставлять логическую единицу (помним, что 1 это примерно +5 вольт) или ноль можно на любой ножке командой digitalWrite, где в параметрах указываем, на какой ножке какой уровень выставить.
Также есть функции AnalogWrite и AnalogRead, позволяющие выдать напряжение на соответствующий вывод в виде ШИМ-сигнала либо считать его с АЦП. Вот так все просто. Никакой инициализации АЦП, никакого вкуривания в ШИМ-модуляцию и настройку таймеров. Конечно, на произвольный вывод ты ШИМ не выведешь, для этого в Ардуино зарезервированы соответствующие выводы, равно как и для АЦП.

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

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

Arduino без Arduino

Глядел я на эту погремушку, вертел в руках… Нет, не готов я платить тридцать баксов за простой микроконтроллер. Будь он даже трижды удобен в программировании. Нафиг-нафиг! Мы пойдем своим путем!

Что собой представляет эта платка изнутри? Ведь ничего особенного: микроконтроллер да микросхема связи с компом. Микроконтроллер стоит рублей 80-100, а вместо дорогой и гламурной USB-микросхемы FT232RL можно смело воткнуть наш брутальный MAX232 за двенадцать рублей и повесить все на COM-порт. Добавить туда же импульсный стабилизатор за 5 рублей, а то и вовсе без него, запитав все от компового блока питания. Сварганить этот коктейль хоть на макетке, хоть на печатной плате по лазерно-утюжному методу. Получим тот же самый Arduino, но уже суровой самопальной выделки. Всего за 150 рублей! Либо за 250, если ты захочешь USB-версию и разоришься на FT232.

Осталось только прошить загрузчик, он же – Bootloader. Если ты уже сталкивался с контроллерами, то наверняка заметил, что в Arduino не используется программатор, а программа загружается прямо через интерфейс RS232 (в той или иной форме). Как так? А все просто! Дело в том, что уже с завода модули Arduino идут с прошитым загрузчиком. Это такая небольшая программка, которая сидит в начале памяти, сжирая несколько байт ПЗУ и слушая COM-порт. Как только там появляется управляющая команда, что, мол, сейчас в порт польется прошивка, загрузчик тут же вострит уши – начинает ловить приходящие байты и заботливо складывать их в Flash-память кристалла. Таким образом, микроконтроллер может сам себя прошить. После загрузки основного флеша, проц перезагружается, а управление переходит от загрузчика к залитой программе. И так до следующего сеанса сброса и загрузки.

Раз уж мы решили получить все сразу и задешево, то загрузчика, естественно, в микроконтроллере, купленном в магазине, не будет. Но это не беда! В первый раз, что ли, нам контроллер прошивать? Тем более, для AVR программатор делается из пяти проводков, посредством которых микроконтроллер цепляется к LPT-порту. Если у тебя нет LPT, то можно и через COM – потребуется несколько диодов и сопротивлений. Схему такого программатора ты найдешь на сайте avr.nikolaew.org в разделе программатор. Если же у тебя нет ни COM, ни LPT, то на данном этапе ты в пролете. Ищи, у кого есть, и шейся у них.

Как правильно Boot’ить AVR

Сначала определись с типом контроллера. Я рекомендую брать ATmega168: больше памяти и более фарширована (на ней, кстати, построены все последние версии Arduino). Но ее может не быть в твоем лабазе. Тогда подойдет Mega8. Лезь в папку, куда ты установил оболочку Arduino, и ищи там hardware/bootloaders. В этой директории разработчики заботливо сложили для тебя как прошивку загрузчика, так и его исходные коды (можешь изучить на досуге). Выбирай загрузчик под свой проц и ищи там файл с расширением «hex» – это он!

Дальше открываешь программу прошивальщик, например, мой любимый uniprof от Николаева. Убеждаешься в том, что МК правильно определился – должно загореться его название над окном с кодом. Затем тыкаешь кнопку «Загрузка Hex», выбираешь свою прошивку и, когда левое поле заполнится шестнадцатеричными кодами, нажимаешь кнопку Prog. Все, загрузчик залился. Не бойся, встанет как надо – все адреса жестко записаны в hex-файле.

Осталось только прописать fuse bits, иначе ничего не заработает. Вот тут – внимание и еще раз внимание. Fuse bits это страшная вещь, одно неверное движение и кристалл для тебя мертв! Так что, гляди в оба.

Первым делом узнай, какие фьюзы тебе нужны. Открой блокнотом файл burn.bat, что лежит рядом с прошивкой. Ищи там строку вида:

tools\avr\bin\uisp -dpart=ATmega8 -dprog=stk500 -dserial=com1 -dspeed=115200 --wr_fuse_l=0xdf --wr_fuse_h=0xca

Видишь, тут параметры «wr_fuse_l=0xdf» и «wr_fuse_h=0xca»? Это и есть требуемое значение Fuse bit. Который wr_fuse_l – это младший байт, а wr_fuse_h – старший.
Открой калькулятор и переведи их из шестнадцатеричной в двоичную. Не ошибись! Проверяй все дважды, а лучше трижды. 

Нажми в прошивающей проге кнопку Fuse, а затем (это очень важно) нажми во всех окошках кнопку Read, чтобы считать старое значение Fuses. Найди там разделы Fuse (low) и Fuse (High) и расставь туда нужные галочки. В uniprof в разделе fuses нумерация фьюзов идет сверху. То есть, те биты, которые выше, имеют меньший номер. Например, требуемый порядок для Mega8 будет таков:

Low Fuse 0xDF = 1101 1111
1 = Cksel0
1 = Cksel1
1 = Cksel2
1 = Cksel3
1 = Sut0
0 = Sut1
1 = Boden
1 = Bodelevel

High Fuse 0xCA = 1100 1010
0 = Bootrst
1 = Bootsz0
0 = Bootsz0
1 = Eesave
0 = CKOPT
0 = SPIEN
1 = WDTON
1 = RSTDSBL

Для Меги 168 – аналогичным макаром, только не забудь взять фьюзы из другого файла. Сразу же после зашивки Fuse микроконтроллер перестанет определяться программатором. Это нормально – ты переключил его на внешний кварц. Вставляй его в панельку и можешь обращаться к нему через бутлоадер.

Подцепляй интерфейсный шнурок в комп и выбирай в меню Tools свой COM-порт, к которому у тебя подцеплена железка, да тип агрегата, который ты собрал (под Mega8 или Mega168). Теперь ты стал гордым обладателем Arduino-совместимого девайса!

RETI

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

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

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

Ссылки

На диске тебя ждут


Журнал "Хакер" N2 2009г.