В настоящее время для микроконтроллеров фирмы Atmel существует множество языков программирования: от классического BASCOM-AVRBasic[1] до Assembler и C. Наиболее распространёнными являются язык ассемблера и язык C. В этих языках реализованы практически все возможности программирования встраиваемых систем на данном типе микроконтроллеров[2].
Рассмотрим общие особенности программирования на этих языках для существующих микропроцессорных систем, а также частности программирования в аппаратной среде микроконтроллеров, как встраиваемых микро-ЭВМ.
В настоящее время в различных публикациях по вопросам программирования микропроцессорных систем и, в частности, систем на микроконтроллерах, утверждается приоритет языка программирования C и приводится ряд преимуществ этого языка программирования по отношению к языку ассемблера. Цель данной статьи – критически рассмотреть преимущества языка C по отношению к языку ассемблера, произведя сравнительный анализ данных систем программирования, являющихся основными при программировании микропроцессорных систем.
Как известно, все существующие языки программирования можно разделить на две основные категории:
- языки программирования низкого уровня;
- языки программирования высокого уровня.
К первой группе относят семейство языков ассемблера, например, Turbo Assembler, Macro Assembler. Эти средства разработки позволяют получить наиболее короткий и быстродействующий код.
Ко второй группе относятся упомянутые выше BASCOM-AVRBasic и язык программирования C.
Известно, что язык C, в некотором роде, занимает промежуточное положение, объединяя возможности языков высокого уровня с функциональностью языков ассемблера[3], однако, это не совсем так. Основные функции языков ассемблера имеют основанием низкоуровневый доступ к компьютеру, определяющий полноценную возможность управления процессором, что, с одной стороны, позволяет достигать максимальной скорости реакции программы на действия пользователя[4, с. 10], а с другой стороны позволяет достичь определённых преимуществ в размере конечного исполняемого кода программ[2].
У опытных программистов на языках высокого уровня, к которым всё-таки относится и язык программирования C, часто возникают возражения по описанным выше вопросам, основанные на том, что некоторые операторы языка C или даже Turbo Pascal напрямую преобразуются в машинные коды. Также допустимо утверждать, что такие языки программирования как FORTH обеспечивают непосредственный низкоуровневый доступ. Но несмотря на то, что C или иные языки программирования обеспечивают выполнение некоторых низкоуровневых операций, эти языки всё равно не могут сравниться с языком ассемблера в возможностях доступа к процессору [4, с. 9]. Высокоуровневые языки, несмотря на наличие возможности выполнения низкоуровневых операций, требуют комбинирования своих функций с функциями языка ассемблера, путём встраивания ассемблерного кода в код программ, написанных на этих языках[4, с.11][4, с.332][4, с.358].
Как уже было отмечено выше, ассемблер – это низкоуровневый язык программирования, что позволяет достичь значительного уровня оптимизации уже при непосредственном написании кода программы. При этом оптимизация достигается уже при программировании и её уровень контролируется непосредственно. Фактически, программируя, мы одновременно оптимизируем программу. При использовании автоматических компиляторов необходима синтетическая оптимизация. В настоящее время при программировании на языке C используются так называемые оптимизирующие компиляторы или оптимизаторы кода, например, компилятор фирмы Microsoft, упомянутый в статье [5].В таких системах оптимизация программного кода происходит при компиляции программы, то есть при преобразовании исходного текста программы в машинный код.
В настоящее время не существует единого мнения по вопросам доверия оптимизации, выполненной автоматически.
Обоснованием позиции, опирающейся на не совершенство синтетической оптимизации, может служить тестовый обзор [6]. Известно, что оптимизирующие компиляторы разных производителей имеют значительные различия при работе с различными комбинациями программного кода и по-разному переводят его в мнемонику конкретного микроконтроллера. Несмотря на то, что ядро и система команд микроконтроллеров AVR создавались в тесном сотрудничестве с фирмой IAR Microsystems, производителем компиляторов для языков программирования C/C++, как показано в обзоре [6] при использовании данного оптимизатора кода, также возможны неточности при генерации ассемблерных мнемокодов.
Несмотря на то, что автоматическая оптимизация кода значительно ускоряет разработку программ, часто она может приводить к трудно обнаруживаемым ошибкам конечного программного кода, рассмотрим следующий пример [7]:unsigned short int i; void main (void) { DDRB = 255; PORTB = 0; while(1) { if (PINB == 255) PORTB = 0; else PORTB++; for (i=0; i<10000; i++){} //Далее может быть иной программный код}}Пример представляет собой программу на языке программированияCдля микроконтроллера фирмыAtmel, семействаAVR. В верхней строке программы объявляется глобальная переменнаяiтипа без знаковое короткое целое (unsignedshortint), которая согласно [3, с. 18] имеет размер два байта и может принимать значения от 0 до 65535. Данная переменная будет использоваться позднее для организации цикла задержки. Далее происходит инициализация аппаратных портов ввода-вывода микроконтроллера. Внутри бесконечного циклаwhile(1), значимость которого при программировании микроконтроллеров рассмотрена ниже, расположен программный код, изменяющий значение на контактах портаBмикроконтроллераAVRпо следующему правилу: если на всех контактах портаBобнаруживаются потенциалы единицы, то обнулить контакты, иначе увеличить значение в регистре-защёлке портаB. Последний цикл без выполняемого в теле кода предназначен для формирования задержки вывода для того, чтобы изменение потенциалов портаBможно было зафиксировать, например, с помощью светодиодов. Далее следует комментарий.Если включить автоматическую оптимизацию, то компилятор сочтёт цикл задержки бесполезной тратой времени и исключит его из программы[7]. Таким образом, изменение параметров портаBне может быть зафиксировано. Если же программная задержка важна для разрабатываемой системы, то последствия могут оказаться непредсказуемыми.Из вышесказанного можно заключить, что автоматическая оптимизация на данном этапе своего развития нуждается в изменениях и доработках и к её использованию не следует прибегать повсеместно, что делает её малозначительным преимуществом языков программирования высокого уровня.В большинстве публикаций, посвящённых языку ассемблера [4, с. 11], указывается на непереносимость и аппаратную зависимость программ, написанных на нём, по сравнению с языками высокого уровня, такими какC. Однако, программы на языкеCтакже могут быть аппаратно зависимыми и вследствие чего непереносимыми, особенно, при работе с графическими контроллерами. Некоторые функции неработоспособны при программировании под графические контроллеры различных производителей. Таким образом, приходится разрабатывать различные наборы функций для прямого взаимодействия с драйверами видеокарт [8, с.249]. Кроме того, программы автоматической оптимизации кодов, созданные для языкаC, о которых написано выше, сами являются аппаратно зависимыми и непереносимыми, например, считающийся одним из лучших компиляторовIntelCCompilerпроизводит некорректную оптимизацию программ для процессоров других производителей [9].Известно утверждение, что программирование на языке ассемблера затруднено слабой читаемостью программ, что в свою очередь приводит к большему числу ошибок при программировании на этом языке, нежели на языке программированияC[2]. В данном случае читаемость программ, как и количество в них ошибок, занесённых при программировании, зависит в большей степени от опыта, внимательности и стараний программиста, а также от того факта, насколько хорошо известен разработчику тот или иной язык программирования[4, с. 11]. Кроме того, за якобы лучшей читаемостью программ, написанных на языке программированияC, скрывается множество недокументированных возможностей, как отрицательно, так и положительно влияющих на правильную работу конечного программного продукта. Язык программированияC– громоздкий язык. Таким образом, хотя разработка программ на языкеC, при поверхностном взгляде, быстрее программирования на языке ассемблера, однако программирование на нём требует знания нюансов, без которых написание корректно работающих программ невозможно [10, с.104]. Язык ассемблера, в свою очередь, представляет собой набор простых правил, изучив которые, можно уверенно программировать на нём, а знание и изучение архитектуры целевой микропроцессорной системы упрощает процесс программирования и последующего чтения программ [7].Сегодня большинство программистов убеждены, что одним из основных преимуществ языкаCпо отношению к языку ассемблера является наличие библиотечных программ, например, подпрограмм вычисления сложных выражений, вида (x* 2 + 8) [4, с.11]. Несмотря на удобство программирования с их использованием, следует признать, что отсутствие встроенных библиотечных программ, скорее преимущество языка ассемблера, нежели его недостаток, так как при использовании таких программ в языках высокого уровня теряется возможность полного управления ресурсами компьютера и, следовательно, возможность написания максимально эффективных, быстрых и компактных программ, кроме того существует большое количество ассемблерных библиотек, позволяющих выполнять операции, характерные для языков высокого уровня[4, с.11], например, стандартные библиотеки адресации для микроконтроллеров фирмыAtmel, позволяют обращаться к регистрам и портам микроконтроллера аналогично программам наC, в противном случае пришлось бы вручную изучать адреса регистров и вносить их в управляющие конструкции [11].Из всего вышесказанного может сложиться впечатление, что автор данного обзора является противником программирования на языкеC. Это не так, в течение пятнадцати лет программирования автора, из которых десять лет посвящено изучению языкаC, к изучению которого автор приступил ранее, чем к изучению языка ассемблера, был сделан вывод, что последний оказался практически эффективнее по сравнению с языком программированияC. В условиях программирования малых микропроцессорных систем и однокристальных микро-ЭВМ, к которым относятся микроконтроллеры, в частности фирмыAtmel, а такие технические особенности этих микроконтроллеров, как развитая регистровая память, включающая тридцать два регистра общего назначения, исключают необходимость использования сложных высокоуровневых языков программирования, хотя и допускают её [11].Как можно заключить из вышеописанного, преимущества языка программированияCдостаточно спорны. В настоящее время он обладает одним принципиальным преимуществом, а именно знакомство с ним большинства программистов, которые программировали на нём изначально для персональных компьютеров с процессорами архитектурыx86. Особенностью такой архитектуры является наличие единственного регистра, в общем используемого и для пересылок и для арифметических операций[4, с.53], в этих условиях переход к высокоуровневым языкам является естественным, но, как уже было замечено выше, технические особенности архитектурыEnhancedRISC, микроконтроллеров фирмыAtmelпозволяют отказаться от высокоуровневых языков при программировании[11]. Таким образом, если большинство программистов по каким-то причинам не пожелали использовать или изучить язык ассемблера, язык программированияCподходит для использования в случаях, когда группа программистов работает над программным кодом для одной задачи. Здесь требуется достоверная читаемость кода каждым из них субъективно, и языкCстановится своеобразным «LinguaFranca» программирования, подобно английскому языку. Для написания же эффективных, быстродействующих и компактных программ язык ассемблера предпочтительнее языкаC.Общение автора данного обзора с программистами систем на микроконтроллерах, работающих с языкомCи знающих его достаточно хорошо, показали, что они по непонятным причинам демонстрируют нежелание изучать и использовать язык ассемблера. Несмотря на то, что они часто сталкиваются с описанными выше «подводными камнями» языка при отладке программ, тратя на неё при этом значительное количество времени, язык ассемблера вызывает у них отторжение, как на техническом уровне, так и психологически. Причин неприязни они, зачастую, не называют, либо говорят об описанных выше спорных.Как говорил классик программирования Дональд Кнут, «каждый, кто всерьёз интересуется компьютерами, должен рано или поздно изучить по крайней мере один машинный язык» [7]. Как показал опыт автора, проблемы в освоении языка ассемблера, связаны с недостаточным знанием английского языка. Язык ассемблера – необычный компьютерный язык. Почти весь текст исходной программы состоит из непроизносимых словcli,movsb,sbb[4,c. 17] в архитектуреx86, илиADD,TST,SBR,CBR,RJMP[11] в архитектуреRISC, микроконтроллеровAVR, фирмыAtmel. Человек, не владеющий английским языком в должной мере, предпочитает распространённые языки программирования высокого уровня, где операторы если и не постигаются интуитивно, то зачастую имеют многозначное толкование в соответствии с множеством вариантов использования. Программисты запоминают операторы высокоуровневых языков программирования, в большей степени основываясь не на логике, которое несёт название функции, а на логике выполняемых оператором действий. Например, студенты, изучающие немецкий язык, при изучении языка программированияBASIC, часто неверно произносят названия функций и команд данного языка программирования, но это не мешает им постигать программирование на этом языке [12, с. 5]. При изучении языка ассемблера мнемонические операторы имеют в большинстве случаев однозначное соответствие между названием оператора и выполняемым им действием и изучение в этом случае должно также основываться на знании, понимании и правильной интерпретации названий и расшифровок операторов для успешного программирования в будущем. Например, упоминавшийся выше, операторcli, означаетclearif, то есть сброс флага разрешения прерыванийifи представляет собой сокращение [4, с.484], а операторSBRаббревиатуру отSetBit(s)inRegister[12] и т.п. Кроме того, опыт автора показал, что большинство руководств по языку ассемблера для микроконтроллеров имеют также ошибки, намеренно или случайно допущенные при переводе на русский язык, и программа, написанная с использованием таких руководств неработоспособна. Только при использовании оригинальных, зачастую англоязычных руководств по применению языка ассемблера становится возможным их практическое применение, что является ещё одним стимулом к изучению английского языка программистами.Отдельно хотелось бы заметить, что хотя язык ассемблера считается языком программирования для профессионалов [13, с. 104] [14c. 130] он не так сложен. Преимуществами языка ассемблера является, низкоуровневый доступ к процессору, достижение максимальной скорости за счёт возможности полностью управлять процессом вычисления, компактность и скорость программ [4, с.10]. Программам на языке ассемблера присуща точность исполнения заложенного алгоритма в отсутствии описанных выше нюансов, основанных на своеобразном «языковом барьере» между высокоуровневым языком программирования и реальным вычислительным процессом, так как программы на языках высокого уровня преобразуются в машинные коды опосредованно посредствам промежуточного языка, ассемблерные мнемонические операторы имеют прямое соответствие «код-машинная операция» [3],[4], [13],[14]. Как уже отмечалось выше, язык ассемблера чрезвычайно эффективен в условиях систем на микроконтроллерах фирмыAtmel, также большинство программ для микроконтроллерных систем сохранили условности характерные для традиционных технологий программирования, при которых имеется ограничение на используемые вычислительные ресурсы и от программ требуется прежде всего эффективность и компактность [15]. При таких условиях, в большинстве случаев, возможностей языка ассемблера достаточно, а возможности языкаCизбыточны.В заключение хотелось бы процитировать авторитетного автора, специалиста по языку ассемблера, Тома Свана, в предисловии к своей книге «ОсвоениеTurboAssembler» он пишет: «…если кто-то вам говорил, что ассемблер очень сложен, не верьте.»[4, с.5].Литература:
AtmelAVRBasicCompiler(BASCOM) // Официальный сайт [Электронный ресурс] – режим доступа:http://microcontrollershop.com/product_info.php?products_id=352Программирование микроконтроллеровAVR// Электронный журнал «Мой робот» [Электронный ресурс] – режим доступа:http://myrobot.ru/stepbystep/mc_programming.phpГлушаков, С.В., Программирование наC++ [Текст] /C.В. Глушаков, Т.В. Дуравкина – М.:АСТ, 2008 – 685 с.Сван, Том, ОсвоениеTurboAssembler: Пер. с англ. [Текст] / Том Сван – К.;М.;СПб.: Диалектика, 1996 – 544 с.Оптимизация компилятора // Электронный журнал «Техника оптимизации» [Электронный ресурс] – режим доступа:http://howoptimize.ru/optimization.htmlMissedOptimization// Электронный журнал «EasyElectronics.ru» [Электронный ресурс] – режим доступа:http://we.easyelectronics.ru/AVR/missed-optimization.htmlАссемблер илиC? // Электронный журнал «Controllersystems» [Электронный ресурс] – режим доступа:http://controllersystems.com/books/praktika_programmirovaniya_atmel_avr/assembler-ili-s.htmlФленов, Михаил, Искусство программирования игр наC++ [Текст] // Михаил Фленов – СПб.:БХВ-Петербург, 2006 – 256 с.Придётся лиIntelубрать из компилятора функцию, намеренно выдающую плохой код для процессоровAMD? // Электронный журнал «Железные войны» [Электронный ресурс] – режим доступа:http://www.holyware.ru/viewtopic.php?f=52&t=2296Касперски Крис, Сишные трюки // Крис Касперски – журнал «Хакер», август 2008 (116) 2008, с.104AtmelAVR ATiny213 Datasheet // Atmel Microcontroller Manuals [Электронныйресурс] –режимдоступа:http://www.myrobot.ru/downloads/datasheet_t2313.phpСафронов И., Бейсик в задачах и примерах [Текст] // И.Сафронов – Д.;К.;М.;СПб.: БХВ-Петербург, 2000 – 224 с.Авдюхин, Алексей, Высокий уровень программирования // Алексей Авдюхин – журнал «Хакер», июль 07 (127) 2009, с.104Лебединский, Юрий, Роман с ВМ // Юрий Лебединский – журнал «PCMagazineRussianEdition– Компьютер сегодня», №1 (127), январь 2002, с. 130Павловская, Т.А.,C/C++ Программирование на языке высокого уровня [Текст] / Т.А.Павловская – СПб.:Питер, 2004 – 461с.

