Контакти

Arduino оператори. Arduino цикли. Декілька пов'язаних умов

Цикли з використанням операторів 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

У деяких випадках нам потрібно організувати цикл таким чином, щоб інструкції блоку виконувалися хоча б один раз, а потім уже здійснювалася перевірка. Для таких алгоритмів можна використовувати конструкцію dowhile. Приклад:

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

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

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;

Залежно від значення змінної 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

Цикл для ідеально підходить там, де ми хочемо виконати підрахунок. У ситуації, коли необхідно виконати певні дії в результаті якоїсь події, яка не обов'язково є передбачуваною (наприклад, ми чекаємо натискання кнопки), ми можемо використовувати оператор 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: // мітка, з якою програма продовжить роботу.

Команда дозволяє перехід до позначеної мітки, тобто до місця у програмі.

Сьогодні вивчатимемо не менш важливу частину мови програмування, як цикли. Навіщо вони потрібні? Наприклад, поставимо собі за мету. Потрібно запалювати шість світлодіодів по черзі з періодом 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); (4, LOW); delay(50); digitalWrite(5, LOW); delay(50); digitalWrite(6, 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;І це теж працюватиме, якщо після виконання умова буде істинною. Для циклу не важливо, що відбувається в тілі, його цікавить чи справді умова чи ні. От і все. У наступному уроці розбиратимемо функції, навіщо вони потрібні і спробуємо написати свою.

/ /

Оператор For

Конструкція 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використовується для повторення блоку операторів, укладених у фігурні дужки. Лічильник збільшення зазвичай використовується для збільшення і завершення циклу. Оператор 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); ) )



Сподобалася стаття? Поділіться їй