Temat: LabVIEW - obsługa portu szeregowego
Do komunikacji szeregowej w środowisku LabVIEW wykorzystujemy bloczki z grupy Instrument I/O -> Serial lub Instrument I/O -> VISA. Aby bloczki te były dostępne, należy upewnić się, że zainstalowane zostały sterowniki Device Drivers.
Zaczynamy od umieszczenia na diagramie blokowym kontrolek realizujących nawiązanie oraz zamknięcię sesji połączenia z portem szeregowym. Są to odpowiednio VISA Open oraz VISA Close dostępne w palecie VISA -> VISA Advanced.
Rysunek 1 kontrolki realizujące połączenie z portem szeregowym
Zastosowanie powyższych kontrolek spowoduje nawiązanie połączenia z użyciem domyślnych parametrów (baud rate: 9600, data bits: 8, parity: none, stop bits: 1, flow control: none).
Jeżeli chcemy komunikować się z wykorzystaniem parametrów transmisji innych niż domyślne, zamiast z VISA Open możemy skorzystać z kontrolki VISA Configure Serial Port, dostępnej w palecie Serial.
Rysunek 2 Konfiguracja parametrów portu szeregowego
Rysunek 3 Odbieranie danych z portu szeregowego
Aby zrealizować odbieranie danych z portu szeregowego, pomiędzy kontrolki otwarcia i zamknięcia sesji wstawiamy pętlę while, w której będziemy sprawdzać, czy w buforze portu znajdują się dane gotowe do odczytu. W tym celu stosujemy bloczek Bytes at port, dostępny w palecie Serial. Jeżeli wartość zwrócona przez ten bloczek jest większa od 0, przekazujemy ją do kontrolki VISA Read, co spowoduje odczytanie z portu takiej liczby bajtów, jaka aktualnie znajduje się w nim do odczytu. Odczytany w ten sposób komunikat możemy wyświetlić lub przesłać do dalszego przetwarzania.
Stosujemy w tym przypadku standardowy szablon aplikacji z pętlą while, z okresem taktowania określonym przez kontrolkę Wait until nex ms multiple, warunkiem stopu aktywnym w momencie naciśnięcia przez użytkownika przycisku Stop na panelu frontowym.
Odporność na błędy
Praktyka pokazuje, że taki sposób odczytu danych z portu szeregowego nie jest odporny na mogące pojawić się w trakcie komunikacji zakłócenia. Na przykład możliwa jest sytuacja, w której komunikat o całkowitej długości 10 bajtów, pojawi się w buforze w dwóch partiach, po 6 i 4 bajty. Wówczas kontrolka Bytes at port zwróci najpierw wartość 6, a w kolejnej iteracji wartość 4, co spowoduje odczytanie i przesłanie przez program do dalszego przetwarzania dwóch osobnych fragmentów, zamiast całego komunikatu. Może to spowodować błąd lub niepoprawne rozpoznanie treści komunikatu przez kolejne bloczki.
Aby uchronić się przed taką sytuacją, stosujemy podczas odczytu z portu szeregowego dodatkowy bufor, w którym przechowujemy dane do momentu otrzymania kompletnego komunikatu. W tym celu konieczne jest określenie, jakim znakiem kończy się dany komunikat, najczęściej jest to znak końca linii ‘\n’.
Aby zrealizować doklejanie każdego nowo odczytanego napisu do bufora, stosujemy mechanizm rejestru przesuwnego. Przed uruchomieniem pętli while jako wartość początkową rejestru ustawiamy stałą będącą pustym napisem (Empty String Constant). Każdorazowo odczytane dane z portu szeregowego doklejamy do bufora przy pomocy kontrolki Concatenate Strings. Jednocześnie sprawdzamy, czy ostatni znak odczytanego napisu jest równy znakowi końca linii. W tym celu stosujemy kontrolkę String Subset, której jako offset podajemy długość napisu określoną przez bloczek String Length, a następnie pomniejszoną o 1, a jako length wartość 1. Jeżeli stwierdzimy, że otrzymaliśmy cały komunikat, wyświetlamy go lub przesyłamy do dalszego przetwarzania, a do rejestru przesuwnego przesyłamy pusty napis. Jeżeli komunikat jeszcze nie jest kompletny, aktualnie znajdujące się w buforze dane nie są przetwarzane, lecz przesyłane poprzez rejestr przesuwny na wejście kolejnej iteracji pętli while.
Rysunek 4 Odbieranie danych z wykorzystaniem bufora
Odbieranie oraz wysyłanie danych
Jeżeli chcemy w programie umożliwić oprócz odbierania danych również ich nadawanie poprzez wysyłanie wpisywanych przez użytkownika komunikatów, możemy do tego celu wykorzystać strukturę zdarzeniową Event Structure.
Do odbierania danych wykorzystujemy zdarzenie Timeout, którego parametr czasowy określamy, tak jak poprzednio ustawiony okres taktowania pętli while.
Rysunek 5 Zdarzeniowe odbieranie danych
Wysyłanie danych z kontrolki tekstowej Message będzie realizowane po naciśnięciu przez użytkownika przycisku Send. W tym celu dodajemy do listy zdarzeń struktury Event zdarzenie „Send” : Mouse up. Wewnątrz diagramu dla tego zdarzenia umieszczamy bloczek VISA Write, na którego wejście przesyłamy wpisany przez użytkownika komunikat z doklejonymi znakami powrotu karetki oraz końca linii: „\r\n”. Dodatkowo przed wysłaniem komunikatu sprawdzamy, czy nie jest on pusty przy pomocy kontrolki Empty String/Path?. W przypadku zaistnienia takiej sytuacji zapis nie zostanie zrealizowany.
Rysunek 6 Zdarzeniowe wysyłanie danych
Propozycje ćwiczeń i modyfikacji
1. Zmodyfikować program tak, aby zamiast wyświetlania ostatnio odczytanego komunikatu, wyświetlana była cała historia komunikacji z automatycznym przewijaniem w miarę otrzymywania kolejnych komunikatów.
2. Przetestować komunikację pomiędzy dwoma instancjami programu uruchomionymi na jednym komputerze z wykorzystaniem emulatora portów szeregowych COM0COM.
3. Do sprawdzenia ostatniego znaku komunikatu wykorzystać bloczek Slice String, znajdujący się w bibliotece OpenG, instalowanej przez program VI Package Manager.