Pętle w Arduino pozwalają wielokrotnie wykonywać ten sam fragment programu. Do wyboru są trzy podstawowe konstrukcje języka C++: for, while oraz do...while. Każda może doprowadzić do podobnego wyniku, ale różnią się sposobem określania liczby powtórzeń i momentem sprawdzania warunku.
Najprostsza zasada brzmi: użyj for, gdy znasz liczbę powtórzeń; while, gdy działanie ma trwać do spełnienia warunku; a do...while, gdy blok musi zostać wykonany przynajmniej raz. Poniższe porównanie pomoże wybrać właściwą pętlę i uniknąć blokowania programu.
Pętle w Arduino — którą wybrać?
| Sytuacja | Najlepszy wybór | Dlaczego? |
|---|---|---|
| Znasz liczbę powtórzeń | for | Licznik, warunek i jego zmiana znajdują się w jednym miejscu. |
| Nie znasz liczby powtórzeń, a warunek może od początku być fałszywy | while | Warunek jest sprawdzany przed pierwszym wykonaniem bloku. |
| Blok musi wykonać się co najmniej raz | do...while | Warunek jest sprawdzany dopiero na końcu. |
| Arduino ma jednocześnie reagować na przycisk, mierzyć czas i sterować wyjściami | loop() i millis() | Długa pętla oczekująca mogłaby zatrzymać pozostałe zadania. |
Szybka decyzja: znasz liczbę obiegów — wybierz
for. Nie znasz jej — sprawdź, czy kod ma wykonać się obowiązkowo jeden raz. Jeśli tak, wybierzdo...while; jeśli nie, wybierzwhile.
Czym różnią się for, while i do…while?
| Cecha | for | while | do...while |
|---|---|---|---|
| Typowe zastosowanie | Znana liczba powtórzeń | Powtarzanie zależne od warunku | Wykonanie przynajmniej raz |
| Sprawdzenie warunku | Przed każdym obiegiem | Przed każdym obiegiem | Po każdym obiegu |
| Minimalna liczba wykonań | 0 | 0 | 1 |
| Miejsce zmiany licznika | Zwykle w nagłówku | Wewnątrz bloku lub przed nim | Wewnątrz bloku lub przed nim |
| Średnik po warunku | Nie | Nie | Tak |
Wybór pętli wpływa przede wszystkim na czytelność kodu. W wielu przypadkach program można przepisać z jednej konstrukcji na inną bez zmiany rezultatu, ale warto wybrać zapis, który najlepiej pokazuje zamiar autora.
Ten sam przykład zapisany trzema sposobami
Każda z poniższych symulacji wypisuje w Monitorze portu szeregowego liczby od 0 do 10. Uruchom je kolejno i porównaj kod, sposób sterowania licznikiem oraz wynik działania.
Pętla for
To najbardziej naturalny zapis, ponieważ liczba obiegów jest znana. Deklaracja licznika, warunek i inkrementacja znajdują się w jednym nagłówku. Szczegółowe omówienie znajdziesz w lekcji pętla for w Arduino.
Pętla while
Pętla daje ten sam wynik, ale trzeba samodzielnie utworzyć licznik i pamiętać o jego zmianie. Gdyby zabrakło instrukcji i++, warunek pozostałby prawdziwy i program nie opuściłby pętli.
Pętla do…while
Ta symulacja również wypisze liczby od 0 do 10. Ponieważ warunek początkowy jest prawdziwy, rezultat wygląda podobnie jak dla while. Różnicę widać dopiero wtedy, gdy warunek jest fałszywy jeszcze przed pierwszym obiegiem.
while i do…while przy fałszywym warunku
Uruchom poniższą symulację. Zmienna i ma wartość 0, a sprawdzany warunek to i > 1. Pętla while nie wykona się ani razu, ponieważ najpierw sprawdza warunek. Pętla do...while najpierw wykona swój blok, dlatego pokaże jeden wynik mimo fałszywego warunku.
Kiedy używać pętli for?
for najlepiej sprawdza się, gdy przed rozpoczęciem pętli wiadomo, ile razy ma zostać wykonana. Typowe zastosowania w Arduino to:
- kolejne włączanie kilku diod LED,
- przeglądanie elementów tablicy,
- wykonywanie określonej liczby pomiarów,
- generowanie serii impulsów,
- wypełnianie lub zerowanie bufora danych.
Zmianę licznika zwykle realizują operatory ++ lub --. Jeżeli nie są jeszcze jasne, zobacz lekcję operatory inkrementacji i dekrementacji.
W C++ istnieje również skrócony zapis range-based for, który kolejno pobiera wartości z tablicy. Nadal jest to odmiana pętli for, a nie czwarty podstawowy rodzaj pętli.
Kiedy używać pętli while?
while wybierz wtedy, gdy liczba obiegów nie jest znana, ale można wskazać warunek kontynuowania. Może to być oczekiwanie na określony stan wejścia, przetwarzanie danych znajdujących się w buforze albo powtarzanie obliczeń do uzyskania oczekiwanego wyniku.
Warunek jest sprawdzany przed wejściem do bloku. Jeśli od początku ma wartość false, instrukcje wewnątrz pętli nie wykonają się ani razu. Więcej przykładów, w tym użycie break, continue i flag logicznych, zawiera lekcja pętla while i do…while w Arduino.
Kiedy używać pętli do…while?
do...while przydaje się, gdy operację trzeba wykonać przynajmniej jeden raz, zanim będzie można zdecydować o jej powtórzeniu. Przykładem jest pierwsze pobranie danych, próba nawiązania komunikacji albo wyświetlenie menu przed sprawdzeniem decyzji użytkownika.
Zapamiętaj: konstrukcja
do...whilekończy się średnikiem po nawiasie z warunkiem:} while (warunek);.
Funkcja loop() nie jest instrukcją pętli
W szkicu Arduino funkcja loop() jest automatycznie wywoływana ponownie po dojściu do końca. Nie jest jednak czwartym rodzajem pętli C++. To część mechanizmu środowiska Arduino, który w uproszczeniu wielokrotnie uruchamia zwykłą funkcję.
W wielu programach nie trzeba umieszczać w loop() dodatkowej nieskończonej pętli. Pozostawienie krótkiej, szybko kończącej się funkcji ułatwia równoległą obsługę przycisków, czujników, komunikacji i odmierzania czasu.
Ważne: długa pętla
whilemoże zatrzymać wykonywanie dalszych instrukcji wloop(). Jeżeli Arduino ma zajmować się kilkoma rzeczami naraz, zastosuj maszynę stanów i odmierzanie czasu opisane w poradniku Arduino millis() bez delay().
break, continue i pętle zagnieżdżone
Przerwanie pętli instrukcją break
Instrukcja break natychmiast kończy najbliższą pętlę. Jest przydatna, gdy podczas przeglądania danych znaleziono już szukany element albo wystąpił warunek wymagający wcześniejszego wyjścia.
Pominięcie obiegu instrukcją continue
continue pomija pozostałą część bieżącego obiegu i rozpoczyna następny. W pętli while trzeba uważać, aby przed wykonaniem continue została zmieniona wartość wpływająca na warunek. W przeciwnym razie łatwo utworzyć pętlę nieskończoną.
Pętle zagnieżdżone
Pętla może znajdować się wewnątrz innej pętli. Takie zagnieżdżenie wykorzystuje się między innymi przy obsłudze wierszy i kolumn matrycy LED. Trzeba jednak pamiętać, że liczba wykonań się mnoży: pętla wewnętrzna wykonana 10 razy w pętli zewnętrznej wykonywanej 20 razy da łącznie 200 obiegów.
Najczęstsze błędy w pętlach Arduino
- Brak zmiany warunku — pętla
whilenigdy się nie kończy, ponieważ licznik lub flaga pozostają bez zmian. - Średnik zaraz po warunku — zapis
while (warunek);tworzy pustą pętlę. - Przypisanie zamiast porównania —
if (stan = HIGH)przypisuje wartość; porównanie zapisuje się jakostan == HIGH. - Zły warunek graniczny — użycie
<=zamiast<może spowodować wyjście poza zakres tablicy. - Blokowanie programu — oczekiwanie w długiej pętli uniemożliwia normalne wykonywanie pozostałych zadań.
- Nadmierne zagnieżdżanie — kod staje się trudniejszy do zrozumienia, a liczba operacji szybko rośnie.
Podsumowanie wyboru pętli
Wybieraj for do pracy z licznikiem i znaną liczbą powtórzeń. Stosuj while, gdy dalsze działanie zależy od warunku sprawdzanego przed obiegiem. Sięgaj po do...while, jeśli blok musi wykonać się co najmniej raz. Jeżeli program ma stale obsługiwać wiele niezależnych zadań, nie zamykaj go w długiej pętli oczekującej — pozwól funkcji loop() wykonywać się szybko i steruj zadaniami za pomocą stanów oraz millis().
Najczęstsze pytania o pętle w Arduino
Która pętla jest najszybsza?
Przy równoważnych warunkach różnice wydajności między for i while zwykle nie mają praktycznego znaczenia. Kompilator często tworzy bardzo podobny kod wynikowy. Ważniejsze są czytelność programu i liczba operacji wykonywanych wewnątrz pętli.
Czy pętla while może zablokować Arduino?
Tak. Jeżeli warunek nigdy nie stanie się fałszywy, program nie wykona instrukcji umieszczonych za pętlą. Przerwania sprzętowe mogą nadal działać, ale zwykły kod znajdujący się dalej w loop() nie zostanie obsłużony.
Czy można umieścić pętlę for wewnątrz while?
Tak. Wszystkie rodzaje pętli można dowolnie zagnieżdżać. Instrukcja break zakończy wtedy tylko najbliższą pętlę, w której została wykonana.
Czy loop() zastępuje pętlę nieskończoną?
W typowym szkicu Arduino tak: środowisko ponownie wywołuje funkcję loop() po jej zakończeniu. Zwykle nie ma potrzeby dodawania wewnątrz niej konstrukcji while (true).
Następne kroki: przejdź do szczegółowych lekcji o pętli for oraz pętlach while i do…while, a następnie uruchom zawarte w nich przykłady.