Witajcie!
W dzisiejszym odcinku poznamy w jaki sposób obsłużyć transmisję RS232 w Visual C# oraz co najważniejsze w jaki sposób parsować nadlatujące dane...
W Visual C# mamy odpowiednią kontrolkę do obsługi tego typu transmisji tj. kontrolkę serialport w zakładce Components
rysunek_kontrolka
Kontrolka ta daje nam do dyspozycji wiele metod, jednak my zainteresujemy się tymi:
a) Open()
b) BaudRate()
c) PortName()
d) ReadTo()
e) Write()ad a. Metoda ta odpowiada za otwarcie portu. Zadziała jeżeli określimy poprawną nazwę portu szeregowego(ex. COM1, COM2 etc)
ad b. Metoda ta odpowiada za określenie prędkości transmisji - pobiera ona dane typu int.
ad c. Metoda ta pozwala na ustawienie ustawienie nazwy portu szeregowego jaki chcemy otworzyć - pobiera ona dane typu string. Powinna być ona ustawiona w kodzie źródłowym programu przed operacją otwarcia portu lub ustawiona we właściwościach kontrolki.
ad d. Metoda ReadTo pozwala na odebranie łańcucha via RS232 do napotkania jakiegoś znaku(
ex. ReadTo("\n") ) w przypadku przykładu łańcuch zostanie odczytany do napotkania znaku nowej linii, i właśnie takim znakiem będziemy kończyć każdorazowe odebranie łańcucha. Sam łańcuch zostanie przekazany do zadeklarowanej zmiennej typu string.
ad e. Metoda ta pozwala na przesłanie łańcucha lub pojedynczego znaku.
#2 - PARSOWANIE ŁAŃCUCHA
Odebrany łańcuch w nomenklaturze transmisji danych nazywamy ramką. Nasza ramka będzie miała następującą postać:
Kod:
32,27,28ABF953,2835C5B8,\r\n
Ramka składa się z temperatury pierwszego czujnika następnie temperatury drugiego czujnika a potem są numery seryjne tych dwóch czujników DS18B20 a na końcu jest znak karetki i nowej linii.
Zauważcie że łańcuch został podzielony na tokeny(o nich była mowa w pierwszej książce Mirka w rozdziale o TCP/IP) tak aby łatwo było ją analizować.
Po tej dawce teorii trzeba przejść do praktyki
.
Tradycyjnie zakładamy nowy projekt i przechodzimy do projektowania aplikacji. W moim przypadku aplikacja składa się z trzech form(W pierwszej będziemy ustawiać rejestrator i podglądać dane ON-LINE, w drugiej zaś będzie tabela pomiarowa która pozwoli na podgląd temperatur z czujników, dat i godzin
odbioru danych, wyliczenie amplitudy temperatur z poszczególnych czujników, wartości maksymalnych i minimalnych oraz wartości średnich. Co najważniejsze będzie można kreślić wykres temperatury powietrza i ustawieniu zakresu kreślenia(data pomiaru). Trzecia forma będzie podglądem wykresu który zostanie narysowany na podstawie tabeli pomiarowej.
Pierwszą formę przygotujemy tak aby można było dokonywać swobodnego wyboru portu komunikacyjnego, interwału czasowego pomiaru temperatury. Dodamy również możliwość podglądu temperatur z obu czujnikach na odpowiadnio sformatowanych textboxach. Również dodamy możliwość przedstawienia numerów seryjnych za pomocą kontrolki label.
Dobra teraz przechodzimy do oprogramowania zdarzenia Load dla pierwszej formuły:
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
W kodzie znajduje się nowa pętla
foreach któa odpowiada za poruszanie się po kolekcji a konkretniej mówiąc przełączenie pomiędzy poszczególnymi elementami kolekcji - w naszym przypadku tablicy port.
Skoro mamy oprogramowane zdarzenie ładowania Formy to teraz przejdziemy do oprogramowanie przycisku
Połącz który będzie umożliwiał łączenie z portem COM jak i rozłączanie się z nim.
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Po raz kolejny pojawia się novum w postaci bloku try i catch. Blok ten odpowiada za obsługę błędów. W części try umieszczamy czynności które mogą być niebezpieczne dla poprawnego działania aplikacji - chodzi o to że wykonanie danych czynności może doprowadzić do błędu(zwykle z winy samego użytkownika
). W części catch znajduje się czynności które potencjalny błąd obsługują m.in tam są wstawiane czynności odpowiadające za wyświetlenie komunikatu o błędzie, nawet wyłączenie samej aplikacji.
Teraz przejdziemy do oprogramowania przycisku START który będzie odpowiadał za rozpoczęcie pomiaru temperatury.
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Głównym zadaniem tego przycisku jest włączanie/wyłączanie timery i jego startowanie/zatrzymywanie. Ustawia on również bardzo ważny parametr jakim jest Interval czyli odcinek czasowy jaki będzie timer odmierzać.
Chciałbym również nadmienić o tym że kontrolkę timer należy ustawić aby parametr Enable był ustawiony na false. Można wykonać to w kodzie źródłowym lub we właściwościach samej kontrolki.
Teraz przejdziemy do oprogramowania zdarzenia tick dla kontrolki Timer
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Tak... ten kod zdarzenia który razi swoją wielkością tak na prawdę uruchamia całą machinę m.in wydaje rozkaz rozpoczęcia pomiaru i wysyłania do naszego programu temperatur i numerów seryjnych(tak bynajmniej ja mam napisany program do uC.
Teraz przejdziemy do całego gwoździa programu - zdarzenia odbioru danych. Na początek jednak przejdziemy znanym skrótem F7 do kodu źródłowego pierwszej formy. W przestrzeni nazw zadeklarujemy zmienne które będziemy później wykorzystywać do pewnych operacji...
rysunek kod
Ok! Teraz przechodzimy do zdarzenia DataReceived kontrolki serialport.
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
W kodzie obsługi zdarzenia widać warunek który czyści łańcuch po pierwszym odbiorze danych, dlaczego go umieściłem? Już tłumaczę, kiedy testowałem programy z wykorzystaniem kontrolki serialport miałem do czynienia ze źle odbieranymi łańcuchami po resecie urządzenia po "nie poprawnym rozłączeniu programu z portem com(wyłączałem program bez uprzedniego zamknięcia portu com) otrzymywałem złe dane np. zamiast 32 otrzymywałem 3232 lub inne tego typu kwiatki... i z tego powodu tak się zabezpieczyłem
.
Do projektu Logera temperatury pozwoliłem sobie dodać zakładkę
Terminal w której umieściłem odpowiednio sformatowaną kontrolkę richtextbox(kontrolka znajduje się w zakładce common controls) która będzie pełniła role tego terminala. Kontrolkę tą dostosowałem w ten sposób że tło(właściwość BackColor) ustawiłem na czarny a kolor tekstu(właściwość ForeColor) ustawiłem na kolor Limonkowy
.
Terminal ten pozwoli za zaobserwowanie nadlatujących ramek z urządzenia via port COM.
Teraz przejdziemy do zdarzenia które odpowiadać będzie za parsowanie odebranego łańcucha.Jak już wcześniej wspominałem łańcuch podzieliłem na tokeny(odseparowałem poszczególne dane przecinkiem) tak aby można było w prosty sposób przeanalizować nadlatujących łańcuch i "wyjąć z tego łańcucha" dane do poszczególnych elementów naszej aplikacji.
Zapewne zastanawiacie się dlaczego musiałem utworzyć nowe zdarzenie do tego a nie mogłem po prostu umieścić parsowania danych bezpośrednio w zdarzeniu odbiorczym, otóż w tego typu zdarzeniach nie można "montować" skomplikowanych czynności ponieważ nie dało by ich się wykonać w tym jednym zdarzeniu - kompilator przy próbie skompilowania programu gdzie właśnie bezpośrednio unieślibyśmy takie czynności w tego typu zdarzeniach, nie chciał by go skompilować.
Do samego parsowania danych wykorzystałem znaną metodę split - czyli załadowanie do tablicy elementów odseparowanych wybranym przez nas znakiem(w naszym przypadku to przecinek). W zdarzeniu tym będziemy cyklicznie powiększać zdefiniowane tablice o 1 ponieważ tam będziemy zapisywać już wyodrębnione dane do poszczególnych tablic aby móc je później wysłać do tablicy pomiarowej do dalszej analizy...
Kod zdarzenia parsującego dane:
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Teraz gdy nasze dane zostały odpowiednio wyodrębnione dla relaksu oprogramujemy przycisk
Tabela pomiarowa
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Myślę że w przypadku tego przycisku nie muszę nic więcej mówić ponieważ najważniejsze elementy są okraszone odpowiednim komentarzem
.
Teraz zabierzemy się za checkbox
Wykres 3D - będzie on odpowiadać za włączanie/wyłączanie widoku 3D wykresu w pierwszej formie.
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Wszelkiego rodzaju prace na pierwszej formie zostały zakończone więc teraz przejdziemy do drugiej formy naszego loggera temperatury.
Nie będę opisywał wszystkich elementów które znajdują się na drugiej formie. Jak włączycie aplikacje(postarm się gdzieś wrzucić wersje skompilowaną i źródłową do pobrania) zauważycie że jest tam takie(a raczej są
) pola tekstowe z maską wprowadzającą dane. Jest to kontrolka
mascedTextBox, która znajduje się w zakłdce
Common Controls.
Jeśli chodzi o przyciski to tutaj pokaże kod obsługi kreślenia wykresu na podstawie danych z poszczególnych dni:
język csharp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Pierwsza pętla for odpowiedzialna jest za odnalezienie pierwszej daty pomiaru. Gdy zostanie ona odnaleziona(zostanie spełniony warunek że zawartość pola maskedTextBox będzie taka sam jak wartość zmiennej łańcuchowej kompar - czyli wartości cyklicznie pobieranej z naszej tabeli w pętli for) pętla for zostaje przerwana i program przechodzi do następnej pętli która szuka drugiej daty.Tam zaś gdy zostanie odnaleziona druga data poszukiwania nie są zakończone, ponieważ pętla for się obraca aż do ostatniej temperatury która jest przydzielona drugiej dacie którą mamy zapisaną w drugim polu maskedTextBox. A na sam koniec w trzeciej pętli for zostają pobrane adresy do dat a raczej do wyników pomiarów i zostają wykreślone dwa wykresy.
Najlepiej jak sami przeanalizujecie na spokojnie algorytm jaki jest w programie i wtedy jeszcze bardziej będzie wszystko jasne
.
Trzeciego formularza nie będę opisywał bo jest tam tylko wykres dwóch temperatur.
Tym samym kończę cykl poradników do Visual C# na forum, następne być może(jak czas pozwoli) pojawią się na blogu który mam zamiar założyć lub na jakiejś stronie - o czym będę informować na bieżąco. Mam nadzieje że udało mi się w miarę jasno i zrozumiale dla otoczenia przedstawić wam jak łatwo można korzystać z Visual C# i finalnie wykonać program do komunikowania się z własnym urządzeniem z wykorzystaniem parsowania danych które według mnie jest nieodzowne do wykonywanie programów do sprzętu pomiarowego.