программирование микроконтроллеров против объектно-ориентированного программирования

Я выполнил базовое объектно-ориентированное программирование на C++ (создание B-дерева, алгоритмов хэширования, двойных связанных списков) и выполнил небольшой проект на C (например, создание научного калькулятора и т. д.).

Насколько аппаратное программирование (особенно для микроконтроллеров) отличается от программного/объектно-ориентированного программирования с точки зрения мышления и «мышления», которые должен иметь программист?

Один из них обычно считается сложнее, чем другой, большинство моих людей?

С моим опытом (как описано выше) мне потребуется много подготовки для того, чтобы заняться аппаратным программированием, или я могу сразу же погрузиться без особой подготовки?

Самая большая кривая обучения будет заключаться в том, как управлять конкретным оборудованием в вашем микро. Это потребует изучения листов данных в течение нескольких часов. К сожалению, простого выхода нет.
@rrazd, я заметил, что вы включили тег arduino. Это потому, что вы хотите использовать язык разводки и библиотеки Arduino? Или вы будете писать свои встраиваемые приложения на чистом C? Если вы намерены придерживаться среды Arduino, это довольно безопасно и легко поиграть, поскольку они сделали некоторые абстракции вне аппаратного обеспечения.
@Jon, я планирую использовать плату Arduino для начала. Разве это не похоже на язык Си? Я думал, что это включает в себя те же основные понятия....
Мне интересно, имеете ли вы в виду то, что многие люди назвали бы «программированием ввода-вывода», или вы ожидаете перекомпоновки оборудования с помощью кода. Arduino определенно первый; последний будет областью FPGA.
@rrazd, я решил превратить свой ответ на ваш последний комментарий в ответ. Смотри ниже.
Я понимаю, что должен задать равный, но противоположный вопрос, поскольку пришел из аппаратного обеспечения и теперь мне нужно глубоко изучить ОО.
@rrazd - я изменил название; «аппаратное программирование» звучит слишком похоже на HDL (язык описания оборудования), например VHDL и Verilog, которые используются для программирования FPGA и CPLD.

Ответы (7)

Вам придется полностью отказаться от объектно-ориентированной парадигмы при работе с большинством микроконтроллеров.

Микроконтроллеры, как правило, ограничены регистрами и оперативной памятью, имеют низкую тактовую частоту и не имеют конвейерных/параллельных путей кода. Например, вы можете забыть о Java на PIC.

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

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

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

Возможно, вам придется рефакторить части кода вручную на языке ассемблера, чтобы реализовать функции, которые компилятор не поддерживает (или поддерживает плохо).

Вы должны написать математический код, учитывающий размер слова и отсутствие возможностей FPU большинства микроконтроллеров (т. е. выполнение 32-битного умножения на 8-битном микро = зло).

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

Вам не нужно полностью отказываться от объектно-ориентированной парадигмы, но на небольших микропроцессорах может оказаться необходимым отказаться от реализации тяжеловесных объектов и действительно подумать о том, как лучше решить каждую проблему. Часто это процедурные, но легкие объекты, хорошо реализованные (обычно вручную), иногда могут уменьшить размер сложных проектов микроконтроллеров.
Все это верно, за исключением отказа от объектной ориентации. Вероятно, вы не будете использовать язык с объектно-ориентированными функциями, но это не исключает объектной ориентации. Для микроконтроллеров вы собираетесь написать драйверы для всех аппаратных периферийных устройств (АЦП, контроллеры последовательной шины, ШИМ и т.д.). Такой драйвер всегда должен быть написан объектно-ориентированным образом, чтобы он был 1) автономным и не знал/не заботился об остальной части программы, и 2) реализовывал частную инкапсуляцию, чтобы остальная часть программы не могла зайти и возиться с ним. Это на 100% возможно в C и не повлияет на производительность.
Я категорически не согласен с первым предложением, все мои проекты микроконтроллеров были построены на C++ и с использованием объектно-ориентированного подхода, а микроконтроллеры, которые мы использовали, были не очень большими (32 КБ ПЗУ), также объектно-ориентированный загрузчик занимал менее 2 КБ, я не вижу ограничений. Вы не можете делать сумасшедшие вещи, но дизайн может быть объектно-ориентированным без проблем.
@Arsenal Обратите внимание, что я сказал «большинство», и обратите внимание, что вы комментируете ветку четырехлетней давности. :)
Совершенно не согласен с первым и последним предложением. А также ассемблер используется довольно редко и, в основном, только для 8-битных микроконтроллеров (просто посмотрите этот форум, сколько постов с ассемблерным кодом вы можете найти?). Вы, конечно, можете и (ИМХО) должны писать в стиле ОО для 32-битных микроконтроллеров.

Вам нужно подумать о нескольких вещах:

  • Вы будете использовать C в качестве языка
  • Вы все еще можете создать ощущение объектной ориентации, используя указатели на функции, чтобы вы могли переопределять функции и т. д. Я использовал этот метод в прошлых и текущих проектах и ​​работает очень хорошо. Так что OO частично присутствует, но не в смысле C++.

Есть и другие ограничения, такие как ограниченная скорость и память. Итак, как правило, я избегаю:

  • Используя кучу, если есть способ решить проблему без Malloc, я так и делаю. Например, я предварительно выделяю буферы и просто использую их.
  • Я намеренно уменьшаю размер стека в настройках компилятора, чтобы решить проблемы с размером стека на ранней стадии, оптимизируйте его тщательно.
  • Я предполагаю, что каждая строка кода будет прервана событием, поэтому я избегаю нереентерабельного кода.
  • Я предполагаю, что даже прерывания являются вложенными, поэтому я пишу этот код соответственно
  • Я избегаю использования ОС, если в этом нет необходимости. 70% встроенных проектов на самом деле не нуждаются в ОС. Если мне нужно использовать ОС, я использую только что-то с доступным исходным кодом. (Фриртос и т.д.)
  • если я использую ОС, я почти всегда абстрагируюсь, чтобы сменить ОС за считанные часы.
  • Для драйверов и т. Д. Я буду использовать только библиотеки, предоставленные поставщиком, я никогда не возился с битами напрямую, если у меня нет другого выбора. Это делает код читабельным и улучшает отладку.
  • Я смотрю на циклы и другие вещи, особенно в ISR, чтобы убедиться, что они достаточно быстрые.
  • Я всегда держу под рукой несколько GPIO для измерения параметров, переключения контекста, времени выполнения ISR и т. д.

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

+1 за «вы можете использовать парадигмы OO, если хотите». То, что вам нужно проверить у двери, не является ОО-дизайном. OOD — это просто философия, которая побуждает вас хранить связанный код и данные вместе. Что вам нужно оставить позади, так это способ реализации объектно-ориентированного программирования в корпоративных системах с несколькими уровнями абстракции, инверсией управления и всем прочим. Задача вашей прошивки - гонять железо, вот и все.

Я делаю и то, и другое, так что вот мое мнение.

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

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

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

Вы работаете над кодом, который работает во внешней системе по отношению к вашей системе разработки, с различной степенью видимости вашей цели от платформы к платформе. Если вы находитесь под вашим контролем, нажимайте на средства разработки, чтобы повысить прозрачность вашей целевой системы. Используйте отладочные последовательные порты, отладочный вывод с битовым ударом, знаменитый мигающий свет и т. Д. Конечно, как минимум научитесь использовать осциллограф и использовать контактный ввод-вывод с «областью, чтобы увидеть, когда определенные функции входят / выходят, срабатывают ISR и т. д. Я наблюдал, как люди боролись буквально на годы дольше, чем необходимо, просто потому, что они никогда не удосужились настроить/научиться использовать правильную ссылку отладчика JTAG.

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

Хотя определенные навыки отладки требуются как для ПК, так и для встроенного ПО, для встроенного ПО это гораздо важнее.

Я предполагаю, что ваш опыт работы с С++ основан на ПК.

Программисты, переходящие с ПК на микроконтроллер, часто допускают ошибку, заключающуюся в том, что они не понимают, насколько ограниченными могут быть ресурсы . На ПК вас никто не остановит, если вы создадите таблицу со 100 000 записей или напишете программу, которая компилируется в 1 МБ машинного кода.
Существуют микроконтроллеры , обладающие большими ресурсами памяти, особенно высокого класса, но они все еще далеки от того, к чему вы привыкли. Для хобби-проекта вы, вероятно, всегда можете использовать максимум, но в профессиональном проекте вам часто придется работать с меньшим устройством, потому что оно дешевле .
В одном проекте я работал с TI MSP430F1101.. 1 КБ памяти программ, 128 байт конфигурации Flash, 128 байт RAM. Программа не помещалась в 1К, поэтому пришлось написать 23-х байтную функцию в конфигурации Flash. С этими маленькими контроллерами вы считаете побайтно . В другом случае память программы была на 4 байта меньше. Босс не разрешил мне использовать контроллер с большей памятью, но вместо этого мне пришлось оптимизировать уже оптимизированный машинный код (он уже был написан на ассемблере), чтобы вместить дополнительные 4 байта. Вы поняли картину.

В зависимости от платформы, на которой вы работаете, вам придется иметь дело с вводом-выводом очень низкого уровня . В некоторых средах разработки есть функции для записи на ЖК-дисплей, но в других вы сами, и вам придется прочитать техническое описание ЖК-дисплея от начала до конца, чтобы узнать, как им управлять.
Возможно, вам придется управлять реле, это проще, чем ЖК-дисплеем, но вам потребуется перейти на уровень регистров микроконтроллера. Опять же даташит или руководство пользователя. Вам нужно будет познакомиться со структурой микроконтроллера, которую вы найдете на блок-схеме, опять же в таблице данных. Во времена микропроцессоров мы говорили о модели программирования, который представлял собой набор регистров процессора. Современные микроконтроллеры настолько сложны, что описание всех регистров может занять большую часть 100-страничного описания. IIRC только описание модуля часов для MSP430 занимало 25 страниц.

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

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

Я писал игры для Atari 2600, которая является довольно ограниченной платформой; моя первая опубликованная игра была, по сути, кодом 4K (поскольку у меня была тележка 32K, я добавил некоторые дополнительные вкусности, но версия 4K была полностью играбельной); Оперативная память составляет 128 байт. Мне интересно размышлять о том, что в год, когда я написал эту игру (2005), были опубликованы другие игры, которые были буквально в миллион раз больше.
@supercat - Да, но этого и следовало ожидать, в 2005 году Atari 2600 было уже 200 лет! Я никогда не играл в такие экшн-игры, как шутеры от первого лица, но когда я смотрю на то, что нужно для них, GPU, намного более мощный, чем ваш CPU, как программно, так и электрически, я не могу не покачать головой :-). Я играл в шахматы (Sargon) на 16k TRS-80 IIRC. Flight Simulator моего брата не нуждался в большем.
Не совсем 200 лет. Он дебютировал в 1977 году, так что ему не было даже 30. Хотя я согласен с тем, что это было эоны назад с технологической точки зрения, я все еще поражен тем фактом, что это не просто стократное или тысячекратное увеличение. , но в МИЛЛИОНОВ кратном увеличении как оперативной памяти, так и размера кода. Скорость не получила такого большого прироста, так как 2600 был 1,19 МГц, а более новые системы работают только в низком гигагерцовом диапазоне. Они могут делать гораздо больше за цикл, чем 2600 (которые могли — и должны были — генерировать 1/76 строки видео за цикл), но я не думаю, что они в 1 000 000 раз быстрее.

«аппаратное программирование» может означать многое. Программирование очень маленького чипа (например, 10F200, 512 инструкций, несколько байтов оперативной памяти) может быть почти похоже на разработку электронной схемы. С другой стороны, программирование большого микроконтроллера Cortex (1 МБ FLASH, 64 КБ ОЗУ) может быть очень похоже на программирование ПК/графического пользовательского интерфейса с использованием большого набора инструментов графического интерфейса. ИМХО, хорошему программисту встраиваемых систем/программ реального времени нужны навыки как со стороны разработки программного обеспечения, так и со стороны проектирования схем. Для больших uC C++ — хороший выбор языка, для очень маленьких C может быть единственным выбором. Знание ассемблера может быть полезным, но я бы не рекомендовал делать серьезные проекты полностью на ассемблере.

Я проделал серьезную встроенную работу с людьми из обеих сторон (SWI и EE). Обычно я предпочитаю людей из SWI, при условии, что у них есть некоторый опыт многопоточного программирования.

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

Для каждого метода библиотеки arduino, который вы вызываете, существует множество кода C/C++, который делает это возможным, он просто красиво упакован для использования в качестве API. Взгляните на исходный код arduino в каталоге hardware/arduino/*, и вы увидите все написанные для вас C/C++, которые напрямую взаимодействуют с регистрами микроконтроллера AVR. Если ваша цель — научиться писать такие вещи (непосредственно для аппаратного обеспечения), то вам предстоит многое охватить. Если ваша цель состоит в том, чтобы заставить что-то работать, используя их библиотеки, то, возможно, не о чем говорить, поскольку большая часть тяжелой работы выполняется за вас, а их библиотеки и среда разработки очень просты в использовании.

Некоторые практические правила при работе с устройствами с ограниченными ресурсами, которые могут применяться как к среде Arduino, так и к другим:

Обратите внимание на то, сколько памяти вы используете. Как размер кода (который идет во флэш-память), так и статическое использование ОЗУ (константы в вашем коде, которые всегда будут существовать в ОЗУ). Я бы сказал, что статическое использование ОЗУ немного важнее для начала, так как его легко не заметить. Нередко у вас есть только 1000 байтов для работы со стеком, кучей и константами. Будьте мудры в том, как вы их тратите, поэтому избегайте таких вещей, как длинные массивы целых чисел (по 4 байта каждый), когда достаточно байтов или беззнаковых символов (по 1 байту каждый). Другой ответ здесь очень хорошо охватывает некоторые другие важные моменты, поэтому я остановлюсь здесь, я в основном хотел донести мысль о том, что многое нужно охватить, если вы не используете библиотеку arduino и пишете свои собственные библиотеки C.

Что касается программирования микроконтроллеров и ООП, то они не являются чем-то противоположным. Это правда, что все библиотеки поставщиков написаны на чистом C, но все платформы также поддерживают C++ OOP. Кроме того, разработчики могут создавать и создавать библиотеки высокого уровня C++ и микропрограммы устройств. Хорошим примером являются библиотеки Arduino, официальные и созданные пользователем — в основном классы C++. Возможно, не все преимущества ООП могут быть полностью использованы во встраиваемой среде, но хорошо известные преимущества C++ по сравнению с C здесь также действуют.

Что касается мышления и мышления, как отмечалось в других ответах, микроконтроллеры - это платформы с очень ограниченными ресурсами (особенно в ОЗУ, меньше в скорости) - такие вещи, как динамическое выделение памяти, исключения С++ обычно исключаются. Если выбрано правильное оборудование, легко адаптироваться к этим ограничениям и использовать другие методы (также широко используемые на других платформах).

На мой взгляд, более сложной задачей может быть еще одно дополнительное измерение встроенного программирования — синхронизация. Это связано с тем, что обычно встроенное программное обеспечение много работает с событиями в реальном времени, строго синхронизированными протоколами для управления периферийным оборудованием и самой общей задачей (это также некоторые параллели на других платформах «высокого уровня», таких как многопоточные приложения).

Будьте готовы прочитать много таблиц данных при работе с новым оборудованием - я думаю, это может быть связано с частью вопроса «мышление» :) Конечно, потребуются некоторые знания в области EE и оборудования.

Также я хотел бы отметить, что в наши дни разработка встраиваемого программного обеспечения не требует языка ассемблера. На самом деле Java (кстати, это ООП по умолчанию) уже здесь и становится все сильнее (по крайней мере, для некоторого класса встраиваемых устройств, например устройств IoT, у него может быть очень светлое будущее).

С точки зрения опасений, те, которые связаны с (пере)распределением динамической памяти , как правило, являются большим препятствием для традиционного объектно-ориентированного программирования, чем синхронизация .
Возможно, вы правы. Но есть люди, которые программировали в 80-90-х годах для программного обеспечения реального режима MSDOS, с доступным 64K (сегмент памяти данных) ОЗУ, и для них это было «естественно». Возможно, MSDOS PC был более «встроенной» средой, чем сегодняшний STM32F4 :)
STM32F4 обычно имеет больше памяти для программ в виде флэш-памяти, но ПК обычно поставляется с гораздо большим объемом оперативной памяти для хранения изменяемых объектов времени выполнения. В то время как вся эта штука с дальним указателем, вызванная сегментированной адресацией, была проблемой, у обоих отсутствует настоящий MMU, и это будет еще более серьезной проблемой в системе с меньшим объемом оперативной памяти, которой является STM32F4. Кроме того, время безотказной работы ПК, как правило, было короче, а допустимая частота отказов выше.