Arduino циклы. Циклы FOR и WHILE в Arduino Ардуино выход из цикла

Конструкция for используется для повторения блока операторов, заключенных в фигурные скобки. Счетчик приращений обычно используется для приращения и завершения цикла. Оператор for подходит для любых повторяющихся действий и часто используется в сочетании с массивами коллекций данных/выводов.

Заголовок цикла for состоит из трех частей:

for (initialization ; condition ; increment ) {операторы выполняющиеся в цикле}

Инициализация (Initialization) выполняется самой первой и один раз. Каждый раз в цикле проверяется условие (condition), если оно верно, выполняется блок операторов и приращение (increment), затем условие проверяется вновь. Когда логическое значение условия становится ложным, цикл завершается.

Пример
// Затемнение светодиода с использованием ШИМ-вывода int PWMpin = 10; // Светодиод последовательно с резистором 470 ом на 10 выводов void setup() { // настройка не нужна } void loop() { for (int i=0; i <= 255; i++){ analogWrite(PWMpin, i); delay(10); } }

Цикл for в Си гораздо более гибкий, чем циклы for в других языках программирования, например, в Бейсике. Любой из трех или все три элемента заголовка могут быть опущены, хотя точки с запятой обязательны. Также операторы для инициализации, условия и приращения цикла могут быть любым допустимым в Си операторами с независимыми переменными, и использовать любой тип данных Си, включая данные с плавающей точкой (floats). Эти необычные для цикла for типы операторов позволяют обеспечить программное решение некоторых нестандартных проблем.

Например, использование умножения в операторе счетчика цикла позволяет создавать логарифмическую прогрессию:

For(int x = 2; x < 100; x = x * 1.5){ println(x); }

Генерируется: 2,3,4,6,9,13,19,28,42,63,94

Другой пример, плавное уменьшение или увеличение уровня сигнала на светодиод с помощью одного цикла for :

Void loop() { int x = 1; for (int i = 0; i > -1; i = i + x){ analogWrite(PWMpin, i); if (i == 255) x = -1; // переключение управления на максимуме delay(10); } }

», мы узнали, как использовать цикл «for» для организации работы контроллера. Этот тип цикла используется повсеместно и с лихвой перекрывает «потребность в зацикленных операциях». Однако существует еще один тип цикла — «while». ничем не лучше, чем цикл for, просто он использует в работе другие принципы.

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

Продолжим работу со схемой, состоящую из 2-х светодиодов.

Кроме того, мы продолжим работать с кодом, который мы дорабатывали в 14 уроке.

Назад в прошлое: контроллер запрашивает у пользователя данные, ожидает ввода, а затем присваивает полученные значения переменным blinkNumberGreen и blinkNumberRed . Это позволяет пользователю управлять количество миганий каждого из 2-х светодиодов.

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

Давайте разбираться, как это работает:

int z = 1 ; // объявляем переменную и присваиваем ей значение 1

while (z <=10) { //запускаем цикл while

Serial . println (z ); //выводим текущее значение переменной z через последовательный порт

z = z +1 // увеличиваем значение переменной z на 1

} // завершаем цикл

Цикл while будет продолжать выполнять команды до тех пор, пока «условие», описанное в круглых скобках, истинно. В приведенном выше примере, цикл будет продолжать выполнять команды пока z меньше или равно 10. В теле цикла отрабатываются 2 команды:

  • Выведение значения переменной через последовательный порт;
  • Увеличение значение переменной на 1 (по-научному – инкрементирование).

Благодаря увеличению значения переменной, в конечном итоге, программа выйдет из цикла. Если, представить на секунду, что мы забыли указать эту строку или произойдёт, какой-то сбой, то программа благополучно зациклится (иными словами зависнет).

Цикл начинает свою работу с того, что проверяет истинность условия. Если, z меньше или равно 10, то программа отрабатывает цикл. Затем следует повторная проверка условия и т.д. Когда значение переменной достигнет z = 11 , условие больше не будет истинным. Программа не отработает цикл и перейдёт в следующую строку, идущую сразу после фигурной скобки цикла.

Достаточно теории, переходим к практике. Заменим циклы for в исходном коде, на циклы while.

Мигалка в исполнении цикла FOR:

for (int i = 1; i <= blinkNumberGreen; i++) // запускаем цикл for

{

Serial . print (» Зелёный мигнул «);

Serial.println (i);

digitalWrite (greenLed, HIGH); // включаем зелёный светодиод

delay (timeOnGreenLed); // ждём

digitalWrite (greenLed, LOW); // выключаем зелёный светодиод

delay (timeOffGreenLed); // ждём

}

Мигалка в исполнении цикла WHILE:

int i =1; //объявляем переменную и присваиваем ей значение 1

while (i <= blinkNumberGreen)

{ // запускаем цикл while

Serial.print (» Зелёный мигнул «);

Serial.println(i);

digitalWrite(greenLed,HIGH); // включаем зелёный светодиод

delay(timeOnGreenLed); // ждём

digitalWrite(greenLed,LOW); // выключаем зелёный светодиод

delay(timeOffGreenLed); // ждём

i = i +1 //увеличиваем значение переменной на 1

}

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

Циклы с использованием операторов for и while являются одной из важнейших конструкций языка C++, лежащего в основе Ардуино. Они встречаются абсолютно в каждом скечте, даже если вы не подозреваете об этом. В этой статье мы познакомимся поближе с циклами, узнаем, в чем отличие for от while, как можно упростить написание программы с их помощью и каких ошибок следует избегать.

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

Оператор WHILE используется в C++ и Ардуино для организации повтора одних и тех команд произвольное количества раз. По сравнению с FOR цикл WHILE выглядит проще, он обычно используется там, где нам не нужен подсчет числа итераций в переменной, а просто требуется повторять код, пока что-то не изменится, не наступит какие-то событие.

Синтаксис WHILE

while(<условие или список условий>)
{
<программный блок, который будет повторяться>
}

В качестве условий может использоваться любая конструкция языка, возвращающая логическое значение. Условиями могут быть операции сравнения, функции, константы, переменные. Как и при любых других логических операциях в Ардуино любое значение, кроме нуля будет восприниматься как истина (true), ноль – ложь (false).

// Бесконечный цикл while(true){ Serial.println("Waiting…"); } // Цикл, выполняющийся до изменения значения функции checkSignal() while(!checkSignal()){ Serial.println("Waiting…"); }

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

While(true) Serial.print("Waiting for interruption"); delay(1000);

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

Пример использования цикла while

Чаще всего while используется для ожидания какого-либо события. Например, готовности объекта Serial к работе.

Serial.begin(9600); while (!Serial) { ; // Для некоторых плат ардуино требуется ждать, пока не освободится последовательный порт }

Пример ожидания прихода символа от внешних устройств по UART:

While(Serial.available()){ int byteInput = Seria.read(); // Какие-то другие действия }

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

Цикл FOR в Ардуино

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

Синтаксис цикла FOR

Здесь конструкция будет немного сложнее:
for (<начальное значение счетчика>;<условие продолжения выполнения цикла>;<изменение значения счетчика на каждом шаге>){
<список_команд>
}

Самый простой пример:

For(int i=5;i<10;i++){ // Конструкция «3 в одном» pinMode(i, OUTPUT); }

Мы сразу создали переменную, инициализировали ее, указали, что в конце каждого цикла значение счетчика нужно увеличивать на единицу. И все – теперь можно использовать переменную внутри цикла.

Шаг переменной может быть иным. Вот примеры:

  • for(int i=0; i<10; i=i+2) // Шаг 2
  • for(int i=0; i<10; i+=2) // Аналогичен предыдущему
  • for(int i=10; i>0; i–) // Идем обратно – от 10 до 1

Цикл do while

В некоторых случаях нам нужно организовать цикл таким образом, чтобы инструкции блока выполнялись хотя бы один раз, а затем уже осуществлялась проверка. Для таких алгоритмов можно использовать конструкцию do while. Пример:

Do { Serial.println("Working"); } while (checkSomething());

Никаких сложностей этот вариант цикла не представляет – мы просто перенесли блок с условиями вниз, поэтому все содержимое внутри фигурных скобок после оператора do выполнится до первой проверки.

Операторы continue и break

Бывают ситуации, когда вам нужно экстренно прервать выполнение цикла внутри блока цикла, не дожидаясь до перехода к блоку проверки условий. Для этого можно использовать оператор break :

While (true) { if (checkSomething()) { break; } }

Если мы просто хотим остановить ход выполнения текущей итерации, но не выйти из цикла, а перейти к блоку проверки условий, то должны использовать оператор continue :

While (true) { if (checkSomething()) { continue; } }

Операторы continue и break могут использоваться со всеми вариантами циклов FOR и WHILE.

Вложенные циклы в Ардуино

Любые варианты циклов можно спокойно совмещать друг с другом, делая вложенные конструкции. Переменные, определенные в блоке «вышележащего» цикла будут доступны во внутреннем. Самый часто встречаемый пример такого рода циклов – обход двумерных массивов. В следующем примере мы используем двойной цикл: первый будет перебирать строчки (переменная i), второй, вложенный – столбцы (переменная j) массива, который мы определили в переменно arr.

Int arr; void setup() { for (int i = 0; i < 10; i++) { for (int j = 0; j < 3; j++) { arr[i][j] = i * j; Serial.println(arr[i][j]); } } }

Подробнее о циклах

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

Зачем нужен цикл

На самом деле, главная задача цикла – повторить одни и те же конструкции языка несколько раз. Такая потребность возникает практически в каждой программе и уж точно без цикла не обходится ни один скетч Ардуино – функция loop() тоже вызывается в бесконечном цикле.

Давайте рассмотрим следующий пример. Вам нужно подать питание одновременно на 5 светодиодов, подключенных к плате Arduino с 5 по 9 пины. Самым очевидным вариантом для этого будет размещение пяти инструкций подряд:

digitalWrite(5, HIGH);

digitalWrite(6, HIGH);

digitalWrite(7, HIGH);

digitalWrite(8, HIGH);

digitalWrite(9, HIGH);

Опустим пока вопрос рискованности такого действия, ведь одновременное включение такого числа светодиодов создает повышенную нагрузку на схему питания платы. Главное для нас сейчас то, что мы создали пять строк кода, каждая из которых отличается от других всего лишь на одну цифру. Такой подход имеет следующие недостатки:

  • При любом изменении придется вносить правки одновременно во множество строк. Например, если нам понадобится переключить светодиоды на пины со 2 по 6 или не включить, а выключить напряжение, то придется сделать 5 изменений в коде. А если инструкций и изменений будет больше?
  • Объемный код с большим количеством однотипных инструкций неудобно и неприятно читать. Пять одинаковых строчек – не сильно страшно. Но привычка к грязному коду со временем приведет к десяткам и сотням лишних страниц в листинге, что повергнет в уныние и вас, и ваших коллег.
  • В процессе «копипастинга» почти одинаковых инструкций можно легко совершить ошибку, например, забыв поменять номер пинов: digitalWrite(5, HIGH); digitalWrite(5, HIGH);
  • Вы с легкостью провалите собеседование в любую нормальную софтверную компанию, показав интервьюеру такой код.

Исходя из всего этого, можно сделать вывод, что повторное многократное использование одних и тех же строк почти всегда нужно избегать и заменять циклами. Более того, во многих ситуациях без циклов не обойтись в принципе, их ничем заменить не получится. Вы не сможете изменить количество повторений кода в момент выполнения программы. Например, вам нужно обработать каждый элемент массива данных , поступившего от внешних устройств. Вы никогда не предугадаете, сколько будет данных, сколько раз повторить обработку и поэтому не сможете вставить нужное количество инструкций в момент написания статьи.

И тут нам на помощь приходят циклы.

Правила синтаксиса

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

В нашем описанном выше примере мы могли бы сказать контроллеру следующее:

Повтори команду digitalWrite 5 раз

В идеальном мире с роботами-программистами этого бы, наверное, хватило, но так как мы разговариваем с компьютером на языке C++, нам нужно перевести эту фразу на этот язык:

Повтори команду – нужно использовать специальные инструкции, говорящие контроллеру, что сейчас начинается что-то интересное с циклами while или for

digitalWrite – оставляем как есть, но пишем один раз и заключаем в фигурные скобки. Как быть с номерами пинов – чуть ниже.

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

Давайте посмотрим на пример такой «переведенной» команды цикла с инструкцией while:

Int counter = 0; // Переменная, в которой будет храниться значение счетчика // Мы просим процессор повторять конструкцию в фигурных скобках до тех пор, пока условие в круглых скобках будет возвращать истину. // В нашем случае counter – наш счетчик, 5 – предельное значение, условие значение счетчика меньше 5. // Но мы можем указывать совершенно разные логические операторы while (counter < 5) { digitaWrite(5, HIGH); // Будем включать светодиод counter++; // Увеличиваем значение счетчика } // Дойдя до сюда, исполняющий процессор переместится в начало блока и опять займется проверкой условий. Если условия вернут истину, команды в блоке между { и } выполнятся еще раз. Если условие не выполнится - процессор переместится к концу блока и пойдет дальше. Этот цикл больше его не заинтересует.

Тем, кто заметил в приведенном коде ошибку, ставим пятерку и пишем блок цикла по-другому:

While (counter < 5) { // Вот теперь мы будем включать разные светодиоды, с 5 (0+5) по 9 (4+5) digitalWrite(counter + 5, HIGH); counter++; }

Такого же результата можно добиться с использованием цикла FOR:

For(int counter =0; counter<5; counter ++){ digitalWrite(counter+5, HIGH); }

Как видим, в данном случае мы сразу помещаем все необходимые операции со счетчиком в одну инструкцию FOR – это гораздо удобнее, если вам нужно подсчитывать нужное количество.

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

Заключение

В этой статье мы рассмотрели очень важные конструкции языка Ардуино: циклы FOR и WHILE. Вы сможете встретить эти операторы практически в любом более-менее сложном скетче, потому что без циклов многие операции над данными были бы невозможны. Ничего сложного в синтаксисе циклов нет – вы без труда к ним привыкните и сможете активно использовать в своих проектах.

Операторы if и else в Arduino используются для создания блоков условий в тексте программы. С их помощью можно создавать интеллектуальные системы, которые самостоятельно принимают решение о том, что должна делать программа в зависимости от текущих условий. В этой статье мы рассмотрим синтаксис if в ардуино, а также примеры применения условий в разных ситуациях.

if – это оператор языка C++, который активно используется и в Arduino. Для обозначения условий в ардуино используется такая конструкция:

If (условие) { // В этом блоке список команд, выполняющихся, если условие истино или имеет значение, отличное от 0 } else { // В этом блоке список команд, выполняющихся, если условие ложно или имеет значение, равное 0 }

Условие – это некоторое логическое выражение, возвращающее истину (TRUE) или ложь (FALSE) . В одном условии можно использовать несколько выражений, объединяя их специальными логическими операторами. Мы подробно рассмотрим эти операторы чуть позже. Примеры условий:

  • if(a) – вернет истину, если значение переменной a не равно 0 или FALSE
  • if(a==5 && b>5) – вернет истину, если значение a равно 5, а b больше 5.
  • if(!a) – вернет истину, если a сдержит 0 или FALSE.

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

if (условие )

// Команда

// Команда

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

if(условие )

// Команды

В следующих разделах мы познакомимся с конкретными примерами и рассмотрим варианты синтаксиса. Но сперва давайте немного поговорим о том, что же такое условия и для чего они нужны в Arduino. Если вы уже имели опыт написания программ, смело можете порпустить этот раздел.

Условия в тексте программы Arduino

Что такое условие

Представьте себя на минуту вежливым роботом, который очень любит вкусные апельсины. К вам могут подходить разные люди и дарить совершенно разные сладости, но вы должны оставлять себе только круглые предметы оранжевого цвета. Какой алгоритм вы бы выбрали для своей программы?

Самый простой вариант, приходящий в голову, выглядит так:

  1. Получить предмет из рук человека.
  2. Определить цвет.
  3. Если цвет оранжевый, то взять.
  4. Иначе (если цвет не оранжевый), то не брать, но сказать спасибо.

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

Как же теперь отразить эти условия в программе для ардуино?

Условие и ветвление в тексте программы

Если представить алгоритм действий как последовательность команд, то в момент возникновения условия нам надо как-то разделить эту одну последовательность на две. Конечно, в момент выполнения команд контроллер всегда выполняет только одну цепочку команд. Но вот какой именно программный блок выбрать – он определяет сам, исходя из каких-то данных, полученных из окружения: сигналов датчиков, значений переменных и т.д. Каждый раз при запуске программы внешние сигналы будут разные, поэтом и выбираемая последовательность будет отличаться.

Вариантов условий и наших ответных действий может быть множество и все они должны быть в тексте нашей программы. Мы должны придумать какой-то способ, чтобы пометить в этом тексте, какие команды в какой ситуации нужно выбрать.

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

На одном листе можно нарисовать множество веток и изобразить логику принятия решения. Но когда мы пишем программу в Arduino IDE, графического способа у нас нет. Разбить текст на несколько колонок мы тоже не можем. Единственный остающийся вариант – как-то пометить те или иные последовательности команд с помощью специальных конструкций. Именно для этих целей и служат блоки if и else.

С помощью if и else мы «разделяем» список команд на те, которые будут выполняться при одних условиях и те, которые будут выполнять при других. Мы разветвляем программу, именно поэтому блок условий часто называют реализацией ветвления.

Рассмотрим еще раз синтаксис и поясним значение каждого оператора:

if(условие){

  • if (условие) – здесь мы формулируем условие, которое при запуске программы может выполниться (тогда результат будет TRUE или любое число, не равное 0) или нет (тогда результат будет FALSE или 0).
  • В случае TRUE будут выполнены команды из первого блока в фигурных скобках.
  • Если условие вернет FALSE, то будет выполнен блок в фигурных скобках после слова else .

Давайте же рассмотрим примеры использования if else в реальном коде ардуино.

Примеры if и else в ардуино

Простой пример блока условия

Самый простой пример использования условий:

If(1){ Serial.println("True"); }else{ Serial.println("False"); }

В мониторе порта у нас появится надпись “True”, потому что условие всегда выдаст 1 и всегда будет выполняться только первый блок. Написав if(0), мы заставим постоянно выполняться второй блок после else.

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

Рассмотрим следующий пример, подставив вместо конкретной константы переменную. Ардуино определит значение переменой в блоке if и выберет первый или второй блок для продолжения работы.Бессмысленность та же, но уже используем переменную, значение которой можно легко менять.

Boolean b = true; if(b){ Serial.println("True"); }

Пример if с digitalRead

А вот теперь давайте рассмотрим первый осмысленный пример. Мы получим значение цифрового датчика и просигнализируем светодиодом, если digitalRead вернет значение высокого уровня сигнала.

If(digitalRead(10)){ digitalWrite(13, HIGH); }else{ digitalWrite(13, LOW); }

Заметьте, мы не знаем в момент написания кода, какой вариант будет выполнен – ведь значение датчика (или уровень шума) на входе могут быть совершенно разными. В момент выполнения кода только сам контроллер решит, какие команды будут выполнены, исходя из тех значений, которые будут на входе в тот момент.

Пример if с роботом

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

If (getOrange()) { Serial.println("Thank you! I like it!"); } else { Serial.println("Thank you! But I don’t like it!"); }

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

Пример if и сравнение диапазонов

Давайте рассмотрим пример if с функцией analogRead(). Мы получим значение с датчика и сравним его с некоторым пороговым значением.

if(analogRead(A0)>500){

Serial.println(“Ok!”);

Здесь ардуино в блоке if вызовет , получит значение сигнала на пине A0 и выберет первый или второй вариант действий в зависимости от значения. Для сравнения значения мы используем символ «>». Нам доступны и другие варианты:

  • «>» – вернет истину, если значение «больше».
  • «>-» – вернет истину, если значение «больше или равно указанному».
  • «<» – вернет истину, если значение меньше
  • «<=» – вернет истину, если значение меньше или равно
  • «!=» – вернет истину, если значение не равно указанном, т.е. больше или меньше

Логические операторы в условиях

В блоке условий можно вставлять несколько логических выражений. Например, для того, чтобы потребовать не только оранжевый, но и круглый объект, мы должны объединить два условия с помощью оператора «&&» (нужно указать именно два символа). Использование этого оператора определяет жесткие условия, когда для выполнения логического выражения нам нужно обязательно выполнить все внутренние выражения. Рассмотрим пример для нашего робота (считаем, что у нас есть функции isOrange() и isSphere()):

If(isOrange() && isSphere()){ Serial.println("Thank you! I like it!"); }

Список операторов условий:

  • && – условие И
  • || – условие ИЛИ
  • ! – отрицание условия

Более подробно логические условия рассмотрены в статье про логические операторы

Несколько связанных условий

Завершим наш рассказ об if в ардуино описанием ситуации, когда мы по-разному должны реагировать не на два, а на большее количество вариантов условий. Например, для робота ардуино с датчиком расстояния нужно выполнить такие условия:

  • Расстояние робота до препятствия больше 2 метров – едем на максимальной скорости
  • Расстояние робота до препятствия меньше 2 метров, но больше 1 метра – уменьшаем скорость
  • Расстояние робота до препятствий меньше1 метра – еще раз уменьшаем скорость.
  • Расстояние робота до препятствия меньше 20 см – останавливаемся и поворачиваем.

В Arduino такие множественные «подусловия» реализуются сочетанием оператора else и if. Давайте рассмотрим его на нашем примере. Пусть у нас определена функция getDistance(), возвращающая расстояние в сантиметрах. Тогда условие будет выглядеть так:

If (getDistance() > 200) { // Не сбавляем скорость, едем вперед } else if (getDistance() >= 100) { /* В этом условии мы поверяем, не больше ли значение 100. В принципе, 200 или 300 тоже больше 100, но первый блок выполнится первым, поэтому отработка при условии >200 уже будет выполнена. Если бы значение было больше 200, то до нашего блока управление просто не дошло. Поэтому в этом блоке мы будем рассматривать ситуацию, когда значение меньше 200, но больше 100. Робот уменьшит скорость – он почувствует, что скоро препятствие. */ } else if (getDistance() >= 20) { /* Расстояние меньше метра (если больше – мы бы попали в предыдущий блок), но еще больше 20. Притормозим, готовясь к препятствию. */ } else { /* А вот теперь уже все понятно. Расстояние меньше 20 (иначе все верхние блоки сработали бы). Поэтому смело считаем, что перед нами препятствие и поворачиваем. */ }

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

Заключение

Условия в любом языке программирования имеют крайне важное значение. Ни одна серьезная программа на ардуино не обходится без условий if else. Именно в блоках условий проявляется интеллект робота, автоматического устройства и программиста, который его программирует. Именно в условиях отрабатываются все тонкости алгоритмов и именно там спрятаны боьшинство логических ошибок алгоритмов. Обязательно постарайтесь понять и отработать навыки работы с блоком if на реальных примерах. И обращайтесь к учебникам, если останутся какие-то неясности и непонимания.

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

Arduino IDE позаимствовал с C/C++ большинство необходимых элементов управления. Их синтаксис идентичен с C. Ниже мы в двух словах опишем их синтаксис.

Оператор if

Оператор if позволяет выполнить определенный фрагмент программы в зависимости от результата проверки определенного условия. Если условие выполняется, то код программы будет выполнен, если же условие не выполняется, то код программы будет пропущен. Синтаксис команды if выглядит следующим образом:

If(условие) { инструкция1; инструкция2; }

Условием может быть любое сравнение переменной или значения, возвращаемое функцией. Основным критерием условия if является то, что ответ всегда должен быть или истина (true) или ложь (false). Примеры условий для оператора if:

If(a!=2) { } if(x<10) { } if(znak==’B’) { }

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

Люди, которые приступают к изучению программирования, часто делают ошибку, приравнивая значение указанной переменной с помощью одного знака «=». Такая запись однозначно указывает на присвоение значения переменно, и, следовательно, условие всегда будет «true», то есть выполняться. Проверка того, что переменная равна определенному значению, всегда обозначается двойным знаком равно (==).

В качестве условия можно использовать состояние функции, например:

If(init()) { Serial.print(«ок»); }

Приведенный выше пример будет выполнен следующим образом: на первом этапе вызывается функция init(). Эта функция возвращает значение, которое будет интерпретировано как «true» или «false». В зависимости от результата сравнения будет отправлен текст «ок» или ничего не будет отправлено.

Оператор if…else

Расширенным оператором if является оператор if….else. Он обеспечивает выполнение одного фрагмента кода, когда условие выполняется (true), и выполнение второй фрагмент кода, если условие не выполняется (false). Синтаксис операторf if….else выглядит следующим образом:

If (условие) { // команда A } else { // команда B }

Команды «A» будут выполняться только в том случае, если условие выполнено, команда «B» будет выполняться, когда условие не выполнено. Одновременное выполнение команды «A» и «B» невозможно. Следующий пример показывает, как использовать синтаксис if…else:

If (init()) { Serial.print(«ок»); } else { Serial.print(«ошибка»); }

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

Обычной практикой является отрицание условия. Это связано с тем, что функция, которая выполнена правильно возвращает значение 0, а функция, которая отработала неверно по какой-то причине, возвращает ненулевое значение.

Объяснение такого «усложнения жизни» — просто. Если функция выполнена правильно, то это единственная информация, которая нам нужна. В случае же ошибки, стоит иногда понять, что пошло не так, почему функция не выполнена правильно. И здесь на помощь приходят числа, отличающиеся от нуля, т. е. с помощью цифровых кодов мы можем определить тип ошибки. Например, 1 — проблема с чтением какого-то значения, 2 — нет места в памяти или на диске и т. д.

В последнем измененном примере показано, как вызвать функцию, которая возвращает ноль при правильном выполнении:

If (!init()) { Serial.print(«ок»); } else { Serial.print(«ошибка»); }

Оператор switch case

Оператор if позволяет проверить только одно условие. Иногда необходимо выполнить одно из действий в зависимости от возвращаемого или прочитанного значения. Для этого идеально подходит оператор множественного выбора switch. Ниже показан синтаксис команды switch:

Switch (var) { case 1: //инструкция для var=1 break; case 2: // инструкция для var=2 break; default: // инструкция по умолчанию (если var отличается от 1 и 2) }

В зависимости от значения переменной var выполняются инструкции в определенных блоках. Метка case означает начало блока для указанного значения. Например, case 1: означает, что данный блок будет выполнен для значения переменной var, равной один.

Каждый блок должен быть завершен с помощью команды break. Он прерывает дальнейшее выполнение оператора switch. Если команду break пропустить, то инструкции будут выполняться и в последующих блоках до команды break. Метка default не является обязательной, как и else в команде if. Инструкции, расположенные в блоке default выполняются только тогда, когда значение переменной var не подходит ни к одному шаблону.

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

Switch (x) { case 1: //инструкция для x=1 break; case 2: case 3: case 5: // инструкция для x=2 или 3 или 4 break; case 4: // инструкция для x=4 break; case 6: // инструкция для x=6 break; default: // инструкция по умолчанию (если х отличается от 1,2,3,4,5,6) }

В зависимости от значения переменной x будет выполнен соответствующий блок инструкций. Повторение case 2: case 3: case 5: информирует компилятор о том, что если переменная x имеет значение 2 или 3 или 5, то будет выполнен один и тот же фрагмент кода.

Оператор for

Оператор for используется для многократного выполнения одного и того же кода. Часто необходимо выполнить одни и те же инструкции, изменив только значение какой-то переменной. Для этого идеально подходит цикл for. Синтаксис команды выглядит следующим образом:

Int i; for(i=0;i<10;i++) { // инструкции для выполнения в цикле }

Первый параметр, приводимый в инструкции for — начальное значение переменной. Еще один элемент — это проверка условия о продолжении выполнения цикла. Цикл выполняется до тех пор, пока выполняется условие. Последний элемент — это изменение значения переменной. Чаще всего мы увеличиваем или уменьшаем ее значение (по необходимости). В этом примере, инструкции, содержащиеся в цикле будут выполняться при i=0…9.

Часто переменная, используемая в цикле объявляется там же:

For(int i=0;i<10;i++) { // инструкции для выполнения в цикле }

Переменная, которая используется для подсчета последующих шагов цикла, может использоваться внутри нее для вызова функции с соответствующими параметрами.

For(int i=10;i>0;i—) { Serial.print(i); // отправятся номера 10,9,8,7,6,5,4,3,2,1 }

Оператор while

Цикл for идеально подходит там, где мы хотим выполнить подсчет. В ситуации, когда необходимо выполнить определенные действия в результате какого-то события, которое не обязательно является предсказуемым (например, мы ждем нажатия кнопки), то мы можем использовать оператор while, который выполняет блок оператора до тех пор, пока выполняется условие. Синтаксис оператора while выглядит следующим образом:

While(условие) { // блок инструкций для выполнения }

Важно, чтобы проверка состояния происходила в начале цикла. Может случиться так, что инструкции внутри цикла while не исполняться никогда. Кроме того, возможно создание бесконечного цикла. Давайте посмотрим два примера:

Int x=2; while(x>5) { Serial.print(x); } —————————————- int y=5; while(y>0) { Serial.print(y); }

Первый блок операторов, расположенный внутри while не выполнится никогда. Переменная x имеет значение два и она не станет больше 5. Во втором примере мы имеем дело с бесконечным циклом. Переменная «y» имеет занчение 5, т. е. больше нуля. Внутри цикла не происходит никакого изменения переменной «y», поэтому цикл никогда не будет завершен.

Это распространенная ошибка, когда мы забываем об изменении параметра, вызывающего прекращение цикла. Ниже приведено два правильных примера применения цикла while:

Int x=0; while(x<10) { //блок инструкций x++; } —————————————- while(true) { if(условие) break; // блок инструкций }

В первом примере мы позаботились об изменении значения переменной, которая проверяется в условии. В результате цикл когда-нибудь завершится. Во втором примере был преднамеренно создан бесконечный цикл. Этот цикл эквивалентен функции loop () в Arduino IDE. Кроме того, внутри цикла введена проверка условия, после выполнения которого цикл завершается командой break.

Оператор do…while

Разновидностью цикла while является цикл do…while. Кроме синтаксиса он отличается местом проверки условия. В случае do…while проверка условия производится после выполнения блока инструкций. Это означает, что блок инструкций в теле цикла выполнится хотя бы один раз. Ниже приведен синтаксис команды do…while:

Do { // блок инструкций } while(условие)

Все, что написано об операторе while относится также и к do…while. Ниже приведен пример использования цикла do…while:

Int x=10; do { // блок инструкций x—; } while(x>0); —————————————- do { // блок инструкций if(условие) break; } while(true);

Оператор break

Оператор break позволяет выйти из цикла (do…while, for, while) и выйти из опции switch. В следующем примере рассмотрим выполнение команды break:

For(i=0;i<10;i++) { if(i==5) break; Serial.print(i); }

Цикл должен быть исполнен для чисел от 0 до 9, но для числа 5 выполняется условие, которое запускает оператор break. Это приведет к выходу из цикла. В результате в последовательный порт (Serial.print) будет отправлены только числа 0,1,2,3,4.

Оператор continue

Оператор continue вызывает прекращение выполнения инструкций цикла (do…while, for, while) для текущего значения и переход к выполнению следующего шага цикла. В следующем примере показано, как работает оператор continue:

For(i=0;i<10;i++) { if(i==5) continue; Serial.print(i); }

Как не трудно заметить, цикл будет выполнен для значения от 0 до 9. Для значения 5 исполнится команда continue, в результате чего инструкции, находящиеся после этой команды выполнены не будут. В результате в последовательный порт (Serial.print) будут отправлены числа 0,1,2,3,4,6,7,8,9.

Оператор return

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

Int checkSensor(){ if (analogRead(0) > 400) { // чтение аналогового входа return 1; // Для значений больше 400 возвращается 1 else{ return 0; // для других возвращается 0 } }

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

Void имя_функции() { инструкция1; if(x==0) return; инструкция2; инструкция3; }

В приведенном выше примере инструкция1 будет выполнять всегда, когда вызывается функция. Выполнение же инструкция2 и инструкция3 зависит от результата команды if. Если условие будет выполнено (true), то будет выполнена команда return и функция завершит работу.

В случае, когда условие не выполнено команда return так же не выполняется, а выполняются инструкции инструкция2 и инструкция3, и после этого функция завершает свою работу.

Оператор goto

Из идеологических соображений необходимо пропустить это описание… Оператор goto является командой, которую не следует использовать в обычном программировании. Он вызывает усложнения кода и является плохой привычкой в программировании. Настоятельно рекомендуем не использовать эту команду в своих программах. Из-за того, что goto есть в официальной документации на сайте arduino.cc приведем его краткое описание. Синтаксис команды goto:

…. goto metka; // перейдите на строку с надписью ‘metka’ ….. …. …. metka: // метка, с которой программа продолжит работу …

Команда позволяет переход к обозначенной метке, т. е. к месту в программе.