Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00145 007796 10468826 na godz. na dobę w sumie
RS 232C - praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera. Wydanie III - książka
RS 232C - praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera. Wydanie III - książka
Autor: Liczba stron: 504
Wydawca: Helion Język publikacji: polski
ISBN: 83-246-0778-1 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> inne - programowanie
Porównaj ceny (książka, ebook, audiobook).

Na uczelniach, w szkołach i biurach pojawia się coraz więcej zaawansowanych urządzeń komputerowych podłączanych przez port szeregowy. Czy koniecznie trzeba płacić wysokie stawki informatykom, aby wykorzystać pełnię możliwości tych nowoczesnych narzędzi? Na szczęście nie. Obsługa transmisji szeregowej przy użyciu standardu RS 232C może być na tyle łatwa, że uczniowie, studenci, nauczyciele, pracownicy naukowi czy inżynierowie mogą samodzielnie tworzyć potrzebne im oprogramowanie.

Dzięki książce 'RS 232C -- praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera. Wydanie III' także i Ty szybko nauczysz się pisać programy sterujące urządzeniami podłączanymi przez port szeregowy. Dowiesz się, jak działa transmisja asynchroniczna oraz czym jest standard RS 232C. Poznasz interfejs RS 232C dla systemu Windows i nauczysz się go używać w środowiskach programistycznych Builder i Delphi, co pozwoli Ci pisać potrzebne oprogramowanie w języku Pascal lub C++. Najnowsze, poprawione wydanie zawiera jeszcze więcej przykładów, dzięki którym błyskawicznie będziesz mógł sprawdzić nabytą wiedzę w praktyce.

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

RS 232C – praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera. Wydanie III Autor: Andrzej Daniluk ISBN: 978-83-246-0778-5 Format: B5, stron: 504 Na uczelniach, w szko³ach i biurach pojawia siê coraz wiêcej zaawansowanych urz¹dzeñ komputerowych pod³¹czanych przez port szeregowy. Czy koniecznie trzeba p³aciæ wysokie stawki informatykom, aby wykorzystaæ pe³niê mo¿liwoœci tych nowoczesnych narzêdzi? Na szczêœcie nie. Obs³uga transmisji szeregowej przy u¿yciu standardu RS 232C mo¿e byæ na tyle ³atwa, ¿e uczniowie, studenci, nauczyciele, pracownicy naukowi czy in¿ynierowie mog¹ samodzielnie tworzyæ potrzebne im oprogramowanie. Dziêki ksi¹¿ce „RS 232C — praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera. Wydanie III” tak¿e i Ty szybko nauczysz siê pisaæ programy steruj¹ce urz¹dzeniami pod³¹czanymi przez port szeregowy. Dowiesz siê, jak dzia³a transmisja asynchroniczna oraz czym jest standard RS 232C. Poznasz interfejs RS 232C dla systemu Windows i nauczysz siê go u¿ywaæ w œrodowiskach programistycznych Builder i Delphi, co pozwoli Ci pisaæ potrzebne oprogramowanie w jêzyku Pascal lub C++. Najnowsze, poprawione wydanie zawiera jeszcze wiêcej przyk³adów, dziêki którym b³yskawicznie bêdziesz móg³ sprawdziæ nabyt¹ wiedzê w praktyce. • Standard RS 232C • Transmisja asynchroniczna • Obs³uga RS 232C w systemach MS-DOS i Windows • Wykorzystanie elementów interfejsu Windows API w œrodowiskach Builder i Delphi • Testowanie programów do obs³ugi transmisji szeregowej • Tworzenie aplikacji wielow¹tkowych • Narzêdzia graficzne • Przyk³adowe aplikacje i ich analiza • Specyfikacje najwa¿niejszych funkcji Wydawnictwo Helion ul. Koœciuszki 1c 44-100 Gliwice tel. 032 230 98 63 e-mail: helion@helion.pl Spis treści 5 Spis treści Przedmowa do wydania trzeciego ...................................................... 9 Wprowadzenie ................................................................................ 11 Rozdział 1. Definicja interfejsu ......................................................................... 15 Rozdział 2. Nowoczesna transmisja asynchroniczna oraz standard RS 232C ...... 19 RTS-CTS handshaking .................................................................................................... 24 Konwertery interfejsu RS 232C ...................................................................................... 28 Konwertery USB/RS 232C .............................................................................................. 29 Właściwości portu konwertera .................................................................................. 31 Protokół XON-XOFF ...................................................................................................... 33 Protokół ENQ-ACK ........................................................................................................ 33 Protokół ETX-ACK ......................................................................................................... 34 Protokół SOH-ETX ......................................................................................................... 34 Protokoły typu master-slave ............................................................................................ 34 Rola oprogramowania a podstawowe funkcje interfejsu ................................................. 36 Podsumowanie ................................................................................................................. 38 Rozdział 3. Jak testować programy do transmisji szeregowej? ........................... 39 Mirror w MS-DOS ........................................................................................................... 39 Terminal dla Windows .................................................................................................... 41 Podsumowanie ................................................................................................................. 43 Rozdział 4. Transmisja szeregowa w MS-DOS .................................................... 45 Borland C++ .................................................................................................................... 45 Borland Pascal ................................................................................................................. 53 Funkcja 00h ............................................................................................................... 55 Funkcja 01h ............................................................................................................... 56 Funkcja 02h ............................................................................................................... 56 Funkcja 03h ............................................................................................................... 56 Podsumowanie ................................................................................................................. 58 Ćwiczenia ........................................................................................................................ 58 Rozdział 5. Programowa obsługa interfejsu RS 232C w Windows ...................... 59 Typy danych Windows .................................................................................................... 61 Proces projektowania oprogramowania ........................................................................... 64 Wykorzystanie elementów Windows API w C++Builderze. Część I ............................. 64 Struktura DCB ........................................................................................................... 65 Funkcja CreateFile() .................................................................................................. 65 6 RS 232C — praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera Funkcja GetCommState() .......................................................................................... 70 Funkcja SetCommState() .......................................................................................... 71 Funkcja CloseHandle() .............................................................................................. 71 Testowanie portu szeregowego ....................................................................................... 74 Struktura COMMPROP ............................................................................................ 78 Funkcja GetCommProperties() ................................................................................. 82 Struktura COMMCONFIG ....................................................................................... 88 Funkcje GetCommConfig() i SetCommConfig() ...................................................... 88 Funkcja CommConfigDialog() ................................................................................. 89 Struktura COMMTIMEOUTS .................................................................................. 90 Funkcje GetCommTimeouts() i SetCommTimeouts() .............................................. 91 Nawiązanie połączenia. Wariant I ................................................................................... 91 Segment inicjalizująco-konfiguracyjny ..................................................................... 92 Segment wysyłający komunikaty. Funkcja WriteFile() ............................................ 92 Segment odbierający komunikaty. Funkcja ReadFile() ............................................ 93 Przykładowa aplikacja ............................................................................................... 94 Nawiązanie połączenia. Wariant II .................................................................................. 97 Funkcja SetupComm() .............................................................................................. 98 Funkcja ClearCommError() ...................................................................................... 98 Struktura COMSTAT .............................................................................................. 100 Przykładowa aplikacja ............................................................................................. 102 Zamknięcie portu komunikacyjnego ....................................................................... 106 Nawiązanie połączenia. Wariant III .............................................................................. 107 Funkcje GetCommMask() i SetCommMask() ........................................................ 107 Funkcja WaitCommEvent() .................................................................................... 109 Przykładowa aplikacja działająca w środowisku tekstowym .................................. 110 Przykładowa aplikacja działająca w środowisku graficznym ................................. 118 Nawiązanie połączenia. Wariant IV .............................................................................. 123 Funkcja BuildCommDCB() .................................................................................... 123 Funkcja BuildCommDCBAndTimeouts() .............................................................. 125 Inne użyteczne funkcje .................................................................................................. 126 Podsumowanie ............................................................................................................... 128 Ćwiczenia ...................................................................................................................... 128 Wykorzystanie elementów Windows API w C++Builderze. Część II .......................... 129 Wysyłamy znak po znaku. Funkcja TransmitCommChar() .................................... 129 Wysyłamy pliki. Funkcje _lopen, _lread(), _lwrite(), _lclose() .............................. 133 Wykorzystanie komponentu klasy TTimer ............................................................. 143 Aplikacja nie lubi milczeć. Funkcja GetLastError() ............................................... 162 Break Time — czas oczekiwania aplikacji ............................................................. 167 Podsumowanie ........................................................................................................ 176 Ćwiczenia ................................................................................................................ 176 Wykorzystanie elementów Windows API w Delphi. Część I ....................................... 177 Testowanie portu szeregowego — inaczej .............................................................. 177 Rekord TCOMMPROP ........................................................................................... 183 Nawiązanie połączenia ............................................................................................ 191 Przykładowe aplikacje ............................................................................................. 194 Podsumowanie ........................................................................................................ 203 Ćwiczenia ................................................................................................................ 203 Wykorzystanie elementów Windows API w Delphi. Część II ...................................... 203 Wysyłamy znak po znaku ....................................................................................... 204 Wysyłamy pliki ....................................................................................................... 209 Timer w Delphi ....................................................................................................... 224 Podsumowanie ............................................................................................................... 238 Ćwiczenia ...................................................................................................................... 239 Spis treści 7 Rozdział 6. Aplikacje wielowątkowe ............................................................... 241 Najważniejszy jest użytkownik ..................................................................................... 242 Użytkownik steruje programem .............................................................................. 242 Możliwość anulowania decyzji ............................................................................... 243 Możliwość odbioru komunikatu nawet w trakcie wysyłania danych ..................... 243 Możliwość wysłania odrębnej informacji w trakcie transmisji pliku ..................... 243 Delphi ............................................................................................................................ 244 Funkcja BeginThread() ........................................................................................... 244 Konkurencja dla Timera .......................................................................................... 256 Klasa TThread ......................................................................................................... 264 Wielowątkowość i DLL-e ............................................................................................. 272 C++Builder .................................................................................................................... 280 Zamiast Timera ....................................................................................................... 289 Zamiast Timera. Inny sposób .................................................................................. 296 Klasa TThread ......................................................................................................... 304 Podsumowanie ............................................................................................................... 315 Ćwiczenia ...................................................................................................................... 315 Rozdział 7. Wykorzystanie niektórych narzędzi graficznych .............................. 317 Komponent klasy TChart ............................................................................................... 318 Podsumowanie ............................................................................................................... 328 Ćwiczenia ...................................................................................................................... 328 Rozdział 8. Przykładowe aplikacje wykorzystywane w systemach pomiarowych ........................................................... 329 Kontroler temperatury ................................................................................................... 330 Aplikacja obsługująca kilka urządzeń ........................................................................... 347 Programowanie inteligentne .......................................................................................... 358 Brak powtarzalności kodu ....................................................................................... 359 Czytelność kodu ...................................................................................................... 360 Łatwość testowania ................................................................................................. 364 Podsumowanie ............................................................................................................... 366 Ćwiczenia ...................................................................................................................... 366 Rozdział 9. Tworzenie komponentów .............................................................. 369 Komponent TOpenSerialPort. Realizacja w Delphi ...................................................... 369 Testowanie komponentu ......................................................................................... 374 Komponent TOpenSerialPort. Realizacja w C++Builderze .......................................... 380 Testowanie komponentu ......................................................................................... 386 Komponenty aktywne .................................................................................................... 389 Kompilacja projektu zawierającego komponent aktywny ...................................... 393 Odczytywanie i modyfikacja wartości własności komponentu aktywnego ............ 395 Komponenty w BDS 2006 ............................................................................................. 397 Podsumowanie ............................................................................................................... 398 Ćwiczenia ...................................................................................................................... 398 Rozdział 10. Modelowanie oprogramowania sterującego portem szeregowym .... 399 Schematy dziedziczenia ................................................................................................. 400 Ukrywanie konstruktora ................................................................................................ 405 Interfejsy ........................................................................................................................ 409 Delegowanie operacji .................................................................................................... 415 Delegowanie realizacji interfejsu do własności ............................................................. 422 Podsumowanie ............................................................................................................... 426 Ćwiczenia ...................................................................................................................... 427 8 RS 232C — praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera Rozdział 11. POSIX .......................................................................................... 435 Polecenie stty ................................................................................................................. 436 Ustawienia kontroli przesyłu danych (sterowanie transmisją) ................................ 437 Ustawienia wejściowe ............................................................................................. 437 Ustawienia wyjściowe ............................................................................................. 439 Ustawienia czasów oczekiwania ............................................................................. 439 Ustawienia lokalne .................................................................................................. 440 Specjalne znaki sterujące ........................................................................................ 441 Łączenie atrybutów ................................................................................................. 442 Podstawowe funkcje obsługi portu szeregowego .......................................................... 442 Funkcja open() ......................................................................................................... 442 Funkcja read() ......................................................................................................... 443 Funkcja write() ........................................................................................................ 443 Funkcja close() ........................................................................................................ 443 Struktura termios ........................................................................................................... 444 Funkcja tcgetattr() ................................................................................................... 448 Funkcja tcsetattr() .................................................................................................... 448 Funkcje cfgetispeed() i cfgetospeed() ..................................................................... 449 Funkcje cfsetispeed() i cfsetospeed() ...................................................................... 449 Funkcja tcflush() ..................................................................................................... 450 Funkcja tcdrain() ..................................................................................................... 451 QNX ............................................................................................................................... 451 Funkcja dev_insert_chars() ..................................................................................... 453 Funkcja dev_ischars() ............................................................................................. 453 Funkcja dev_read() .................................................................................................. 454 Funkcja Receive() ................................................................................................... 455 Funkcja Send() ........................................................................................................ 455 Funkcja Creceive() .................................................................................................. 455 Funkcja Reply() ....................................................................................................... 456 Funkcja qnx_proxy_attach() ................................................................................... 456 Funkcja qnx_proxy_detach() ................................................................................... 456 Podsumowanie ............................................................................................................... 457 Ćwiczenia ...................................................................................................................... 457 Dodatek A Specyfikacja funkcji CreateFile() — operacje plikowe ................... 461 Dodatek B Specyfikacja struktur MODEMDEVCAPS, MODEMSETTINGS oraz funkcji GetCommModemStatus() ........................................... 467 MODEMDEVCAPS ...................................................................................................... 467 MODEMSETTINGS ..................................................................................................... 470 GetCommModemStatus() .............................................................................................. 471 Dodatek C Transmisja asynchroniczna. Funkcje rozszerzone ........................... 473 Funkcja WriteFileEx() ................................................................................................... 473 Funkcja ReadFileEx() .................................................................................................... 474 Funkcja FileIOCompletionRoutine() ............................................................................. 474 Funkcja SleepEx() ......................................................................................................... 475 Funkcja WaitForSingleObjectEx() ................................................................................ 475 Dodatek D Zamiana liczb z postaci dziesiętnej na binarną .............................. 477 Dodatek E Funkcje CreateThread(), CreateMutex() i CreateSemaphore() ....... 481 Skorowidz .................................................................................... 487 Rozdział 5. Programowa obsługa interfejsu RS 232C w Windows Czwarte prawo Murphy’ego Gdy dojdziesz do wniosku, że są cztery sposoby, na jakie może się nie powieść dane przedsięwzięcie, i zabezpieczysz się przed nimi, rychło pojawi się piąta możliwość. Murphy’s Law and other reasons why things go wrong!, Artur Bloch, Price Stern Sloan Inc. 1977. Rozdział ten ma za zadanie zapoznać Czytelnika ze sposobami konstrukcji algorytmów realizujących transmisję szeregową w środowisku Windows, które charakteryzuje się pewnymi cechami niemającymi odpowiedników w MS-DOS. Poznanie i umiejętne wykorzystanie tych cech sprawi, iż problem obsługi interfejsów szeregowych z poziomu Windows — uważany powszechnie za trudny — przestanie być dla nas tajemnicą. Pokażemy, w jaki sposób należy tworzyć aplikacje służące do programowej obsługi łącza szeregowego RS 232C zarówno w C++, C++Builderze, jak i w Delphi. Wśród programi- stów istnieje zauważalny podział na osoby programujące głównie w Delphi oraz na prefe- rujące Buildera lub ogólnie C++ dla Windows. Jednak zdaniem wielu osób uniwersalność jest jedną z tych cech, jakie powinny charakteryzować programistę. W rozdziale tym przybliżymy Czytelnikowi podobieństwa i różnice w sposobie konstrukcji algorytmów realizujących transmisję szeregową, pisanych w Delphi oraz Builderze. W dalszej części książki będziemy się spotykać z typami danych, których poznanie i zro- zumienie ma kluczowe znaczenie w projektowaniu aplikacji obsługujących urządzenia zewnętrzne. Zacznijmy od ich przypomnienia. W tabeli 5.1 przedstawiono porównanie podstawowych typów zmiennych wykorzystywanych w kompilatorach, które będą dla nas istotne. Większości z nich można używać zamiennie, pisząc zarówno w Delphi, jak i w C++Builderze. 60 RS 232C — praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera Tabela 5.1. Typy zmiennych stosowanych w Delphi oraz w C++Builderze Rozmiar w bajtach Znak +/– Typ Delphi ShortInt SmallInt LongInt Byte Word Integer Cardinal Boolean ByteBool WordBool LongBool AnsiChar WideChar Char AnsiString String[n] ShortString String Single Double Extended Real Pointer PChar PAnsiChar Comp 1 2 4 1 2 4 4 1 1 2 4 1 2 1 ≈3GB n = 1.255 255 255 lub ≈3GB 4 8 10 4 4 4 4 8 C++Builder signed char short unsigned char unsigned short int unsigned int bool unsigned char unsigned short char wchar_t char AnsiString SmallString n SmallString 255 AnsiString float double long double double void * unsigned char * unsigned char * Comp Bez znaku Bez znaku Integer Integer Integer Integer Integer Integer Integer Integer Integer Bez znaku true/false true/false Bez znaku true/false Bez znaku true/false Integer Bez znaku 1 znak ANSI Character 1 znak Unicode Character Character Bez znaku AnsiString ANSIChar ANSIChar String String ANSIChar AnsiString ANSIChar Floating point number (liczba zmiennoprzecinkowa) Floating point number Floating point number Floating point number Generic pointer (wskaźnik ogólny, adresowy) Pointer to characters Pointer to ANSIChar Floating point number Bez znaku Bez znaku Konstruując nasze programy, będziemy starali się jak najszerzej wykorzystywać standar- dowe zasoby Windows, w szczególności tzw. interfejs programisty Windows API (ang. Application Programming Interface). Jego umiejętne wykorzystanie umożliwi naszym aplikacjom błyskawiczne skonfigurowanie i uzyskanie dostępu do portu komunikacyjne- go. Błędem jest twierdzenie, że sama — nawet bardzo dobra — znajomość języka pro- Rozdział 5. ♦ Programowa obsługa interfejsu RS 232C w Windows 61 gramowania wystarczy, żeby stworzyć poprawnie działający w Windows program. Otóż musimy zdawać sobie sprawę z faktu, o którym często się zapomina — niemożliwe jest napisanie udanej aplikacji mającej pracować w pewnym środowisku (czytaj — systemie operacyjnym) bez znajomości tego środowiska. Wiele już zostało powiedziane na temat dobrych i złych stron Windows, należy jednak pamiętać, że oferuje on nam swoją wizy- tówkę, ofertę współpracy, czyli API. Już nie wystarczy umiejętność wykorzystywania ulubionego kompilatora. Zasoby Delphi czy Buildera połączymy z zasobami systemu operacyjnego, a spoiwem będzie właśnie uniwersalne Windows API. Istnieje wiele warstw API używanych w zależności od potrzeb. W tym i dalszych rozdziałach zajmiemy się szeroko rozumianą warstwą komunikacyjną. Windows API korzysta ze specjalnego systemu nazewnictwa zmiennych, z tzw. notacji węgierskiej wprowadzonej przez Karoja Szimoniego. Zgodnie z nią do rdzenia nazwy zadeklarowanej zmiennej dodaje się przedrostek (ang. prefix). Chociaż istnieją pod tym względem pewne rozbieżności pomiędzy nazewnictwem Microsoftu i Borlanda, to jednak zapis taki bardzo ułatwia szybkie ustalenie roli zmiennej w programie oraz jej typ. W następnych rozdziałach będziemy się starali — wszędzie gdzie jest to możliwe — zachowywać samokomentujące się nazewnictwo API (większość nazw API będziemy traktować jako nazwy własne). Z doświadczenia wiadomo, że stosowanie takiej konwen- cji bardzo pomaga w studiowaniu plików pomocy. Oczywiście moglibyśmy silić się na oryginalność, wprowadzając własne zmienne, zrozumiałe tylko dla piszącego dany pro- gram — wówczas przykłady musiałyby być zapisane jako wręcz humorystyczna miesza- nina języków polskiego i angielskiego. Trzeba też przyznać, że byłby to bardzo skuteczny sposób zaciemnienia obrazu API. Zrozumienie znaczenia nazw tam stosowanych okaże się w przyszłości niezwykle cenne, gdyż API można czytać jak książkę. Aby pomóc Czy- telnikom, którzy nie zetknęli się dotąd z tymi pojęciami, w tabeli 5.2 przedstawiono ogól- ne zasady tworzenia niektórych przedrostków. Windows oferuje nam ponadto kilka typów danych, z których część tylko nieznacznie różni się sposobem zapisu w implementacjach Delphi i Buildera. Typy te mają najczę- ściej postać struktury lub klasy i są bardzo często wykorzystywane w warstwie komunika- cyjnej programów. Typy danych Windows Nowoczesna idea programowania w Windows oparta na wykorzystaniu narzędzi pro- gramistycznych typu RAD, do których zaliczają się C++Builder oraz Delphi, pozwala programistom na maksymalne uproszczenie procesu tworzenia oprogramowania. Jednym z przykładów dążenia do zminimalizowania czasu tworzenia aplikacji jest zastosowanie w Windows pewnych bardzo zwartych w zapisie typów danych, które oczywiście mają swoje odpowiedniki w typach standardowych. W tabeli 5.3 zebrano najistotniejsze typy danych, którymi bardzo często posługują się programy Windows. Należy zdawać sobie sprawę z faktu, iż typy takie jak np. LPVOID i LPSTR nie są w dosłownym słowa tego zna- czeniu typami nowymi, tzn. od początku stworzonymi na potrzeby aplikacji Windows, gdyż zostały zdefiniowane w plikach nagłówkowych za pomocą instrukcji typedef po to, aby uprościć zapis niektórych standardowych typów danych. W tabeli 5.3 przedstawiono wybrane typy danych, którymi posługuje się API Windows. 62 RS 232C — praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera Tabela 5.2. Ogólne zasady tworzenia przedrostków według notacji węgierskiej Przedrostek a b by cb ch dw evt f fdw fn h i id in l lp lpc lpfdw lpfn n np out p pfn que s (sz) st t u w wc Skrót angielski array bool byte unsigned char count of bytes char double word event flag flag of double word function handle integer (ID) identification input long int long pointer long pointer to C-string long pointer to flag of dw long pointer to function short or int near pointer output pointer pointer to function queue string struct type unsigned (word) unsigned int WCHAR Znaczenie Tablica Zmienna logiczna true lub false Znak (bajt) Liczba bajtów Znak Podwójne słowo Zdarzenie Znacznik Znacznik typu dw Funkcja Identyfikator (uchwyt) Typ całkowity 4-bajtowy Identyfikacja Wejście, dane wejściowe Typ całkowity długi 4-bajtowy Wskaźnik typu long int Wskaźnik typu long int do C-łańcucha Wskaźnik typu lp do znacznika typu double word Wskaźnik typu lp do funkcji Typ krótki lub całkowity Bliski wskaźnik (w środowisku 32-bitowym to samo co lp) Wyjście, dane wyjściowe (przetworzone) Wskaźnik (w środowisku 32-bitowym to samo co lp) Wskaźnik do funkcji Kolejka, bufor danych Łańcuch znaków Struktura Typ Bez znaku Słowo Znak zgodny z Unicode Rozdział 5. ♦ Programowa obsługa interfejsu RS 232C w Windows 63 Tabela 5.3. Niektóre typy danych stosowane w Windows Typ Windows BOOL BYTE DWORD LPDWORD LONG LPLONG LPCSTR LPCTSTR LPSTR LPVOID lub Pointer LPCVOID UINT WORD DWORD32 DWORD64 INT INT32 INT64 LONG32 LONG64 LONGLONG Znaczenie int z dwoma wartościami TRUE oraz FALSE unsigned char unsigned long unsigned long * long long * const char * unsigned const char * char * void * const void * unsigned int unsigned short 32-bitowy typ całkowity bez znaku 64-bitowy typ całkowity bez znaku 32-bitowy typ całkowity ze znakiem 32-bitowy typ całkowity ze znakiem 64-bitowy typ całkowity ze znakiem 32-bitowy typ całkowity ze znakiem 64-bitowy typ całkowity ze znakiem 64-bitowy typ całkowity ze znakiem Osobnym typem danych, bardzo często stosowanym w aplikacjach Windows, jest typ HANDLE. Jest on 32- lub 64-bitowym typem danych całkowitych oznaczającym tzw. uchwyt (ang. handle). Należy rozumieć, iż w rzeczywistości dane typu HANDLE nie obrazują jakichś tajemniczych uchwytów zakładanych na elementy aplikacji — są to po prostu 32- lub 64-bitowe liczby identyfikujące określony zasób aplikacji, systemu operacyjnego lub samego komputera. Z tego względu dane typu HANDLE często wygodniej i zręczniej jest określać mianem identyfikatorów, których wartości przechowywane są w określonym miejscu w pamięci. Cechą charakterystyczną identyfikatorów jest to, iż jeśli na początku programu inicjuje się je określonymi wartościami, w momencie zakończenia pracy aplikacji lub jej fragmentu należy przydzieloną im pamięć odpowiednio zwalniać. W tym celu wykorzystuje się funkcję API Windows: BOOL CloseHandle(HANDLE hObject); z argumentem w postaci określonego identyfikatora. Zaopatrzeni w powyższą terminologię pójdźmy dalej i zobaczmy, do czego mogą nam być przydatne poszczególne struktury oraz funkcje interfejsu programisty — Windows API. 64 RS 232C — praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera Proces projektowania oprogramowania Zanim przejdziemy do szczegółowego omawiania aspektów tworzenia programów obsłu- gujących port szeregowy w Windows, należy wybrać jedną z metod projektowania tego rodzaju aplikacji. Praktyka wskazuje, że dla pojedynczych użytkowników lub niewielkich organizacji dobrze sprawdza się metodologia oparta na programowaniu przyrostowym i iteracyjnym (ang. iterative and incremental development). W dalszej części książki będziemy korzystać z metody projektowania iteracyjnego. Takie podejście do zagadnienia sprawi, iż tworzone aplikacje oprócz wysokiej sprawności działania będą jeszcze miały dwie bardzo ważne i nieczęsto spotykane w literaturze cechy. Będą mianowicie: (cid:141) w pełni rozbudowywalne, (cid:141) łatwe do samodzielnej modyfikacji nawet przez osoby dopiero poznające zasady programowania w środowiskach Buildera i Delphi. Wszystkie prezentowane algorytmy będziemy się starali konstruować w ten sposób, aby pewne słynne twierdzenie wypowiedziane niegdyś przez Murphy’ego w omawianych programach nie miało zastosowania. Brzmi ono następująco: Twierdzenie o komplikacji procedur Każdą dowolnie skomplikowaną procedurę można skomplikować jeszcze bardziej. Twierdzenie odwrotne nie jest prawdziwe: nadzwyczaj rzadko się zdarza, aby skomplikowaną procedurę można było uprościć. Murphy’s Law and other reasons why things go wrong!, Artur Bloch, Price Stern Sloan Inc. 1977. Wykorzystanie elementów Windows API w C++Builderze. Część I Poznawanie tajników obsługi portu szeregowego w Windows rozpoczniemy, z czysto praktycznych względów, od pisania programów w C++Builderze. C++ ma składnię taką jak API, dlatego prościej nam będzie zapoznać się z budową funkcji oraz struktur ofero- wanych przez interfejs programisty. Ułatwi to też zrozumienie, w jaki sposób i w jakiej kolejności należy umieszczać je w programie. Rozdział 5. ♦ Programowa obsługa interfejsu RS 232C w Windows 65 Struktura DCB Fundamentalne znaczenie ma struktura kontroli urządzeń zewnętrznych DCB (ang. Device Control Block). W Windows struktura DCB w pewnym sensie odpowiada funkcji 00h przerwania 14h BIOS-u. Udostępnia nam jednak nieporównywalnie większe możliwości programowej obsługi łącza szeregowego; umożliwia bezpośrednie programowanie reje- strów układu UART. W tabelach 5.4 oraz 5.5 przedstawiono specyfikację bloku kontroli urządzeń zewnętrznych DCB. Większość pól tej struktury to pola jednobitowe. fDtrControl, fRtsControl są polami dwubitowymi. Aktualnie nieużywane w XP pole fDummy2 jest siedemnastobitowe. W per- spektywie, wraz z wReserved oraz wReserved1, będzie wykorzystane na potrzeby innych protokołów komunikacyjnych. W Windows API blok kontroli urządzeń deklarowany jest w sposób następujący: typedef struct _DCB { DWORD DCBlength; ... } DCB; Deklaracja ta tworzy nowe słowo kluczowe typu DCB (struktura). Zalecane jest, aby przed użyciem tej struktury jako parametru do elementu DCBlength wpisać wartość sizeof(DCB). Strukturę tworzy zbiór logicznie powiązanych elementów, np. zmiennych lub (i) pól bitowych. Pole bitowe stanowi zbiór przylegających do siebie bitów, znajdujących się w jednym słowie. Adres struktury pobieramy za pomocą operatora referencji , co umożliwia nam działania na jej składowych. Do struktury jako całości możemy odwołać się przez jej nazwę, zaś do poszczególnych jej elementów, czyli zmiennych oraz pól bitowych, przez podanie nazwy zmiennej reprezentującej strukturę oraz — po kropce — nazwy konkretnej zmiennej lub pola struktury, np.: dcb.fDtrControl = DTR_CONTROL_ DISABLE. Operator składowych struktur . jest lewostronnie łączny. Grupa związanych ze sobą zmiennych i pól bitowych traktowana jest jako jeden obiekt. Zanim przejdziemy do praktycznego zastosowania poznanych pól struktury DCB, musimy zapoznać się z czterema podstawowymi funkcjami Windows API służącymi do progra- mowej konfiguracji portów szeregowych. W dalszej części książki funkcji takich będzie przybywać, ale te przedstawione poniżej należy traktować jako najbardziej podstawowe. Funkcja CreateFile() Jest to funkcja służąca do utworzenia i otwarcia pliku lub urządzenia. Już sama nazwa wskazuje, że może być wykorzystywana nie tylko do obsługi portu szeregowego. Teraz jednak będzie nas interesować tylko to konkretne zastosowanie. Specyfikacja zasobów funkcji CreateFile() najczęściej używanych do operacji plikowych zamieszczona jest w dodatku A. Funkcja ta da nam 32- lub 64-bitowy identyfikator danego portu przecho- wywany pod właściwością HANDLE, do którego będą adresowane wszystkie komunikaty. 66 RS 232C — praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera Tabela 5.4. Zmienne struktury DCB reprezentujące dopuszczalne parametry ustawień portu szeregowego Typ Zmienna Znaczenie DWORD DWORD DCBlength BaudRate Rozmiar struktury Określenie prędkości transmisji (b/s) WORD WORD wReserved XonLim WORD XoffLim BYTE BYTE ByteSize Parity Nieużywane Określenie minimalnej liczby bajtów w buforze wejściowym przed wysłaniem specjalnego znaku sterującego XON Określenie maksymalnej liczby bajtów w buforze wejściowym przed wysłaniem specjalnego znaku sterującego XOFF Wybór liczby bitów danych Określenie kontroli parzystości BYTE StopBits Wybór bitów stopu char XonChar char XoffChar char ErrorChar char EofChar Char EvtChar Określenie wartości znaku XON dla nadawania i odbioru (wysłanie znaku przywraca transmisję) Określenie wartości znaku XOFF dla nadawania i odbioru (wysłanie XOFF wstrzymuje transmisję do czasu odebrania znaku XON) Określenie wartości znaku zastępującego bajty otrzymane z błędem parzystości Określenie wartości znaku końca otrzymanych danych Określenie wartości znaku służącego do sygnalizowania wystąpienia danego zdarzenia WORD wReserved1 Obecnie nieużywane Wartość, stała symboliczna Należy wpisać CBR_110 CBR_19200 CBR_300 CBR_38400 CBR_600 CBR_56000 CBR_1200 CBR_57600 CBR_2400 CBR_115200 CBR_4800 CBR_128000 CBR_9600 CBR_256000 CBR_14400 0 Domyślnie: 65 535; w praktyce XonLim ustala się jako ½ rozmiaru deklarowanego wejściowego bufora danych Domyślnie: 65535; w praktyce XoffLim ustala się jako ¾ rozmiaru deklarowanego bufora wejściowego 5, 6, 7, 8 EVENPARITY — parzysta; MARKPARITY — bit parzystości stale równy 1; NOPARITY — brak kontroli; ODDPARITY — nieparzysta ONESTOPBIT — 1 bit stopu; ONE5STOPBITS — w przypadku słowa 5-bitowego bit stopu wydłużony o ½; TWOSTOPBITS — 2 bity stopu Standardowo (char) DC1, dziesiętnie: 17 Standardowo (char) DC3, dziesiętnie: 19 Opcjonalnie: 0 lub SUB Opcjonalnie: 0 Opcjonalnie: 0 Rozdział 5. ♦ Programowa obsługa interfejsu RS 232C w Windows 67 Tabela 5.5. Pola bitowe reprezentujące dopuszczalne wartości znaczników sterujących struktury DCB Typ Pole bitowe Właściwości pola DWORD fBinary DWORD fParity DWORD fOutxCtsFlow DWORD fOutxDsrFlow Tryb binarny (Win API podtrzymuje jedynie ten tryb transmisji danych) Umożliwia ustawienie sprawdzania parzystości — sposobu reakcji na bit parzystości Umożliwia ustawienie sprawdzania sygnału na linii CTS w celu kontroli danych wyjściowych Umożliwia ustawienie sprawdzania sygnału na linii DSR w celu kontroli danych wyjściowych DWORD fDtrControl Specyfikacja typu kontroli sygnału DTR DWORD fTXContinueOnXoff Kontrola przerwania transmisji w przypadku przepełnienia bufora wejściowego i ewentualnie wystąpienia znaków XoffChar oraz XonChar DWORD fDsrSensitivity Specyfikacja wykorzystania poziomu sygnału na linii DSR Wartość, znaczenie, stała symboliczna TRUE TRUE — kontrola parzystości włączona; FALSE — bit parzystości nie jest sprawdzany TRUE — jeżeli sygnał CTS jest nieaktywny, transmisja jest wstrzymywana do czasu ponownej aktywacji linii CTS; FALSE — włączenie sygnału na linii CTS nie jest wymagane do rozpoczęcia transmisji TRUE — jeżeli sygnał DSR jest nieaktywny, transmisja jest wstrzymywana do czasu ponownej aktywacji linii DSR; FALSE — włączenie sygnału na linii DSR nie jest wymagane do rozpoczęcia transmisji DTR_CONTROL_DISABLE / 0 — sygnał na linii DTR jest nieaktywny; DTR_CONTROL_ENABLE / 1 — sygnał na linii DTR jest aktywny; DTR_CONTROL_HANDSHAKE / 2 — włączenie potwierdzania przyjęcia sygnału DTR — potwierdzenie musi być odebrane na linii DSR. Używane w trybie półdupleksowym. Ewentualne błędy transmisji w tym trybie są usuwane przez funkcję EscapeCommFunction() TRUE — wymuszanie kontynuowania transmisji nawet po wystąpieniu znaku XOFF i wypełnieniu wejściowego bufora danych powyżej XoffLim bajtów; FALSE — transmisja nie jest kontynuowana, dopóki bufor wejściowy nie zostanie opróżniony do pułapu XonLim bajtów i nie nadejdzie znak XON potwierdzenia dalszego odbioru TRUE — otrzymane bajty są ignorowane, o ile linia DSR nie jest w stanie wysokim; FALSE — stan linii DSR jest ignorowany 68 RS 232C — praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera Tabela 5.5. Pola bitowe reprezentujące dopuszczalne wartości znaczników sterujących struktury DCB — ciąg dalszy Typ Pole bitowe Właściwości pola DWORD fInX Programowe ustawienie protokołu XON-XOFF w czasie odbioru danych DWORD fRtsControl Specyfikacja kontroli sygnału na linii RTS DWORD fOutX DWORD fErrorChar DWORD fNull Programowe ustawienie protokołu XON-XOFF w czasie wysyłania danych Umożliwia zastąpienie bajtów otrzymanych z błędem parzystości znakiem ErrorChar Odrzucenie odebranych nieważnych lub uszkodzonych bajtów Wartość, znaczenie, stała symboliczna TRUE — znak XoffChar jest wysyłany, kiedy bufor wejściowy jest pełny lub znajduje się w nim XoffLim bajtów; znak XonChar jest wysyłany, kiedy bufor wejściowy pozostaje pusty lub znajduje się w nim XonLim bajtów; FALSE — XON-XOFF w czasie odbioru nie jest ustawiony RTS_CONTROL_DISABLE / 0 — sygnał na linii RTS jest nieaktywny; RTS_CONTROL_ENABLE / 1 — sygnał na linii RTS jest aktywny; RTS_CONTROL_HANDSHAKE / 2 — włączenie potwierdzania przyjęcia sygnału RTS (potwierdzenie musi być odebrane na linii CTS). Używane w trybie półdupleksowym. Sterownik podwyższa stan linii RTS, gdy wypełnienie bufora wejściowego jest mniejsze od ½. Stan linii RTS zostaje obniżony, gdy bufor wypełniony jest w ¾. Ewentualne błędy transmisji w tym trybie usuwane są przez funkcję EscapeCommFunction(); RTS_CONTROL_TOGGLE / 3 — linia RTS jest w stanie wysokim, jeżeli są bajty do transmisji i jest ona możliwa; po opróżnieniu bufora komunikacyjnego linia RTS pozostaje w stanie niskim TRUE — transmisja zostaje przerwana po odebraniu znaku XoffChar i wznowiona po otrzymaniu znaku XonChar; FALSE — XON-XOFF w czasie wysyłania nie jest ustawiony TRUE — zastąpienie jest wykonywane, ponadto fParity musi być ustawione jako TRUE; FALSE — zastąpienie nie jest wykonane TRUE — nieważne bajty zostaną odrzucone przy odbiorze; FALSE — nieważne bajty nie będą odrzucane Rozdział 5. ♦ Programowa obsługa interfejsu RS 232C w Windows 69 Tabela 5.5. Pola bitowe reprezentujące dopuszczalne wartości znaczników sterujących struktury DCB — ciąg dalszy Typ Pole bitowe Właściwości pola DWORD fAbortOnError Ustawienie wstrzymywania operacji nadawanie-odbiór przy wykryciu błędu transmisji Wartość, znaczenie, stała symboliczna TRUE — wszelkie operacje nadawania i odbioru są wstrzymywane, zaś dalsza komunikacja nie jest możliwa, dopóki błąd nie zostanie usunięty przez wywołanie funkcji ClearCommError(); FALSE — nawet jeżeli wystąpi błąd, transmisja jest kontynuowana — błąd może być usunięty przez wywołanie funkcji ClearCommError() DWORD fDummy2 Zarezerwowane, nieużywane Ogólnie rzecz ujmując, przed rozpoczęciem czytania z portu szeregowego (lub innego urządzenia) należy o powyższym fakcie poinformować system operacyjny. Czynność tę określa się jako otwieranie portu do transmisji. Jednak zanim zaczniemy wykonywać jakiekolwiek operacje na porcie, system operacyjny musi sprawdzić, czy wybrany port komunikacyjny istnieje i czy w danym momencie nie jest już przypadkiem w jakiś sposób wykorzystywany. W przypadku uzyskania dostępu do portu system operacyjny przeka- zuje do aplikacji jego identyfikator. We wszystkich operacjach wejścia-wyjścia zamiast szczegółowej nazwy portu komunikacyjnego używa się właśnie jego identyfikatora. Składnia CreateFile() wygląda następująco1: HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD ShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDistribution, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); Niekiedy identyfikatory tego typu nazywa się uchwytami. Niestety, dosłowne prze- tłumaczenie angielskiego słowa handle jako uchwyt, np. handle of drawer — uchwyt, rączka szuflady, nie jest w pełni adekwatne. Właściwsze wydaje się utożsamianie handle z identyfikatorem (unikalną wartością zlokalizowaną w danym obszarze pa- mięci i skojarzoną z konkretnym portem komunikacyjnym, oknem czy plikiem). W po- tocznej angielszczyźnie handle może również oznaczać ksywę pozwalającą na szybką identyfikację danej osoby lub rzeczy. Koncepcja identyfikatorów nie jest niczym nowym, stosowano ją już w MS-DOS, jednak dopiero w Windows zyskała nową jakość. Na tym etapie naszych rozważań tylko trzy parametry powyższej funkcji są istotne dla kompletnej konfiguracji portu szeregowego. Wyjaśnimy teraz ich znaczenie. 1 Pełna specyfikacja funkcji CreateFile() została zamieszczona w dodatku A. 70 RS 232C — praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera Pierwszy parametr, lpFileName, jest wskaźnikiem do zadeklarowanego ciągu znaków zakończonego zerem (zerowym ogranicznikiem), tzw. null terminated string, lub do C-łańcucha (dokładniej: do pierwszego znaku tego łańcucha), w którym przechowywana będzie nazwa (wartość) portu. Z poprzednich rozdziałów pamiętamy, że ogólnie przyjęte jest stosowanie nazewnictwa portów szeregowych jako COMn (nazwy COMn znajdują się na liście nazw zastrzeżonych), gdzie n oznacza numer portu. Deklaracja numeru portu szeregowego, np. 2., będzie więc przedstawiać się w sposób bardzo prosty: LPCTSTR portName = COM2 ; lub, co jest równoważne: unsigned const char *portName = COM2 ; Można też zmienną, pod którą przechowywać będziemy numer portu, zadeklarować w sposób tradycyjny, używając typu char. Deklaracja taka będzie w pełni poprawna: char portName[5] = COM2 ; Parametr dwDesiredAccess typu DWORD umożliwia ustalenie rodzaju dostępu do portu szeregowego. Z praktycznego punktu widzenia najwygodniej jest ustalić rodzaj dostępu jako GENERIC_READ | GENERIC_WRITE (zapisuj do portu lub odczytuj z portu). Umożliwi nam to płynne wysyłanie i odbieranie komunikatów, co w pełni odpowiada półduplek- sowemu wariantowi transmisji. Jeżeli zechcemy korzystać jedynie z trybu simpleksowe- go, do dwDesiredAccess wystarczy przypisać jeden z wybranych rodzajów dostępu. Windows API posługuje się łańcuchami o długości większej niż 256 znaków. Aby przełamać to ograniczenie, zrezygnowano z zapamiętywania w pierwszym bajcie liczby określającej długość łańcucha znaków. W C-łańcuchach ostatnim znakiem, kończą- cym ciąg jest 0 (NULL lub heks. 00), którego nie należy mylić ze znakiem zero (48 lub heks. 30). Stąd nazwa null terminated string.C-łańcuchy osiągają długość 65535 znaków plus końcowy, tzw. NULL-bajt. Są one dynamicznie alokowane w pamięci, zaś ilość pamięci zajmowanej przez C-łańcuch jest automatycznie dostosowywana do jego długości, co w pełni odpowiada architekturze Windows. Parametrowi dwCreationDistribution należy przypisać właściwość OPEN_EXISTING — otwórz istniejący (port). Pozostałym przyporządkujemy następujące wartości: DWORD ShareMode = 0 (FALSE); LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL; DWORD dwFlagAndAttributes = 0 (FALSE); HANDLE hTemplateFile = NULL. Funkcja GetCommState() Funkcja zwraca ustawienia portu ostatnio zapamiętane w strukturze DCB: BOOL GetCommState(HANDLE hCommDev, LPDCB lpdcb), Rozdział 5. ♦ Programowa obsługa interfejsu RS 232C w Windows 71 gdzie: hCommDev jest identyfikatorem danego portu, CreateFile() zwraca nam ten identyfikator, a lpdcb jest wskaźnikiem do struktury DCB zawierającej informację o aktualnych ustawieniach parametrów łącza szeregowego. Funkcja GetCommState() (jak i wszystkie inne typu BOOL) zwraca wartość TRUE w przypad- ku pomyślnego jej wykonania, ewentualnie wartość FALSE w sytuacji przeciwnej. Funkcja SetCommState() Wybrany przez nas port szeregowy ostatecznie skonfigurujemy zgodnie ze specyfikacją struktury DCB za pomocą funkcji SetCommState(), która reinicjalizuje i uaktualnia wszyst- kie dostępne parametry w ustawieniach łącza szeregowego: BOOL SetCommState(HANDLE hCommDev, LPDCB lpdcb) Jednak tutaj parametr, na który wskazuje lpdcb, musi już zawierać informacje o nowych, wybranych przez nas parametrach ustawień portu komunikacyjnego. Należy też pamiętać, że funkcja SetCommState() nie zostanie wykonana pomyślnie, jeżeli posługując się struk- turą DCB, element XonChar ustalimy identycznie z XoffChar. Funkcja CloseHandle() Przed zakończeniem działania aplikacji otwarty port szeregowy należy koniecznie zamknąć i zwolnić obszar pamięci przydzielony na jego identyfikator, korzystając z: BOOL CloseHandle(HANDLE hCommDev) We wszystkich przedstawionych powyżej funkcjach hCommDev w pełni identyfikuje dany port szeregowy, zawierając kompletną informację o tym, do którego łącza szeregowego będziemy wysyłać komunikaty. Ponieważ funkcje te mogą obsługiwać komunikaty wysyłane do wielu portów komunikacyjnych (jak również odbierane od wielu portów), zatem każdy otwarty i zainicjalizowany port szeregowy będzie identyfikowany właśnie za pomocą swojego własnego hCommDev. Nie należy przydzielać tego samego identyfikato- ra do dwóch różnych portów komunikacyjnych, tak samo jak nie należy z jednym portem kojarzyć dwóch różnych identyfikatorów. Przy pisaniu aplikacji obsługujących łącze szeregowe należy koniecznie zamknąć port przed opuszczeniem programu. W razie korzystania z zegara systemowego przy ob- słudze RS-a lub techniki programowania wielowątkowego trzeba pamiętać, że samo zamknięcie aplikacji nie powoduje automatycznego zamknięcia portu. Jego identyfi- kator dalej będzie przechowywany w pamięci. W pewnych przypadkach aplikacja z niezamkniętym portem szeregowym może stać się programem rezydentnym i uniemożliwić powtórne otwarcie wybranego portu. Dobrym zwyczajem jest w pierwszej kolejności zaprojektowanie funkcji lub procedury obsługi zdarzenia zamykającego otwarty port. System operacyjny powinien być zawsze poin- formowany o fakcie zamknięcia portu. 72 RS 232C — praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera W praktyce zdarzają się jednak sytuacje, w których zamknięcie portu okaże się niemoż- liwe, np. z powodu jakiegoś błędu w algorytmie lub niewłaściwego sposobu wywołania danej funkcji. Mówimy wówczas, że program się załamał lub zawiesił. Ten problem powtarza się często w trakcie testowania programów komunikacyjnych. Nie należy wów- czas od razu używać kombinacji klawiszy Ctrl, Alt, Del. W takich przypadkach wygodniej jest rozwinąć z głównego menu opcję Project oraz wybrać Compile Unit, tak jak poka- zano to na rysunku 5.1. Nazwa działającej aplikacji powinna się pojawić na dolnym pasku zadań. Rysunek 5.1. Przykładowy sposób wstrzymywania działania aplikacji z otwartym portem szeregowym Po pojawieniu się informacji Debug session in progress. Terminate? (Usuwanie sesji w toku. Zakończyć?) (rysunek 5.2) należy nacisnąć przycisk OK. Po kolejnym komunikacie (rysunek 5.3) znów należy dokonać potwierdzenia. Tak postępując, w większości przypadków odzyskamy program oraz odblokujemy łącze szeregowe. Sposób ten okaże się szczególnie przydatny przy kłopotach z aplikacją komunikacyjną korzystającą z komponentu typu TTimer, generującego zdarzenia w rów- nych odstępach czasu. Może oczywiście zdarzyć się sytuacja, w której nie będziemy w stanie powtórnie skompilować programu i samodzielnie prawidłowo zamknąć portu komunikacyjnego. Wówczas program należy usunąć z pamięci poleceniem menu Run/Program Reset. Rozdział 5. ♦ Programowa obsługa interfejsu RS 232C w Windows 73 Rysunek 5.2. Okno dialogowe Debug session Rysunek 5.3. Kompilacja projektu 74 RS 232C — praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera Testowanie portu szeregowego Mając na uwadze wszystko, co powiedzieliśmy do tej pory, spróbujemy napisać w C++Bu- ilderze prosty program wykorzystujący przedstawione powyżej funkcje Windows API oraz niektóre zasoby struktury DCB. Zadaniem naszej aplikacji będzie ustawienie wybranych parametrów danego portu szere- gowego, otwarcie go oraz odczytanie nowych ustawień. W tym celu stwórzmy nową standardową aplikację (polecenie File — New Application). Niech jej formularz składa się z dwóch przycisków klasy TButton, pięciu komponentów klasy TEdit oraz pięciu TLabel. Korzystając z inspektora obiektów (Object Inspector) oraz z karty własności (Properties), własność Name przycisku Button1 zmieńmy na CloseComm, zaś jego własność Caption na Zamknij. Podobnie własność Name przycisku Button2 zmieńmy na OpenComm, zaś Cap- tion na Otwórz port. Własności Caption komponentów z klas TLabel zmieńmy odpo- wiednio na Prędkość transmisji, Liczbę bitów danych, Parzystość, Bity stopu, Linia DTR. Własności Text komponentów klasy TEdit wyczyśćmy. Formularz naszej aplikacji, wyglądającej podobnie jak na rysunku 5.4, znajduje się na dołączonym CD w katalogu KODYBUILDERR05P05_01. Na listingu 5.1 pokazano kod głównego modułu omawianej aplikacji. Rysunek 5.4. Formularz główny projektu Projekt_05_01.bpr Listing 5.1. Kod głównego modułu aplikacji testującej podstawowe parametry transmisji portu szeregowego #include vcl.h #pragma hdrstop #include Unit_05_01.h #pragma package(smart_init) #pragma resource *.dfm TForm1 *Form1; HANDLE hCommDev; // identyfikator portu szeregowego // void *hCommDev; DCB dcb; // struktura kontroli portu Rozdział 5. ♦ Programowa obsługa interfejsu RS 232C w Windows 75 LPCTSTR portName = COM2 ; // wskaźnik do nazwy portu // const char *portName = COM2 ; LPCTSTR sbuffer2 = Uwaga! ; LPCTSTR sbuffer1 = Niewłaściwa nazwa portu lub port jest aktywny. ; //-------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //----funkcja zamyka otwarty port szeregowy----------------- BOOL __fastcall closeSerialPort(HANDLE hCommDev) { if ((hCommDev == 0) || (hCommDev == INVALID_HANDLE_VALUE)) return FALSE; else { CloseHandle(hCommDev); return TRUE; } } //-----zamknięcie portu i aplikacji--------------------------- void __fastcall TForm1::CloseCommClick(TObject *Sender) { closeSerialPort(hCommDev); Application- Terminate(); } //---otwarcie portu i ustawienie jego parametrów--------------- void __fastcall TForm1::OpenCommClick(TObject *Sender) { hCommDev = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (hCommDev != INVALID_HANDLE_VALUE) // sprawdza, czy port jest otwarty prawidłowo { dcb.DCBlength = sizeof(dcb); // aktualny rozmiar // struktury DCB GetCommState(hCommDev, dcb); // udostępnienie aktualnych // parametrów DCB dcb.BaudRate = CBR_1200; // prędkość transmisji dcb.fParity = TRUE; // sprawdzanie parzystości dcb.Parity = NOPARITY; // ustawienie parzystości dcb.StopBits = TWOSTOPBITS; // bity stopu dcb.ByteSize = 7; // bity danych dcb.fDtrControl = 1; // np. kontrola linii DTR SetCommState(hCommDev, dcb); // reinicjalizacja DCB } else { switch ((int)hCommDev) { case IE_BADID: 76 RS 232C — praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera // W przypadku błędnej identyfikacji portu // BADIDentify pokaż komunikat MessageBox(NULL, sbuffer1, sbuffer2, MB_OK); break; }; } //--sprawdzenie i wyświetlenie ustawionej prędkości------ switch (dcb.BaudRate) { case CBR_9600: Edit1- Text = IntToStr(dcb.BaudRate); break; case CBR_1200: Edit1- Text = IntToStr(dcb.BaudRate); break; case CBR_300: Edit1- Text = IntToStr(dcb.BaudRate); break; case CBR_110: Edit1- Text = IntToStr(dcb.BaudRate); break; } //--sprawdzenie i wyświetlenie ustawionych bitów danych- switch (dcb.ByteSize) { case 8: Edit2- Text = IntToStr(dcb.ByteSize); break; case 7: Edit2- Text = IntToStr(dcb.ByteSize); break; case 6: Edit2- Text = IntToStr(dcb.ByteSize); break; case 5: Edit2- Text = IntToStr(dcb.ByteSize); break; } //--sprawdzenie i wyświetlenie ustawionej parzystości---- switch (dcb.Parity) { case NOPARITY: Edit3- Text = Brak ; break; case ODDPARITY: Edit3- Text = Nieparzysta ; break; case EVENPARITY: Edit3- Text = Parzysta ; break; case MARKPARITY: Edit3- Text = Znacznik: 1 ; break; } //--sprawdzenie i wyświetlenie ustawionych bitów stopu--- switch (dcb.StopBits) Rozdział 5. ♦ Programowa obsługa interfejsu RS 232C w Windows 77 { case ONESTOPBIT: Edit4- Text = 1 ; break; case TWOSTOPBITS: Edit4- Text = 2 ; break; case ONE5STOPBITS: Edit4- Text = 1.5 ; break; } //--sprawdzenie i wyświetlenie stanu linii DTR----------- switch (dcb.fDtrControl) { case DTR_CONTROL_DISABLE: Edit5- Text = Nieaktywna ; break; case DTR_CONTROL_ENABLE: Edit5- Text = Aktywna ; break; case DTR_CONTROL_HANDSHAKE: Edit5- Text = Handshaking ; break; } } //----------------------------------------------------------- void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction Action) { Action=caFree; } //-------------------------------------------------------------- Stworzyliśmy zatem bardzo prostą, wręcz „dydaktyczną” aplikację, ale taki właśnie był nasz cel. Możemy zauważyć, że obsługa tego programu sprowadza się do wywołania funkcji obsługi zdarzenia OpenCommClick(). Naciśnięcie przycisku Otwórz port powoduje automatyczne skonfigurowanie wybranego wcześniej portu szeregowego oraz odczytanie jego aktualnie wybranych ustawień. Dobrze byłoby, gdyby Czytelnik spróbował samo- dzielnie skonfigurować port z większą liczbą parametrów, a następnie je odczytał. Nabiera się przez to większej wprawy w manipulowaniu znacznikami struktury DCB. Zamknięcie portu i aplikacji nastąpi po wywołaniu funkcji obsługi zdarzenia CloseCommClick(), w której z kolei dokonujemy wywołania funkcji CloseSerialPort() zamykającej port sze- regowy i aplikację. Przyglądając się kodowi funkcji obsługi zdarzenia OpenCommClick(), zauważymy, że tuż po wywołaniu CreateFile() zastosowaliśmy następującą instrukcję warunkową sprawdzającą, czy funkcja ta zwróciła prawidłowy identyfikator zadeklaro- wanego portu: if (hCommDev != INVALID_HANDLE_VALUE) { ... } else { switch ((int)hCommDev) { 78 RS 232C — praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera case IE_BADID: // W przypadku błędnej identyfikacji portu // BADIDentify pokaż komunikat ... break; }; } Łatwo można się przekonać, że w przypadku błędnego przydzielenia identyfikatora dla portu COMn, funkcja CreateFile() zwraca wartość INVALID_HANDLE_ VALUE (niewłaściwa wartość identyfikatora) zdefiniowaną w Windows API. Jest to bardzo skuteczna metoda zabezpieczenia się przed próbą otwarcia nieistniejącego lub już otwartego portu (urządze- nia). Zauważmy też, że aby odczytać aktualną wartość hCommDev, musieliśmy wymusić przekształcenie typów, używając operacji rzutowania (int)hCommDev. Każdy już się chyba przekonał, że identyfikator czy — jak kto woli — uchwyt typu HANDLE nie jest żadnym numerem bezpośrednio nadanym portowi komunikacyjnemu, lokalizuje jedynie unikalny obszar pamięci, do którego należy się odwołać, by uzyskać dostęp do danego urządzenia. Raz otwartego portu komunikacyjnego nie można otworzyć powtórnie, podobnie jak nie uda się otworzyć już otwartego okna. Nie można też powtórnie skorzystać z ob- szaru pamięci, z którego właśnie korzystamy. Jeżeli mimo wszystko port nie został otwarty prawidłowo, dobrze by było, gdyby apli- kacja powiadomiła nas o tym fakcie. W tym celu można skorzystać z komunikatów Windows typu IE_ (ang. Identify Error — błąd identyfikacji portu) urządzenia lub jego ustawień. W tabeli 5.6 przedstawiono najczęściej otrzymywane od Windows komunikaty tego typu. Tabela 5.6. Najczęściej używane komunikaty błędnej identyfikacji ustawień portu szeregowego Identyfikacja komunikatu Wartość IE_BADID IE_BAUDRATE IE_BYTESIZE IE_DEFAULT IE_HARDWARE IE_MEMORY IE_NOPEN IE_OPEN –1 –12 –11 –5 –10 –4 –3 –2 Znaczenie Niewłaściwa identyfikacja urządzenia Błędnie określona szybkość transmisji Błędnie określona liczba bitów danych Niewłaściwie określone parametry domyślne urząd
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

RS 232C - praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera. Wydanie III
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: