I_R_W15_M03 Przykładowe projekty
Budowa sygnalizacji świetlnej
Układ, który zbudujemy oraz oprogramujemy będzie realizować następujący scenariusz:
Pojazdy mają zielone światło. Pieszy, który stoi na czerwonym świetle, naciska przycisk, aby zmienić je na zielone.
Światło dla pojazdów zmienia się na żółte. Kierowcy są w ten sposób informowani, że należy się zatrzymać, ponieważ za chwilę światło będzie czerwone.
Światło dla pojazdów zmienia się na czerwone; piesi mają światło zielone.
Światło zielone dla pieszych zaczyna migać. Pojazdy nadal mają czerwone światło.
Światło dla pieszych zmienia się na czerwone. Z kolei kierowcy widzą palące się równocześnie światła czerwone i żółte.
Po osiągnięciu punktu 5. wracamy do stanu sygnalizacji opisanego w punkcie 1.
Elementy potrzebne do budowy
płytka Arduino Uno
płytka stykowa
kabel USB typu A‑B
czerwone diody LED (2 sztuki)
żółta dioda LED
zielone diody LED (2 sztuki)
włącznik zwierny
rezystory 220 omega (5 sztuk)
rezystor 10 komega
przewody i zworki połączeniowe
Zacznijmy od umieszczenia na płytce prototypowej trzech diod LED symbolizujących światła dla samochodów oraz dwóch odpowiadających światłom dla pieszych. Załóżmy, że diody, które będą stanowiły sygnalizator dla pojazdów, podłączymy do pinów 8., 9. i 10., natomiast diody dla pieszych podepniemy do pinów 6. i 7. Oczywiście możesz wybrać inne piny, jednak musisz zmodyfikować wówczas kod szkicu, który przedstawimy niżej.

Połączmy diody zgodnie ze schematem.
1. Łączymy masę (GND) z płytki Arduino z ujemną szyną płytki stykowej.

2. Łączymy piny 8., 9. i 10. z płytką stykową. Numery wierszy na płytce prototypowej nie mają znaczenia (możesz wybrać inne niż pokazano na zdjęciu). Warto natomiast używać kolorowych przewodów – na początku pracy z płytką Arduino bardzo ułatwia to konstruowanie i oprogramowywanie układów.

Wpinamy rezystory 220 omega. Jedną nóżkę każdego z nich umieszczamy w szynie danych, do której podłączyliśmy już przewód, a drugą wpinamy do drugiej szyny danych.

4. Wpinamy do płytki stykowej diody LED. Pamiętajmy, aby anoda znajdowała się od strony rezystora, a katoda miała kontakt elektryczny z szyną masy.

Część układu symulująca światła dla pojazdów jest gotowa. Pora na światła dla pieszych. Łączymy przewodami pin 6. i 7. z płytką stykową.

Wpinamy do płytki stykowej rezystory 220 omega oraz dwie diody LED. Postępujemy tak samo jak w poprzednich punktach.

Sygnalizatory są podłączone. Brakuje jeszcze jednego elementu – przycisku, dzięki któremu piesi będą mogli włączać zielone światło. Zastosujemy włącznik chwilowywłącznik chwilowy, zwany również przyciskiem RESET.

Naciśnięcie przycisku chwilowego, powoduje zwarcie styków 2–3 oraz 1–4 i przepływ prądu. Styki 1–2 oraz 3–4 są natomiast zawsze zwarte. Możesz jednak spotkać się również z przyciskiem rozwiernym – w jego przypadku styki są zawsze zwarte, a naciśnięcie powoduje ich rozwarcie.
Narysujmy na schemacie przycisk, który posłuży do sterowania światłami. Zwróć uwagę na linię reprezentującą przewód łączący wyprowadzenie napięcia 5 V z pinem 2. W miejscach, w których linia ta przecina się z innymi liniami, pojawia się zaokrąglenie. Nie oznacza to, że zastosowaliśmy specjalny przewód albo że go wygięliśmy. Jest to po prostu informacja, że między przecinającymi się na schemacie liniami nie ma kontaktu elektrycznego.

Łączymy pin 2. z płytką stykową – styk przewodu wkładamy w otwór szyny danych.
8. Podłączamy zasilanie do tej samej kolumny, do której jest podpięty pin 2. Następnie, zachowując jeden wiersz przerwy (nóżki włącznika są szeroko rozstawione, co zobaczysz za chwilę), wpinamy styk przewodu. Drugi przewód umieszczamy w wyprowadzeniu napięcia 5 V na płytce Arduino Uno.

Wpinamy włącznik chwilowy pionowo: powinien się on znaleźć na środku płytki. W poziomie natomiast nóżki powinny być w tych samych wierszach, w których podłączono wcześniej przewody.

10. Podłączamy rezystor 10 komega do masy, wpinając go w tym samym wierszu, w którym znajduje się przycisk RESET. Rezystor ten służy do utrzymania na pinie numer 2 stanu niskiego. Bez tego połączenia na pinie 2. mogłoby pojawić się przypadkowe napięcie. W rezultacie bez wciskania przycisku zostałaby wykonana sekwencja poleceń odpowiadająca za włączenie zielonego światła dla pieszych.

Wydaje się, że rezystor jest źle podłączony, ponieważ powinien być wpięty w szynę, w której znajduje się przewód niebieski (biegnący od pinu numer 2 płytki). Rzeczywiście, powinien być on tam wpięty – i tak właśnie jest. Jak pamiętamy, włącznik chwilowy ma dwie pary styków zawsze zwarte.
Programowanie układu
Układ jest gotowy. Pozostaje go zaprogramować. Możemy podłączyć płytkę Arduino do komputera. Na każdym etapie programowania będziemy bowiem sprawdzać, czy poszczególne elementy sygnalizacji działają poprawnie.
Uruchamiamy aplikację Arduino IDE. Pojawia się nowy szkic, w którym są wpisane domyślne funkcje, czyli setup() oraz loop(). Za chwilę będziemy je modyfikować.
Wcześniej spójrz jednak na nazwę pliku. Domyślnie składa się ona z liczb oznaczających dzień i miesiąc oraz z litery. Pierwszy szkic w danym dniu oznaczany jest literą A, każdy kolejny – następnymi literami. Zmień jednak nazwę na taką, która będzie informowała o zawartości szkicu. W tym celu wydaj polecenie Plik | Zapisz jako i podaj nazwę szkicu (na przykład „sygnalizator”). Możesz zapisać plik w folderze domyślnym lub wybrać inny. My zostawiliśmy ten, który zasugerowała aplikacja.
Podczas programowania będziemy używać stałych i zmiennych różnych typów. Stałymi w znanym ci już szkicu Blink były: OUTPUT, HIGH oraz LOW. Są to specyficzne stałe Arduino związane z operacjami na liniach portów mikrokontrolera. Inne stałe, których nazwy zaczerpnięto bezpośrednio z języka C, muszą mieć nadane określone wartości, których nie wolno później modyfikować. W kodach szkiców Arduino stałe są oznaczane kolorem niebieskim.
Zmienne, czyli wartości, które możemy modyfikować, są oznaczane w szkicach Arduino kolorem czarnym. Każda zmienna przechowuje informację ściśle określonego rodzaju. Do dyspozycji mamy następujące typy zmiennych:
bit– przyjmuje wartości 0 lub 1,bool– (skrót od boolean) przyjmuje wartośćtrue(prawda) lubfalse(fałsz),byte– przechowuje wartość całkowitą, 8‑bitową, należącą do zakresu 0–255,char– przechowuje pojedynczy znak alfanumeryczny,int– przechowuje liczby całkowite z zakresu –32 768 do +32 767,long– przechowuje wartości od –2 147 483 648 do 2 147 483 647.
W szkicu Blink zmienną jest numer pinu, do którego podłączamy diodę LED. W oryginalnym szkicu numer pinu pojawia się tylko trzy razy. Jednak w bardziej rozbudowanych programach zmienna może występować nawet kilkadziesiąt razy lub częściej. W takiej sytuacji powinna być ona zadeklarowana na samym początku szkicu.
Numer pinu jest najwyżej liczbą dwucyfrową (i do tego całkowitą), więc odpowiednim typem dla takiej zmiennej jest byte lub int. Definiując zmienną warto podawać nazwę, która jasno wskazuje, co zmienna ma przechowywać. Przykładowo, jeśli zmienna ma wskazywać pin, do którego podłączamy czerwoną diodę, możemy nazwać ją Pin_czerwona lub czerwonaPin. W nazwach zmiennych nie używamy spacji – zastępujemy je znakiem podkreślenia. Po wprowadzeniu typu i nazwy zmiennej wpisujemy znak równości (=), następnie podajemy wartość i kończymy deklarację średnikiem. Później we wszystkich miejscach w szkicu, w których znajduje się numer pinu, wpisujemy nazwę zmiennej. Co to daje?
Załóżmy, że zmieniliśmy nieco koncepcję projektu i nie chcemy korzystać już z pinu 13., lecz z pinu 11.. Jeżeli przepniemy przewód z pinu 13. do pinu 11., to dioda LED na płytce Arduino będzie świeciła nadal, lecz dioda umieszczona na zewnątrz już nie. Wszędzie, gdzie pojawiał się numer pinu 13, należałoby zamienić go na 11. Dzięki deklaracji zmiennej wystarczy jednak wprowadzić tę wartość tylko raz.
1. Wszystkie elementy szkicu warto opatrywać komentarzami. Pisząc program zaczynamy od informacji, że poniżej zadeklarujemy zmienne. Komentarz umieszczamy wewnątrz sekwencji znaków „/*” oraz „*/” lub po dwóch ukośnikach //, w przypadku gdy komentarz jest jednowierszowy. Zmiennymi będą wszystkie piny, do których zostaną podpięte diody oraz włącznik chwilowy. Numery pinów to liczby całkowite, więc zastosujemy zmienne typu byte lub int. Aby z kodu jasno wynikało, które piny odpowiadają za świecenie sygnalizatora dla pojazdów, a które dla przechodniów, w nazwach zmiennych wpisujemy na przykład ciągi „auta” i „ludzie”:
2. W funkcji setup() należy określić, które piny mają być wejściami, a które wyjściami. W przypadku sygnalizatorów wszystkie piny, do których podłączono diody, będą pinami wyjściowymi (OUTPUT). Natomiast wyłącznik będzie wykonywał określone zadanie – jego naciśnięcie spowoduje wprowadzenie danych do systemu sygnalizacji – i wpływał na działanie diod. Pin przycisku jest zatem pinem wejściowym (INPUT):
W ciele funkcji
loop()ustalamy, jak mają się zachowywać diody. Początkowo powinny być włączone: zielone światło dla pojazdów oraz czerwone dla pieszych. Pozostałe diody należy wyłączyć. Dwa pierwsze piny mają mieć zatem ustawiony wysoki stan napięcia (HIGH), a kolejne – stan niski (LOW):
4. Weryfikujemy poprawność szkicu i przesyłamy go do płytki Arduino.

Pieszy powinien nacisnąć przycisk w celu wymuszenia zmiany świateł. Aby sprawdzić, czy przycisk został naciśnięty zastosujemy instrukcję warunkową if.
Jak działa instrukcja if? Najpierw sprawdzana jest wartość wyrażenia logicznego (warunku). Jeżeli jest ono prawdziwe, zostaje wykonana pierwsza instrukcja. Jeżeli warunek nie jest spełniony, to wykonywana jest instrukcja podana po słowie else (w przeciwnym wypadku).
W przypadku sygnalizatora będziemy sprawdzać, czy włącznik chwilowy jest naciśnięty. Jeżeli tak, to światła powinny się zmieniać. W przeciwnym razie nadal powinno palić się światło zielone dla pojazdów i czerwone dla przechodniów.
Wewnątrz funkcji
loop(), za stanami pinów, które określiliśmy wcześniej, wstawiamy instrukcję warunkowąif. Na razie nie będzie ona działać, ponieważ brakuje informacji, jakie operacje mają zostać wykonane. Dotychczas ustalaliśmy stany pinów korzystając z funkcjidigitalWrite(). Teraz sytuacja się zmienia – musimy odczytać stan pinu, do którego podłączony jest włącznik. Zastosujemy funkcjędigitalRead():
W wyrażeniu logicznym pojawia się podwójny znak równości (==). Nie jest to błąd. Podając pojedynczy znak równości przypisujemy zmiennej określoną wartość. Tak jest na samym początku szkicu, kiedy poszczególnym zmiennym przypisywaliśmy numery pinów. Natomiast podwójny znak równości służy do porównania wartości. Instrukcję należy zatem rozumieć w następujący sposób: jeśli odczytany stan pinu, na którym znajduje się włącznik, jest wysoki, to…
Po naciśnięciu przycisku światło zielone dla pojazdów ma zostać wyłączone (niski stan napięcia); powinno zapalić się za to światło żółte (wysoki stan napięcia). Światło powinno być ciągłe – zatem za pomocą argumentu funkcji
delay()określamy, jak długo dioda ma się świecić. Przyjmijmy, że będzie to pięć sekund. Czas ten oczywiście wyrażamy w milisekundach.
Weryfikujemy poprawność kodu, przesyłamy go ponownie do płytki Arduino i kiedy światła będą włączone, naciskamy przycisk. Powinna się zapalić żółta dioda, a zielona zgasnąć. Po pięciu sekundach układ powróci do stanu początkowego.
W sygnalizatorze dla pojazdów dioda żółta powinna się następnie wyłączyć; włączyć ma się z kolei dioda czerwona. Natomiast w sygnalizacji dla pieszych musi włączyć się dioda zielona (czerwona ma zgasnąć). Załóżmy, że damy pieszym sześć sekund na przejście przez pasy:
Jeżeli zostawimy szkic w takim stanie, to piesi na zielonym świetle będą musieli przebiegać przez ulicę. Zmiana sygnalizacji (powrót do sytuacji początkowej, czyli zatrzymanie pieszych i otwarcie drogi dla pojazdów) nastąpi bowiem nagle. Czerwone światło dla pieszych pojawi się po sześciu sekundach bez jakiegokolwiek ostrzeżenia. Musimy uprzedzić przechodniów, że światło zaraz się zmieni na czerwone. Zielone światło powinno więc zacząć migać.
Załóżmy, że światło ma się wyłączyć i włączyć pięć razy. Moglibyśmy teraz wpisać odpowiednie instrukcje, powtarzając je właśnie pięciokrotnie. W tak małym projekcie nie jest to problemem. Ale co zrobić gdy instrukcję trzeba powtórzyć sto razy? Istnieje proste rozwiązanie tego problemu. Jest nim pętla for.
forforInstrukcja for określa, ile razy ma zostać wykonany blok poleceń zapisany w jej ciele. Pętla korzysta ze zmiennej, której najczęściej nadaje się nazwę i - jak iterator lub „licznik”. Zmienną należy zadeklarować na samym początku szkicu. Sama pętla ma postać:
Przedstawiony zapis odczytujemy następująco: nadaj zmiennej licznik wartość początkową 1; powtarzaj instrukcje do momentu, kiedy zmienna osiągnie wartość n; w każdym kroku zwiększaj wartość zmiennej o 1.
Przyjrzyjmy się jeszcze samemu licznikowi. Zapisaliśmy tu, że licznik w każdym cyklu pętli zwiększa wartość o 1 (licznik+1). Zatem w pierwszym kroku wartość licznika to wartość początkowa 1. W drugim to już 1+1=2, w trzecim 2+1=3 itd. Kiedy licznik osiągnie wartość n, pętla zostaje skończona. Bardzo często za wartość początkową przyjmuje się 0. Wówczas zamiast zapisu <= n wprowadzamy < n.
Zobaczmy, jak będzie to wyglądało w przypadku sygnalizatora.
Zacznijmy od deklaracji licznika:
9. Poniżej poprzednich instrukcji wprowadzamy pętlę for():
10. W kolejnym etapie światło dla przechodniów zmienia się z zielonego (napięcie ma być niskie) na czerwone (napięcie ma być wysokie). Po tej zmianie dajemy sygnał kierowcom, żeby przygotowali się do jazdy. Taka informacja to jednoczesne włączenie światła czerwonego i żółtego. Niech diody o tych barwach świecą na przykład przez dwie sekundy. Pamiętaj, że te instrukcje należy wpisać poniżej pętli for, a nie w jej wnętrzu.
Zapisujemy szkic ([Ctrl]+[S]), weryfikujemy jego poprawność, przesyłamy do płytki Arduino i sprawdzamy, czy sygnalizacja działa.
11. W zasadzie na tym moglibyśmy poprzestać. Został nam jednak jeszcze „przeciwny wypadek”, czyli słowo kluczowe else w instrukcji warunkowej. Czy musimy uzupełniać szkic? W tym szczególnym przypadku nie. Możemy usunąć sekcję else{}. Jeśli chcemy jednak postępować zgodnie z zasadami sztuki, powinniśmy dopisać do programu pewne instrukcje.
Dla sygnalizatorów trzeba określić stan pinów przy założeniu, że włącznik chwilowy nie został naciśnięty, czyli jego napięcie jest niskie. Te stany będą identyczne z wprowadzonymi na samym początku pętli loop():
Program jest gotowy, system sygnalizacji działa bezbłędnie, a ty wiesz coraz więcej. Nie zamykaj jednak jeszcze szkicu. Zauważ, że wszystkie instrukcje pisaliśmy rozpoczynając od lewej strony ekranu. Czy tak napisany szkic wygląda przejrzyście? Zdecydowanie nie.
Dlaczego zatem nie formatowaliśmyformatowaliśmy od razu kodu? Otóż dlatego, aby pokazać, jak program formatuje go sam. Wystarczy, że wciśniesz kombinację klawiszy Ctrl+T lub wybierzesz w menu Narzędzia polecenie Automatyczny format.
Kod od razu wygląda lepiej. Pojawiły się wcięcia i widać już, gdzie zaczynają się i kończą deklaracje, funkcje i pętle. Oczywiście z automatycznego formatowania możesz skorzystać na każdym etapie programowania. Warto jednak wyrobić w sobie nawyk przesuwania na prawo wszystkiego, co rozpoczyna się nawiasem klamrowym. W Arduino zazwyczaj stosuje się przesunięcie za pomocą dwóch spacji, ale można też używać do tego klawisza Tab.
Poniżej znajduje się cały kod programu sformatowany w sposób automatyczny oraz film pokazujący działanie szkicu.

Film dostępny pod adresem /preview/resource/Ryf10yFXwS6gt
Film nawiązujący do treści lekcji dotyczącej świateł drogowych. Na filmie przedstawiono płytkę stykową z podpiętymi przewodami, rezystorami oraz diodami LED i włącznikiem. Diody ustawione są następująco od lewej diody dla pieszych: czerwona, zielona, odstęp i dalej diody dla pojazdów, czerwona, żółta i zielona. Najpierw równocześnie świecą dioda czerwona dla pieszych oraz zielona dla pojazdów. Następnie osoba klika włącznik, co powoduje zaświecenie diody czerwonej dla pieszych i żółtej dla pojazdów. Po kilku sekundach następuje kolejna zmiana, w wyniku której świeci się dioda zielona dla pieszych oraz czerwona dla pojazdów. Po następnych kilku sekundach dioda zielona dla pieszych zaczyna migać, a po chwili przez około dwie sekundy świecą się diody: czerwona dla pieszych, czerwona i żółta dla pojazdów. Następnie wracamy do punktu wyjścia: świecą się dwie diody: czerwona dla pieszych i zielona dla pojazdów.