Arduino while выход из цикла. Arduino циклы

Видео 14.04.2024

Рассмотрим, как работают операторы циклов for, while и do while в Arduino IDE, как правильно использовать циклы в скетчах и каких ошибок следует избегать. На простых примерах продемонстрируем, как можно остановить цикл или перейти из одного цикла в другой. Для того, чтобы разобраться в правильности написания циклов, прежде всего, следует изучить виды и свойства алгоритмов в робототехнике .

Как работают циклы в Arduino IDE

Любой цикл в C++ и языке программирования Ардуино представляет собой действие, которое повторяется множество или бесконечное количество раз. Ни одна программа для микроконтроллера Ардуино не обходится без цикла, например, void loop вызывается в бесконечном цикле. Операторы циклов бывают трех видов: for, while и do while — остановимся на каждом операторе, рассмотрим, как они работают на примерах.

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

Описание цикла for в Ардуино с примером

Конструкция for в Arduino задается следующим образом:

for (инициализация; условие; изменение){ }

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

for (byte i=0; i<=5; i++){ digitalWrite (13, HIGH ); delay (500); digitalWrite (13, LOW ); delay (500); }

В примере скетча задана переменная с начальным значением i=0 , в условии указано, что цикл будет выполняться до тех пор, пока переменная не станет равна или больше пяти i<=5 . В изменении указано, что переменная на каждом шаге цикла будет увеличиваться на единицу. В итоге, выход из цикла for произойдет, когда переменная станет равна пяти, поэтому светодиод пять раз моргнет, прежде чем цикл закончится.

Шаг переменной (изменение) может быть любым. Если необходимо увеличивать переменную сразу на две единицы, то изменение счетчика следует записать так: i=i+2 . Цикл for может использоваться внутри процедуры void setup, например, для указания режима работы сразу нескольким пинам. А также в процедуре void loop, например, в программе для последовательного включения светодиодов на Arduino.



Описание работы программы Arduino с циклами for и while

Описание цикла while Ардуино с примером

Конструкция while в Arduino задается следующим образом:

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

Цикл while будет выполняться непрерывно и бесконечно, пока условие в круглых скобках является истиной. Выход из цикла будет достигнут, когда изменится переменная в условии while, поэтому что-то должно изменять ее значение. Изменение переменной может происходить в программном коде внутри цикла или при считывания значений с любого датчика, например, с ультразвукового дальномера HC-SR04 .

byte i=0; // необходимо создать переменную до цикла while (i<5){ // цикл выполняется, пока i меньше 5 digitalWrite (13, HIGH ); delay (500); digitalWrite (13, LOW ); delay (500); i++; // изменение переменной }

При использовании функции while, переменную необходимо создавать до начала цикла. В примере скетча светодиод моргнет пять раз, прежде чем закончится цикл. Если не изменять переменную внутри фигурных скобок i++ , то цикл будет повторяться бесконечно. Второй способ сделать выход из цикла while Arduino Uno , это считывать данные с датчика и использовать условный оператор if для изменения переменной.

Еще один цикл, который можно использовать в Arduino IDE — это цикл с постусловием do … while . При использовании данной конструкции команды в цикле выполнятся минимум один раз, вне зависимости от условия, так как условие проверяется уже после выполнения тела цикла. В следующем примере кода, светодиод включится независимо от показаний датчика и только потом выполнится проверка постусловия.

int water; // создаем переменную до цикла do { digitalWrite (13, HIGH ); water = analogRead (AO); } while (water<5) // выполняем проверку датчика digitalWrite (13, LOW );

Как выйти из цикла while или for

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

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

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 являются одной из важнейших конструкций языка 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. Вы сможете встретить эти операторы практически в любом более-менее сложном скетче, потому что без циклов многие операции над данными были бы невозможны. Ничего сложного в синтаксисе циклов нет – вы без труда к ним привыкните и сможете активно использовать в своих проектах.

Сегодня будем изучать не менее важную часть языка программирования, как циклы. Зачем они нужны. Давайте например поставим себе цель. Нужно зажигать шесть светодиодов по очереди с периодом в 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; И это тоже будет работать, если после выполнения условие будет истинно. Для цикла не важно что происходит в теле, его интересует истинно ли условие или нет. Вот и все. В следующем уроке будем разбирать функции, зачем они нужны и попробуем написать свою.

Рекомендуем почитать

Наверх