Телевизоры. Приставки. Проекторы и аксессуары. Технологии. Цифровое ТВ

Циклы FOR и WHILE в Arduino. Arduino — управляющие операторы Подробнее о циклах

Сегодня будем изучать не менее важную часть языка программирования, как циклы. Зачем они нужны. Давайте например поставим себе цель. Нужно зажигать шесть светодиодов по очереди с периодом в 50 мс, а потом по очереди их гасить с тем же интервалом. Ну что может быть проще. Пишем следующий код:
void setup() { pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); pinMode(6, OUTPUT); pinMode(7, OUTPUT); } void loop() { digitalWrite(2, HIGH); delay(50); digitalWrite(3, HIGH); delay(50); digitalWrite(4, HIGH); delay(50); digitalWrite(5, HIGH); delay(50); digitalWrite(6, HIGH); delay(50); digitalWrite(7, HIGH); delay(50); digitalWrite(2, LOW); delay(50); digitalWrite(3, LOW); delay(50); digitalWrite(4, LOW); delay(50); digitalWrite(5, LOW); delay(50); digitalWrite(6, LOW); delay(50); digitalWrite(7, LOW); delay(50); } Сначала мы про инициализировали шесть цифровых выводов со второго по седьмой как выходы, а в основной программе написали поочередно включение светодиода, задержка и так шесть раз. После тоже самое но каждый раз выключали светодиод. Теперь заливаем в Arduino и радуемся работой. Но все таки тут что-то не так. Если внимательно взглянуть на код программы, то можно заметить что есть части кода которые повторяются на протяжении всей программы. Например должно сразу бросится в глаза повторение паузы. А при инициализации выводов меняется только его номер. При включении и выключении тоже меняется только номер. Для такой маленькой программы конечно можно и так оставить, контроллер сожрет это и не поперхнется, а вот если нужно выполнить повторяющийся код, ну например 1000 раз. Я думаю терпения набивать его хватит, а вот хватит ли памяти у МК? Конечно можно спросить, а на кой фиг нам 1000 одинаковых операций? Ну да, тяжело представить.) Но вот не задача, а если у нас есть массив на 1000 ячеек. Такое часто бывает, например несколько датчиков записывают параметры в массив и как скажете разбираться в этом бардаке. Надо бы как-нибудь разобрать его по каким-либо параметрам. Вот для таких казусов и придумали циклы. Цикл - это некая часть кода которая выполняется определенное количество раз. Одна выполненная часть программы в цикле называется итерация. Количество итераций может быть от 0 до бесконечности. Для выполнения циклов в языке программирования предусмотрено аж три варианта цикла. Поверьте, но этого хватает за глаза на любой изощренный кодинг. Давай те ка это все рассмотрим по подробнее.
  • while(условие) {}
  • do {} while(условие);
  • for(счетная переменная; условие; увеличение счетной переменной) {}
Первый цикл while(условие) {} . Как он работает. После слова while в скобках должно быть условие. Условие может быть любы, лишь бы было истинным. Как только условие станет ложным, цикл прекратит свою работу и программа продолжит работать со следующей строки после цикла. Давайте на примере.
char i = 0; while(i Собственно что тут у нас написано. Сначала мы инициализируем счетную переменную i и обнуляем ее. Далее заходим в цикл и начинаем проверять условие в скобках. Если значение i меньше чем 10, то выполнить тело цикла. В самом теле цикла просто увеличиваем значение счетной переменной на единицу и снова проверяем условие. В нашем случае цикл будет выполнятся 10 раз. То есть сначала значение i равно нулю. Ноль меньше чем десять. Далее увеличили переменную на единицу и сравнили, единица меньше чем десять и так далее. Как только счетная переменная станет равна десяти, то проверяем, десять меньше чем десять? Конечно нет и после проверки цикл прекратит работу. Вот так работает этот цикл. А что делать если нужно по любому один раз выполнить код в теле цикла, даже если он не устраивает условие. Для этого есть друго цикл, под названием do {} while(условие) . Работает он точно также как и предыдущий цикл, за исключением одного но. В этом цикле сначало выполняется тело цикла, а затем происходит проверка. Давайте посмотрим как это выглядит в коде.
char i = 0; do { i++; } while((i > 0) & (i Смотрите как интересно. Сначала мы как и в прошлый раз инициализируем счетную переменную нулем, но в условии записали чтобы i было больше нуля и меньше десяти. То есть значение переменной должно лежать в диапазоне от единицы до девяти. Если бы мы так написали с применением предыдущего цикла, то он не разу бы не выполнился. Но у нас есть волшебное слово do . То есть что произойдет. Сначала в теле цикла значение счетной переменной увеличится и станет единицей, а это больше чем ноль, условие станет истинно. соответственно цикл будет продолжать выполнятся пока счетная переменная не станет равна десяти. И на по следок третий вариант цикла. Как он работает:
char i; for(i = 0; i Как это работает. Сначала опять инициируем счетную переменную, но уже без конкретного значения. Далее пишем слово for , а вот в скобках пишем сначала нашу счетную переменную и присваиваем ей начальное значение. Затем проверяем условие и если оно истинно, то выполняем тело цикла и увеличиваем значение счетной переменной. По сути это тоже самое что и while() {} поэтому какой цикл использовать это уже на ваше усмотрение. Пару слов о некоторых моментах. Если например написать while(1); , то цикл будет выполнятся вечно. Или если с for , то это будет выглядеть так for(;;); . Будте внимательны. Иногда при выполнении цикла ну просто очень хочется все бросить и выйти из него, а условие не позволяет. Как быть? Для этого есть еще одна команда break; . Как только в теле цикла МК наткнется на эту команду, он тут же выйдет из цикла и продолжит выполнение программы со следующей строки после цикла. А вот если у нас при работе цикла возникает условие не удовлетворяющие условие или к примеру момент при котором нам не нужно продолжать выполнять конец тела цикла? Тут нам поможет команда continue; . Как только МК наткнется на эту команду, он брасает все и переходит к выполнению следующей итерации цикла. Надеюсь я все понятно объяснил. Теперь получив данные знания, давайте перепишем нашу программу, но уже используя циклы.
void setup() { byte i = 2; // Счетная переменная while(i // Если i меньше 8, то выполняем тело цикла { pinMode(i, OUTPUT); // Инициализация выводов начиная с 2 i++; // Увеличиваем счетную переменную на единицу } } void loop() { byte i = 2; while(i Давайте рассмотрим по ближе. Сначала мы инициализировали счетную переменную i и присвоили ей значение два. Почему два? А потому что я специально выбрал пины со второго по седьмой, дабы убедится что начальное значение не имеет ни какого значения. Каламбур какой-то получился) Ну понятно, да. Далее пишем условие цикла. Нам нужно сделать шесть итераций, так как у нас шесть светодиодов. Замечательно, считаем два плюс шесть будет восемь. Ага, значит нам нужно проверять счетную переменную до тех пор пока она будет меньше восьми. Так и написали while(i . Теперь у нас цикл отработает шесть раз. Что нам нужно сделать внутри тела цикла. Да ничего сложного, просто вписать функцию инициализации вывода на выход, только вместо номера вывода подставить счетную переменную. В чем фокус. Как только МК зайдет в тело цикла, он перед тем как выполнять функцию инициализации вывода, посмотрим на передаваемые аргументы. Один из них должен нести в себе номер вывода, а у нас там счетная переменная. Что делать? А ничего, умный МК посмотрит что там переменная и гордо вытянет из нее число. А у нас там двойка. Ну и замечательно, про инициализируем второй вывод. После увеличим значение счетной переменной еще на единицу и проверим условие. Ага, три меньше восьми, давайте ка все снова и по хорошему, только в переменной теперь три. Значит инициализировать вывод будем уже третий, а затем увеличим счетную переменную на единицу. Вот таким образом перебирая цикл мы настроим все нужные нам выводы. Причем увеличение на единицу счетную переменную это не жесткое условие. Никто не мешает написать например так: i = ((127*i)/31) & 0xF4; И это тоже будет работать, если после выполнения условие будет истинно. Для цикла не важно что происходит в теле, его интересует истинно ли условие или нет. Вот и все. В следующем уроке будем разбирать функции, зачем они нужны и попробуем написать свою.

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

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: // метка, с которой программа продолжит работу …

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

», мы узнали, как использовать цикл «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

}

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

Доброе время суток. Перед вами, дорогие читатели, третий урок посвященный программированию Arduino.

  • познакомились с устройством монтажной платы;
  • собрали «в железе» и прошили нашу первую схему.

Сегодня мы соберём схему, в которой будет использовано два цифровых выхода платы Arduino Uno. Соответственно нам понадобится 2 светодиода разных цветов (для наглядности), 2 резистора, джамперы и всё та же монтажная плата (или то на чём вы раньше проводили монтаж). В одной из схем будем включать красный светодиод, а во второй – белый.

Преступаем к сборке «самоделки » согласно следующей схеме. Советую использовать в своих проектах программу «Fritzing». С её помощью можно планировать разводку схем до момента непосредственного монтажа.

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

Открываем программную среду arduino IDE.

Набираем программу.

Загружаем её – смотрим на результат. Красный и белый светодиоды мигают по очереди.

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

Представим, что мы только что написали системы управления электрическим двигателем. Забудем о том, что подпрограмма может молотить вечно. Наш движок включился и выключился. Цикл вкл./выкл. запускается по нажатию «мифической кнопки».

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

Копируем блок из 4 строчек (включение выключение белого светодиода) 9 раз – в итоге получаем 10 циклов вкл./выкл. Добавим еще «второй движок» — красный светодиод он будет вкл/выкл всего один раз.

Загружаем программу – смотрим на результат.

Все получилось, но вот в чём проблема, а если потребность в прогонке вкл/выкл возрастет до 100 или до 1000, что опять будем всё копировать? Как-то не хочется… Так стоп! Мы с вами изучали . Пора применить знания на практике. Для нашей задачи отлично подойдёт цикл с заданным числом повторений – цикл for. Для того, чтобы не нагружать программу глобальными переменными, объявим локальную переменную «счётчика выполнения цикла» в заголовке цикла.

Операторы 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 на реальных примерах. И обращайтесь к учебникам, если останутся какие-то неясности и непонимания.



Похожие публикации