Kurs Arduino – cz. 2 – wejścia i wyjścia

W tej części kursu Arduino dowiemy się w jaki sposób można odczytywać stan wejść mikrokontrolera oraz poznamy sposób działania zmiennych i jedną z najważniejszych instrukcji, jakich możemy użyć w kodzie programu – instrukcję warunkową if. Wyczekujących na tą część przepraszam za tak długi czas od poprzedniego wpisu, z drugiej strony ten jest trochę dłuższy :). Zatem do dzieła!

Układ elektroniczny

Bazą do naszych dalszych eksperymentów będzie następujący układ elektroniczny:

Jego schemat elektryczny prezentuje się następująco:

Jak możesz zauważyć, poza diodą LED, z której korzystaliśmy przy okazji pierwszej części kursu Arduino, na płytce znajdują się także przycisk i potencjometr. Tak więc potrzebne będą:

Zmontowany układ

  • Arduino,
  • Płytka stykowa,
  • Siedem przewodów połączeniowych,
  • Dioda LED,
  • Rezystor (w zakresie ok. 100-500 omów)
  • Potencjometr (w zakresie ok. 10k-100k omów)
  • Przycisk (typu tact-switch)

Po zmontowaniu możemy zacząć pisać kod.

Odczytywanie stanu przycisku

Poniższy program odczytuje stan przycisku podłączonego do pinu A1 i w zależności od tego czy przycisk jest wciśnięty, zapala lub gasi diodę:

Zmienne

Jakich nowości tym razem użyliśmy w kodzie? Już na samym początku zdefiniowaliśmy dwie zmienne pin_przycisk i pin_dioda. Czym są zmienne? Zmienne to miejsca w pamięci programu, które przechowują jakieś dane. Zmienną możesz sobie wyobrazić jako szufladę opisaną etykietą. Możesz coś do niej włożyć i odwołujesz się do niej za pomocą wybranej wcześniej nazwy (etykiety). Zmienne w języku C++ (a w nim piszemy) wymagają również podania typu tak, aby procesor wiedział jak ich używać, ale o tym dalej.

Po co używać zmiennych? Po to, aby przechowywać dane potrzebne podczas działania programu lub dla wygody (tak jak tutaj zrobiliśmy). Zamiast pisać numer pinu, piszemy jego czytelną, więcej mówiącą nazwę. Dzięki temu program jest czytelniejszy i łatwiej można wprowadzić zmiany – jeśli przepniemy przycisk do innego pinu, wystarczy  numer zmienić tylko w jednym miejscu, zamiast szukać go w wielu miejscach programu.

Jak używać zmiennych? Jest to bardzo proste. Samo utworzenie zmiennej wygląda w ten sposób:


Jak widzisz, możemy podać wartość początkową, ale nie musimy tego robić. Ważne, żebyśmy byli pewni, że w zmiennej podczas jej używania znajdą się poprawne dane. Jeśli niczego nie przypiszemy, mogą się tam znaleźć losowe wartości. Nazwa zmiennej nie może być dowolna, bezpiecznie jest używać wyłącznie liter (cyfry też mogą się pojawić, ale nie na początku) i znaku podkreślenia “_”.

Jak już wspomniałem, zmienna musi mieć przypisany swój typ. Najczęściej używane to:

  • char – służy do przechowywania znaków,
  • byte, int, long – mogą przechowywać liczby całkowite,
  • float, double – przechowują liczby zmiennoprzecinkowe.

Typy wymienione w poszczególnych kategoriach różnią się wielkością, a co za tym idzie, możliwością przechowywania danych. Np. typ byte (bajt) może przyjąć tylko 256 wartości, a do zmiennej typu long zmieścimy liczby rzędu miliardów.

Zmiennych po utworzeniu używa się już pisząc wyłącznie ich nazwę. Możemy wykonywać na nich operacje takie jak porównanie (o czym za chwilę) czy przypisanie. Aby przypisać nową wartość do zmiennej należy podać jej nazwę, a następnie po znaku “=” wpisać nową wartość. Wartość taka nie musi być wpisana wprost, może też być matematycznie obliczona z pomocą operatorów arytmetycznych.

  • dodawanie (“+”),
  • odejmowanie (“-“),
  • mnożenie (“*”),
  • dzielenie (“/”),
  • reszta z dzielenia (“%”).
Najłatwiej jest to zrozumieć na przykładach:

Do zmiennej możemy również przypisać wartość zwracaną przez funkcję, tak jak to ma miejsce w pierwszej instrukcji w funkcji loop (jest podświetlona w kodzie programu).

Jeśli już wspomniałem o funkcjach, warto też poświęcić chwilkę zasięgowi zmiennych. Jeśli zmienna została zdefiniowana poza funkcjami (tak jak np. pin_przycisk), jest dostępna w całym programie. Natomiast jeśli zmienną utworzyliśmy w obrębie funkcji, jest ona dostępna tylko wewnątrz niej (np. zmienna przycisk). Wbrew pozorom nie służy to utrudnianiu życia – funkcje zostały wymyślone aby utrzymywać porządek w kodzie i poprawnie napisane zajmują się jedną czynnością. Dla reszty programu nie ma znaczenia co dzieje się wewnątrz niej, ważne jest działanie, które zostaje wykonane. To jak to zrobi i jakich środków funkcja użyje (np. jakie zmienne zadeklaruje) na zewnątrz jest zazwyczaj nieistotne.

Instrukcja warunkowa

Kolejną nowością jaką spotkasz w programie jest instrukcja warunkowa if. Umożliwia ona wykonywanie kodu w zależności od spełnienia określonego warunku – w naszym programie stanu wciśnięcia przycisku. Jak wygląda składnia takiej instrukcji?


Tak więc możemy, ale nie musimy zapisywać działania gdy warunek jest niespełniony. Jak może wyglądać warunek? Najpierw podstawowe operatory porównania:

  • równe (“==”),
  • różne (“!=”),
  • mniejsze (“<“),
  • większe (“>”),
  • mniejsze lub równe (“<=”),
  • większe lub równe (“>=”).

Najważniejszą rzeczą jaka musisz zapamiętać jest to, że operator przypisania (“=”) jest czymś całkowicie innym niż operator równości (“==”). Początkujący często używają jednego znaku “=”, co może być źródłem wielu trudnych do wykrycia problemów.

Pora na przykłady:


Po poznaniu sposobu działania zmiennych i instrukcji warunkowej nie powinieneś(aś) mieć większych problemów ze zrozumieniem działania tego programu. Działanie nowych funkcji pochodzących z biblioteki Arduino opisałem na końcu tego artykułu. Pora więc na następny, ale bardzo podobny program.

Odczytywanie stanu wejścia analogowego

Ten program również zapala diodę, ale o tym czy ją zaświecić czy zgasić decyduje teraz sygnał analogowy, napięcie na wejściu musi być odpowiednio wysokie. Aby je móc łatwo zmieniać, skorzystamy z potencjometru, który będzie mógł podawać na wejście mikrokontrolera napięcia mieszczące się w ramach napięć zasilających, czyli od ok. 0V do 5V.

Pora na listing:


Jak możesz łatwo zauważyć, generalna struktura programu się nie zmieniła. Na początku przypisujemy do zmiennych oznaczenia pinów i ustawiamy ich tryby pracy. Później w głównej pętli programu odczytujemy wartość z przetwornika analogowo-cyfrowego i na jej podstawie ustalamy czy dioda ma się świecić.

Teraz kilka słów o tym jaka wartość jest zwracana przez funkcję analogRead. Otóż zwraca ona wartość napięcia na wybranym pinie, ale robi to w specyficznej skali – wartość ta jest zapisana w liczbie z zakresu od 0 do 1023, przy czym 0 oznacza zazwyczaj 0V, a 1023 – 5V. Zazwyczaj, ponieważ da się to zmienić poprzez dzielnik napięcia lub podawanie napięcia referencyjnego.

W tym przykładowym programie porównuję wartość odczytaną z wpisanym na stałe progiem 300, który powinien się znaleźć po jednej ze stron skali potencjometru. Możesz z tym poeksperymetować. Przy próbach ustawienia potencjometru jak najdokładniej na tą wartość progową, może okazać się, że dioda zacznie migotać. Dlaczego? Odczyt nie jest nigdy idealny, występują różne wahania. Na odczyt mają wpływ różne czynniki zewnętrzne, czasem nawet wystarczy zbliżenie/odsunięcie dłoni. Ciekawym eksperymentem może być podpięcie czegoś w rodzaju anteny i różne próby wpływania na wynik odczytu.

Funkcje użyte w programach

Oto kilka nowo poznanych funkcji:


Z pomocą funkcji digitalRead możemy poznać stan wybranego wejścia. Wskazujemy je z pomocą numeru przekazanego jako parametr funkcji. Funkcja zwraca jedną z dwóch wartości:

  • LOW (0)  – jeśli napięcie na pinie jest bliskie 0V,
  • HIGH (1) – dla napięć około 5V.

Podobnie jak poprzednia funkcja, ta również służy do odczytywania stanu wejścia. Tym razem z pomocą przetwornika analogowo-cyfrowego, który jest dostępny tylko dla wejść oznaczonych na płytce jako analogowe. Wartość zwracana mieści się w przedziale od 0 do 1023, przy czym wartość bliska 0 oznacza napięcie ok. 0V, a wartość z przeciwnego końca skali 1023 – napięcie ok. 5V. Wartości pomiędzy oznaczają napięcia mieszczące się między tymi dwoma.

 

 

  • Paweł

    Bardzo fajnie, że można się od Ciebie nauczyć prawidłowych nawyków. ;)
    Dzięki za post.

  • Kris59

    jak ten przykład rozwinąć / napisać dla odczytywania stanu 4-rech wejść analogowych i porównać z zadanym parametrem dla 4-ech wyjść (digital ) , każde niezależne ?

  • btomasz

    Najprościej to czterokrotnie powielić zawartość funkcji loop, wtedy musisz też zmienić nazwy występujących tam zmiennych (np. pr) na różniące się.