• Шаг 4а. Если кнопка не была нажата ИЛИ если системное время не достигло значения переменной ignore
, вернуться к Шагу 1. Иначе…
Эти шаги можно скомбинировать в одной функции сравнения if
. Алгоритм выглядел бы так:
• Если (кнопка не нажата ИЛИ системное время меньше значения ignore
), вернуться к Шагу 0.
Но здесь есть проблема. Фраза «вернуться к» предполагает отсылку микроконтроллера к указанной части программы. Казалось бы, естественная команда, но когда вы программируете на языке С, следует избегать передачи управления из одной части программы в другую.
Причина в том, что обилие команд «перейти туда» или «перейти сюда» усложняет понимание программы – не только для других людей, но и для вас самих, когда вы взглянете на нее снова через полгода и не сможете вспомнить, что имелось в виду.
Концепция языка С заключается в том, что каждая часть программы содержится в отдельном блоке и программа запускает их при помощи вызовов по вашему запросу. Воспринимайте каждый блок команд как послушного слугу, который выполняет только одно дело: мытье посуды или вынос мусора. Когда требуется выполнить определенное задание, вы просто зовете слугу по имени.
Такие блоки обычно называются функциями, что немного сбивает с толку, потому что мы уже имели дело с функциями setup()
и loop()
. Фактически, вы можете написать собственную функцию, которая будет работать в целом по такому же принципу.
Я решил, что будет правильнее написать эту программу, выделив функцию проверки статуса в отдельную… хм… функцию. Я назвал ее checkbutton()
, но мог бы назвать как угодно, если только ее название уже не зарезервировано для другой цели.
Вы видите функцию checkbutton()
в нижней части листинга 5.3 с предшествующим ей словом void
, потому что эта функция не возвращает никакого значения в остальную часть программы.
Слова void checkbutton()
– это
• Ждет 50 мс, пока прекратится дребезг контактов.
• Ожидает, пока будет отпущена кнопка.
• Ждет еще 50 мс, пока прекратится дребезг контактов отпущенной кнопки.
• Ждет, пока кнопка будет нажата снова (другими словами, ожидает завершения отпущенного состояния).
• Сбрасывает переменную ignore
.
Когда микроконтроллер доходит до конца этой функции, куда он идет дальше? Все просто: он возвращается к строке, расположенной сразу за той, из которой была вызвана функция. Где она? Сразу под функцией сравнения, выше. Так и происходит вызов функции: вы просто указываете ее имя (включая круглые скобки, внутри которых иногда содержатся параметры, хотя в данном случае их нет).
Вы можете и должны создавать столько функций в программе, сколько пожелаете, используя каждую для выполнения отдельной задачи. Чтобы узнать об этом, рекомендую прочитать любые общие руководства по языку С. Документация к среде Arduino не описывает функции детально, потому что они сложны для понимания, когда речь заходит о передаче значений. Тем не менее, это основополагающая конструкция языка С.
Структура программы
Строка, которая начинается с if (millis() > ignore
, предназначена для того же, что и Шаг 4 в моем алгоритме, но теперь все работает по-другому. Вместо того чтобы решить, отправлять ли микроконтроллер обратно к началу программы, принимается решение, вызывать ли функцию checkbutton()
. Ранее я резюмировал ее логику так: «Если (кнопка не нажата ИЛИ системное время меньше значения ignore
), вернуться к Шагу 0». Пересмотренный вариант гласит: «Если превышен период игнорирования кнопки И кнопка нажата, перейти к функции к checkbutton()
».
После того как микроконтроллер выполнит это и вернется, он достигнет конца основной функции loop
, которая всегда повторяется автоматически.
На самом деле эта программа выполняет только одну задачу. Она выбирает случайные числа и отображает их в виде конфигурации точек снова и снова. Если кнопка нажата, то программа делает паузу и ждет, а когда кнопку нажмут снова, программа продолжает делать то, что делала раньше. Процедура проверки кнопки – всего лишь кратковременный перерыв.
Поэтому, естественная структура для этой программы – основной цикл, который выбирает и отображает цифры, и если кнопка нажата, микроконтроллер отправляется к функции checkbutton()
, а затем возвращается к основному циклу.
Документация среды Arduino ничего не говорит о структуре программы, потому что подразумевает наличие базовых знаний программирования. Поэтому среда Arduino просто требует указать обязательную функцию setup
, за которой следует функция loop
, и все.
Но как только программа увеличится в размере, вам обязательно понадобится разделить ее на подходящие функции, чтобы она не превращалась в запутанный «клубок» операторов. Стандартное руководство по языку С объяснит все более детально.