You are on page 1of 37

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 szkoach i biurach pojawia si coraz wicej zaawansowanych


urzdze komputerowych podczanych przez port szeregowy. Czy koniecznie trzeba
paci wysokie stawki informatykom, aby wykorzysta peni moliwoci tych
nowoczesnych narzdzi? Na szczcie nie. Obsuga transmisji szeregowej przy uyciu
standardu RS 232C moe by na tyle atwa, e uczniowie, studenci, nauczyciele,
pracownicy naukowi czy inynierowie mog samodzielnie tworzy potrzebne im
oprogramowanie.
Dziki ksice RS 232C praktyczne programowanie. Od Pascala i C++ do Delphi
i Buildera. Wydanie III take i Ty szybko nauczysz si pisa programy sterujce
urzdzeniami podczanymi przez port szeregowy. Dowiesz si, jak dziaa transmisja
asynchroniczna oraz czym jest standard RS 232C. Poznasz interfejs RS 232C dla
systemu Windows i nauczysz si go uywa w rodowiskach programistycznych
Builder i Delphi, co pozwoli Ci pisa potrzebne oprogramowanie w jzyku Pascal lub
C++. Najnowsze, poprawione wydanie zawiera jeszcze wicej przykadw, dziki ktrym
byskawicznie bdziesz mg sprawdzi nabyt wiedz w praktyce.
Standard RS 232C
Transmisja asynchroniczna
Obsuga RS 232C w systemach MS-DOS i Windows
Wykorzystanie elementw interfejsu Windows API w rodowiskach Builder i Delphi
Testowanie programw do obsugi transmisji szeregowej
Tworzenie aplikacji wielowtkowych
Narzdzia graficzne
Przykadowe aplikacje i ich analiza
Specyfikacje najwaniejszych funkcji
Wydawnictwo Helion
ul. Kociuszki 1c
44-100 Gliwice
tel. 032 230 98 63
e-mail: helion@helion.pl

Spis treci

Spis treci
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
Waciwoci portu konwertera .................................................................................. 31
Protok XON-XOFF ...................................................................................................... 33
Protok ENQ-ACK ........................................................................................................ 33
Protok ETX-ACK ......................................................................................................... 34
Protok SOH-ETX ......................................................................................................... 34
Protokoy 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 obsuga interfejsu RS 232C w Windows ...................... 59


Typy danych Windows .................................................................................................... 61
Proces projektowania oprogramowania ........................................................................... 64
Wykorzystanie elementw Windows API w C++Builderze. Cz I ............................. 64
Struktura DCB ........................................................................................................... 65
Funkcja CreateFile() .................................................................................................. 65

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
Nawizanie poczenia. Wariant I ................................................................................... 91
Segment inicjalizujco-konfiguracyjny ..................................................................... 92
Segment wysyajcy komunikaty. Funkcja WriteFile() ............................................ 92
Segment odbierajcy komunikaty. Funkcja ReadFile() ............................................ 93
Przykadowa aplikacja ............................................................................................... 94
Nawizanie poczenia. Wariant II .................................................................................. 97
Funkcja SetupComm() .............................................................................................. 98
Funkcja ClearCommError() ...................................................................................... 98
Struktura COMSTAT .............................................................................................. 100
Przykadowa aplikacja ............................................................................................. 102
Zamknicie portu komunikacyjnego ....................................................................... 106
Nawizanie poczenia. Wariant III .............................................................................. 107
Funkcje GetCommMask() i SetCommMask() ........................................................ 107
Funkcja WaitCommEvent() .................................................................................... 109
Przykadowa aplikacja dziaajca w rodowisku tekstowym .................................. 110
Przykadowa aplikacja dziaajca w rodowisku graficznym ................................. 118
Nawizanie poczenia. Wariant IV .............................................................................. 123
Funkcja BuildCommDCB() .................................................................................... 123
Funkcja BuildCommDCBAndTimeouts() .............................................................. 125
Inne uyteczne funkcje .................................................................................................. 126
Podsumowanie ............................................................................................................... 128
wiczenia ...................................................................................................................... 128
Wykorzystanie elementw Windows API w C++Builderze. Cz II .......................... 129
Wysyamy znak po znaku. Funkcja TransmitCommChar() .................................... 129
Wysyamy 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 elementw Windows API w Delphi. Cz I ....................................... 177
Testowanie portu szeregowego inaczej .............................................................. 177
Rekord TCOMMPROP ........................................................................................... 183
Nawizanie poczenia ............................................................................................ 191
Przykadowe aplikacje ............................................................................................. 194
Podsumowanie ........................................................................................................ 203
wiczenia ................................................................................................................ 203
Wykorzystanie elementw Windows API w Delphi. Cz II ...................................... 203
Wysyamy znak po znaku ....................................................................................... 204
Wysyamy pliki ....................................................................................................... 209
Timer w Delphi ....................................................................................................... 224
Podsumowanie ............................................................................................................... 238
wiczenia ...................................................................................................................... 239

Spis treci

Rozdzia 6. Aplikacje wielowtkowe ............................................................... 241


Najwaniejszy jest uytkownik ..................................................................................... 242
Uytkownik steruje programem .............................................................................. 242
Moliwo anulowania decyzji ............................................................................... 243
Moliwo odbioru komunikatu nawet w trakcie wysyania danych ..................... 243
Moliwo wysania odrbnej informacji w trakcie transmisji pliku ..................... 243
Delphi ............................................................................................................................ 244
Funkcja BeginThread() ........................................................................................... 244
Konkurencja dla Timera .......................................................................................... 256
Klasa TThread ......................................................................................................... 264
Wielowtkowo i DLL-e ............................................................................................. 272
C++Builder .................................................................................................................... 280
Zamiast Timera ....................................................................................................... 289
Zamiast Timera. Inny sposb .................................................................................. 296
Klasa TThread ......................................................................................................... 304
Podsumowanie ............................................................................................................... 315
wiczenia ...................................................................................................................... 315

Rozdzia 7. Wykorzystanie niektrych narzdzi graficznych .............................. 317


Komponent klasy TChart ............................................................................................... 318
Podsumowanie ............................................................................................................... 328
wiczenia ...................................................................................................................... 328

Rozdzia 8. Przykadowe aplikacje wykorzystywane


w systemach pomiarowych ........................................................... 329
Kontroler temperatury ................................................................................................... 330
Aplikacja obsugujca kilka urzdze ........................................................................... 347
Programowanie inteligentne .......................................................................................... 358
Brak powtarzalnoci kodu ....................................................................................... 359
Czytelno kodu ...................................................................................................... 360
atwo testowania ................................................................................................. 364
Podsumowanie ............................................................................................................... 366
wiczenia ...................................................................................................................... 366

Rozdzia 9. Tworzenie komponentw .............................................................. 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 zawierajcego komponent aktywny ...................................... 393
Odczytywanie i modyfikacja wartoci wasnoci komponentu aktywnego ............ 395
Komponenty w BDS 2006 ............................................................................................. 397
Podsumowanie ............................................................................................................... 398
wiczenia ...................................................................................................................... 398

Rozdzia 10. Modelowanie oprogramowania sterujcego portem szeregowym .... 399


Schematy dziedziczenia ................................................................................................. 400
Ukrywanie konstruktora ................................................................................................ 405
Interfejsy ........................................................................................................................ 409
Delegowanie operacji .................................................................................................... 415
Delegowanie realizacji interfejsu do wasnoci ............................................................. 422
Podsumowanie ............................................................................................................... 426
wiczenia ...................................................................................................................... 427

RS 232C praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera

Rozdzia 11. POSIX .......................................................................................... 435


Polecenie stty ................................................................................................................. 436
Ustawienia kontroli przesyu danych (sterowanie transmisj) ................................ 437
Ustawienia wejciowe ............................................................................................. 437
Ustawienia wyjciowe ............................................................................................. 439
Ustawienia czasw oczekiwania ............................................................................. 439
Ustawienia lokalne .................................................................................................. 440
Specjalne znaki sterujce ........................................................................................ 441
czenie atrybutw ................................................................................................. 442
Podstawowe funkcje obsugi 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 dziesitnej na binarn .............................. 477


Dodatek E

Funkcje CreateThread(), CreateMutex() i CreateSemaphore() ....... 481


Skorowidz .................................................................................... 487

Rozdzia 5.

Programowa obsuga
interfejsu RS 232C
w Windows
Czwarte prawo Murphyego
Gdy dojdziesz do wniosku, e s cztery sposoby, na jakie moe si nie powie
dane przedsiwzicie, i zabezpieczysz si przed nimi, rycho pojawi si pita
moliwo.
Murphys 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 algorytmw
realizujcych transmisj szeregow w rodowisku Windows, ktre charakteryzuje si
pewnymi cechami niemajcymi odpowiednikw w MS-DOS. Poznanie i umiejtne
wykorzystanie tych cech sprawi, i problem obsugi interfejsw szeregowych z poziomu
Windows uwaany powszechnie za trudny przestanie by dla nas tajemnic.
Pokaemy, w jaki sposb naley tworzy aplikacje suce do programowej obsugi cza
szeregowego RS 232C zarwno w C++, C++Builderze, jak i w Delphi. Wrd programistw istnieje zauwaalny podzia na osoby programujce gwnie w Delphi oraz na preferujce Buildera lub oglnie C++ dla Windows. Jednak zdaniem wielu osb uniwersalno
jest jedn z tych cech, jakie powinny charakteryzowa programist. W rozdziale tym
przybliymy Czytelnikowi podobiestwa i rnice w sposobie konstrukcji algorytmw
realizujcych transmisj szeregow, pisanych w Delphi oraz Builderze.
W dalszej czci ksiki bdziemy si spotyka z typami danych, ktrych poznanie i zrozumienie ma kluczowe znaczenie w projektowaniu aplikacji obsugujcych urzdzenia
zewntrzne. Zacznijmy od ich przypomnienia. W tabeli 5.1 przedstawiono porwnanie
podstawowych typw zmiennych wykorzystywanych w kompilatorach, ktre bd dla nas
istotne. Wikszoci z nich mona uywa zamiennie, piszc zarwno 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


Delphi

Rozmiar w bajtach

ShortInt

Znak +/

Typ

C++Builder

Integer

signed char

SmallInt

Integer

short

LongInt

Integer

Byte

Bez znaku

Integer

unsigned char

Word

Bez znaku

Integer

unsigned short

Integer

Integer

int

Cardinal

Bez znaku

Integer

unsigned int

Boolean

true/false

ByteBool

true/false

Bez znaku
WordBool

bool
unsigned char

Integer
unsigned short

true/false

Bez znaku

Integer

LongBool

true/false

Bez znaku

Integer

AnsiChar

1 znak ANSI

Character

WideChar

1 znak Unicode Character

wchar_t

Char

Bez znaku

Character

char

char

AnsiString

3GB

ANSIChar

AnsiString

AnsiString

String[n]

n = 1.255

ANSIChar

String

SmallString<n>

ShortString

255

ANSIChar

String

SmallString<255>

String

255 lub 3GB

ANSIChar

AnsiString

AnsiString

Single

Floating point number


(liczba
zmiennoprzecinkowa)

float

Double

Floating point number

double

Extended

10

Floating point number

long double

Real

Floating point number

double

Pointer

Generic pointer
(wskanik oglny,
adresowy)

void *

PChar

Bez znaku

Pointer to characters

unsigned char *

PAnsiChar

Bez znaku

Pointer to ANSIChar

unsigned char *

Comp

Floating point number

Comp

Konstruujc nasze programy, bdziemy starali si jak najszerzej wykorzystywa standardowe zasoby Windows, w szczeglnoci tzw. interfejs programisty Windows API (ang.
Application Programming Interface). Jego umiejtne wykorzystanie umoliwi naszym
aplikacjom byskawiczne skonfigurowanie i uzyskanie dostpu do portu komunikacyjnego. Bdem jest twierdzenie, e sama nawet bardzo dobra znajomo jzyka pro-

Rozdzia 5. Programowa obsuga interfejsu RS 232C w Windows

61

gramowania wystarczy, eby stworzy poprawnie dziaajcy w Windows program. Ot


musimy zdawa sobie spraw z faktu, o ktrym czsto si zapomina niemoliwe jest
napisanie udanej aplikacji majcej pracowa w pewnym rodowisku (czytaj systemie
operacyjnym) bez znajomoci tego rodowiska. Wiele ju zostao powiedziane na temat
dobrych i zych stron Windows, naley jednak pamita, e oferuje on nam swoj wizytwk, ofert wsppracy, czyli API. Ju nie wystarczy umiejtno wykorzystywania
ulubionego kompilatora. Zasoby Delphi czy Buildera poczymy z zasobami systemu
operacyjnego, a spoiwem bdzie wanie uniwersalne Windows API. Istnieje wiele
warstw API uywanych w zalenoci od potrzeb. W tym i dalszych rozdziaach zajmiemy
si szeroko rozumian warstw komunikacyjn.
Windows API korzysta ze specjalnego systemu nazewnictwa zmiennych, z tzw. notacji
wgierskiej wprowadzonej przez Karoja Szimoniego. Zgodnie z ni do rdzenia nazwy
zadeklarowanej zmiennej dodaje si przedrostek (ang. prefix). Chocia istniej pod tym
wzgldem pewne rozbienoci pomidzy nazewnictwem Microsoftu i Borlanda, to
jednak zapis taki bardzo uatwia szybkie ustalenie roli zmiennej w programie oraz jej typ.
W nastpnych rozdziaach bdziemy si starali wszdzie gdzie jest to moliwe
zachowywa samokomentujce si nazewnictwo API (wikszo nazw API bdziemy
traktowa jako nazwy wasne). Z dowiadczenia wiadomo, e stosowanie takiej konwencji bardzo pomaga w studiowaniu plikw pomocy. Oczywicie moglibymy sili si na
oryginalno, wprowadzajc wasne zmienne, zrozumiae tylko dla piszcego dany program wwczas przykady musiayby by zapisane jako wrcz humorystyczna mieszanina jzykw polskiego i angielskiego. Trzeba te przyzna, e byby to bardzo skuteczny
sposb zaciemnienia obrazu API. Zrozumienie znaczenia nazw tam stosowanych okae
si w przyszoci niezwykle cenne, gdy API mona czyta jak ksik. Aby pomc Czytelnikom, ktrzy nie zetknli si dotd z tymi pojciami, w tabeli 5.2 przedstawiono oglne zasady tworzenia niektrych przedrostkw.
Windows oferuje nam ponadto kilka typw danych, z ktrych cz tylko nieznacznie
rni si sposobem zapisu w implementacjach Delphi i Buildera. Typy te maj najczciej posta struktury lub klasy i s bardzo czsto wykorzystywane w warstwie komunikacyjnej programw.

Typy danych Windows


Nowoczesna idea programowania w Windows oparta na wykorzystaniu narzdzi programistycznych typu RAD, do ktrych zaliczaj si C++Builder oraz Delphi, pozwala
programistom na maksymalne uproszczenie procesu tworzenia oprogramowania. Jednym
z przykadw denia do zminimalizowania czasu tworzenia aplikacji jest zastosowanie
w Windows pewnych bardzo zwartych w zapisie typw danych, ktre oczywicie maj
swoje odpowiedniki w typach standardowych. W tabeli 5.3 zebrano najistotniejsze typy
danych, ktrymi bardzo czsto posuguj si programy Windows. Naley zdawa sobie
spraw z faktu, i typy takie jak np. LPVOID i LPSTR nie s w dosownym sowa tego znaczeniu typami nowymi, tzn. od pocztku stworzonymi na potrzeby aplikacji Windows,
gdy zostay zdefiniowane w plikach nagwkowych za pomoc instrukcji typedef po to,
aby uproci zapis niektrych standardowych typw danych. W tabeli 5.3 przedstawiono
wybrane typy danych, ktrymi posuguje si API Windows.

62

RS 232C praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera

Tabela 5.2. Oglne zasady tworzenia przedrostkw wedug notacji wgierskiej


Przedrostek

Skrt angielski

Znaczenie

array

Tablica

bool

Zmienna logiczna true lub false

by

byte unsigned char

Znak (bajt)

cb

count of bytes

Liczba bajtw

ch

char

Znak

dw

double word

Podwjne sowo

evt

event

Zdarzenie

flag

Znacznik

fdw

flag of double word

Znacznik typu dw

fn

function

Funkcja

handle

Identyfikator (uchwyt)

integer

Typ cakowity 4-bajtowy

id

(ID) identification

Identyfikacja

in

input

Wejcie, dane wejciowe

long int

Typ cakowity dugi 4-bajtowy

lp

long pointer

Wskanik typu long int

lpc

long pointer to C-string

Wskanik typu long int do C-acucha

lpfdw

long pointer to flag of dw

Wskanik typu lp do znacznika typu double word

lpfn

long pointer to function

Wskanik typu lp do funkcji

short or int

Typ krtki lub cakowity

np

near pointer

Bliski wskanik (w rodowisku 32-bitowym to samo


co lp)

out

output

Wyjcie, dane wyjciowe (przetworzone)

pointer

Wskanik (w rodowisku 32-bitowym to samo co lp)

pfn

pointer to function

Wskanik do funkcji

que

queue

Kolejka, bufor danych

s (sz)

string

acuch znakw

st

struct

Struktura

type

Typ

unsigned

Bez znaku

(word) unsigned int

Sowo

wc

WCHAR

Znak zgodny z Unicode

Rozdzia 5. Programowa obsuga interfejsu RS 232C w Windows

63

Tabela 5.3. Niektre typy danych stosowane w Windows


Typ Windows

Znaczenie

BOOL

int z dwoma wartociami TRUE oraz FALSE

BYTE

unsigned char

DWORD

unsigned long

LPDWORD

unsigned long *

LONG

long

LPLONG

long *

LPCSTR

const char *

LPCTSTR

unsigned const char *

LPSTR

char *

LPVOID lub Pointer

void *

LPCVOID

const void *

UINT

unsigned int

WORD

unsigned short

DWORD32

32-bitowy typ cakowity bez znaku

DWORD64

64-bitowy typ cakowity bez znaku

INT

32-bitowy typ cakowity ze znakiem

INT32

32-bitowy typ cakowity ze znakiem

INT64

64-bitowy typ cakowity ze znakiem

LONG32

32-bitowy typ cakowity ze znakiem

LONG64

64-bitowy typ cakowity ze znakiem

LONGLONG

64-bitowy typ cakowity ze znakiem

Osobnym typem danych, bardzo czsto stosowanym w aplikacjach Windows, jest typ
HANDLE. Jest on 32- lub 64-bitowym typem danych cakowitych oznaczajcym tzw. uchwyt
(ang. handle). Naley rozumie, i w rzeczywistoci dane typu HANDLE nie obrazuj jakich
tajemniczych uchwytw zakadanych na elementy aplikacji s to po prostu 32- lub
64-bitowe liczby identyfikujce okrelony zasb aplikacji, systemu operacyjnego lub
samego komputera. Z tego wzgldu dane typu HANDLE czsto wygodniej i zrczniej jest
okrela mianem identyfikatorw, ktrych wartoci przechowywane s w okrelonym
miejscu w pamici. Cech charakterystyczn identyfikatorw jest to, i jeli na pocztku
programu inicjuje si je okrelonymi wartociami, w momencie zakoczenia pracy
aplikacji lub jej fragmentu naley przydzielon im pami odpowiednio zwalnia. W tym
celu wykorzystuje si funkcj API Windows:
BOOL CloseHandle(HANDLE hObject);

z argumentem w postaci okrelonego identyfikatora.


Zaopatrzeni w powysz terminologi pjdmy dalej i zobaczmy, do czego mog nam by
przydatne poszczeglne 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 szczegowego omawiania aspektw tworzenia programw obsugujcych port szeregowy w Windows, naley wybra jedn z metod projektowania tego
rodzaju aplikacji.
Praktyka wskazuje, e dla pojedynczych uytkownikw lub niewielkich organizacji
dobrze sprawdza si metodologia oparta na programowaniu przyrostowym i iteracyjnym
(ang. iterative and incremental development).
W dalszej czci ksiki bdziemy korzysta z metody projektowania iteracyjnego. Takie
podejcie do zagadnienia sprawi, i tworzone aplikacje oprcz wysokiej sprawnoci
dziaania bd jeszcze miay dwie bardzo wane i nieczsto spotykane w literaturze cechy.
Bd mianowicie:
w peni rozbudowywalne,
atwe do samodzielnej modyfikacji nawet przez osoby dopiero poznajce zasady

programowania w rodowiskach Buildera i Delphi.


Wszystkie prezentowane algorytmy bdziemy si starali konstruowa w ten sposb, aby
pewne synne twierdzenie wypowiedziane niegdy przez Murphyego w omawianych
programach nie miao zastosowania. Brzmi ono nastpujco:
Twierdzenie o komplikacji procedur
Kad dowolnie skomplikowan procedur mona skomplikowa jeszcze bardziej.
Twierdzenie odwrotne nie jest prawdziwe: nadzwyczaj rzadko si zdarza, aby
skomplikowan procedur mona byo uproci.
Murphys Law and other reasons why things go wrong!, Artur Bloch, Price Stern
Sloan Inc. 1977.

Wykorzystanie elementw
Windows API w C++Builderze. Cz I
Poznawanie tajnikw obsugi portu szeregowego w Windows rozpoczniemy, z czysto
praktycznych wzgldw, od pisania programw w C++Builderze. C++ ma skadni tak
jak API, dlatego prociej nam bdzie zapozna si z budow funkcji oraz struktur oferowanych przez interfejs programisty. Uatwi to te zrozumienie, w jaki sposb i w jakiej
kolejnoci naley umieszcza je w programie.

Rozdzia 5. Programowa obsuga interfejsu RS 232C w Windows

65

Struktura DCB
Fundamentalne znaczenie ma struktura kontroli urzdze zewntrznych DCB (ang. Device
Control Block). W Windows struktura DCB w pewnym sensie odpowiada funkcji 00h
przerwania 14h BIOS-u. Udostpnia nam jednak nieporwnywalnie wiksze moliwoci
programowej obsugi cza szeregowego; umoliwia bezporednie programowanie rejestrw ukadu UART. W tabelach 5.4 oraz 5.5 przedstawiono specyfikacj bloku kontroli
urzdze zewntrznych DCB.
Wikszo pl tej struktury to pola jednobitowe. fDtrControl, fRtsControl s polami
dwubitowymi. Aktualnie nieuywane w XP pole fDummy2 jest siedemnastobitowe. W perspektywie, wraz z wReserved oraz wReserved1, bdzie wykorzystane na potrzeby innych
protokow komunikacyjnych. W Windows API blok kontroli urzdze deklarowany jest
w sposb nastpujcy:
typedef struct _DCB {
DWORD DCBlength;
...
} DCB;

Deklaracja ta tworzy nowe sowo kluczowe typu DCB (struktura). Zalecane jest, aby przed
uyciem tej struktury jako parametru do elementu DCBlength wpisa warto sizeof(DCB).
Struktur tworzy zbir logicznie powizanych elementw, np. zmiennych lub (i) pl
bitowych. Pole bitowe stanowi zbir przylegajcych do siebie bitw, znajdujcych si
w jednym sowie. Adres struktury pobieramy za pomoc operatora referencji &, co
umoliwia nam dziaania na jej skadowych. Do struktury jako caoci moemy odwoa
si przez jej nazw, za do poszczeglnych jej elementw, czyli zmiennych oraz pl
bitowych, przez podanie nazwy zmiennej reprezentujcej struktur oraz po kropce
nazwy konkretnej zmiennej lub pola struktury, np.: dcb.fDtrControl = DTR_CONTROL_
DISABLE. Operator skadowych struktur "." jest lewostronnie czny. Grupa zwizanych
ze sob zmiennych i pl bitowych traktowana jest jako jeden obiekt.

Zanim przejdziemy do praktycznego zastosowania poznanych pl struktury DCB, musimy


zapozna si z czterema podstawowymi funkcjami Windows API sucymi do programowej konfiguracji portw szeregowych. W dalszej czci ksiki funkcji takich bdzie
przybywa, ale te przedstawione poniej naley traktowa jako najbardziej podstawowe.

Funkcja CreateFile()
Jest to funkcja suca do utworzenia i otwarcia pliku lub urzdzenia. Ju sama nazwa
wskazuje, e moe by wykorzystywana nie tylko do obsugi portu szeregowego. Teraz
jednak bdzie nas interesowa tylko to konkretne zastosowanie. Specyfikacja zasobw
funkcji CreateFile() najczciej uywanych do operacji plikowych zamieszczona jest
w dodatku A. Funkcja ta da nam 32- lub 64-bitowy identyfikator danego portu przechowywany pod waciwoci HANDLE, do ktrego bd adresowane wszystkie komunikaty.

66

RS 232C praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera

Tabela 5.4. Zmienne struktury DCB reprezentujce dopuszczalne parametry ustawie portu szeregowego
Typ

Zmienna

Znaczenie

Warto,
staa symboliczna

DWORD

DCBlength

Rozmiar struktury

Naley wpisa

DWORD

BaudRate

Okrelenie prdkoci transmisji (b/s)

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

WORD

wReserved

Nieuywane

WORD

XonLim

Okrelenie minimalnej liczby bajtw


w buforze wejciowym przed
wysaniem specjalnego znaku
sterujcego XON

Domylnie: 65 535; w praktyce XonLim


ustala si jako rozmiaru deklarowanego
wejciowego bufora danych

WORD

XoffLim

Okrelenie maksymalnej liczby


bajtw w buforze wejciowym
przed wysaniem specjalnego znaku
sterujcego XOFF

Domylnie: 65535; w praktyce XoffLim


ustala si jako rozmiaru
deklarowanego bufora wejciowego

BYTE

ByteSize

Wybr liczby bitw danych

5, 6, 7, 8

BYTE

Parity

Okrelenie kontroli parzystoci

EVENPARITY parzysta;
MARKPARITY bit parzystoci stale

rwny 1;
NOPARITY brak kontroli;
ODDPARITY nieparzysta
BYTE

StopBits

Wybr bitw stopu

ONESTOPBIT 1 bit stopu;


ONE5STOPBITS w przypadku sowa
5-bitowego bit stopu wyduony o ;
TWOSTOPBITS 2 bity stopu

char

XonChar

Okrelenie wartoci znaku XON


dla nadawania i odbioru (wysanie
znaku przywraca transmisj)

Standardowo (char) DC1, dziesitnie: 17

char

XoffChar

Okrelenie wartoci znaku XOFF


dla nadawania i odbioru (wysanie
XOFF wstrzymuje transmisj do czasu
odebrania znaku XON)

Standardowo (char) DC3, dziesitnie: 19

char

ErrorChar

Okrelenie wartoci znaku


zastpujcego bajty otrzymane
z bdem parzystoci

Opcjonalnie: 0 lub SUB

char

EofChar

Okrelenie wartoci znaku koca


otrzymanych danych

Opcjonalnie: 0

Char

EvtChar

Okrelenie wartoci znaku


sucego do sygnalizowania
wystpienia danego zdarzenia

Opcjonalnie: 0

WORD

wReserved1

Obecnie nieuywane

Rozdzia 5. Programowa obsuga interfejsu RS 232C w Windows

67

Tabela 5.5. Pola bitowe reprezentujce dopuszczalne wartoci znacznikw sterujcych struktury DCB
Warto, znaczenie,
staa symboliczna

Typ

Pole bitowe

Waciwoci pola

DWORD

fBinary

Tryb binarny (Win API


podtrzymuje jedynie ten
tryb transmisji danych)

TRUE

DWORD

fParity

Umoliwia ustawienie
sprawdzania parzystoci
sposobu reakcji na bit
parzystoci

TRUE kontrola parzystoci wczona;


FALSE bit parzystoci nie jest

DWORD

fOutxCtsFlow

Umoliwia ustawienie
sprawdzania sygnau na linii
CTS w celu kontroli danych
wyjciowych

sprawdzany
TRUE jeeli sygna CTS jest

nieaktywny, transmisja jest


wstrzymywana do czasu ponownej
aktywacji linii CTS;
FALSE wczenie sygnau na linii
CTS nie jest wymagane do rozpoczcia
transmisji

DWORD

fOutxDsrFlow

Umoliwia ustawienie
sprawdzania sygnau na linii
DSR w celu kontroli danych
wyjciowych

TRUE jeeli sygna DSR

jest nieaktywny, transmisja


jest wstrzymywana do czasu ponownej
aktywacji linii DSR;
FALSE wczenie sygnau na linii DSR

nie jest wymagane do rozpoczcia


transmisji
DWORD

fDtrControl

Specyfikacja typu kontroli


sygnau DTR

DTR_CONTROL_DISABLE / 0 sygna
na linii DTR jest nieaktywny;
DTR_CONTROL_ENABLE / 1 sygna na linii

DTR jest aktywny;


DTR_CONTROL_HANDSHAKE / 2 wczenie

potwierdzania przyjcia sygnau DTR


potwierdzenie musi by odebrane
na linii DSR. Uywane w trybie
pdupleksowym. Ewentualne bdy
transmisji w tym trybie s usuwane
przez funkcj EscapeCommFunction()
DWORD

DWORD

fTXContinueOnXoff

fDsrSensitivity

Kontrola przerwania
transmisji w przypadku
przepenienia bufora
wejciowego i ewentualnie
wystpienia znakw
XoffChar oraz XonChar

Specyfikacja wykorzystania
poziomu sygnau na linii DSR

TRUE wymuszanie kontynuowania


transmisji nawet po wystpieniu znaku
XOFF i wypenieniu wejciowego bufora
danych powyej XoffLim bajtw;
FALSE transmisja nie jest
kontynuowana, dopki bufor wejciowy
nie zostanie oprniony do puapu XonLim
bajtw 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 reprezentujce dopuszczalne wartoci znacznikw sterujcych struktury DCB
cig dalszy
Typ

Pole bitowe

Waciwoci pola

DWORD

fInX

Programowe ustawienie
protokou XON-XOFF w czasie
odbioru danych

Warto, znaczenie,
staa symboliczna
TRUE znak XoffChar jest wysyany,

kiedy bufor wejciowy jest peny lub


znajduje si w nim XoffLim bajtw; znak
XonChar jest wysyany, kiedy bufor
wejciowy pozostaje pusty lub znajduje
si w nim XonLim bajtw;
FALSE XON-XOFF w czasie odbioru nie

jest ustawiony
DWORD

fRtsControl

Specyfikacja kontroli
sygnau na linii RTS

RTS_CONTROL_DISABLE / 0 sygna

na linii RTS jest nieaktywny;


RTS_CONTROL_ENABLE / 1 sygna

na linii RTS jest aktywny;


RTS_CONTROL_HANDSHAKE / 2 wczenie

potwierdzania przyjcia sygnau RTS


(potwierdzenie musi by odebrane
na linii CTS). Uywane w trybie
pdupleksowym. Sterownik podwysza
stan linii RTS, gdy wypenienie bufora
wejciowego jest mniejsze od . Stan
linii RTS zostaje obniony, gdy bufor
wypeniony jest w . Ewentualne bdy
transmisji w tym trybie usuwane s przez
funkcj EscapeCommFunction();
RTS_CONTROL_TOGGLE / 3 linia RTS

jest w stanie wysokim, jeeli s bajty


do transmisji i jest ona moliwa; po
oprnieniu bufora komunikacyjnego
linia RTS pozostaje w stanie niskim
DWORD

fOutX

Programowe ustawienie
protokou XON-XOFF w czasie
wysyania danych

TRUE transmisja zostaje przerwana po


odebraniu znaku XoffChar i wznowiona
po otrzymaniu znaku XonChar;
FALSE XON-XOFF w czasie wysyania

nie jest ustawiony


DWORD

fErrorChar

Umoliwia zastpienie bajtw


otrzymanych z bdem
parzystoci znakiem
ErrorChar

DWORD

fNull

Odrzucenie odebranych
niewanych lub
uszkodzonych bajtw

TRUE zastpienie jest wykonywane,


ponadto fParity musi by ustawione
jako TRUE;
FALSE zastpienie nie jest wykonane
TRUE niewane bajty zostan

odrzucone przy odbiorze;


FALSE niewane bajty nie bd
odrzucane

Rozdzia 5. Programowa obsuga interfejsu RS 232C w Windows

69

Tabela 5.5. Pola bitowe reprezentujce dopuszczalne wartoci znacznikw sterujcych struktury DCB
cig dalszy
Typ

Pole bitowe

Waciwoci pola

DWORD

fAbortOnError

Ustawienie wstrzymywania
operacji nadawanie-odbir
przy wykryciu bdu
transmisji

Warto, znaczenie,
staa symboliczna
TRUE wszelkie operacje nadawania

i odbioru s wstrzymywane, za dalsza


komunikacja nie jest moliwa, dopki
bd nie zostanie usunity przez
wywoanie funkcji ClearCommError();
FALSE nawet jeeli wystpi bd,

transmisja jest kontynuowana bd


moe by usunity przez wywoanie
funkcji ClearCommError()
DWORD

fDummy2

Zarezerwowane, nieuywane

Oglnie rzecz ujmujc, przed rozpoczciem czytania z portu szeregowego (lub innego
urzdzenia) naley o powyszym fakcie poinformowa system operacyjny. Czynno t
okrela 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 sposb
wykorzystywany. W przypadku uzyskania dostpu do portu system operacyjny przekazuje do aplikacji jego identyfikator. We wszystkich operacjach wejcia-wyjcia zamiast
szczegowej nazwy portu komunikacyjnego uywa si wanie jego identyfikatora.
Skadnia CreateFile() wyglda nastpujco1:
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, dosowne przetumaczenie angielskiego sowa handle jako uchwyt, np. handle of drawer uchwyt,
rczka szuflady, nie jest w peni adekwatne. Waciwsze wydaje si utosamianie
handle z identyfikatorem (unikaln wartoci zlokalizowan w danym obszarze pamici i skojarzon z konkretnym portem komunikacyjnym, oknem czy plikiem). W potocznej angielszczynie handle moe rwnie oznacza ksyw pozwalajc na szybk
identyfikacj danej osoby lub rzeczy. Koncepcja identyfikatorw nie jest niczym nowym,
stosowano j ju w MS-DOS, jednak dopiero w Windows zyskaa now jako.

Na tym etapie naszych rozwaa tylko trzy parametry powyszej funkcji s istotne dla
kompletnej konfiguracji portu szeregowego. Wyjanimy teraz ich znaczenie.

Pena specyfikacja funkcji CreateFile() zostaa zamieszczona w dodatku A.

70

RS 232C praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera

Pierwszy parametr, lpFileName, jest wskanikiem do zadeklarowanego cigu znakw


zakoczonego zerem (zerowym ogranicznikiem), tzw. null terminated string, lub do
C-acucha (dokadniej: do pierwszego znaku tego acucha), w ktrym przechowywana
bdzie nazwa (warto) portu. Z poprzednich rozdziaw pamitamy, e oglnie przyjte
jest stosowanie nazewnictwa portw szeregowych jako COMn (nazwy COMn znajduj
si na licie nazw zastrzeonych), gdzie n oznacza numer portu. Deklaracja numeru portu
szeregowego, np. 2., bdzie wic przedstawia si w sposb bardzo prosty:
LPCTSTR portName = "COM2";

lub, co jest rwnowane:


unsigned const char

*portName = "COM2";

Mona te zmienn, pod ktr przechowywa bdziemy numer portu, zadeklarowa


w sposb tradycyjny, uywajc typu char. Deklaracja taka bdzie w peni poprawna:
char portName[5] = "COM2";

Parametr dwDesiredAccess typu DWORD umoliwia ustalenie rodzaju dostpu do portu


szeregowego. Z praktycznego punktu widzenia najwygodniej jest ustali rodzaj dostpu
jako GENERIC_READ | GENERIC_WRITE (zapisuj do portu lub odczytuj z portu). Umoliwi
nam to pynne wysyanie i odbieranie komunikatw, co w peni odpowiada pdupleksowemu wariantowi transmisji. Jeeli zechcemy korzysta jedynie z trybu simpleksowego, do dwDesiredAccess wystarczy przypisa jeden z wybranych rodzajw dostpu.
Windows API posuguje si acuchami o dugoci wikszej ni 256 znakw. Aby
przeama to ograniczenie, zrezygnowano z zapamitywania w pierwszym bajcie liczby
okrelajcej dugo acucha znakw. W C-acuchach ostatnim znakiem, koczcym cig jest 0 (NULL lub heks. 00), ktrego nie naley myli ze znakiem zero (48
lub heks. 30). Std nazwa null terminated string.C-acuchy osigaj dugo 65535
znakw plus kocowy, tzw. NULL-bajt. S one dynamicznie alokowane w pamici, za
ilo pamici zajmowanej przez C-acuch jest automatycznie dostosowywana do
jego dugoci, co w peni odpowiada architekturze Windows.

Parametrowi dwCreationDistribution naley przypisa waciwo OPEN_EXISTING


otwrz istniejcy (port). Pozostaym przyporzdkujemy nastpujce wartoci:
DWORD ShareMode = 0 (FALSE);
LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL;
DWORD dwFlagAndAttributes = 0 (FALSE);
HANDLE hTemplateFile = NULL.

Funkcja GetCommState()
Funkcja zwraca ustawienia portu ostatnio zapamitane w strukturze DCB:
BOOL GetCommState(HANDLE hCommDev, LPDCB lpdcb),

Rozdzia 5. Programowa obsuga interfejsu RS 232C w Windows

71

gdzie:
hCommDev jest identyfikatorem danego portu, CreateFile() zwraca nam ten
identyfikator, a lpdcb jest wskanikiem do struktury DCB zawierajcej informacj

o aktualnych ustawieniach parametrw cza szeregowego.


Funkcja GetCommState() (jak i wszystkie inne typu BOOL) zwraca warto TRUE w przypadku pomylnego 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(), ktra reinicjalizuje i uaktualnia wszystkie dostpne parametry w ustawieniach cza szeregowego:
BOOL SetCommState(HANDLE hCommDev, LPDCB lpdcb)

Jednak tutaj parametr, na ktry wskazuje lpdcb, musi ju zawiera informacje o nowych,
wybranych przez nas parametrach ustawie portu komunikacyjnego. Naley te pamita,
e funkcja SetCommState() nie zostanie wykonana pomylnie, jeeli posugujc si struktur DCB, element XonChar ustalimy identycznie z XoffChar.

Funkcja CloseHandle()
Przed zakoczeniem dziaania aplikacji otwarty port szeregowy naley koniecznie
zamkn i zwolni obszar pamici przydzielony na jego identyfikator, korzystajc z:
BOOL CloseHandle(HANDLE hCommDev)

We wszystkich przedstawionych powyej funkcjach hCommDev w peni identyfikuje dany


port szeregowy, zawierajc kompletn informacj o tym, do ktrego cza szeregowego
bdziemy wysya komunikaty. Poniewa funkcje te mog obsugiwa komunikaty
wysyane do wielu portw komunikacyjnych (jak rwnie odbierane od wielu portw),
zatem kady otwarty i zainicjalizowany port szeregowy bdzie identyfikowany wanie
za pomoc swojego wasnego hCommDev. Nie naley przydziela tego samego identyfikatora do dwch rnych portw komunikacyjnych, tak samo jak nie naley z jednym portem
kojarzy dwch rnych identyfikatorw.
Przy pisaniu aplikacji obsugujcych cze szeregowe naley koniecznie zamkn port
przed opuszczeniem programu. W razie korzystania z zegara systemowego przy obsudze RS-a lub techniki programowania wielowtkowego trzeba pamita, e samo
zamknicie aplikacji nie powoduje automatycznego zamknicia portu. Jego identyfikator dalej bdzie przechowywany w pamici.
W pewnych przypadkach aplikacja z niezamknitym portem szeregowym moe sta si
programem rezydentnym i uniemoliwi powtrne otwarcie wybranego portu. Dobrym
zwyczajem jest w pierwszej kolejnoci zaprojektowanie funkcji lub procedury obsugi
zdarzenia zamykajcego otwarty port. System operacyjny powinien by zawsze poinformowany o fakcie zamknicia portu.

72

RS 232C praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera

W praktyce zdarzaj si jednak sytuacje, w ktrych zamknicie portu okae si niemoliwe, np. z powodu jakiego bdu w algorytmie lub niewaciwego sposobu wywoania
danej funkcji. Mwimy wwczas, e program si zaama lub zawiesi. Ten problem
powtarza si czsto w trakcie testowania programw komunikacyjnych. Nie naley wwczas od razu uywa kombinacji klawiszy Ctrl, Alt, Del. W takich przypadkach wygodniej
jest rozwin z gwnego menu opcj Project oraz wybra Compile Unit, tak jak pokazano to na rysunku 5.1. Nazwa dziaajcej aplikacji powinna si pojawi na dolnym
pasku zada.

Rysunek 5.1. Przykadowy sposb wstrzymywania dziaania aplikacji z otwartym portem szeregowym

Po pojawieniu si informacji Debug session in progress. Terminate? (Usuwanie sesji


w toku. Zakoczy?) (rysunek 5.2) naley nacisn przycisk OK.
Po kolejnym komunikacie (rysunek 5.3) znw naley dokona potwierdzenia.
Tak postpujc, w wikszoci przypadkw odzyskamy program oraz odblokujemy cze
szeregowe. Sposb ten okae si szczeglnie przydatny przy kopotach z aplikacj
komunikacyjn korzystajc z komponentu typu TTimer, generujcego zdarzenia w rwnych odstpach czasu.
Moe oczywicie zdarzy si sytuacja, w ktrej nie bdziemy w stanie powtrnie
skompilowa programu i samodzielnie prawidowo zamkn portu komunikacyjnego.
Wwczas program naley usun z pamici poleceniem menu Run/Program Reset.

Rozdzia 5. Programowa obsuga interfejsu RS 232C w Windows

Rysunek 5.2. Okno dialogowe Debug session

Rysunek 5.3. Kompilacja projektu

73

74

RS 232C praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera

Testowanie portu szeregowego


Majc na uwadze wszystko, co powiedzielimy do tej pory, sprbujemy napisa w C++Builderze prosty program wykorzystujcy przedstawione powyej funkcje Windows API
oraz niektre zasoby struktury DCB.
Zadaniem naszej aplikacji bdzie ustawienie wybranych parametrw danego portu szeregowego, otwarcie go oraz odczytanie nowych ustawie. W tym celu stwrzmy now
standardow aplikacj (polecenie File New Application). Niech jej formularz skada
si z dwch przyciskw klasy TButton, piciu komponentw klasy TEdit oraz piciu
TLabel.
Korzystajc z inspektora obiektw (Object Inspector) oraz z karty wasnoci (Properties),
wasno Name przycisku Button1 zmiemy na CloseComm, za jego wasno Caption na
&Zamknij. Podobnie wasno Name przycisku Button2 zmiemy na OpenComm, za Caption na &Otwrz port. Wasnoci Caption komponentw z klas TLabel zmiemy odpowiednio na Prdko transmisji, Liczb bitw danych, Parzysto, Bity stopu, Linia DTR.
Wasnoci Text komponentw klasy TEdit wyczymy.
Formularz naszej aplikacji, wygldajcej podobnie jak na rysunku 5.4, znajduje si na
doczonym CD w katalogu \KODY\BUILDER\R05\P05_01\. Na listingu 5.1 pokazano
kod gwnego moduu omawianej aplikacji.
Rysunek 5.4.
Formularz
gwny projektu
Projekt_05_01.bpr

Listing 5.1. Kod gwnego moduu aplikacji testujcej 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 obsuga interfejsu RS 232C w Windows


LPCTSTR portName = "COM2"; // wskanik do nazwy portu
// const char *portName = "COM2";
LPCTSTR sbuffer2 = "Uwaga!";
LPCTSTR sbuffer1 = "Niewaciwa 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;
}
}
//-----zamknicie portu i aplikacji--------------------------void __fastcall TForm1::CloseCommClick(TObject *Sender)
{
closeSerialPort(hCommDev);
Application->Terminate();
}
//---otwarcie portu i ustawienie jego parametrw--------------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 prawidowo
{
dcb.DCBlength = sizeof(dcb); // aktualny rozmiar
// struktury DCB
GetCommState(hCommDev, &dcb); // udostpnienie aktualnych
// parametrw DCB
dcb.BaudRate = CBR_1200;
// prdko transmisji
dcb.fParity = TRUE;
// sprawdzanie parzystoci
dcb.Parity = NOPARITY;
// ustawienie parzystoci
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:

75

76

RS 232C praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera


// W przypadku bdnej identyfikacji portu
// BADIDentify poka komunikat
MessageBox(NULL, sbuffer1, sbuffer2, MB_OK);
break;
};
}
//--sprawdzenie i wywietlenie ustawionej prdkoci-----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 wywietlenie ustawionych bitw danychswitch (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 wywietlenie ustawionej parzystoci---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 wywietlenie ustawionych bitw stopu--switch (dcb.StopBits)

Rozdzia 5. Programowa obsuga 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 wywietlenie 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;
}
//--------------------------------------------------------------

Stworzylimy zatem bardzo prost, wrcz dydaktyczn aplikacj, ale taki wanie by
nasz cel. Moemy zauway, e obsuga tego programu sprowadza si do wywoania
funkcji obsugi zdarzenia OpenCommClick(). Nacinicie przycisku Otwrz port powoduje
automatyczne skonfigurowanie wybranego wczeniej portu szeregowego oraz odczytanie
jego aktualnie wybranych ustawie. Dobrze byoby, gdyby Czytelnik sprbowa samodzielnie skonfigurowa port z wiksz liczb parametrw, a nastpnie je odczyta. Nabiera
si przez to wikszej wprawy w manipulowaniu znacznikami struktury DCB. Zamknicie
portu i aplikacji nastpi po wywoaniu funkcji obsugi zdarzenia CloseCommClick(),
w ktrej z kolei dokonujemy wywoania funkcji CloseSerialPort() zamykajcej port szeregowy i aplikacj. Przygldajc si kodowi funkcji obsugi zdarzenia OpenCommClick(),
zauwaymy, e tu po wywoaniu CreateFile() zastosowalimy nastpujc instrukcj
warunkow sprawdzajc, czy funkcja ta zwrcia prawidowy identyfikator zadeklarowanego 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 bdnej identyfikacji portu
// BADIDentify poka komunikat
...
break;
}

};

atwo mona si przekona, e w przypadku bdnego przydzielenia identyfikatora dla


portu COMn, funkcja CreateFile() zwraca warto INVALID_HANDLE_ VALUE (niewaciwa
warto identyfikatora) zdefiniowan w Windows API. Jest to bardzo skuteczna metoda
zabezpieczenia si przed prb otwarcia nieistniejcego lub ju otwartego portu (urzdzenia). Zauwamy te, e aby odczyta aktualn warto hCommDev, musielimy wymusi
przeksztacenie typw, uywajc operacji rzutowania (int)hCommDev. Kady ju si chyba
przekona, e identyfikator czy jak kto woli uchwyt typu HANDLE nie jest adnym
numerem bezporednio nadanym portowi komunikacyjnemu, lokalizuje jedynie unikalny
obszar pamici, do ktrego naley si odwoa, by uzyska dostp do danego urzdzenia.
Raz otwartego portu komunikacyjnego nie mona otworzy powtrnie, podobnie jak
nie uda si otworzy ju otwartego okna. Nie mona te powtrnie skorzysta z obszaru pamici, z ktrego wanie korzystamy.

Jeeli mimo wszystko port nie zosta otwarty prawidowo, dobrze by byo, gdyby aplikacja powiadomia nas o tym fakcie. W tym celu mona skorzysta z komunikatw
Windows typu IE_ (ang. Identify Error bd identyfikacji portu) urzdzenia lub jego
ustawie. W tabeli 5.6 przedstawiono najczciej otrzymywane od Windows komunikaty
tego typu.
Tabela 5.6. Najczciej uywane komunikaty bdnej identyfikacji ustawie portu szeregowego
Identyfikacja komunikatu
IE_BADID

Warto

Znaczenie

Niewaciwa identyfikacja urzdzenia

IE_BAUDRATE

12

Bdnie okrelona szybko transmisji

IE_BYTESIZE

11

Bdnie okrelona liczba bitw danych

IE_DEFAULT

IE_HARDWARE

10

Niewaciwie okrelone parametry domylne urzdzenia


Odbiornik jest zablokowany

IE_MEMORY

Niewaciwie ustalony rozmiar buforw

IE_NOPEN

Urzdzenie nie jest otwarte do transmisji

IE_OPEN

Urzdzenie pozostaje otwarte

Struktura COMMPROP
W celu dokadniejszego zapoznania si z moliwociami testowania systemw komunikacyjnych dostpnych w Windows w tabeli 5.7 przedstawiono bardzo uyteczn struktur
oferowan przez API. Zawarte w niej informacje mog by wykorzystywane do penego
odczytywania wszystkich istotnych parametrw interesujcego nas cza komunikacyjnego oraz usug potencjalnie przez nie oferowanych.

Rozdzia 5. Programowa obsuga interfejsu RS 232C w Windows

79

Tabela 5.7. Zasoby struktury COMMPROP


Typ

Element struktury

Znaczenie

Zawarto elementu, maska


okrelajca wczony bit

WORD

wPacketLength

Okrela (w bajtach) rozmiar


porcji pakietu danych

Naley odczyta, zaley te


od typu sterownika

WORD

wPacketVersion

Wersja struktury

Nr 2 w Win 9x, XP

DWORD

dwServiceMask

Okrelenie maski bitowej


wskazujcej na typ aktualnie
dostpnej usugi komunikacyjnej

SP_SERIALCOMM jest zawsze

okrelone

DWORD

dwReserved1

Zarezerwowane, nieuywane

DWORD

dwMaxTxQueue

Maksymalny rozmiar
wewntrznego bufora wyjciowego
nadajnika (w bajtach)

0 oznacza, e nie ustalono

Maksymalny rozmiar
wewntrznego bufora wejciowego
odbiornika (w bajtach)

0 oznacza, e nie ustalono

Maksymalna dostpna prdko


transmisji w bitach na sekund

BAUD_075

DWORD

DWORD

dwMaxRxQueue

dwMaxBaud

maksymalnej wartoci

maksymalnej wartoci

BAUD_110
BAUD_134_5

75 b/s
110 b/s
134.5 b/s

BAUD_150

150 b/s

BAUD_300

300 b/s

BAUD_600

600 b/s

BAUD_1200

1200 b/s

BAUD_1800

1800 b/s

BAUD_2400

2400 b/s

BAUD_4800

4800 b/s

BAUD_7200

7200 b/s

BAUD_9600

9600 b/s

BAUD_14400

14 400 b/s

BAUD_19200

19 200 b/s

BAUD_38400

38 400 b/s

BAUD_56K

56K b/s

BAUD_57600

57 600 b/s

BAUD_115200

115 200 b/s

BAUD_128K

128K b/s

BAUD_USER programowalne

80

RS 232C praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera

Tabela 5.7. Zasoby struktury COMMPROP cig dalszy


Typ

Element struktury

Znaczenie

Zawarto elementu, maska


okrelajca wczony bit

DWORD

dwProvSubType

Typ usugi komunikacyjnej

PST_FAX faks
PST_LAT protok LAT

(Local Area Transport)


PST_MODEM modem
PST_NETWORK_BRIDGE

niewyspecyfikowana sie
PST_PARALLELPORT port

rwnolegy
PST_RS232

RS 232

PST_RS422

RS 422

PST_RS423

RS 423

PST_RS449

RS 449

PST_SCANNER skaner
PST_TCPIP_TELNET protok

TCP/IP
PST_UNSPECIFIED brak

specyfikacji
PST_X25 protok X.25
DWORD

DwSettableParams

Specyfikacja maski bitowej


identyfikujcej parametry
transmisji podlegajce
ewentualnym zmianom

SP_BAUD prdko
SP_DATABITS dugo sowa

danych
SP_HANDSHAKING kontrola

przepywu danych
SP_PARITY parzysto
SP_PARITY_CHECK sprawdzanie

parzystoci
SP_RLSD sygna RLSD
SP_STOPBITS bity stopu

W Windows API COMMPROP deklaruje si nastpujco:


typedef struct _COMMPROP {
WORD wPacketLength;
...
} COMMPROP;

Powysza deklaracja tworzy nowe sowo kluczowe typu COMMPROP (struktura).


Zbudujmy teraz aplikacj, za pomoc ktrej bdziemy mogli selektywnie odczytywa stan
poszczeglnych masek bitowych udostpnianych przez COMMPROP.

Rozdzia 5. Programowa obsuga interfejsu RS 232C w Windows

81

Tabela 5.7. Zasoby struktury COMMPROP cig dalszy


Typ

Element struktury

Znaczenie

DWORD

dwProvCapabilities

Okrela mask bitow


identyfikujc rodzaj funkcji
udostpnianych przez usug
komunikacyjn (dostarczyciela
usugi)

Zawarto elementu, maska


okrelajca wczony bit
PCF_16BITMODE tryb 16-bitowy
PCF_DTRDSR kontrola DTR-DSR
PCF_INTTIMEOUTS czas

przeterminowania
PCF_PARITY_CHECK sprawdzanie

parzystoci
PCF_RLSD kontrola RLSD
PCF_RTSCTS kontrola RTS-CTS
PCF_SETXCHAR moliwo
uycia protokou XON/XOFF
PCF_SPECIALCHARS specjalny

znak
PCF_TOTALTIMEOUTS kontrola

czasu przeterminowania transmisji


PCF_XONXOFF podtrzymanie

protokou XON-XOFF
DWORD

dwSettableBaud

Specyfikacja maski bitowej


umoliwiajcej ustawienie
prdkoci transmisji

Tak samo jak w dwMaxBaud

WORD

wSettableData

Specyfikacja maski bitowej


identyfikujcej moliwe do
uycia dugoci sowa danych

DATABITS_5
DATABITS_6
DATABITS_7
DATABITS_8
DATABITS_16
DATABITS_16X szczeglna

dugo sowa danych


DWORD

WORD

dwCurrentTxQueue

wSettableStopParity

Aktualny maksymalny rozmiar


wewntrznego bufora wyjciowego
nadajnika (w bajtach)

0 oznacza, e warto ta nie jest

Specyfikacja maski bitowej


identyfikujcej moliwe do
uycia wartoci bitw stopu
i kontroli parzystoci

STOPBITS_10 1 bit stopu

aktualnie dostpna

STOPBITS_15 1,5 bitu


STOPBITS_20 2 bity
PARITY_NONE brak
PARITY_ODD nieparzysta
PARITY_EVEN parzysta
PARITY_MARK 1
PARITY_SPACE 0

DWORD

dwCurrentRxQueue

Aktualny maksymalny rozmiar


wewntrznego bufora wejciowego
nadajnika (w bajtach)

0 oznacza, e warto ta nie jest

aktualnie dostpna

82

RS 232C praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera

Tabela 5.7. Zasoby struktury COMMPROP cig dalszy


Zawarto elementu, maska
okrelajca wczony bit

Typ

Element struktury

Znaczenie

DWORD

dwProvSpec1

Specyfikacja formatu danych


wymaganych przez dan usug
komunikacyjn

DWORD

dwProvSpec2

Jak wyej

WCHAR

wcProvChar[1]

Jak wyej

W zalenoci od dwProvSubType
aplikacje powinny ignorowa
ten czon, chyba e zawieraj
szczegowe informacje odnonie
do formatu danych wymaganych
przez dostarczyciela usugi
Jeeli dwProvSubType przypisano
PST_MODEM, musi nastpi
odwoanie do struktur
2
MODEMDEVCAPS oraz MODEMSETTINGS ;
dwProvSpec1 i dwProvSpec2 nie s
wwczas uywane

Wykorzystamy tu znany nam ju proces maskowania z uyciem operatora iloczynu


bitowego & (bitowe i). Program bdzie odczytywa warto wybranego elementu struktury, a nastpnie poprzez wybranie kolejnych masek bdzie selektywnie sprawdza, czy
wczone s konkretne bity odpowiedzialne za pewne parametry transmisji. Omawiany
projekt znajduje si na doczonym CD w katalogu \KODY\BUILDER\R05\P05_02\.
Do testowania wybierzmy elementy: dwSettableParams, w XP reprezentowany na 32
bitach, oraz wSettableData i wSettableStopParity, reprezentowane na 16 bitach. Zastosujemy nieco odbiegajcy od przedstawionego wczeniej projekt formularza. Skada si
on bdzie z dwch dobrze nam ju znanych przyciskw reprezentujcych zdarzenia
polegajce na otwarciu oraz zamkniciu portu. Zastosowano ponadto dwa komponenty
klasy TTrackBar, dwa TEdit oraz dwa typu TLabel, tak jak pokazuje to rysunek 5.5.
Obsuga zdarzenia TrackBar1Change() polega na wybraniu interesujcego nas elementu
struktury COMMPROP oraz odczytaniu jego aktualnej wartoci. Jeeli zechcemy sprawdzi,
czy wczony jest konkretny bit reprezentujcy wybrany atrybut transmisji przechowywany w danym elemencie struktury, wystarczy przesun wskanik uruchamiajcy funkcj
obsugi zdarzenia TrackBar2Change().

Funkcja GetCommProperties()
Funkcj, ktra zwraca aktualne waciwoci portu komunikacyjnego identyfikowanego
przez hCommDev, bdzie:
BOOL GetCommProperties(HANDLE

hCommDev, LPCOMMPROP

lpCommProp);

lpCommProp jest wskanikiem do struktury COMMPROP, ktrej format danych w oglnym


przypadku naley najpierw zainicjalizowa, po uprzednim wpisaniu do pola wPacketLength aktualnego rozmiaru struktury:

Mionikom modemw specyfikacj tych struktur prezentujemy w dodatku B.

Rozdzia 5. Programowa obsuga interfejsu RS 232C w Windows

83

Rysunek 5.5.
Formularz gwny
uruchomionego
projektu
Projekt_R05_02.bpr

commprop.wPacketLength = sizeof(COMMPROP);
//...
CommProp.dwProvSpec1 = COMMPROP_INITIALIZED;

Informacje tam zawarte mog by pomocne przy odwoywaniu si do rodziny funkcji


SetCommState(), SetCommTimeouts() lub SetupComm().
Na listingu 5.2 pokazano kod gwnego moduu omawianej aplikacji.
Listing 5.2. Zawarto moduu Unit_R05_02.cpp
#include <vcl.h>
#pragma hdrstop
#include "Unit_05_02.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
HANDLE hCommDev;
//
COMMPROP commprop;
//
LPCTSTR portName = "COM2"; //
//

identyfikator portu
waciwoci portu
wskanik do nazwy portu
szeregowego

LPCTSTR sbuffer1 = "Niewaciwa 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;

84

RS 232C praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera


}
}
//-------zamknicie portu i aplikacji---------------------------void __fastcall TForm1::CloseCommClick(TObject *Sender)
{
closeSerialPort(hCommDev);
Application->Terminate();
}
//----otwarcie portu i ustawienie jego parametrw--------------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 prawidowo
commprop.wPacketLength = sizeof(COMMPROP);
commprop.dwProvSpec1 = COMMPROP_INITIALIZED;
// inicjalizuje format danych usugi.
// Port szeregowy jest zawsze dostpny
memset(&commprop, 0, sizeof(COMMPROP));
GetCommProperties(hCommDev, &commprop);
}
else {
switch ((int)hCommDev) {
case IE_BADID:
ShowMessage(sbuffer1);
break;
};
}
}
//------wybrane maski bitowe-----------------------------------void __fastcall TForm1::TrackBar1Change(TObject *Sender)
{
switch (TrackBar1->Position) {
case 1: {
TrackBar2->Max = 7;
Label1->Caption = "dwSettableParams";
Edit1->Text=IntToStr(commprop.dwSettableParams);
break;
}
case 2: {
TrackBar2->Max = 6;
Label1->Caption = "wSettableData";
Edit1->Text=IntToStr(commprop.wSettableData);
break;
}
case 3: {
TrackBar2->Max = 8;
Label1->Caption = "wSettableStopParity";
Edit1->Text=IntToStr(commprop.wSettableStopParity);
break;
}
} // koniec switch
}

Rozdzia 5. Programowa obsuga interfejsu RS 232C w Windows


//---------------zawarto maski--------------------------void __fastcall TForm1::TrackBar2Change(TObject *Sender)
{
if (TrackBar1->Position == 1) {
switch (TrackBar2->Position) {
case 1: {
Label2->Caption = "SP_PARITY";
Edit2->Text=IntToStr(commprop.dwSettableParams & SP_PARITY);
break;
}
case 2: {
Label2->Caption = "SP_BAUD";
Edit2->Text=IntToStr(commprop.dwSettableParams & SP_BAUD);
break;
}
case 3: {
Label2->Caption = "SP_DATABITS";
Edit2->Text=IntToStr(commprop.dwSettableParams &
SP_DATABITS);
break;
}
case 4: {
Label2->Caption = "SP_STOPBITS";
Edit2->Text=IntToStr(commprop.dwSettableParams &
SP_STOPBITS);
break;
}
case 5: {
Label2->Caption = "SP_HANDSHAKING";
Edit2->Text=IntToStr(commprop.dwSettableParams &
SP_HANDSHAKING);
break;
}
case 6: {
Label2->Caption = "SP_PARITY_CHECK";
Edit2->Text=IntToStr(commprop.dwSettableParams &
SP_PARITY_CHECK);
break;
}
case 7: {
Label2->Caption = "SP_RLSD";
Edit2->Text=IntToStr(commprop.dwSettableParams & SP_RLSD);
break;
}
} // koniec switch
} // koniec if
if (TrackBar1->Position == 2) {
switch (TrackBar2->Position) {
case 1: {
Label2->Caption = "DATABITS_5";
Edit2->Text=IntToStr(commprop.wSettableData & DATABITS_5);
break;
}
case 2: {
Label2->Caption = "DATABITS_6";

85

86

RS 232C praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera


Edit2->Text=IntToStr(commprop.wSettableData & DATABITS_6);
break;
}
case 3: {
Label2->Caption = "DATABITS_7";
Edit2->Text=IntToStr(commprop.wSettableData
break;
}
case 4: {
Label2->Caption = "DATABITS_8";
Edit2->Text=IntToStr(commprop.wSettableData
break;
}
case 5: {
Label2->Caption = "DATABITS_16";
Edit2->Text=IntToStr(commprop.wSettableData
break;
}
case 6: {
Label2->Caption = "DATABITS_16X";
Edit2->Text=IntToStr(commprop.wSettableData
DATABITS_16X);
break;
}
} // koniec switch
} // koniec if

& DATABITS_7);

& DATABITS_8);

& DATABITS_16);

&

if (TrackBar1->Position == 3) {
switch (TrackBar2->Position) {
case 1: {
Label2->Caption = "STOPBITS_10";
Edit2->Text=IntToStr(commprop.wSettableStopParity
STOPBITS_10);
break;
}
case 2: {
Label2->Caption = "STOPBITS_15";
Edit2->Text=IntToStr(commprop.wSettableStopParity
STOPBITS_15);
break;
}
case 3: {
Label2->Caption = "STOPBITS_20";
Edit2->Text=IntToStr(commprop.wSettableStopParity
STOPBITS_20);
break;
}
case 4: {
Label2->Caption = "PARITY_NONE";
Edit2->Text=IntToStr(commprop.wSettableStopParity
PARITY_NONE);
break;
}
case 5: {
Label2->Caption = "PARITY_ODD";

&

&

&

&

Rozdzia 5. Programowa obsuga interfejsu RS 232C w Windows

87

Edit2->Text=IntToStr(commprop.wSettableStopParity &
PARITY_ODD);
break;
}
case 6: {
Label2->Caption = "PARITY_EVEN";
Edit2->Text=IntToStr(commprop.wSettableStopParity &
PARITY_EVEN);
break;
}
case 7: {
Label2->Caption = "PARITY_MARK";
Edit2->Text=IntToStr(commprop.wSettableStopParity &
PARITY_MARK);
break;
}
case 8: {
Label2->Caption = "PARITY_SPACE";
Edit2->Text=IntToStr(commprop.wSettableStopParity &
PARITY_SPACE);
break;
}
} // koniec switch
} // koniec if
}
//-------------------------------------------------------------void __fastcall TForm1::FormClose(TObject *Sender,
TCloseAction &Action)
{
Action=caFree;
}
//--------------------------------------------------------------

Dla przykadu rozpatrzmy parametr dwSettableParams typu DWORD, w XP reprezentowany


na 32 bitach. Odczytujc odpowiedni warto, przekonalimy si, e caa zawarta tam
informacja zapisana jest na 7 pierwszych bitach dwSettableParams.
Uylimy operatora &, aby sprawdzi, czy wczone s poszczeglne bity reprezentujce
atrybuty zwizane z konkretnymi parametrami komunikacyjnymi. Patrzc na wartoci
w postaci binarnej, atwo zorientujemy si, jaki jest aktualny stan logiczny poszczeglnych bitw zawartych w tej zmiennej i za co s one odpowiedzialne, tak jak pokazano to
w zawartoci tabeli 5.8.
W analogiczny sposb moemy przetestowa wszystkie maski bitowe udostpniane przez
COMMPROP, odpowiadajce waciwym pozycjom konkretnych bitw. Jeeli jako rezultat
iloczynu bitowego wartoci elementu struktury z mask okrelajc wczony bit otrzymamy warto 0, oznacza to bdzie, e testowany bit jest wyczony i dany parametr
komunikacyjny nie jest aktualnie dostpny. Lepiej znajcy temat Czytelnicy zapewne ju
zorientowali si, jakie niespodzianki oferuje nam ta struktura. Manipulowanie bitami jest
tu spraw dobrania odpowiednich operatorw przesuwania, maskowania i dopeniania.
Mona np. skasowa bity SP_PARITY i SP_BAUD w elemencie dwSettableParams:
CommProp.dwSettableParams &= ~(SP_PARITY | SP_BAUD);

88

RS 232C praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera

Tabela 5.8. Maski bitowe elementu dwSettableParams struktury COMMPROP


dwSettableParams

Warto
127

Maska

Rezultat maskowania

SP_PARITY

SP_BAUD

SP_DATABITS

SP_STOPBITS

Bit 7
0
0

Bit 6

Bit 5

Bit 4

Bit 3

Bit 2

Bit 1

Bit 0

SP_HANDSHAKING

16

SP_PARITY_CHECK

32

SP_RLSD

64

Podobnie w jakim fragmencie aplikacji mona zastosowa warunek:


if ((CommProp.dwSettableParams & (SP_PARITY | SP_BAUD)) == 0) {
...
}

ktry bdzie prawdziwy, gdy oba bity bd skasowane. Jednak osobom mniej zaawansowanym w operacjach bitowych odradzabym jakiekolwiek prby ingerowania w zawarto COMMPROP.

Struktura COMMCONFIG
Struktura COMMCONFIG zawiera informacje o stanie konfiguracji danego urzdzenia komunikacyjnego. Tabela 5.9 prezentuje jej zasoby.
Windows API COMMCONFIG deklaruje nastpujco:
typedef struct _COMM_CONFIG {
DWORD dwSize;
...
} COMMCONFIG, *LPCOMMCONFIG;

Powysza deklaracja tworzy dwa nowe sowa kluczowe typu COMMCONFIG (struktura) oraz
LPCOMMCONFIG (wskanik do struktury).

Funkcje GetCommConfig() i SetCommConfig()


Aktualn konfiguracj cza komunikacyjnego odczytamy, korzystajc z funkcji API:
BOOL GetCommConfig(HANDLE hCommDev, LPCOMMCONFIG lpCC,
LPDWORD lpdwSize);

gdzie lpCC wskazuje na struktur COMMCONFIG, za lpdwSize jest wskanikiem do zmiennej


okrelajcej rozmiar struktury.

Rozdzia 5. Programowa obsuga interfejsu RS 232C w Windows

89

Tabela 5.9. Specyfikacja struktury COMMCONFIG


Typ

Element struktury

Znaczenie

Zawarto

DWORD

dwSize

Rozmiar struktury w bajtach

Naley wpisa

WORD

wVersion

Wersja struktury

Naley odczyta

WORD

wReserved

Zarezerwowane

DCB

dcb

Struktura kontroli portu szeregowego

Patrz DCB

DWORD

dwProviderSubType

Identyfikacja typu dostarczanej usugi


komunikacyjnej, a tym samym
wymaganego formatu danych

Patrz COMMPROP

DWORD

dwProviderOffset

Okrelenie offsetu dla danych wymaganych


przez dostarczyciela usugi komunikacyjnej;
offset (tzw. przesunicie) okrelony jest
zwykle w stosunku do pocztku struktury

0, jeeli nie okrelono


typu danych

DWORD

dwProviderSize

Rozmiar danych (w bajtach) wymaganych


przez usug komunikacyjn (dostarczyciela
usugi)

Zalenie od typu usugi

WCHAR

wcProviderData[1]

Dane dostarczane wraz z usug (poniewa


przewidywane jest w przyszoci
uzupenienie struktury, aplikacja powinna
uywa dwProviderOffset w celu
okrelenia pooenia wcProviderData)

Jeeli ustalono typ


usugi: PST_RS232
lub PST_PARALLELPORT,
czon ten jest pomijany;
jeeli ustalono PST_MODEM,
naley odwoa si do
MODEMSETTINGS

Biec konfiguracj portu komunikacyjnego zapiszemy za pomoc:


BOOL SetCommConfig(HANDLE hCommDev, LPBYTE lpCC, DWORD dwSize);

gdzie lpCC jest wskanikiem do COMMCONFIG, za dwSize okrela (w bajtach) rozmiar


struktury wskazywanej przez lpCC. Przed przekazaniem tej struktury jako parametru naley do elementu dwSize wpisa warto rwn sizeof(COMMCONFIG).

Funkcja CommConfigDialog()
Funkcja wywietla okno dialogowe zawierajce aktualne ustawienia parametrw portu
szeregowego.
BOOL CommConfigDialog(LPTSTR lpszName, HWND hWnd,
LPCOMMCONFIG lpCC);

lpszName jest wskanikiem do acucha znakw okrelajcego nazw portu, hWnd jest
identyfikatorem waciciela aktualnie wywietlanego okna dialogowego, a lpCC wskazuje
na struktur COMMCONFIG. Uycie tej funkcji, np. w kontekcie obsugi wybranego zdarzenia, moe wyglda nastpujco:
//-------------------------------------------------------------void __fastcall TForm1::Button1Click(TObject *Sender)
{

90

RS 232C praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera


LPCOMMCONFIG commconfig;
CommConfigDialog("COM2", NULL, commconfig);

}
//--------------------------------------------------------------

Struktura COMMTIMEOUTS
Zasoby struktury COMMTIMEOUTS przedstawione s w tabeli 5.10. Udostpniaj one informacje o tzw. czasach przeterminowania transmisji w trakcie przesyania danych (ang.
time-out of transmission). Jest to wany termin, z ktrym niektrzy na pewno ju si
zetknli. W trakcie transmisji asynchronicznej COMMTIMEOUTS determinuje zachowanie si
takich funkcji jak ReadFile() czy WriteFile().
Tabela 5.10. Informacje zawarte w strukturze COMMTIMEOUTS
Typ

Element struktury

Waciwoci

DWORD

ReadIntervalTimeout

Okrela maksymalny czas (w milisekundach) pomidzy


pojawieniem si na linii komunikacyjnej dwu znakw.
W trakcie wykonywania ReadFile() czas jest liczony od
momentu pojawienia si pierwszego znaku. Jeeli przedzia
czasu pomidzy nadejciem dwu znakw przekracza warto
ReadIntervalTimeout, oznacza to, e operacja ReadFile()
jest zakoczona. Warto 0 oznacza, e nie ustalono
wymaganego okresu pomidzy nadejciem dwu kolejnych
znakw. Przypisanie wartoci MAXDWORD powoduje, e czytany
znak jest pobierany z bufora natychmiast po tym, jak si
tam pojawi

DWORD

ReadTotalTimeoutMultiplier

Okrela mnonik (w milisekundach) uyty do obliczenia


cakowitego przedziau czasu (przeterminowanie) dla operacji
czytania (odbioru). Dla wszystkich takich operacji warto ta
jest mnoona przez liczb bajtw przewidzian do odebrania
z dysku lub cza komunikacyjnego.

DWORD

ReadTotalTimeoutConstant

Okrela sta (w milisekundach) uyt do obliczania czasu


przeterminowania operacji czytania. Dla wszystkich takich
operacji warto ta jest dodawana
do ReadTotalTimeoutMultiplier i do oczekiwanej liczby
nadchodzcych bajtw

DWORD

WriteTotalTimeoutMultiplier

Okrela mnonik (w milisekundach) uyty do obliczenia


cakowitego przedziau czasu (przeterminowanie) dla operacji
zapisywania (wysyania). Dla wszystkich takich operacji
warto ta jest mnoona przez liczb bajtw przewidzian
do wysania (zapisania). 0 oznacza, e nie ustalono czasu
przeterminowania dla operacji zapisu na dysku lub do cza
komunikacyjnego

DWORD

WriteTotalTimeoutConstant

Okrela sta (w milisekundach) uyt do obliczania


czasu przeterminowania operacji wysyania. Dla wszystkich
takich operacji warto ta jest dodawana
do WriteTotalTimeoutMultiplier oraz do oczekiwanej
liczby wysyanych bajtw. 0 oznacza, e nie ustalono
czasu przeterminowania dla operacji zapisu (wysyania)

You might also like