Если ты впервые столкнулся с микроконтроллерами, то наверняка у тебя стал выбор на чем писать.
На Си или на Ассемблере. Выбор не прост, не зря программисты однокристальщики раскололись на два непримиримых лагеря. Одни с пеной у рта доказывают, что те кто пишут на Си - лохи изнеженные, а настоящий брутальный кодер должен воспринимать только ассемблер. Другие же, усераясь, доказывают, что на ассемблере разве что лампочками помигать можно, а какой-либо серьезный проект делать на низком уровне невозможно.
Но, истинна, как всегда, находится посредине. Каждый уважающий себя программер должен знать ассемблер, а вот писать должен на том, что более подходит под масштаб задачи. Особенно это касается микроконтроллеров.
Assembler+
Парадоксально, но под микроконтроллеры писать на ассемблере ничуть не сложней чем на Си. В самом деле, программирование контроллера неотделимо от его железа. А когда пишешь на ассемблере, то обращаешься со всей периферией контроллера напрямую, видишь что происходит и как это происходит. Главное, что при этом ты четко понимаешь что, как и зачем ты делаешь. Очень легко отлаживать и работа программы как на ладони.
Да и сам ассемблер изучается очень быстро, за считанные дни. Достаточно постоянно иметь перед глазами систему команд и навык программирования алгоритмов. А соответствующее состояние мозга, когда начинаешь мыслить ассемблерными конструкциями, наступает очень быстро.
C-
А вот с высокими языками, например с Си, ситуация уже куда хуже. Да, повторить какой-нибудь пример из обучалки, вроде вывода строки на дисплей, Сях куда проще, подключил нужную библиотеку, набрал стандартную команду и вот тебе результат. Но это только так кажется. На самом деле, стоит чуть вильнуть в сторону, как начинается темный лес. Особенно, когда дело начинает касаться адресации разных видов памяти.
В таких случаях обычно открывают листинг и смотрят, что там происходит в коде на уровне команд процессора, но вот засада — без знания ассемблера там делать нечего! Зато если понимаешь, как работает программа на уровне команд, то найти багу вроде срыва стека или нарушения атомарного доступа проще простого.
Ну и такие гадкие вещи как overhead. Программа на Си требует значительно больше оперативной памяти, значительно больше места во Flash-памяти, работает куда медленней чем ассемблерная программа. И если на обычном компьютере с его гигагерцами частот, гигабайтами оперативки и дисковой памяти это не столь критично, то вот для контроллера с жалкими килобайтами флеша, у которого частота порой не превышает 16 мегагерц, а оперативки и килобайта не наберется, такой расход ресурсов более чем критичен.
Кроме того, существуют такие контроллеры как ATTiny 1x, у которых либо вообще нет оперативки, либо она такая мизерная, что даже стек там сделан аппаратным. Так что на Си там ничего написать в принципе нельзя.
Assembler+
Представь, что ты прораб, а компилятор это банда джамшутов. И вот надо проделать дырку в стене. Даешь ты джамшутам отвертку и говоришь — ковыряйте. Проковряют они отверткой бетонную стену? Конечно проковыряют, вопрос лишь времени и прочности отвертки. Отвертка сточится (читай памяти процессора или быстродействия не хватит)? Не беда — дадим джамшутам отвертку побольше, благо разница в цене между большой отверткой и маленькой копеечная. В самом деле, зачем прорабу, руководителю, знать такие низкоуровневые тонкости, как прочность и толщина бетонной стены, типы инструмента. Главное дать задание и проконтроллировать выполнение, а джамшуты все сделают сами.
Задача решается? Да! Эффективно это решение? Совершенно нет! А почему? А потому что прораб не знал, что бетон твердый и отверткой его проковырять сложно. А будь прораб сам когда-то рабочим, пусть даже не профи, но своими руками положил плитку, посверлил дырки, то впредь таких идиотских заданий бы не давал. Конечно, нашего прораба можно и в шараге выучить, дав ему всю теорию строения стен, инструмента, материалов. Но ты представь сколько это сухой теории придется перелопатить, чтобы чутье было интуитивным, на уровне спинного мозга? Проще дать в руки инструмент и отправить сверлить стены. Практика — лучший учитель.
Также и с ассемблером. Хочешь писать эффективные программы на высокоуровневом языке — изучи хотя бы один ассемблер, попиши на нем немного. Чтобы потом, глядя на любую СИшную строку, представлять себе, во что это в итоге компилируется и как обрабатывается контроллером. Очень помогает в отладке и написании, а уж про ревесирование чужих программ я вообще не говорю.
Assembler-
Но засиживаться в ассемблерщиках и стараться все сделать на нем далеко не обязательно. Ассемблерный код тяжелей переносить с контроллера на контроллер, в нем при переносе можно наделать много незначительных, но тем не менее фатальных ошибок, отладка которых занимает много времени. Большие проекты писать на ассемблере то еще развлечение. На ассемблере трудно сделать полноценную библиотеку, подключаемую куда угодно. Ассемблер жестко привязан к конкретному семейству контроллеров.
С+
Си хорош за счет огромного числа готового кода, который можно очень легко и удобно подключать и использовать в своих нуждах. За большую читабельность алгоритмов. За возможность взять и перетащить код, например, с AVR на ARM без особых заморочек. Или с AVR на PIC. Разумеется, для этого надо уметь ПРАВИЛЬНО писать на Си, выделяя все аппаратно зависимые части в HAL.
Общий расклад примерно таков, что использование высокоуровневого языка на контроллерах с обьемом памяти меньше 8 килобайт является избыточным. Тут эффективней писать все на Ассемблере. Особенно, если проект подразумевает не просто мигание светодиодом.
8-16 килобайт - тут уже зависит от задачи, а вот пытаться писать на ассемблере прошивку более 16 килобайт можно, но это напоминает прокладку тоннеля под Ла Маншем с помощью зубила.
В общем, знать надо и то и другое. Настоятельно тебе рекомендую начать изучать МК с ассемблера. А как только поймешь, что на асме можешь реализовать все что угодно, любой алгоритм. Когда досконально прочувствуешь работу стека, прерываний, организацию переходов и ветвлений. Когда разные трюки и хитрости, вроде игр с адресами возврата из прерываний и процедур, переходами и конечными автоматами на таблицах и всякие извраты будут вызывать лишь интерес, но никак не взрыв мозга из серии «Аааа, как это работает??? Не понимаю?!!»
Вот тогда и можно изучать Си. Причем, изучать его с дебагером в руках. Не просто изучить синтаксис (там-то как раз все элементарно), а понять ЧТО и КАК делает компилятор из твоего исходника. Поржать над его тупостью или наоборот поудивляться извратам искуственного интелекта. Понять как компилятор делает ветвления, как организует циклы, как идет работа с разными типами данных, как ведется оптимизация. Где ему лучше помочь, написав в ассемблерном стиле, а где не критично и можно, во всю ширь использовать языковые возможности Си.
А вот начать изучение ассемблера после Си мало кому удается. Си расслабляет, становится лень и впадлу. Скомпилировалось? Работает? Ну и ладно. А то что там быдлокод, та пофигу... =)
А как же бейсик, паскаль и прочие языки? Они тоже есть на AVR?
Конечно есть, например BascomAVR или MicroPASCAL и во многих случаях там все проще и приятней. Не стоит прельщаться видимой простотой. Она же обернется тем, что потом все равно придется переходить на Си.
Дело в том, что мир микроконтроллеров далеко не ограничивается одним семейством. Постоянно появляются новые виды контроллеров, развиваются новые семейства. Ведь кроме AVR есть еще и ARM, PIC, STM8 и еще куча прекрасных контроллеров со своими плюсами.
И под каждый из этих семейств есть Си компилятор. Ведь Си это, по сути, промышленный стандарт. Он есть везде и контроллер который не имеет под него компилятора популярным у профессионалов не станет никогда.
А вот на бейсик с паскалем, обычно, всем пофигу. Если на AVR и PIC эти компиляторы и сделали, то лишь потому, что процы эти стали особо популярны у любителей и там наверняка найдется тот, кто заинтересуется и бейсиками всякими. С другим семейством контроллеров далеко не факт, что будет также радужно. Например под STM8 или Cortex M3 я видел Pascal в лучшем случае только в виде кривых студенческих поделок. Никак не тянущих на нормальный компилятор.
Такой разный Си
С Си тоже не все гладко. Тут следует избегать компиляторов, придумывающих свои диалектные фишки. Например, CodeVision AVR (CVAVR) позволяет обращаться к битам порта с помощью такого кода:
PORTB.7 = 1; // Выставить бит 7 порта B в 1
Удобно? Конечно удобно! Вот только в Си так делать нельзя, стандарт языка не позволяет. И ни один другой СИ-компилятор такой кусок кода не примет. Т.к. по стандарту корректней будет так:
PORTB |= 1<<7;
Использование диалектов не позволит тебе скакать с компилятора на компилятор. Таскать код повсюду копипастом. Привязывает к одному конкретному компилятору и далеко не факт, что он окажется хорошим и будет поддерживать все новые контроллеры семейства.
Приплюснутый
Некоторое время назад я считал, что С++ в программировании микроконтроллеров не место. Слишком большой overhead. C тех пор мое мнение несколько поменялось.
Мне показали очень красивый кусок кода на С++, который компилился вообще во что-то феерическое. Компактней и быстрей я бы и на ассемблере не факт что написал. А уж про читабельность и конфигурируемость и говорить не приходится. Все из знакомых программистов, кто видел этот код, говорили что-то вроде «Черт, а я то думал, что я знаю С++».
Так что писать на С++ можно! Но сделать компактный и быстрый код на С++ чертовски виртуозная задача, надо знать этот самый С++ в совершенстве. Судя по тому, что столь качественных примеров эффективности С++ при программировании под МК мне попадалось раз-два, то видимо пороговый уровень входа в эту область весьма и весьма велик.
В общем, как говорил Джон Кармак, «хороший С++ код лучше, чем хороший С код. Но плохой С++ может быть намного ужасней чем плохой С код».
Вводная. Что такое микроконтроллер | Содержание | Архитектура |