Odbieranie danych przez tinyBrd

tinyBrd może nie tylko nadawać ale też odbierać dane

Nie tylko nadawanie

Płytka tinyBrd może nie tylko nadawać dane do centralnego modułu, ale też potrafi odbierać. Dzięki interfejsowi naszej biblioteki Radio, jest to bardzo proste.

Instalcję bibliotek i Nettigo tinyBrd Core opisaliśmy w innym artykule na Akademii. Zakładam, że zainstalowałeś Nettigo tinyBrd Core i przykłady do niego tak jak tam jest to opisane.

Najnowsze wersje

Wszystkie szkice znajdują się na GitHubie: https://github.com/nettigo/tinyBrd. Przykłady do tego artykułu są w katalogu ping-pong.

Przykład 1: Testowanie zasięgu

Gdy chcieliśmy przetestować zasięg modemów NRF24L01 w otwartej przestrzeni, zrobiliśmy proste urządzenie z dwóch tinyBrd. Pierwszy, po naciśnięciu przycisku wysyła pakiet pod ustalony adres. Pod tym adresem znajduje się drugi tinyBrd, który po odebraniu pakietu odsyła go. Pierwszy tinyBrd po odebraniu właściwego pakietu sygnalizował mignięciem diodą zakończenie całego procesu.

W ten prosty sposób mogliśmy łatwo sprawdzić czy w danej fizycznej konfiguracji jest poprawna transmisja w obie strony między modemami.

Jak działa ten program?

Ping!

Funkcja setup

W setup ustawiamy odpowiedni tryby prac wejść/wyjść. Zgodnie z planem, potrzebujemy przycisku i diody LED. tinyBrd ma niewielkie pole lutownicze i da się wykorzystać je do zbudowania naszeje maszyny robiącej ping.

Zmontowany układ PING. Przycisk podłączony do D1 jest zworką pod płytką

Mając zlutowane elementy, jedno wejście przeznaczamy na odczyt przycisku a jedno na świecenie diodą. Ponieważ (jak widać na zdjęciu) nasz przycisk zasłania całą stronę gdzie jest masa (GND), więc diode podłaczyliśmy trochę inaczej niż zwykle. Zamiast do GND podłaczona jest do Vcc, a do pinu cyfrowego z drugiej strony. Przy zachowaniu właściwej polaryzcji diody, by ją zaświecić, na wyjściu cyfrowym musi pojawić się zero. Wówczas, jest różnica napięć między Vcc a wyjściem cyfrowym i dioda świeci. Gdy na wyjściu cyfrowym jest logiczna jedynka, wówczas napięcie jest bliskie Vcc. Nie ma różnicy potencjałów i dioda nie świeci.

Dlatego, za każdym razem jak się pojawi digitalWrite(LED,LOW) to wiedz, że dioda się zaświeci.

  pinMode(LED, OUTPUT);   
  digitalWrite(LED, HIGH);
  pinMode(BUTTON, INPUT_PULLUP);

Użycie INPUT_PULLUP zapewnia nam poprawną pracę przycisku, bez dodatkowego rezystora. Gdy przycisk jest rozwarty, wbudowany rezystor pullup zapewnia stan wysoki na wejściu cyfrowym. Użycie trybu wejścia INPUT i podłączenie samego przycisku skończyłoby się losowymi zmianami stanu wejścia cyfrowego.

Następnie konfigurujemy radio. Ustawiamy trzybajtowy adres, część ping naszego duetu będzie nasłuchiwać na adresie {0,0,1}. Radio będzie nadawać i nasłuchiwać na kanale 100:

  byte address[3] = {0, 0, 1};
  Radio.begin(address, 100);

By być pewnym, że po włączeniu zasilania nasz moduł działa poprawnie dodaliśmy prostą pętlę, która kilka razy mignie naszą diodą. Sygnalizuje to uruchomienie naszego modułu:

  for (byte i = 0; i < 5; i++) {
    lightOn(100);
  }

lightOn jest niewielką funkcją zapalającą diodę na podany w milisekundach czas. Domyślnie jest to 1 sekunda.

Funkcja loop

Mając już skonfigurowane wejścia/wyjścia oraz radio, w funkcji loop sprawdzamy czy został naciśnięty przycisk. Jeżeli tak, to wysyłany jest pakiet danych do drugiego tinyBrd (PONG). Wybraliśmy sobie wartość wysyłanego pakietu 66. Gdy radio NRF24L01 skończyło nadawać, funkcja loop wykonywana jest dalej.

Drugą czynnością w loop jest spradzenie czy NRF24L01 odebrało dane. Jeżeli są dane, to sprawdzamy czy PONG odesłał nam umówioną wartośc 99. Zgadza się? To zapalamy diodę na sekundę, by poinformować operatora, że transmisja w obie strony zakończyła się sukcesem.

  if (digitalRead(BUTTON) == LOW) {
    Radio.write(pongAddr, payload);
    Radio.flush();
    delay(50);
  }

Dodany na końcu delay zapewnia nam, że w razie błyskawicznie zrealizowanej transmisji zjawisko zwane debouncing nie spowoduje, że tinyBrd odczyta w następnym przebiegu ponowne naciśnięcie przycisku.

Radio.write wysyła dane do modułu NRF, ale nie czeka na zakończenie transmisji do drugiego modułu. Dopiero Radio.flush() czeka na zakończenie transmisji, zakończonej sukcesem lub niepowodzeniem. Ponieważ czekamy i tak na odpowiedź od PONGa, nie sprawdzamy jaki status zwróciło Radio.flush().

Adres PONGa został ustalony przez nas na wartość {1,0,0} i jest zapisany w tablicy pongAddr.

A jak sprawdzamy dane, które mógł nam nadesłać PONG?

  if (Radio.available()) {
    received = 0;
    Radio.read(&received);
    if (received == 99) {
      lightOn();
    }

  }

Radio.available() zwraca ile bajtów zostało odebrane. Jeżeli nic nie zostało odebrane, 0, które zwróci funkcja jest traktowane przez if jako wartość FALSE, czyli wykonywanie programu zostanie wznowione dopiero po komendzie if.

Gdy mamy jakiś bajt do odebrania, to używając Radio.read(&received) odczytujemy go, zapisując go w zmiennej received. Zmienna ta jest właśnie typu byte. Ważny jest symbol & przed nazwą zmiennej w wywołaniu fukncji Radio.read. Jeżeli go pominiemy, funkcja zapisze wartośc do zmiennej received, ale po powrocie z tej funkcji wartość receieved powróci do stanu sprzed wywołania funkcji.

W następnym kroku spradzamy czy PONG faktycznie nam odesłał wartość 99, tak jak się spodziewaliśmy. Gdy wszystko się zgadza nie pozostaje nic innego jak tylko zaświecić na 1 sekundę diodę, by zasygnalizować operatorowi poprawną transmisję.

PONG!

Konstrukcja programu działającego na PONGu jest nieco prostsza, ale korzysta z tych samych poleceń.

Po pierwsze, również tutaj podłączyliśmy jedną lampkę LED by móc sygnalizować w prosty sposób zdarzenia.

Funkcja setup

Podobie jak w przypadku PINGa, funkcja setup ustawia wyjście do którego jest podłączona dioda LED. Dla uproszczenia programu zachowaliśmy ten sam sposób podłączenia diody LED, jak w PINGu, choć tutaj można podłączyć diodę LED jak zwykle - nie ma przycisku, który ogranicza dostęp do pól lutowniczych.

Istotna różnica to adres, jaki jest podany do funkcji Radio.begin. Adres przewidziany dla PONGa to {1,0,0} i takiego trzeba użyć.

  byte address[3] = {1, 0, 0};
  Radio.begin(address, 100);

  pinMode(LED, OUTPUT);
  digitalWrite(LED, HIGH);
  for (byte i = 0; i < 5; i++) {
    lightOn(100);
  }

Funkcja loop

Logika nakazuje PONGowi oczekiwać na dane. Gdy odbierze pakiet o wartości 66, to na adres PINGa odsyła pakiet o wartości 99. Lampką LED krótko migamy gdy są dane do odebrania, a gdy zostganie wysłana odpowiedź, mignięcie nieco dłuższe. Cały kod wygląda tak, i wszystkie elementy omówione były przy programie PINGa:

  if (Radio.available()) {
    lightOn(100);
    Radio.read(&payload);
    if (payload == 66) {
      payload = 99;
      Radio.write(pingAddr, payload);
      Radio.flush();
      lightOn(400);
    }
  }

Czego się nauczyliśmy

Po przeczytaniu tego artykułu powinniście wiedzieć: