Структура программы на языке C++ для Arduino
Рассмотрим пример минимально возможной программы на C++ для Arduino, которая ничего не делает:
Разберёмся что здесь написано и почему это обязательно: почему нельзя обойтись просто пустым файлом.
Из чего состоит программа
Для начала стоит понять, что программу нельзя читать и писать как книгу: от корки до корки, сверху вниз, строку за строкой. Любая программа состоит из отдельных блоков. Начало блока кода в C/C++ обозначается левой фигурной скобкой < , его конец — правой фигурной скобкой >.
Блоки бывают разных видов и какой из них когда будет исполняться зависит от внешних условий. В примере минимальной программы вы можете видеть 2 блока. В этом примере блоки называются определением функции. Функция — это просто блок кода с заданным именем, которым кто-то затем может пользоваться из-вне.
В данном случае у нас 2 функции с именами setup и loop . Их присутствие обязательно в любой программе на C++ для Arduino. Они могут ничего и не делать, как в нашем случае, но должны быть написаны. Иначе на стадии компиляции вы получите ошибку.
Классика жанра: мигающий светодиод
Давайте теперь дополним нашу программу так, чтобы происходило хоть что-то. На Arduino, к 13-му пину подключён светодиод. Им можно управлять, чем мы и займёмся.
Скомпилируйте, загрузите программу. Вы увидите, что каждую секунду светодиод на плате помигивает. Разберёмся почему этот код приводит к ежесекундному миганию.
В наши ранее пустые функции мы добавили несколько выражений. Они были размещены между фигурными скобками функций setup и loop . В setup появилось одно выражение, а в loop сразу 4.
Каждое выражение — это приказ процессору сделать нечто. Выражения в рамках одного блока исполняются одно за другим, строго по порядку без всяких пауз и переключений. То есть, если мы говорим об одном конкретном блоке кода, его можно читать сверху вниз, чтобы понять что делается.
Теперь давайте поймём в каком порядке исполняются сами блоки, т.е. функции setup и loop . Не задумывайтесь пока что значат конкретные выражения, просто понаблюдайте за порядком.
Если пронумеровать выражения по порядку, как они исполняются, получится:
Ещё раз напомним, что не стоит пытаться воспринимать всю программу, читая сверху вниз. Сверху вниз читается только содержимое блоков. Мы вообще можем поменять порядок объявлений setup и loop .
Результат от этого не изменится ни на йоту: после компиляции вы получите абсолютно эквивалентный бинарный файл.
Что делают выражения
Теперь давайте попробуем понять почему написанная программа приводит в итоге к миганию светодиода.
Как известно, пины Arduino могут работать и как выходы и как входы. Когда мы хотим чем-то управлять, то есть выдавать сигнал, нам нужно перевести управляющий пин в состояние работы на выход. В нашем примере мы управляем светодиодом на 13-м пине, поэтому 13-й пин перед использованием нужно сделать выходом.
Это делается выражением в функции setup :
Выражения бывают разными: арифметическими, декларациями, определениями, условными и т.д. В данном случае мы в выражении осуществляем вызов функции. Помните? У нас есть свои функции setup и loop , которые вызываются чем-то, что мы назвали «нечто». Так вот теперь мы вызываем функции, которые уже написаны где-то.
Конкретно в нашем setup мы вызываем функцию с именем pinMode . Она устанавливает заданный по номеру пин в заданный режим: вход или выход. О каком пине и о каком режиме идёт речь указывается нами в круглых скобках, через запятую, сразу после имени функции. В нашем случае мы хотим, чтобы 13-й пин работал как выход. OUTPUT означает выход, INPUT — вход.
Уточняющие значения, такие как 13 и OUTPUT называются аргументами функции. Совершенно не обязательно, что у всех функций должно быть по 2 аргумента. Сколько у функции аргументов зависит от сути функции, от того как её написал автор. Могут быть функции с одним аргументом, тремя, двадцатью; функции могут быть без аргументов вовсе. Тогда для их вызова круглые скобка открывается и тут же закрывается:
На самом деле, вы могли заметить, наши функции setup и loop также не принимают никакие аргументы. И загадочное «нечто» точно так же вызывает их с пустыми скобками в нужный момент.
Вернёмся к нашему коду. Итак, поскольку мы планируем вечно мигать светодиодом, управляющий пин должен один раз быть сделан выходом и затем мы не хотим вспоминать об этом. Для этого идеологически и предназначена функция setup : настроить плату как нужно, чтобы затем с ней работать.
Перейдём к функции loop :
Она, как говорилось, вызывается сразу после setup . И вызывается снова и снова как только сама заканчивается. Функция loop называется основным циклом программы и идеологически предназначена для выполнения полезной работы. В нашем случае полезная работа — мигание светодиодом.
Пройдёмся по выражениям по порядку. Итак, первое выражение — это вызов встроенной функции digitalWrite . Она предназначена для подачи на заданный пин логического нуля ( LOW , 0 вольт) или логической единицы ( HIGH , 5 вольт) В функцию digitalWrite передаётся 2 аргумента: номер пина и логическое значение. В итоге, первым делом мы зажигаем светодиод на 13-м пине, подавая на него 5 вольт.
Как только это сделано процессор моментально приступает к следующему выражению. У нас это вызов функции delay . Функция delay — это, опять же, встроенная функция, которая заставляет процессор уснуть на определённое время. Она принимает всего один аргумент: время в миллисекундах, которое следует спать. В нашем случае это 100 мс.
Пока мы спим всё остаётся как есть, т.е. светодиод продолжает гореть. Как только 100 мс истекают, процессор просыпается и тут же переходит к следующему выражению. В нашем примере это снова вызов знакомой нам встроенной функции digitalWrite . Правда на этот раз вторым аргументом мы передаём значение LOW . То есть устанавливаем на 13-м пине логический ноль, то есть подаём 0 вольт, то есть гасим светодиод.
После того, как светодиод погашен мы приступаем к следующему выражению. И снова это вызов функции delay . На этот раз мы засыпаем на 900 мс.
Как только сон окончен, функция loop завершается. По факту завершения «нечто» тут же вызывает её ещё раз и всё происходит снова: светодиод поджигается, горит, гаснет, ждёт и т.д.