Port szeregowy i interfejs USART, czyli komunikacja z PC

Port szeregowy i interfejs USART, czyli komunikacja z PC

Zauważyłem, że problem komunikacji z komputerem za pomocą portu szeregowego jest często poruszany na naszym forum.

Napisałem kilka programów komunikacyjnych, dlatego postanowiłem stworzyć ten mały tutorial. W artykule opiszę interfejs USART, w który wyposażona jest większość mikrokontrolerów.

Następny artykuł z serii »

Głównym tematem będzie jednak stworzenie aplikacji na PC, mogącej komunikować się z mikrokontrolerem za pomocą portu szeregowego. Aplikacja jest stworzona dla układów wykorzystujących właśnie USART. Takie rozwiązanie umożliwia nie tylko przesyłanie danych za pomocą RS232, ale również przez USB i konwerter FT232, bluetooth, IrDA i inne interfejsy, używające wirtualnego portu COM.

Interfejs USART

Jak już wspomniałem, jest to interfejs komunikacyjny, dostępny w większości popularnych mikrokontrolerów. W niektórych można znaleźć nawet kilka pracujących niezależnie USARTów.

W artykule będę się posługiwał ATmegą16, ale programy powinny być łatwe do przeniesienia na inne pokrewne procesory. Do transferu danych za pomocą USARTu służą sygnały TxD (transmisja danych) oraz RxD (odbiór danych).

Prędkość transmisji (baud rate) jest z góry ustalona dla danego połączenia. Dokonuje się tego przez wpisanie odpowiedniej wartości do rejestru UBRR (USART Baud Rate Register), wyliczonej w oparciu o częstotliwość taktowania mikrokontrolera.

Warto zwrócić uwagę na pewną rzecz. Istnieją standardowe prędkości transmisji: 2400, 4800, 9600 itd. Aby zapewnić transmisję z błędem na poziomie 0.00%, częstotliwość taktowania mikrokontrolera musi być oczywiście znana i stabilna, ale także musi być wielokrotnością 1,8432MHz. Wybór innej częstotliwości spowoduje pogorszenie dokładności.

W datasheecie Atmela można znaleźć dokładny opis użytego interfejsu, a w tym m.in. wzór do obliczania baud rate oraz tabelkę z popularnymi częstotliwościami taktowania, prędkościami transmisji, odpowiednimi wartościami rejestru UBRR oraz odpowiadającymi tym ustawieniom błędami.

Ramka danych w transmisji UART wygląda następująco:

Ramka danych UART

Ramka danych UART

Zawiera bit startu, sygnalizujący początek kolejnej ramki (od 5 do 9 bitów danych), bit parzystości, służący do kontroli błędów odbioru. Może działać w trzech trybach - brak kontroli (no), suma zawsze parzysta (even), suma zawsze nieparzysta (odd).

Popularną konfiguracją, w której pracuje interfejs USART, jest podłączenie do portu RS232 komputera. Aby tego dokonać, niezbędna jest konwersja stanów logicznych, której można dokonać za pomocą popularnego scalaka MAX232.

Poniżej schemat połączenia uC do RSa:

Podłączenie USART do komputera

Inne, częste konfiguracje to USART, pracujący z FT232RL i podłączony do portu USB, moduł Bluetooth, np. BTM-222 (należy przy nim pamiętać o napięciu zasilania 3,3 V), czy połączenie ze sobą dwóch mikrokontrolerów. Nie będę się nad nimi rozpisywać. Schematy połączeń można bez problemu znaleźć w internecie. Przejdźmy zatem do programu od strony PC.

Środowisko programistyczne

Głównym kryterium wyboru środowiska programistycznego jest obecność dedykowanych bibliotek do obsługi portów szeregowych.

Dlatego nie ma sensu komplikować sobie życia. Poza tym wiele środowisk zdecydowanie ułatwia tworzenie prostych w obsłudze i ładnie wyglądających aplikacji okienkowych. Na pewno jest to miła odmiana dla topornych programów konsolowych.

Do napisania swojego programu wybrałem platformę .NET i Visual C# 2010, ale nic nie stoi na przeszkodzie, aby napisać taki program na przykład w Javie. Proces powstawania aplikacji, a nawet potrzebne funkcje w Javie są bardzo podobne, więc nie powinno być problemu z przeniesieniem tego artykułu na inny język.

Jeśli ktoś miał już do czynienia z C, C++ czy Javą, przesiadka na C# nie powinna stanowić dużego problemu. Do niektórych nowych rzeczy trzeba się przyzwyczaić, ale reszta jest całkiem podobna. Osoby, które preferują Bascoma, Pascala i inne podobne języki może zainteresują się Visual Basic. Jednak im również polecam C# ze względu na to, że jest reprezentantem dużo popularniejszej rodziny języków oraz łatwiej znaleźć pomoc w Internecie.

Program Visual C# Express 2010 można pobrać darmowo ze strony microsoftu, studenci mogą darmowo pobrać Visual Studio 2010 z MSDNAA. Dla pozostałych licencja na Visual Studio niestety jest płatna. Ja używam wersji Express.

Po zakończonej, udanej instalacji otwieramy Visual C# 2010 Express i wybieramy:

File->New Project

Ukazuje nam się poniższe okno (w pełnej wersji Visual Studio 2010 mamy do wyboru więcej rodzajów projektów).

Visual C# 2010 Express New Project

Visual C# 2010 Express New Project

Wybieramy Windows Forms Aplication Visual C#, a na dole wybieramy nazwę dla naszego projektu i klikamy OK. Powinien nam się ukazać widok Designera:

usart_4

Widzimy w nim, jak wygląda nasza aplikacja okienkowa. Jeżeli klikniemy teraz zielony przycisk Play na górnym pasku lub Debug->Start Debugging zobaczymy, że aktualnie nasz program jest pustym okienkiem, a jedyną jego funkcjonalnością są 3 przyciski w prawym górnym rogu.

Dobrze jest od razu rozmieścić panele opcji w celu wygodniejszej pracy z programem. Najpierw klikamy na zaznaczony kółkiem młotek. Uaktywnia on panel z elementami, które możemy dodawać do naszej formy.

Po kliknięciu na nasze okienko Form1 prawym przyciskiem i wybranie Properties, ukażą nam się opcje obiektu. Ta zakładka będzie nam często potrzebna. Dlatego przesunąłem ją na prawo bez autoukrywania. Drzewo projektu przeniosłem za to na lewą stronę ekranu. Ostatecznie wszystko wygląda tak:

usart_5

Wprowadzenie do C#

Teraz parę słów o języku C#. Jest to język obiektowy, czyli składający się z elementów (obiektów), należących do klas. Każda klasa posiada swoje parametry - zmienne oraz metody - funkcje, działające na tych parametrach, zwracające ich wartości, konwertujące do innych typów itp.

Poszczególne części składowe klas mogą mieć atrybuty private (dostępne tylko dla metod danej klasy) lub public (dostępne również dla innych klas). Atrybutów tych używa się w celu zwiększenia bezpieczeństwa kodu. Powszechną praktyką jest ustawianie zmiennych klasy jako prywatne, a metod jako publiczne.

Szczególne metody to konstruktor (funkcja o takiej samej nazwie jak klasa, klasy mogą mieć więcej niż jeden konstruktor. Poszczególne z nich mają taką samą nazwę, ale różne argumenty) oraz destruktor. Odpowiadają one za inicjalizację oraz zakończenie życia obiektu, należącego do danej klasy.

Poza tym klasy mogą po sobie dziedziczyć parametry i metody, parametrem jednej klasy mogą być inne itp. Z początku może się to wydawać dość zagmatwane, ale w rzeczywistości jest ogromnym ułatwieniem. Typy zmiennych, takie, jak int czy double również są w C# klasami. Można zatem wykorzystywać metody, w które są wyposażone. Przykładowo ToString() daje na wyjściu zapis np. liczby int jako łańcucha znaków. Nie zmienia to oczywiście dotychczasowych zastosowań tych rodzajów zmiennych. W związku z tym inty można dalej normalnie dodawać, odejmować itp. ale oprócz tego mają dodatkowe funkcjonalności.

Taka czysta teoria dotycząca języka i tak nie ma większego sensu, więc przejdziemy już do tworzenia naszej aplikacji. Jeżeli kogoś bardziej interesują podstawy języka C# oraz programowania na platformie .NET polecam bardzo obszerną bibliotekę microsoftu oraz przeszukanie Internetu, gdzie istnieje ogromna ilość tutoriali i kursów dla początkujących, a także artykułów na każdym poziomie zaawansowania.

Tworzenie szablonu aplikacji

Najpierw zastanówmy się, jak nasza aplikacja ma wyglądać i co ma robić. Ten etap projektowania jest znacznie uproszczony dzięki Designerowi i możliwości podglądu okna na bieżąco. Na pewno będzie potrzebny panel konfigurujący połączenie oraz jakiś sposób wysyłania i odbierania wiadomości.

Na początku warto zrobić zwykły terminal z dwoma polami tekstowymi. W jednym będą ukazywać się wiadomości wysłane, a w drugim odebrane albo jedno pole tekstowe z całą "rozmową". Później będzie można rozszerzyć funkcjonalność na transmisję według jakiegoś bardziej zaawansowanego protokołu np. do odbierania w sposób ciągły danych z czujników robota, wczytywania zawartości EEPROM albo do sterowania serwomechanizmami.

Nasza aplikacja będzie się składać z trzech zakładek - terminala ogólnego przeznaczenia, protokołu komunikacji z konkretnym mikrokontrolerem, a także opcji połączenia.

Powiększmy nasze okienko. W opcjach można również zmienić nazwę, tekst i rozmiar czcionki w celu ułatwienia sobie późniejszej pracy i lepszej estetyki. Następnie po odszukaniu w Toolboxie w grupie Containers TabControl, dodajmy go do naszego okna. W opcjach Taba należy znaleźć parametr Dock i przestawić na Fill. Wtedy wypełni całe okno. Następnie szukamy opcji Tab Pages i klikamy na przycisk "...". Tam dodajemy trzeciego taba i zmieniamy nazwy oraz wyświetlamy tekst zgodnie z poniższym obrazkiem:

usart_6

Nazwy i tekstu drugiego taba jeszcze nie zmieniałem. Najpierw zrobimy terminal, a tab zarezerwowany na bardziej wysublimowany sposób komunikacji, zostawię sobie na ewentualną drugą część. Równie dobrze można zrobić jedynie taby z opcjami i terminalem, bo, jak widać, zarządzanie tabami jest bardzo proste i wymaga jedynie użycia przycisków Add i Remove. Teraz przechodzimy do taba opcji i dodajemy elementy typu label, combobox i button. Docelowo chcemy uzyskać coś takiego:

usart_7

Za każdym razem pamiętamy o zmianie pól Text i Name w opcjach. Nazwy zmieniamy na takie, żeby było wiadomo do czego służy dany element. Ja na przykład używam cbName, cbBaud, butRefresh itp. Przy ComboBoxach należy jeszcze w opcji DropDownStyle wybrać DropDownList, aby można było wybierać wartości tylko ze zdefiniowanego przez nas zbioru.

Dla ComboBoxów dotyczących prędkości transmisji i ilości bitów danych należy jeszcze ręcznie zdefiniować elementy tego zbioru. Odnajdujemy opcję Items i klikamy na kropki przy napisie Collection. Tam wpisujemy dla bitów danych wartości od 5 do 9, każda odzielona enterem. Natomiast w drugim wpisujemy wszystkie standardowe prędkości transmisji czyli:

Po zrobieniu zakładki opcji, podobnej do tej na rysunku albo według własnego uznania, możemy przejść do projektowania terminala. Mój wygląda tak:

usart_8

Składa się z dwóch Labeli, dwóch Buttonów, jednego Rich Text Boxa, jednego NumericUpDown i z jednego PictureBoxa. Czerwony kwadracik będzie przyciskiem do rozpoczynania/kończenia połączenia i jednocześnie będzie pokazywać aktualny status.

W dużym polu tekstowym będą wyświetlane dotychczas wysłane/odebrane dane w kodzie szesnastkowym. Za pomocą małego pola Numeric będzie można wybierać wartość nowego bajtu do wysłania w kodzie szesnastkowym.

Naciśnięcie przycisku Wyślij będzie powodować wysłanie aktualnej wartości przez port COM, a Wyczyść będzie czyścić Log. Należy pamiętać o kilku ustawieniach w opcjach. W PictureBoxie ustawiamy BackColor na Red, w RichTextBoxie ustawiamy ReadOnly na True, aby przypadkowo nie zmieniać zawartości loga.

W NumericUpDown zmieniamy opcję Hexadecimal na true, aby liczby były wyświetlane szesnastkowo, a wartości Minimum i Maximum odpowiednio na 0 i 255, aby zamykały się w jednym bajcie.

W ten sposób udało nam się zakończyć fazę projektowania "designu" naszej aplikacji. Do tej pory wszystko było proste i nie miało nic wspólnego z prawdziwym programowaniem. Nasza aplikacja już wygląda całkiem nieźle i po kompilacji nawet ma niektóre funkcje takie jak wybieranie wartości bajtu czy możliwość wyboru niektórych opcji z rozwijanej listy.

Następnym krokiem będzie dodanie funkcjonalności odpowiednim przyciskom i implementacja połączenia szeregowego. Ale to już zrobimy za pomocą zwykłego programowania a nie przeciągania elementów i zmiany ich właściwości.

Programowanie

Aby zobaczyć prawdziwy kod naszego programu musimy w Solution Explorerze znaleźć główny plik (domyślnie jest to Form1.cs), kliknąć prawym przyciskiem i wybrać View Code. Naszym oczom ukaże się zapis:

Pierwsza linijka określa przestrzeń nazw do której należą definiowane przez nas klasy. Projekt może korzystać z wielu plików i nie trzeba ich scalać za pomocą popularnego w innych językach słowa include. Wystarczy, że wszystkie pliki w projekcie będą miały tę samą przestrzeń nazw.

Dalej mamy deklarację naszej głównej klasy oraz jej konstruktor, w którym znajduje się funkcja InitializeComponent. To ona tworzy okienko jakie widzimy po kompilacji programu.

Nasuwa się pytanie, co to za magiczna funkcja, która nie przyjmuje żadnych parametrów i dokładnie wie jakie okienko ma dla nas stworzyć. Odpowiedź na to pytanie kryje się pod słowem kluczowym partial oraz w innym pliku należącym do naszego projektu - Form1.Designer.cs. Jeśli go otworzymy, widzimy również definicję naszej klasy ze słówkiem partial w przestrzeni nazw TutorialCOM. Jest to oczywiście druga część deklaracji naszej głównej klasy. Właśnie tam znajduje się funkcja InitializeComponent, aktualizowana automatycznie, kiedy dodajemy coś do designera.

Na początku pliku z kodem możemy znaleźć linijki, rozpoczynające się od słowa using. Informują one kompilator o standardowych przestrzeniach nazw, jakich będziemy używali w naszym programie.

Te aktualnie wygenerowane w naszym pliku odnoszą się do klas używanych w designerze. Co daje użycie słowa using? Najłatwiej będzie to przedstawić na przykładzie.

Do naszego programu będziemy potrzebować namespace System.IO.Ports, gdzie znajduje się klasa SerialPort, obsługująca port szeregowy. Do naszego programu musimy dodać element powyższej klasy, aby móc realizować połączenie. We wnętrzu klasy możemy zdefiniować sobie zmienną:

System.IO.Ports.SerialPort port;

Jeżeli dalej będziemy chcieli odwoływać się do elementów tej przestrzeni nazw, za każdym razem od nowa musimy pisać System.IO.Ports. Przy okazji widzimy po wpisaniu kropki, że Visual Studio wyświetla rozwijaną listę z dostępnymi elementami do wyboru co wielce ułatwia pisanie. Mimo wszystko umieszczanie za każdym razem tej ścieżki znacząco przedłuża pisanie. Dlatego właśnie w początkowej części pliku możemy dodać linijkę:

using System.IO.Ports;

Wtedy nasza definicja zmiennej może zostać skrócona do samego:

SerialPort port;

Od tej pory nie musimy za każdym razem pisać pełnej ścieżki. Dzięki słowu kluczowemu using, kompilator wie, gdzie szukać używanych przez nas klas. Mamy dodaną zmienną typu SerialPort. Teraz musimy ją zainicjalizować w konstruktorze za pomocą następującego kodu:

Opcje połączenia będziemy modyfikować w odpowiedniej zakładce. Musimy więc zadbać o to, żeby wyświetlały tam się poprawne wartości, zarówno aktualne, jak i dostępne na rozwijanych listach. W tym celu musimy utworzyć obsługę zdarzenia, które będzie się uruchamiać zawsze, kiedy wejdziemy do zakładki opcji. W tym celu w konstruktorze dodajemy event:

a pod spodem funkcję go obsługującą:

Opcje.Enter jest eventem przypisanym do obiektu o nazwie opcje i uruchamianym zawsze, kiedy wejdziemy w tę zakładkę. Za każdym razem, gdy zajdzie ten event wykonywane są wszystkie EventHandlery (czyli funkcje), jakie się w nim znajdują.

Na evencie można wykonać operację dodania Event Handlera += lub odjęcia -=. Natomiast w funkcji obsługującej event, poza prostym przypisaniem Stringów do tekstów danych pól, mamy ciekawą konstrukcję foreach. Służy ona do operacji na wszystkich możliwych elementach jakie znajdziemy w danym zbiorze, kiedy jeszcze nie wiemy, ile ich będzie.

W naszym wypadku dodajemy do listy każdy element typu String, jaki znajdziemy w zbiorach nazw portów, opcji parzystości i opcji stopu. Dzięki temu jeśli podłączymy coś do 5 portów COM, to na liście znajdzie się 5 elementów, a jeżeli nic nie podłączymy, to lista będzie pusta. Jest to niezwykle przydatna komenda.

Jeśli teraz skompilujemy program to możemy łatwo sprawdzić działanie rozwijanych list. Przed użyciem foreach, czyścimy zawartość list, aby ewentualnie nie duplikować, ani żeby nie było tam nieaktualnych wartości. Ważne jest, by najpierw użyć konstrukcji foreach, a dopiero potem przypisać teksty, ponieważ funkcja Clear kasuje zawartość listy włącznie z aktualną wartością.

Dlatego właśnie dodałem przycisk Odśwież, za pomocą którego będziemy mogli aktualizować od razu te parametry. Jeżeli otworzymy designera i klikniemy dwukrotnie na przycisk Odśwież, automatycznie wygeneruje nam się cały kod do obsługi eventu kliknięcia przycisku. U nas jednak ten event będzie wyglądał dokładnie tak samo jak w przypadku uaktywnienia opcji. Więc można usunąć wygenerowaną funkcję handlera, a w Form1.Designer.cs odszukać wiersz:

i zamienić go na:

Utwórzmy teraz event kliknięcia przycisku Domyślnie tak, aby automatycznie zmieniał wartości na takie, jakie chcemy. Ja dałem następujące:

Natomiast dla przycisku Anuluj sprawmy, aby przyjmował takie wartości, jak przy aktywacji zakładki:

Mamy już gotową całą zakładkę opcji. Możemy wybierać właściwości połączenia z listy, a kliknięcie przycisku wywołuje odpowiednią akcję. Zróbmy teraz porządek z zakładką Terminal. Czerwony kwadracik ma służyć do ustanawiania połączenia. W tym celu należy stworzyć event od kliknięcia i umieścić tam następujący kod:

Na pierwszy rzut oka może on wydawać się straszny, dlatego teraz dokładnie go przeanalizujemy.

Jeżeli port jest otwarty, kończymy połączenie, a picturebox i label ustawiamy jak na początku. Jeżeli natomiast port jest zamknięty i chcemy go otworzyć, musimy się liczyć z możliwościami błędów. Dlatego właśnie używamy struktury try-catch.

Najpierw wykonywane są polecenia z nawiasu try. Jeżeli program napotka jakiś błąd, przechodzi do sekcji catch i wyświetla na ekranie informacje o błędzie. Jeśli nie byłoby tego fragmentu, program by się zawieszał. Jeżeli natomiast wykona bez problemów całą zawartość nawiasu try, pomija część catch i przechodzi dalej.

Sama zawartość nawiasu try składa się najpierw z przepisania wartości portu z opcji, otwarcia portu i ustawienia koloru kwadratu na zielony, a tekstu na informację o aktywnym połączeniu. Funkcja wyrzuca również na terminal odpowiednią wiadomość statusową w kolorze pomarańczowym. Do tego służy funkcja DodajKolorowy, do której jeszcze wrócimy.

Wysyłanie danych

Kiedy klikniemy przycisk Wyślij, aktualna wartość pola NumericUpDown powinna zostać wysłana przez COMa. W tym celu tworzymy kolejny event poprzez dwukrotne kliknięcie w designerze. Jego obsługa wygląda następująco:

Warto tu zwrócić uwagę na kilka rzeczy. Po pierwsze - funkcja ToString z argumentem "X" zamienia liczby int na postać szesnastkową. Jest to dużo szybsze w porównaniu z samodzielnie napisaną podobną funkcją.

Konstrukcja warunkowa if-else zabezpiecza nas przed próbą wysłania wiadomości przy nieaktywnym połączeniu. Skupmy się teraz na funkcji DodajKolorowy. Zmiana koloru czcionki jest niezbędna, ponieważ w jednym polu tekstowym mają być wyświetlane wiadomości wychodzące, przychodzące i statusowe. Jeżeli jednak będziemy to próbowali robić w konwencjonalny sposób, a tekst dodamy xxx.Text += "string"; to poprzedni tekst również zmieni kolor psując kompletnie efekt. Dlatego trzeba obejść problem za pomocą dodatkowej funkcji, wykorzystującej polecenie AppendText:

Znając długość pierwotną i końcową tekstu w boxie, zaznaczamy daną część Stringa, a następnie zmieniamy kolor tylko zaznaczonej części. W ten sposób obchodzimy problem kolorowania całości tekstu przez standardową funkcję dodawania Stringa. Jako że będzie nam to potrzebne w kilku miejscach, stworzenie funkcji odpowiedniej do tego jest dla nas ułatwieniem.

Odbieranie wiadomości

Na koniec zostało nam najtrudniejsze zadanie. Musimy dodać event, wyświetlający przychodzącą wiadomość w TextBoxie. Może się wydawać, że zadanie nie będzie się bardzo różniło od poprzednich eventów, jednak rzeczywistość jest nieco inna. Rozpoczynamy od dodania w konstruktorze klasy eventu od przychodzących danych do portu COM:

Teraz wystarczy dorobić funkcję Handlera do tego eventa. I tu właśnie pojawia się trudność.

Dzieje się tak dlatego, że składowe części aplikacji tworzą oddzielne wątki. Bezpośrednia zmiana przez jeden wątek części składowej drugiego może powodować błędy. Aby uniknąć tego problemu należy użyć konstrukcji zwanej delegatem i operacji invoke. Więcej informacji o tych dwóch tworach znajdziecie tutaj oraz tutaj.

Delegat kryje w sobie odwołanie do jakichś funkcji. Aby móc go używać, należy stworzyć deklarację delegata oraz obiekt typu zadeklarowanego delegata. Kod umieszczamy w ciele klasy, obok deklaracji zmiennej port. W naszym przypadku będzie to wyglądać następująco:

Zadeklarowaliśmy w ten sposób delegata, zwracającego wartość typu void i niewymagającego żadnych argumentów oraz obiekt typu Delegat1 o nazwie moj_del1. Następnie, w konstruktorze funkcji, należy dokonać inicjalizacji:

WpiszOdebrane to funkcja, którą dopiero utworzymy i która będzie miała za zadanie dopisywanie odebranego tekstu do textboxa. W inicjalizacji delegata widać wielkie podobieństwo do eventów. Gdybyśmy nazwali naszego delegata xxxEventHandler zamiast Delegat1, nie byłoby żadnej różnicy.

Eventy to tak naprawdę delegaty utworzone już wcześniej w standardowych bibliotekach i poddane standaryzacji zwracanych wartości i argumentów wejściowych. Poza tym klasy, których eventy dotyczą, mają już zaimplementowany odpowiedni kod. Dzięki niemu event jest wywoływany. Przejdźmy teraz do utworzenia funkcji WpiszOdebrane:

Jak widać, ogranicza się ona do dodania do terminala tekstu w odpowiednim kolorze. Teraz musimy jeszcze dodać wywołanie naszego delegata po wykryciu przychodzącego bitu:

Zawiera ono wspomniane wcześniej słówko Invoke. Odpowiada ono za bezpieczne wywołanie funkcji delegata tak, aby nie zakłócić pracy innych wątków. Po dodaniu tej linijki mamy już w pełni sprawny terminal. Teraz wystarczy wybrać z górnego menu: debug->build solution, odnaleźć na dysku folder projektu, wejść w katalog bin/Release i znaleźć tam plik exe z naszym programem.

Zdaję sobie sprawę, że niektóre poruszone tutaj rzeczy mogą być trudne, dlatego w załączniku dodaję cały kod źródłowy programu. Przy okazji polecam samodzielne studiowanie materiałów z internetu, szczególnie z msdn, jeżeli chcecie w przyszłości wykorzystać C# do innych projektów.

Podsumowanie

Napisanie takiego terminala może bezpośrednio nie jest zbyt przydatne robotykowi. Tym bardziej, że wiele tego typu programów można po prostu ściągnąć, a mają one dużo więcej opcji. Jest to jednak doskonała okazja do poznania wszystkich funkcji sterujących portem szeregowym w naszym środowisku programistycznym i wstęp do trudniejszych projektów.

Sama aplikacja posiada jedną niewykorzystaną zakładkę. Zostanie ona wykorzystana, jeśli uda mi się napisać drugą część tego poradnika. Chciałbym w nim poruszyć zagadnienie prostego programu obsługującego USART ze strony mikrokontrolera oraz pomyśleć nad jakimś standardem przesyłania danych i jego implementacją zarówno od strony PC jak i uC.

Następny artykuł z serii »

Załączniki

TutorialCOM (rar, 81 KB)

Pliki projektu.

avr, komunikacja, RS232, terminal, USART

Trwa ładowanie komentarzy...