Praktyczne programowanie, R 1do4-04, Szablon dla tlumaczy


Spis treści

Od autora

Wprowadzenie

Rozdział 1 Definicja interfejsu

Rozdział 2 Nowoczesna transmisja asynchroniczna oraz standard RS 232C

RTS — CTS handshaking

Konwertery interfejsu RS 232C

Protokół XON-XOFF

Protokół ENQ-ACK

Rola oprogramowania a podstawowe funkcje interfejsu

Podsumowanie

Rozdział 3 Jak testować programy do transmisji szeregowej

Mirror w MS DOS

Terminal dla Windows 3.x oraz 9x

Podsumowanie

Rozdział 4 RS 232C w MS DOS

Borland C++

Borland Pascal

Podsumowanie

Ćwiczenia

Rozdział 5 Programowa obsługa interfejsu RS 232C w Windows

Wykorzystanie elementów Win32 API w C++Builder. Część I

Testowanie portu szeregowego

Nawiązanie połączenia

Segment inicjalizująco-konfiguracyjny

Segment wysyłający komunikaty

Segment odbierający komunikaty

Przykładowa aplikacja

Podsumowanie

Ćwiczenia

Wykorzystanie elementów Win32 API w C++Builder. Część II

Wysyłamy znak po znaku

Wysyłamy pliki

Wykorzystanie komponentu TTimer

Aplikacja nie lubi milczeć

Podsumowanie

Ćwiczenia

Wykorzystanie elementów Win32 API w Delphi. Część I

Testowanie portu szeregowego — inaczej

Nawiązanie połączenia

Segment wysyłający komunikaty

Segment odbierający komunikaty

Przykładowe aplikacje

Podsumowanie

Ćwiczenia

Wykorzystanie elementów Win32 API w Delphi. Część II

Wysyłamy znak po znaku

Wysyłamy pliki

Timer w Delphi

Podsumowanie

Ćwiczenia

Rozdział 6 Aplikacje wielowątkowe

Najważniejszy jest Użytkownik

Użytkownik steruje programem

Możliwość anulowania decyzji

Możliwość odbioru komunikatu nawet w trakcie wysyłania danych

Możliwość wysłania odrębnej informacji w trakcie transmisji pliku

Delphi

Konkurencja dla Timera

C++Builder

Zamiast Timera

Podsumowanie

Rozdział 7 Wykorzystanie niektórych narzędzi graficznych

Komponent TChart

Komponent TPaintBox

Komponent TImage

Samodzielne tworzenie mapy bitowej

Podsumowanie

Rozdział 8 Przykładowe aplikacje wykorzystywane w systemach pomiarowych

Kontroler temperatury

Aplikacja obsługująca kilka urządzeń

Podsumowanie

Uzupełnienie 1

Uzupełnienie 2

Uzupełnienie 3

Skorowidz

Podziękowania

Pragnę wyrazić podziękowanie firmie Lake Shore Cryotronics, Inc. za wyrażenie zgody na wykorzystanie do celów niniejszej książki znakomitych urządzeń pomiarowych.

Osobne podziękowanie pragnę złożyć na ręce Pana Zbigniewa Joachimaka, przedstawiciela Lake Shore w Polsce.

Dziękuję również firmie RADWAG za wyrażenie zgody na wykorzystanie doskonałej wagi na potrzeby tego opracowania.

Panu mgrowi inż. Witoldowi Jureczko pragnę wyrazić swą wdzięczność za udostępnienie zebranych przez niego materiałów, które okazały się bardzo pomocne w redagowaniu jednego z rozdziałów książki.

Autor

Od Autora

Wśród bardzo dostępnych publikacji na temat zastosowań współczesnych języków programowania brakuje przystępnego opisu wykorzystania ich w programach komunikacyjnych. Jest to szczególnie widoczne w odniesieniu do dwu obecnie najpopularniejszych środowisk programistycznych: Delphi oraz C++Buildera. Bardzo często słyszy się opinie, że można zbudować poprawnie działającą aplikację komunikacyjną bez konieczności odwoływania się do właściwości systemu operacyjnego. Czynność tę powinien za programistę automatycznie wykonywać BIOS lub sam system operacyjny. W DOS sytuacja ta jest zupełnie możliwa. Pewna znajomość Pascala czy C++ powinna w zupełności wystarczyć do zbudowania dobrze działającego programu komunikacyjnego. Stosowanie takiego podejścia w Windows jest nie do zaakceptowania. Niekiedy można przeczytać, że Delphi czy Builder same w sobie są już generatorami aplikacji, tzw. RAD (ang. Rapid Application Development). Być może jest to prawda, ale na pewno nie w odniesieniu do komunikacji komputerowej. Bardzo chciałbym, aby książka ta przekonała Czytelnika, że najlepsze efekty może dać tylko umiejętne połączenie właściwości sytemu operacyjnego z możliwościami oferowanymi przez nasz ulubiony kompilator.

Wprowadzenie

W niniejszej książce podjęto próbę przybliżenia Czytelnikom zasad programowej obsługi transmisji szeregowej. Jest tu wszystko, co niezbędne do zaprojektowania i stworzenia prawdziwych programów obsługujących łącze szeregowe. Chociaż tytuł może wskazywać na typowo sprzętowy — hardware'owy jej charakter opracowania, jednak książka ta jest przeznaczona nie tylko dla stosunkowo wąskiego kręgu osób zajmujących się sterowaniem i komunikacją komputerową. Postaramy się przedstawić tutaj nowe spojrzenie na pewien fragment czegoś, co klasycznie określane jest mianem szeroko rozumianego hardware'u. Zamierzeniem autora jest, aby niniejsze opracowanie w jak najmniejszym stopniu dotyczyło ogólnie znanych wątków łącza szeregowego. Na problem transmisji szeregowej spojrzymy z o wiele szerszej perspektywy, z perspektywy inżynierii oprogramowania. W ciągu ostatniej dekady w tej dziedzinie informatyki nastąpił olbrzymi postęp. Już nie musimy się martwić, z jakich części i w jaki sposób zbudować określony przyrząd. Nie jest też problemem wyprowadzanie sygnałów sterujących z jakiś egzotycznych układów pomiarowych — wszystkie takie przyrządy zostały już dawno poddane standaryzacji. Tak naprawdę ważne dzisiaj jest to, w jaki sposób oprogramować konkretne urządzenie dostępne na rynku. Postaramy się odpowiedzieć na to pytanie, poznając zasady pisania takich algorytmów zarówno w Pascalu jak i w C++ oraz Delphi i C++Builderze. Takie ujęcie tematu powinno spowodować, że w książce tej znajdą coś dla siebie zarówno osoby piszące w Pascalu (Delphi) jak i osoby zainteresowane C++ (Builderem). Problem programowej obsługi łącza szeregowego w MS DOS ujmiemy na tyle, na ile jest on niezbędny dla zrozumienia ogólnych zasad tworzenia tego typu algorytmów. Chociaż jest to niewątpliwie bardzo ciekawe i kształcące zajęcie, to jednak programy tego typu nie są już perspektywiczne. Tak naprawdę będzie nas interesować, jak tworzyć prawdziwe i dobrze działające aplikacje dla Windows. Jednak w tym przypadku będziemy zmuszeni zastosować prawdziwą technologię oprogramowania, niezbędnym okaże się poznanie interfejsu programisty, który dostarcza nam Windows. Książka ta jest nie tylko prezentacją typów danych, funkcji czy struktur oferowanych nam przez system operacyjny, ale przede wszystkim zawiera dużo wskazówek dla programistów w postaci szczegółowo przedstawionych przykładowych aplikacji. Chociaż szczególnie dokładnie omówimy standard RS 232C, to nie zabraknie też informacji, w jaki sposób z poziomu Delphi czy C++Buildera przejść do obsługi innych wersji łącza szeregowego. Przedstawione wiadomości na temat uniwersalnego API Windows Czytelnik będzie mógł wykorzystać przy rozwiązywaniu wielu innych problemów, niekoniecznie związanych z transmisją danych przez łącze szeregowe.

Nie brakuje oczywiście na rynku znakomitych programów, takich jak: TestPoint, LabView, LabWindows czy LabTech. Są to jednak relatywnie drogie produkty, których cena niejednokrotnie przewyższa wartość urządzenia, jakie należy oprogramować. Można oczywiście zamówić konkretną aplikację u producenta, ale to również wiąże się z dodatkowymi i niepotrzebnymi kosztami dla firmy, szkoły czy uczelni. Zresztą, umiejętność samodzielnego pisania programów o różnorodnym przeznaczeniu jest tą cechą, która wyróżnia programistę od innych osób zajmujących się szeroko rozumianą informatyką — informatyk nie zawsze bywa programistą. Jeżeli jednak Czytelnik z jakiś względów będzie musiał nauczyć się kiedyś programów wymienionych na początku niniejszego akapitu, wiadomości nabyte podczas czytania tej książki na pewno zaprocentują i pozwolą łatwiej zrozumieć zasadę ich działania.

Książka ta nie jest podręcznikiem w stylu „wstęp do programowania”, zakłada pewną znajomość podstaw Pascala i C++ oraz środowisk Delphi i Buildera. Z całą pewnością natomiast można ją traktować jako wstęp do szeroko rozumianej warstwy komunikacyjnej Windows 9x. Przygotowując niniejszy tekst, korzystałem z Borland Pascala v.7, C++ v. 3.1 w MS DOS oraz Delphi 5 i C++Buildera 5 dla Windows. Chociaż wymienione kompilatory mają szereg nowych i ciekawych właściwości, jednak ich dokładny opis nie był celem tej książki. Starałem się natomiast, aby zamieszczone algorytmy Czytelnik mógł bez większych problemów zaimplementować również w starszych wersjach Delphi czy Buildera.

Rozdział 1 Definicja interfejsu

W książce tej często będziemy posługiwać się pewnymi pojęciami, których zdefiniowanie pomoże uniknąć w przyszłości niejasności dotyczących użytych sformułowań. Na wstępie zdefiniujmy, co będziemy rozumieli poprzez urządzenia zewnętrzne (peryferyjne) komputera. Będą nimi np.: modemy, skanery, drukarki lub wszelkiego rodzaju przyrządy pomiarowe, dla których komputer jako całość pełnić będzie rolę kontrolera, sterując ich pracą. Dalej będziemy je nazywali po prostu urządzeniami.

Bardzo często w praktyce trzeba połączyć z komputerem jakiś konkretny przyrząd, np.: woltomierz, amperomierz, czujnik temperatury, zasilacz wysokiego napięcia, wagę elektroniczną, kasę fiskalną czy nawet inny komputer. Z reguły (nie dotyczy to do komputerów) wymagane przez to urządzenie poziomy prądów i napięć są różne od dostarczanych przez PC. Również szybkość przestrajania się i działania takich przyrządów bywa różna i nie zawsze jest zgodna z szybkością działania PC. Z tego względu niezbędnym jest stosowanie specjalnych układów, zapewniających odpowiednie wzajemne dopasowanie urządzeń i komputera, tzw. interfejsów. Być może niektórzy Czytelnicy znają definicję interfejsu, a ściślej systemu interfejsu, w wersji określonej polską normą PN-83/T-0653. Z jej treści możemy wywnioskować że system interfejsu jest to zbiór niezależnych od urządzeń elementów mechanicznych, elektrycznych i funkcjonalnych, koniecznych w procesie wymiany informacji pomiędzy urządzeniami. Na potrzeby niniejszej książki definicję tę, stworzoną w początkach ery komputeryzacji w Polsce, nieco rozszerzymy i uogólnimy. W tłumaczeniu z angielskiego interface oznacza obszar wzajemnego oddziaływania (niekiedy wyraz ten tłumaczy się dosłownie jako sprzęg). Dla nas pierwsze tłumaczenie będzie intuicyjnie jasne i zadowalające. Przez interfejs, a dokładniej system interfejsu będziemy rozumieli pewien fizyczny układ, organizujący komunikację komputera (urządzenia) z innym urządzeniem zewnętrznym. Integralną częścią tego układu musi być system procedur i funkcji, programowo realizujących komunikację, czyli specjalistyczne oprogramowanie.

Wymiana danych pomiędzy komputerem a urządzeniami (lub pomiędzy dwoma urządzeniami) realizowana jest dzięki wcześniejszemu ustaleniu protokołu transmisji, czyli specyficznego zbioru reguł, procedur lub różnego rodzaju konwencji dotyczących formatu i czasu trwania przesyłania danych.

Przesyłane dane mogą być buforowane lub nie buforowane. Bufor (ang. buffer) definiowany jest jako obszar pamięci użytej do skompensowania różnic w szybkości przesyłania danych lub w czasie występowania znaków sterujących (lub innych zdarzeń) podczas transmisji pomiędzy urządzeniami.

Wymiana danych realizowana jest przez tzw. kanał transmisyjny, którego właściwości zależeć będą od jego fizycznej formy. Wszelkie dane mogą być przesyłane za pośrednictwem różnego rodzaju przewodów, kabli światłowodowych czy fal radiowych.

Przedstawione definicje są zgodne z normami przyjętymi w 2000 roku przez: Intel, Microsoft, Compaq, Lucent Technologies, Philips, NEC oraz Hawlett Packard. Definicje te zostały opublikowane w Universal Serial Bus Specification Revision 2.0.

Wraz z rozwojem szeroko rozumianej techniki komputerowej powstało wiele standardów interfejsów, zarówno analogowych, cyfrowych szeregowych, cyfrowych równoległych, jak i cyfrowych szeregowo-równoległych. Standaryzacji poddano wszystkie rozwiązania konstrukcyjne w zakresie budowy gniazd przyłączeniowych, rozmieszczenia w nich sygnałów elektrycznych o określonych parametrach. Zunifikowano metody transmisji danych oraz ich protokoły.

W przypadku interfejsów analogowych mamy do czynienia z transmisją, gdzie informacja przekazywana jest w postaci zmian amplitudy prądu lub napięcia. Jej przebieg czasowy może być określany czasem trwania impulsu (transmisja z podziałem czasowym) lub częstotliwością sygnału (transmisja z podziałem częstotliwościowym). Pierwszy z wymienionych sposobów umożliwia przesyłanie informacji w ściśle określonych sekwencjach czasowych. Wymaga to jednak stosowania skomplikowanej synchronizacji, zarówno od strony nadającego jak i odbierającego sygnał. W drugim przypadku niezbędne jest używanie specjalnych modulatorów i demodulatorów sygnału. Ze względu na znaczny stopień komplikacji protokołu transmisji interfejsy te wychodzą już powoli z użycia.

Interfejsy cyfrowe wykorzystują kodowane sygnały binarne do przesyłu danych. W przypadku interfejsów szeregowych dane przesyłane są szeregowo bit po bicie. Do najważniejszych standardów, realizujących transmisję szeregową należy zaliczyć: RS 232C (w Europie zwany V.24) i jego rozwinięcia: RS 422, RS 423, RS 449, RS 485, interfejs IEEE 1394 (Firewire), stosowany głównie w urządzeniach przetwarzających dźwięk i obraz oraz najnowszy produkt USB (ang. Universal Serial Bus). Standard RS w swej podstawowej wersji wymaga jedynie trzech przewodów do realizacji transmisji — dwóch sygnałowych plus przewód masy. W USB wszystkie dane przesyłane są kolejno za pośrednictwem czterożyłowego kabla. Cyfrowe interfejsy równoległe transmitują poszczególne bajty danych równolegle. Wiąże się to z koniecznością stosowania dosyć rozbudowanego okablowania takich urządzeń. Do najważniejszych tego typu standardów należy zaliczyć ten stosowany powszechnie w drukarkach Centronics pracujący z napięciami o poziomach TTL. W roku 1992 opracowano 8-bitowy standard portu do transmisji równoległej EPP (ang. Enhanced Parallel Port), pozwalający realizować dwukierunkową transmisję z szybkością do 2 MB/s przy długości kabla 2 m. Pewną odmianą EPP jest opracowany w tym samym roku interfejs ECP (ang. Extended Capabilities Port). W porównaniu do swojego poprzednika protokół ten przewiduje możliwość zmian prędkości transmisji w zależności od aktualnych potrzeb. Spośród bardziej zaawansowanych interfejsów równoległych należy wymienić wprowadzony w latach 80. VME oraz najnowszy VXI (VMEbus Extension for Instrumentation). Bez wątpienia najlepszym z nich zarówno pod względem szybkości przesyłu danych jak i parametrów elektrycznych, okazał się ten ostatni. Jednak jest on bardzo kosztowny i obecnie bywa stosowany jedynie w wysoko specjalizowanych układach kontrolno-pomiarowych. Wśród cyfrowych interfejsów szeregowo-równoległych największą popularność zdobył IEEE 488 (międzynarodowy standard znany też jako IEC 626). Jest szeroko wykorzystywany w przemyśle i laboratoriach naukowych. W tym przypadku transmisja odbywa się bitowo-równolegle oraz bajt po bajcie szeregowo.

Do niedawna interfejsów szeregowych używano w prostszych układach pomiarowych i komunikacyjnych, traktowane były jako uzupełnienie opcjonalnie stosowanych IEEE 488. Bardzo szybki rozwój inteligentnych-programowalnych urządzeń spowodował, że znowu dostrzeżono dobre strony RS. Zawsze podkreślano, że wadą urządzeń opartych na transmisji szeregowej jest jej mała prędkość. Jednak zarzut ten stracił już mocno na znaczeniu wraz z pojawieniem się nowej generacji pewnej rodziny układów scalonych, tzw. UART (ang. Universal Asynchronous Receiver - Transmitter), będących integralną częścią płyt głównych komputerów i przetwarzających strumień danych z postaci szeregowej na równoległą i odwrotnie. --> Możesz samodzielnie przekonać się, jaką prędkość transmisji szeregowej jest w wstanie zapewnić Twój PC. W tym celu należy uruchomić Panel sterowania, wybrać opcję System, potem Menedżer urządzeń, następnie Porty COM & LPT, dalej np. Port komunikacyjny COM2, potem Ustawienia portu i sprawdzić, jaką prędkość w bitach na sekundę możesz uzyskać. W moim PC mam niezłą płytę główną i mogę uzyskać prawie milion bitów na sekundę! Jak na popularny sprzęt uważam, że nieźle. Oczywiście muszę mieć jeszcze urządzenie zewnętrzne, mogące pracować z taką prędkością, ale to już inna historia[Author:kdh] . Niezaprzeczalną zaletą interfejsów szeregowych RS jest ich niski koszt, dzięki czemu urządzenia w nie zaopatrzone stały się ogólnie dostępne. Postęp cywilizacyjny, jaki dokonał się w ostatnim dwudziestoleciu, pokazał oprócz wielu innych i taką ciekawą prawidłowość, że nie może stać się standardem żadne urządzenie, jeżeli nie będzie dostępne przeciętnemu podatnikowi. Trzeba zdawać sobie sprawę, iż dzisiaj to stwierdzenie odnosi się raczej do zamożniejszych społeczeństw, ale i u nas też zaczyna już powoli obowiązywać. Nie tak dawno miałem możliwość uczestniczyć w projektowaniu pewnego dużego sytemu, zbierającego dane właśnie z wykorzystaniem transmisji szeregowej za pomocą łączy RS 232C.

Na pewno wielkie nadzieje należy wiązać z USB. Twórcy tego złącza: Intel, Microsoft, Compaq, Hawlett Packard, Lucent, Philips, IBM i NEC postawili sobie za cel skonstruowanie interfejsu o znakomitych parametrach eksploatacyjnych, umożliwiającego komputerowi swobodną komunikację z wieloma najprzeróżniejszymi urządzeniami. Można je swobodnie dołączać do PC bez potrzeby ustawiania adresów portów, kanałów DMA czy poziomów przerwań — system operacyjny natychmiast powinien je rozpoznać. W standardzie tym urządzenia zewnętrzne przyłączane są do komputera poprzez tzw. koncentratory (ang. Hub). Są już dostępne na rynku, pracujące w tym standardzie klawiatury, monitory (które mogą również pełnić rolę koncentratorów, o ile posiadają kilka gniazd USB), myszy, czytniki, nagrywarki CD i DVD, dyski twarde, różnego rodzaju skanery, drukarki i głośniki. Pojawiają się również — na razie nieliczne — prototypy przyrządów pomiarowych opartych na USB. Miałem okazję uczestniczyć w prezentacji jednego z takich urządzeń. Muszę jednak zauważyć, i nie jest to tylko moje odczucie, że pełne wdrożenie USB do szeroko rozumianych systemów pomiarowo-komunikacyjnych będzie wymagało jeszcze bardzo wiele wysiłku, szczególnie ze strony projektantów konkretnych przyrządów. Niektórzy z nich zdają się zapominać, że przeznaczenie np. wagi cyfrowej czy zasilacza wysokiego napięcia jest inne od przeznaczenia odtwarzacza DVD. Nie wszystkie urządzenia działające na zasadzie „włącz i zapomnij” są efektywne. Poważnym mankamentem tego nowego standardu jest wymóg ciągłej aktualizacji sterowników komunikacyjnych oraz rozróżnialność urządzeń ze względu na pobór mocy — maksymalny prąd zasilający jedno urządzenie nie powinien obecnie przekraczać 500 mA. Nie istnieje też w chwili obecnej kompletna, zunifikowana specyfikacja złącza USB. Niestety, producenci płyt głównych jeszcze nie doszli pod tym względem do całkowitego porozumienia. Jak na razie różne typy złączy należy stosować do różnych urządzeń. Zauważmy jednak, że obserwowane ciągłe udoskonalanie standardów transmisji szeregowej, ciągłe zwiększanie szybkości i niezawodności działania RS 232, który jeszcze długo pozostanie używanym standardem oraz prace nad USB wskazują, że przyszłość może należeć do tego typu transmisji.

Rozdział 2 Nowoczesna transmisja asynchroniczna oraz standard RS 232C

Podstawową wersję RS 232 (ang. Recommended Standard) wprowadzono w 1962 roku w USA. Początkowo standard ten miał służyć jedynie do obsługi modemów. Od tego czasu był poddawany kilkakrotnej aktualizacji celem bardziej optymalnego dostosowania na potrzeby szeregowej transmisji danych. Największą popularność zdobyła wersja RS 232C wprowadzona w 1969 roku, zaś oficjalnie do rangi standardu została podniesiona w roku 1986. RS 232C jest powszechnie stosowanym i akceptowanym standardem dla szeregowej wymiany danych cyfrowych pomiędzy urządzeniem DTE (ang. Data Terminal Equipment), obecnie utożsamianym z komputerem, a DCE (ang. Data Communication Equipment) — urządzeniem zewnętrznym (w oryginale modemem). W sposób jednoznaczny definiuje on parametry elektryczne, mechaniczne i logiczne łącza szeregowego. Oficjalna jego nazwa brzmi: Interface Between Data Terminal and Data Circuit Termination Equipment Employing Serial Binary Data Interchange. RS 232C stosowany bywa wszędzie tam, gdzie mniej istotną rolę odgrywa przepustowość łącza, natomiast ważna jest niezawodność i prostota obsługi protokołu komunikacyjnego.

Komputery osobiste wyposażone są w łącza szeregowe przystosowane do transmisji asynchronicznej, tzn. komputer i urządzenie muszą pracować z jednakową, wcześniej uzgodnioną prędkością oraz taką samą strukturą znaków. Transmisja taka może być realizowana w trybie bez potwierdzenia odbioru lub z potwierdzeniem odbioru. Drugi sposób zapewnia nam możliwość kontrolowania poprawności wysyłanych-odbieranych danych. Dane przesyłane są w postaci tzw. ramki (ang. frame), która jest najmniejszą porcją możliwej do przesłania informacji. Bity przesyłane są kolejno. Do kodowania znaków stosuje się najczęściej kod ASCII (American Standard Code of Information Interchange). Początkowo stosowano 128 znaków zapamiętywanych na 7 bitach. W tym przypadku pierwszy bit danych — bit nr 0 poprzedzony był znacznikiem początku ramki — bitem startu. Ósmy bit (bit nr 7) służył do kontroli parzystości. Następnie przesyłany był znacznik końca ramki — jeden lub dwa bity stopu. Wraz z pojawieniem się strony kodowej ASCII o 256 znakach, pierwsze 32 znaki z przedziału 0-31 oraz znak 127 zaczęto rezerwować na potrzeby transmisji danych lub jako znaki sterujące dla urządzeń zewnętrznych. Obecnie zbiór ASCII jest podzestawem Unicode zawierającego 65536 znaków, który używany jest do reprezentowania znaków większości języków świata. W tabeli 2.1 przedstawiono używane obecnie w transmisji szeregowej znaki sterujące. W przyszłości będziemy z nich często korzystać.

Tabela 2.1. Pierwsze 32 znaki strony kodowej ASCII

Liczba Liczba Znak Nazwa angielska Znaczenie

dzieś. heksad.

0 00 NUL Null Znak pusty

1 01 ☺ SOH Start of Heading Początek nagłówka zawierającego

adres lub polecenie

2 02 ☻ STX Start of Text Początek tekstu

3 03 ♥ ETX End of Text Koniec tekstu

4 04 ♦ EOT End of Transmission Koniec transmisji

5 05 ♣ ENQ Enquiry Zapytanie

6 06 ♠ ACK Acknowledge Potwierdzenie

7 07 ● BEL Bell Dzwonek

8 08 ◘ BS Backspace Usuwanie poprzedniego znaku

9 09 ○ HT Horizontal Tabulation Pozioma tabulacja

10 0A ◙ LF Line Feed Przejście kursora do

następnego wiersza

11 0B ♂ VT Vertical Tabulation Pionowa tabulacja

12 0C ♀ FF Form Feed, page eject Przesuw strony

13 0D ♪ CR Carriage Return Powrót kursora do początkowej

pozycji w tym samym wierszu

14 0E ♫ SO Shift Out Następne znaki nie będą

alternate character set interpretowane jako znaki ASCII

15 0F ☼ SI Shift In, resume Powrót do domyślnej strony

default character set kodowej ACSII

16 10 ► DLE Data Link Escape Zmiana znaczenia następnego

znaku, który będzie interpretowany

jako kombinacja bitów sterujących

danym urządzeniem

17 11 ◄ DC1 Device Control 1 XON kontrola przepływu

danych

18 12 ↕ DC2 Device Control 2 Sterowanie urządzeniem

19 13 ‼ DC3 Device Control 3 XOFF kontrola przepływu

danych

20 14 ¶ DC4 Device Control 4 Sterowanie urządzeniem

21 15 § NAK Negative Acknowledge Meldunek błędu

22 16 ▬ SYN Synchronous Idle Znak synchronizacyjny

23 17 ↕_ ETB End of Transmission Block Koniec transmisji bloku

danych

24 18 ↑ CAN Cancel Anulowanie danych

25 19 ↓ EM End of Medium Koniec zapisu danych

26 1A → SUB Substitue Character Zastąpienie znaku, znak

wstawiony w odbiorniku w

miejsce błędnie odebranego,

np. z błędem parzystości

27 1B ← ESC Escape Rezygnacja bez potwierdzenia

28 1C ∟ FS File Separator Separator plików

29 1D ↔ GS Group Separator Separator grup

30 1E ▲ RS Record Separator Separator zapisu

31 1F ▼ US Unit Separator Separator jednostek

...

127 7F ⌂ DEL Delete Unieważnienie znaku

Obecnie ramka może zawierać od 5 do 8 bitów danych (jednak większość spotykanych urządzeń posługuje się słowem 7 lub 8 bitowym) poprzedzonych bitem startu oraz zakończonych bitem parzystości i jednym lub więcej bitami stopu. Przed rozpoczęciem transmisji bit startu przyjmuje zawsze wartość 0, zaznaczając wyraźnie moment początkowy. Odwrotność czasu trwania transmisji jednego bitu określa szybkość przesyłu w bitach na sekundę. Korzystając z funkcji BIOS-u, możemy uzyskać transmisję w granicach od 110 do 9600 b/s. Przekonamy się, że w Windows może być ona znacznie, znaczne większa. Powodem tych rozbieżności są pewne różnice w sposobie inicjalizacji procedur obsługujących łącze szeregowe stosowane w BIOS i Windows. Możliwa do uzyskania szybkość transmisji zależy przede wszystkim od typu układu scalonego UART, w jaki zaopatrzona jest nasza płyta główna. Niezależnie od tego, że przetwarza on dane z postaci szeregowej na równoległą i odwrotnie, to obsługuje również sygnały sterujące interfejsu RS 232C. Czytelników zainteresowanych budową i możliwością programowania takich układów odsyłam do znakomitej książki Piotra Metzgera Anatomia PC, wyd. Helion (1996).

Bit kontroli parzystości przesyłany za ostatnim bitem danych jest jedną z metod monitorowania poprawności transmitowanych danych. Z reguły przyjmuje dwie wartości: 0 lub 1. Ilości jedynek w polu danych może być uzupełniana do liczby parzystej (evenparity) lub nieparzystej (oddparity). Bit parzystości może być stale równy 1 (markparity), stale równy 0 (space) lub może być nie ustawiony (noparity). Bity stopu zawsze oznaczają koniec ramki. Może wówczas nastąpić transmisja kolejnej „paczki” danych.

RS 232C jest interfejsem cyfrowym, zatem jego poziomom logicznym (0-1) należy przypisać określone przedziały napięć zarówno ujemnych jak i dodatnich, które są z reguły nieco wyższe od stosowanych w komputerze. Pozwala to w dużym stopniu uniezależnić sygnał na wejściu interfejsu od przypadkowych zakłóceń. Dla sygnałów sterujących i sygnałów współpracy logicznej 1 odpowiada przedział od +3 do +25V, tzw. stan aktywny, wysoki, włączony lub „ON”. Logicznemu 0 odpowiada przedział od -3 do -25 V, jest to stan nieaktywny, niski, wyłączony lub „OFF”. Dla linii przesyłania danych logicznej 1 (tzw. „Mark”) opowiada przedział napięć od -3 do -25V, zaś logicznemu zeru (tzw. „Space”) przedział od +3V do +25V. Widzimy więc, że sygnały sterowania i współpracy są aktywne w stanie wysokim, zaś sygnały danych w stanie niskim (Mark). Na rysunku 2.1. pokazano przebieg czasowy przykładowej ramki, symbolizującej wysłanie jednej litery ”a” reprezentowanej na ośmiu bitach — dziesiętnie 97, binarnie 01100001. Bit parzystości został ustawiony jako markparity, zastosowano też dwa bity stopu.

Rysunek 2.1. Czasowy przebieg ramki na linii przesyłania danych przy wysłaniu litery „a”

0x01 graphic

Łącze w trakcie ciszy utrzymywane jest stanie logicznej 1. Transmisja rozpoczyna się od bitu startu, który zawsze przyjmuje wartość logicznego 0. Po nim następuje transmisja ośmiu bitów reprezentujących znak. Póżniej jest bit parzystości, potem dwa bity stopu zamykające ramkę. Bitowi stopu odpowiada stan niski. Po nim łącze wraca do stanu ciszy. Jeden lub dwa bity stopu stosowane są po to, by odbiornik i nadajnik mogły dokonać wzajemnej synchronizacji przed transmisją kolejnej ramki danych. W praktyce układy nadajników zasilane są napięciem ±12V, dając amplitudę sygnałów ±8V. W tej sytuacji bitom 0 oraz 1 transmitowanego bajta odpowiadają napięcia odpowiednio +12V oraz -12V.

Standardową linię interfejsu RS 232C stanowi 25-żyłowy przewód, przy czym większość z tych linii wykorzystuje się dla potrzeb transmisji synchronicznej. W standardzie IBM wykorzystuje się jedynie 9 sygnałów, które są wystarczające do zrealizowania transmisji asynchronicznej. W komputerach PC używano początkowo dwóch rodzajów złączy szeregowych: 9- oraz 25-końcówkowych typu DB-9 i odpowiednio DB-25. W komputerach zaopatrzonych w nowsze płyty główne spotyka się jedynie złącza DB-9. Podobnie wersji DB-25 nie spotyka się już w nowoczesnych urządzeniach pomiarowych. Na rysunku 2.2 przedstawiono wygląd obydwu rodzajów tych złączy.

Rysunek 2.2. Końcówki DB-9 i DB-25. Ciemne kółka oznaczają nieaktywne wyprowadzenia

0x01 graphic
0x01 graphic

Wykaz sygnałów wykorzystywanych obecnie w interfejsie RS 232C z uwzględnieniem przedstawionych typów złączy podano niżej. Linia 23 DSRD (Data Signal Rate Detector) w złączu DB-25 nie została uwzględniona w poniższym zestawieniu, gdyż obecnie praktycznie nie jest wykorzystywana.

Tabela 2.2. Wykaz sygnałów wykorzystywanych w RS 232C

DB-25

DB-9

Opis sygnału

Kierunek sygnału

1

PG Protective Ground — masa ochronna

2

3

TxD Transmitted Data — dane wysyłane

Wyjście DTE (PC)

3

2

RxD Received Data — dane odbierane

Wejście DTE

4

7

RTS Request To Send — żądanie nadawania. PC zgłasza do urządzenia gotowość odbioru danych

Wyjście DTE

5

8

CTS Clear To Send — gotowość do wysyłania danych. Urządzenie potwierdza przyjęcie sygnału RTS

Wejście DTE

6

6

DSR Data Set Ready — odbiornik gotowy do odbioru danych wysłanych przez komputer

Wejście DTE

7

5

SG Signal Ground — masa sygnałowa

8

1

(RLSD) DCD Data Carier Detect — odbiór fali nośnej. Linia wykorzystywana głównie przez modemy

Wejście DTE

20

4

DTR Data Terminal Ready — gotowość komputera do odbierania-wysyłania danych.

Wyjście DTE

22

9

RI Ring Indicator — wskaźnik wywołania. Linia wykorzystywana głównie przez modemy

Wejście DTE

Linie TxD oraz RxD są przeznaczone do obustronnego przesyłania danych. Nazywamy je liniami danych. Pozostałe zaś są liniami sterującymi lub kontrolnymi (oczywiście za wyjątkiem linii masy). Ogólnie sygnały przekazywane łączem RS 232C można podzielić na trzy grupy:

  1. sygnały danych: RxD, TxD,

  2. sygnały sterujące urządzeniem zewnętrznym: RTS, DTR,

  3. sygnały odbierane od urządzenia (kontrolne): CTS, DSR, RI, RLSD (DCD).

RTS — CTS handshaking

Jak już wspomniałem, zamierzeniem moim jest, aby książka ta jak najmniej dotyczyła wątków historycznych łącza szeregowego. Pełny opis funkcji linii magistrali interfejsu RS 232C Czytelnik może znaleźć w bogatej literaturze przedmiotu. Nie będziemy się również szczegółowo zajmować poszczególnymi trybami transmisji szeregowej. Dla nas tak naprawdę istotnym będzie tryb półdupleksowy z potwierdzeniem odbioru (transmisja dwukierunkowa naprzemienna), tzw. handshaking. W tym trybie komputer i urządzenie mogą naprzemiennie nadawać i odbierać, wykorzystując jeden logiczny kanał danych. Jest to metoda pytanie — odpowiedź. Należy przyznać, że sposób ten jest najprostszym i najskuteczniejszym środkiem wyegzekwowania interesującej nas informacji. Aby zrealizować taką prawdziwą konwersację pomiędzy komputerem a urządzeniem wystarczy wykorzystać dwie linie danych RxD i TxD oraz dwie linie sterujące RTS i CTS z magistrali RS 232C. Sygnał RTS musi być stale aktywny lub przełączany do tego stanu przed rozpoczęciem nadawania. Podobnie nadawanie znaków może nastąpić tylko wówczas, gdy sygnał CTS będzie włączony. Taki sposób sprzętowej kontroli transmisji nazywany jest Hardware flow control lub RTS — CTS handshaking lub jako Out-of-Band flow control — sygnały sterujące są generowane i sprawdzane niezależnie od sygnałów danych. Dostępny jest on w większości współczesnych systemów komunikacyjnych. Ideę takiej konwersacji przedstawimy na przykładzie połączenia pomiędzy dwoma złączami DB-9.

Rysunek 2.3. Przykład połączenia poprzez złącza DB-9 komputera z urządzeniem pracującym w pełnym trybie półdupleksowym

0x01 graphic

Linia wejściowa TxD (3) komputera połączona jest z linią wejściową RxD (2) urządzenia. Linie te służą obustronnej wymianie danych. Za pomocą sygnałów RTS (7) — CTS (8) dokonywany jest wybór aktualnego kierunku transmisji. Po załączeniu łącza szeregowego linia DTR (4) zostaje włączona. W odpowiedzi urządzenie aktywuje linię DSR (6), sygnalizując gotowość do współpracy. Komputer, chcąc przesłać dane do urządzenia, aktywuje swój sygnał RTS (7), czekając na potwierdzenie od urządzenia na linii CTS (8). Jeżeli została ona uaktywniona, komputer wysyła dane linią TxD. Po zakończeniu transmisji linia RTS jest wyłączana (OFF), na co urządzenie odpowiada również przełączeniem linii CTS do stanu nieaktywnego (OFF). Ogólnie rzecz biorąc dane przesyłane do komputera linią RxD będą odbierane wówczas, gdy linie DSR i RLSD (DCD) (1) będą włączone. Patrząc na rysunek 2.3 ktoś mógłby zauważyć, że jest to typowy układ połączeń stosowany przy współpracy pomiędzy dwoma urządzeniami DTE. Jak to się ma do klasycznego połączenia DTE — DCE ? Należy przyznać, że z owym klasycznym sposobem łączenia ma to niewiele wspólnego. Przyczyna jest prosta — nowoczesne urządzenia pomiarowe zaopatrzone są już w programowalne jednostki arytmetyczno-logiczne i tak na dobrą sprawę są już same w sobie komputerami. Innych produktów nie spotyka się obecnie zbyt często na rynku. Jeżeli w instrukcji obsługi kupionego urządzenia nie znajdziesz schematu podobnego do tego z rys. 2.3 oznaczać to będzie, że sprzedawca zrobił kolejny dobry interes, pozbywając się magazynowych zapasów.

Rysunek 2.4 przedstawia pełną sekwencję stanów linii interfejsu RS 232C. Należy jednak zwrócić uwagę, że w większości spotykanych obecnie przypadków DSR i DTR pozostają zwarte, gdyż nowoczesne urządzenia pomiarowe w ogóle nie posługują się linią DSR, zaś linia DCD wykorzystywana jest przeważnie przez modemy. Jeżeli jednak chcielibyśmy z niej zrobić użytek, należy wejście DCD komputera połączyć z linią wyjściową DTR urządzenia. Analogicznie jak na rysunku 2.3 można połączyć ze sobą dwa komputery. W tym przypadku układ połączeń można jeszcze uprościć, zwierając linie RTS — CTS oraz DSR — DTR.

Rysunek 2.4. Pełna sekwencja stanów linii interfejsu RS 232C

0x01 graphic

W nowoczesnych przyrządach pomiarowych coraz częściej spotyka się złącze modułowe RJ-11, charakteryzujące się niewielkimi rozmiarami i prostotą montażu przewodów we wtyczkach. Bardzo często wykorzystuje się tu jedynie dwa sygnały dla potrzeb transmisji asynchronicznej. Na rysunku 2.5 pokazano wygląd takiego złącza, w tabeli zaś specyfikację najczęściej wykorzystywanych przez nie sygnałów. Należy jednak zauważyć, że niekiedy występują tu pewne rozbieżności. Niektórzy producenci nieco odmiennie definiują linie sygnałowe w RJ-11, ale zawsze jest to wyraźnie zaznaczone w instrukcji obsługi przyrządu.

Rysunek 2.5. Złącze modułowe RJ-11

0x01 graphic

Tabela 2.3. Specyfikacja linii sygnałowych złącza RJ-11 wg LakeShore

RJ-11

Opis sygnału

1

RxD Received Data — dane odbierane

2

RxD Received Data — dane odbierane

3

Gnd Ground — masa sygnałowa

4

Gnd Ground — masa sygnałowa

5

TxD Transmitted Data — dane wysyłane

6

TxD Transmitted Data — dane wysyłane

Rysunek 2. 6. Przykład nowoczesnego układu połączeń złączy DB-9 oraz RJ-11 stosowanego przez LakeShore

0x01 graphic

Rysunek 2. 7. Przykład nowoczesnego układu połączeń złączy DB-25 oraz RJ-11 stosowanego przez LakeShore

0x01 graphic

Nieco inną specyfikację sygnałów w złączu RJ-11 podają ComputOne oraz SPECIALIX.

Tabela 2.4. Specyfikacja linii sygnałowych złącza RJ-11 wg niektórych producentów

RJ-11

ComputOne

SPECIALIX

1

DTR

RLSD (DCD)

2

TxD

RxD

3

Gnd

DTR / RTS

4

RLSD (DCD)

Gnd

5

RxD

TxD

6

RTS

CTS

Wielu producentów stosuje również złącza modułowe RJ-45. Poniżej zostały przedstawione niektóre stosowane rozwiązania.

Rysunek 2.8. Złącze modułowe RJ-45

0x01 graphic

Tabela 2.5. Specyfikacja linii sygnałowych złącza RJ-45 wg niektórych producentów

RJ-45

Comput-One

Chase

DIGIBOARD

MICRO-

ANEX1

MICRO-

ANEX2

EQUINOX

IBM

1

DCD

DSR

RTS

RTS

CTS2

2

RTS

RTS

RTS

DTR

DTR

DTR

DTR2

3

RxD

PG1

PG1

TxD

TxD

RxD

TxD2

4

DCD

TxD

TxD

DCD

Gnd

Gnd2

5

Gnd

RxD

RxD

RxD

RxD

TxD

DCD2

6

TxD

Gnd

Gnd

Gnd

Gnd

Gnd

RxD2

7

DTR

CTS

CTS

DSR

DSR

RTS2

8

CTS

DTR

DTR

CTS

CTS

CTS

1Linia PG zwykle połączona jest z obudową. Jako potencjał odniesienia używana jest linia Gnd.

2Identycznie jak w ComputOne, odwrócono tylko numerację styków.

Na rysunkach 2.6 i 2.7 pokazano przykłady możliwego układu połączeń pomiędzy komputerem zaopatrzonym w złącze DB-9 lub DB-25 a nowoczesnym urządzeniem wyprowadzającym sygnały poprzez RJ-11. Tutaj również widać, że linia wyjściowa TxD komputera połączona jest z odpowiednią linią wejściową RxD urządzenia. Pozostałe linie po stronie komputera pozostają zwarte lub niewykorzystane. Nowoczesne urządzenia nie wykorzystują zbyt wielu linii sterujących. Linie DTR (4), CTS (8), DSR (6) i DCD (1) pozostają zwarte. Linia RTS (7) — żądanie nadawania — nie jest wykorzystywana. Jak więc będzie wybierany kierunek transmisji? Taki sposób podłączenia, jaki przedstawiono na przykładzie rysunków 2.6 i 2.7 natychmiast sugeruje, że mamy do czynienia z inteligentnym urządzeniem „znaczącym” koniec wysyłanych przez siebie danych parą znaków CR LF, tzw. „terminatorem”. Program obsługujący taki przyrząd, napotykając przy odbiorze danych znaki CR LF, będzie już wiedział, że właśnie otrzymał kompletną informację i należy przejść do ewentualnego nadawania. Jeżeli tylko potrafimy w ten sam lub inny chytry sposób odpowiedzieć miernikowi, otrzymamy bezbłędną obustronną transmisję. Taka metoda programowej kontroli transmisji określana jest mianem Software flow control. Nieustanne śledzenie poziomów wielu sygnałów pojawiających się na złączu RS przechodzi powoli do historii. Jedyną trudnością do przezwyciężenia będzie wówczas problem zbudowania odpowiedniej aplikacji.

Konwertery interfejsu RS 232C

Istniej wiele rodzajów konwerterów sygnałów interfejsu RS 232C na inne standardy RS. Do najczęściej stosowanych należą układy służące do łączenia urządzeń wyposażonych w interfejs RS 232C z urządzeniami wyposażonymi w interfejs RS 485 lub RS 422. Transmisja szeregowa w standardach 485 lub 422 jest dużo szybsza i bardziej odporna na zakłócenia, zapewnia ponadto większy zasięg transmitowanych sygnałów.

W standardzie RS 485 szeregowa transmisja danych cyfrowych odbywa się przez dwuprzewodową symetryczną linię transmisyjną, do której można dołączyć nawet 32 nadajniki i odbiorniki. Stosując odpowiednie powielacze sygnału, liczbę takich urządzeń można znacznie zwiększyć. Interfejs ten umożliwia realizację wielopunktowej transmisji w trybie półdupleksowym. Standard elektryczny RS 422 nie różni się w istocie od RS 485. Różnica polega na możliwości dołączenia do jednej pary przewodów jednego nadajnika nawet do 10 odbiorników. W układzie RS 422 możliwa jest transmisja w trybie pełnego dupleksu, czyli w modzie jednoczesnego nadawania i odbioru danych.

Konwertery interfejsu RS 232C konstruowane są w postaci niewielkich pudełek, zawierających z jednej strony złącze DB-25 lub DB-9 do podłączenia do łącza RS 232C w komputerze, zaś z drugiej strony inne złącze, np. PHOENIX do podłączenia linii i napięcia zasilającego. Układy te zapewniając izolację galwaniczną łączonych urządzeń i linii transmisyjnej, z reguły zasilane są oddzielnym zasilaczem stabilizowanym. Stosując tego rodzaju konwertery sygnałów możliwe jest uzyskanie szybkości transmisji w granicach 2,5 Mb/s przy maksymalnej długości linii około 1200 m, co wydaje się rozwiązaniem w pełni zadawalającym nawet w warunkach przemysłowych. Zestaw dwóch konwerterów może być z powodzeniem stosowany do realizacji połączenia pomiędzy dwoma urządzeniami zaopatrzonymi w interfejs RS 232C.

Protokół XON-XOFF

Wiele urządzeń wymaga stosowania programowej kontroli przepływu danych z wykorzystaniem tzw. protokołu XON-XOFF. Przykładem praktycznego wykorzystania niektórych znaków pokazanych w tabeli 2.1 jest właśnie ten protokół, czasami nazywany DC1-DC3 lub ^Q-^S. Jeżeli dane przychodzą zbyt szybko do odbiornika i urządzenie odbierające nie może ich tak szybko pobierać z bufora wejściowego, program sterujący może wysłać znak XOFF (DC3 lub dziesiętnie 19 albo Control — S). Urządzenie nadające zatrzymuje dalszą transmisję (jeżeli oczywiście wie, co to jest XOFF), dopóki od strony odbiornika nie nadejdzie znak XON (DC1 lub dziesiętnie 17 albo Control — Q). Jeżeli jednak XOFF zostanie wysłany zbyt późno, może nastąpić przepełnienie bufora wejściowego. Podobnie opóźnienie wysłania XON z reguły powoduje zablokowanie portu komunikacyjnego. We współczesnych, inteligentnych urządzeniach o wysokim stopniu wzajemnej synchronizacji protokół ten przewiduje wysłanie XOFF, jeżeli bufor wejściowy jest wypełniony powyżej ¾ deklarowanego rozmiaru. Program sterujący urządzeniem wysyła znak XON, jeżeli bufor jest wypełniony mniej niż w ½. W tym przypadku transmisja musi przebiegać w pełnym trybie dupleksowym. Dane przekazywane są jednocześnie w obu kierunkach niezależnie od siebie, po oddzielnych liniach transmisyjnych (patrz tab. 2.3). Wykorzystujemy tu dwie pary linii RxD i TxD (RTS i CTS nie mają znaczenia), linia DTR może (ale nie musi) być wykorzystywana do włączania i wyłączania urządzenia. Windows podtrzymuje ten protokół, o czym Czytelnik może się przekonać zaglądając do Panelu sterowania i Właściwości portów komunikacyjnych oraz czytając dalej tę książkę.

Protokół ENQ-ACK

Jest to jedna z obecnie rzadziej stosowanych metod kontroli przepływu danych w urządzeniach pomiarowych. Urządzenie transmitujące wysyła regularnie zapytanie ENQ (patrz tab. 2.1) po każdej, wcześniej ustalonej porcji transmitowanych danych. Kiedy odbierający jest gotowy do przyjęcia kolejnego bloku informacji, wysyła do nadającego potwierdzenie ACK, sygnalizując tym samym gotowość przyjęcia następnej porcji danych. W metodzie tej z reguły nie kontroluje się stopnia wypełnienie bufora pamięci. Jeżeli nadający po wysłaniu kolejnej porcji informacji nie otrzyma potwierdzenia jej odbioru, zaczyna wysyłać przez pewien, ściśle ustalony czas znak, np. LF dając, odbiornikowi możliwość ewentualnego przetworzenia wcześniej otrzymanych danych. Jeżeli po tym czasie nie nadejdzie potwierdzenie ACK, nadajnik wstrzymuje dalszą transmisję do czasu jego otrzymania.

Rola oprogramowania a podstawowe funkcje interfejsu

Aby zrealizować prawidłową wymianę informacji pomiędzy komputerem i urządzeniami zewnętrznymi, dla których pełnić on będzie rolę kontrolera, należy w pierwszej kolejności określić funkcje szeroko rozumianego interfejsu w tym systemie. W dobrze zaprojektowanym układzie interfejs powinien spełniać następujące wymagania:

  1. Zapewnienie właściwego sposobu inicjalizacji połączenia.

Aby uzyskać dostęp do urządzenia przyłączonego do portu komunikacyjnego, port ten należy fizycznie uaktywnić — otworzyć do transmisji. W standardowym PC mamy z reguły do dyspozycji tylko dwa szeregowe porty komunikacyjne. Często zachodzi jednak konieczność obsłużenia wielu urządzeń. Stosuje się wówczas specjalne karty lub konwertery, umożliwiające uzyskanie dostępu do większej ich liczby. Przyrządy podłączone do portów komunikacyjnych muszą być rozróżnialne, jeżeli chcemy nimi naprawdę sterować. Będą takimi, jeżeli aplikacja będzie w stanie rozróżnić poszczególne porty szeregowe i odpowiednio do nich kierować komunikaty oraz odbierać dane. Właściwa inicjalizacja portu polega na nadaniu mu unikalnego identyfikatora, którym można swobodnie operować w trakcie działania programu.

  1. Zapewnienie właściwej synchronizacji transmitowanych danych pomiędzy komputerem i urządzeniami zewnętrznymi oraz udostępnienie metod natychmiastowej i automatycznej korekty różnego rodzaju błędów, pojawiających się w czasie transmisji.

Większość standardowych interfejsów ma wbudowane funkcje synchronizacji, które w pewnym stopniu mogą minimalizować pojawiające się opóźnienia w kanale transmisyjnym, jedną z głównych przyczyn powstawania błędów. Rolą oprogramowania będzie ich umiejętne wyzwalanie. Aplikacja zarządzająca transmisją musi być skonstruowana w sposób zapewniający bezbłędne funkcjonowanie systemu pomiarowego lub komunikacyjnego. Właściwa reakcja na pojawiające się w czasie transmisji błędy oraz możliwość ich ewentualnej korekcji są zawsze istotnymi elementami programu komunikacyjnego.

  1. Zapewnienie właściwej kontroli transmisji oraz wyboru jej kierunku.

Kontrolowanie aktualnego kierunku transmisji może być realizowane sprzętowo lub programowo. Na pewno bardziej przydaną jest umiejętność programowej kontroli przepływu danych. Użytkownik danego systemu wie najlepiej, jakie dane i w jakim czasie chce otrzymać od urządzenia. Aplikacja obsługująca dany interfejs musi być tak zaprojektowana, aby możliwym był „płynny” wybór kierunku nadawanie-odbiór. W tym miejscu należy zwrócić szczególną uwagę na to, by nie tracić danych w momencie zmieniania kierunku transmisji. Stosując metodę buforowania danych, program musi być wyczulony na możliwość odbierania swoich własnych komunikatów przy nagłej zamianie ról z nadajnika na odbiornik.

  1. Udostępnienie możliwości zatrzymania transmisji w dowolnym momencie, bez ryzyka utraty danych.

Tę właściwość same interfejsy posiadają tylko w ograniczonym stopniu. Program kontrolujący transmisję jest naprawdę funkcjonalny wówczas, gdy zawiera opcje umożliwiające czasowe wstrzymanie operacji odbioru-nadawania bez ryzyka utraty informacji. Jest to szczególnie ważne w przypadku aplikacji wielowątkowych lub generujących własne przerwania systemowe. Właściwość tę musi uwzględniać oprogramowanie sterujące jednocześnie portem szeregowym oraz różnego rodzaju kartami przetwornikowymi zaopatrzonymi w przetworniki analogowo-cyfrowe. W obecnych komputerach procesor programuje zaledwie kilka rejestrów sterujących urządzenia wysyłając rozkaz wykonania pewnej operacji (np. odebranie znaku przez port szeregowy). Istnieją przynajmniej dwa sposoby poinformowania procesora o tym, że dana operacja właśnie się zakończyła. Po pierwsze można zastosować tzw. polling, gdzie procesor wysyła regularne zapytania do urządzenia. Częstotliwość tych zapytań jest kontrolowana przez aktualnie działającą aplikację. Jednak w praktyce bardzo trudno jest określić optymalną częstotliwość takich odpytywania i z tego względu sposób ten jest bardzo niewygodny. Drugi sposób polega na tym, że samo urządzenie zgłasza wykonanie danego zadania. W stosownym momencie procesor przerywa wykonywanie aktualnego programu, pamiętając stan swoich rejestrów uaktywnia funkcje reagujące na zgłoszenie danego urządzenia. Mówimy wówczas, że nastąpiło przerwanie sprzętowe interrupt pochodzące od urządzenia. Ten sposób sterowania przepływem danych w PC jest stosowany wszędzie tam, gdzie mamy do czynienia z intensywnym i nieregularnym przepływem danych pomiędzy urządzeniami a pamięcią operacyjną. W praktyce mamy możliwości programowej kontroli aktualnie występujących przerwań. Jednak w rzeczywistości jest to zadanie uciążliwe i lepiej jest wykorzystać zalety programowania obiektowo-zdarzeniowego.

  1. Zapewnienie możliwości odpowiedniego odbierania, przechowywania i wysyłania danych.

Standardowe interfejsy mają możliwość buforowania danych. Jest to zaleta, którą doceniamy wtedy, gdy nie jesteśmy w stanie w sposób ciągły odbierać przychodzących danych lub nie możemy ich wysłać w ściśle określonym momencie. Oprogramowanie sterujące przepływem danych pełni w takich przypadkach rolę wspomagającą. Aplikacja powinna umieć odczytać aktualny stan bufora wejściowego i zdecydować o pobraniu z niego interesujących nas danych. Odbierając informacje w sposób ciągły, należy nieustannie kontrolować bufor danych, nawet w sensie fizycznej ingerencji. Dobrze działający program nie może dopuścić do jego przepełnienia, gdyż grozi to całkowitą utratą informacji. Rolą oprogramowania będzie również odpowiednie czyszczenie bufora danych w trakcie transmisji. Jest to zawsze punkt newralgiczny systemu komunikacyjnego.

W celu ujednolicenia i uproszczenia sposobów projektowania oprogramowania wykorzystywanego w różnych systemach pomiarowych stworzono standard opisujący zestaw uniwersalnych instrukcji programujących urządzenia pomiarowe, tzw. język SCPI (ang. Standard Commands for Programmable Instruments). Zdefiniowane są tam wszystkie ujednolicone przez producentów urządzeń pomiarowych instrukcje (rozkazy), umożliwiające zaprogramowanie nowoczesnego przyrządu w zależności od wykonywanego przezeń zadania. Programiści dostali więc do dyspozycji uniwersalny język zapytań i odpowiedzi, należy tylko umiejętnie go wykorzystać. Niestety, to niewątpliwe udogodnienie nie zwalnia nas od konieczności samodzielnego stworzenia (lub kupna) aplikacji, potrafiącej wykorzystać zalety SCPI. Czytelników pragnących poszerzyć swoje wiadomości na ten temat odsyłam do książki Wojciecha Mielczarka Urządzenia pomiarowe i systemy kompatybilne ze standardem SCPI, wyd. Helion (1999).

Podsumowanie

W rozdziale tym zostały zaprezentowane podstawowe wiadomości dotyczące szeregowej transmisji asynchronicznej oraz standardu RS 232C. Tematy te zostały potraktowane w sposób zwięzły, ale zupełnie wystarczający do zrozumienia zagadnień związanych z programową kontrolą łączy szeregowych. W książce tej, wraz z wprowadzaniem konkretnych algorytmów mogących obsługiwać komunikację szeregową, omówione zagadnienia będą stopniowo uzupełniane. Bardziej szczegółowe informacje dotyczące standardu RS 323C Czytelnik może znaleźć w bogatej literaturze przedmiotu oraz na licznych stronach www. Przedstawione też zostały rzadko spotykane przykłady nowoczesnych sposobów połączeń, coraz częściej stosowane w szeregowej transmisji danych. Zapoznaliśmy się też z najważniejszymi stosowanymi obecnie protokołami kontroli transmisji danych. Dowiedzieliśmy się również, jakimi cechami powinny charakteryzować się aplikacje, obsługujące transmisję szeregową.

Rozdział 3 Jak testować programy do transmisji szeregowej ?

Celem tego rozdziału jest przedstawienie ogólnodostępnych programów, za pomocą których można testować łącze szeregowe. Są to bardzo wygodne w użyciu narzędzia, pozwalające bardzo szybko sprawdzić, czy napisany właśnie program nie jest przypadkiem zgodny jedynie sam z sobą. Osoby pragnące zapoznać się ze sposobami programowej realizacji transmisji szeregowej, a nie posiadające specjalistycznych urządzeń, z powodzeniem mogą traktować drugi komputer (niekoniecznie wysokiej klasy) jako swojego rodzaju tester. Niektóre z programów przedstawionych w dalszej części książki były testowane za pomocą 386 SX.

Mirror w MS DOS

Mirror jest typowym programem umożliwiającym testowanie różnego rodzaju łączy komunikacyjnych, w tym standardu RS 232C. Program ten z reguły jest dostępny wszędzie tam, gdzie w użyciu były (lub jeszcze są) interfejsy CAMAC. Jeżeli Czytelnik spotka komputer przyłączony do CAMAC-a, Mirror najczęściej będzie znajdował się w katalogu \ASM. Po jego uruchomieniu i przeczytaniu informacji o producencie należy nacisnąć dowolny klawisz, by przejść do wyboru opcji programu, tak jak pokazuje to rysunek 3.1.

Rysunek 3.1.

Dostępne opcje Mirrora

0x01 graphic

Ponieważ interesuje nas tylko port szeregowy, należy więc w dolnym pasku komend wpisać 5 (lub inną liczbę odpowiadającą opcji COMM) i potwierdzić klawiszem Enter. Po uzyskaniu informacji, że dostępne łącza zostały zdiagnozowane, należy nacisnąć Home. Po tej operacji zobaczymy główne menu programu — rysunek 3.2.

Rysunek 3.2.

Główne menu programu

0x01 graphic

Komendy wpisujemy w dolnej linii po zapytaniu Command? W celu opuszczenia programu wystarczy wpisać qu (quit).

Obszar Communications parameters służy do wyboru ustawień parametrów transmisji danego portu szeregowego. Numer łącza wybierzemy wpisując PO Enter:

Rysunek 3.3.

Sposób posługiwania się menu

0x01 graphic

Następnie wybieramy konkretny numer portu, np. 2 i znowu potwierdzamy. W sposób analogiczny dokonamy ustawień wszystkich interesujących nas parametrów transmisji. Powiedzmy, że chcemy ustalić jej prędkość — wystarczy po Command? wpisać SP Enter i dokonać odpowiedniego wyboru.

Jeżeli zostały ustalone wszystkie niezbędne parametry komunikacyjne, czyli prędkość (SPeed), długość słowa danych (DAta), numer portu (POrt), parzystość (PArity) oraz ilość bitów stopu (STop) wystarczy nacisnąć Home, by przejść do okna, w którym możemy już wpisywać z klawiatury informacje przeznaczone do wysłania. Powrotu do poprzedniej planszy programu dokonujemy naciskając Home. Widzimy, że obsługa tego programu nie powinna sprawić nikomu trudności. Udostępnia on jeszcze szereg opcji, z którymi można się samodzielnie zapoznać. Nas jednak nie będą one interesowały, gdyż nie będziemy z nich w trakcie tej książki korzystać.

Terminal dla Windows 3.x oraz 9x

Aplikacja ta służy programowej realizacji bezpośredniego połączenia dwóch komputerów lub komputera i modemu poprzez interfejs RS 232C. Jej wygląd oraz zasada działania nie różnią się w obu wersjach Windows. W wersji Windows 3.x Terminal.exe znajduje się w Akcesoriach pod charakterystyczną ikoną przedstawiającą komputer i telefon. Program ten działa równie dobrze w środowisku 32-bitowym. Po jego uruchomieniu wybieramy opcję Ustawienia — patrz rysunek 3.4. Mamy tu szereg ciekawych możliwości, jednak dla nas najbardziej interesującą będzie Transmisja.

Rysunek 3.4.

Główne menu programu

0x01 graphic

Po rozwinięciu tej planszy można wybrać sposób przesyłania tekstu (standardowy, znak po znaku lub co wiersz). Potem należy w pierwszej kolejności określić numer portu komunikacyjnego. Po jego wyborze wszystkie pozostałe opcje staną się dostępne, tak jak pokazuje to rysunek 3.5.

Rysunek 3.5.

Wybór parametrów transmisji szeregowej

0x01 graphic

Naciskając OK właściwie jesteśmy już w stanie nadawać z klawiatury lub odbierać informacje z sąsiedniego komputera (na którym w przyszłości będzie uruchomiona samodzielnie napisana przez nas aplikacja).

Rozwijając menu Przesyłanie bez problemu określimy dany plik tekstowy, który możemy przesłać lub odebrać. Trzeba przyznać, że poważną wadą tego programu jest ograniczenie się do możliwości operowania tylko na plikach tekstowych lub binarnych. Nas będą głównie interesowały tzw. pliki beztypowe, powszechnie używane obecnie przy sterowaniu różnego rodzaju urządzeniami zewnętrznymi. Kolejną wadą omawianego programu jest również to, że zupełnie nie nadaje się do sterowania czymkolwiek. Co najwyżej, korzystając z niego jesteśmy w stanie stwierdzić, czy z danym przyrządem można w ogóle nawiązać jakąkolwiek komunikację. Jednak mimo tych niedogodności program znakomicie będzie nadawał się do testowania naszych algorytmów.

Zważywszy na fakt, że już niedługo będziemy musieli zająć się również programową obsługą plików, przypomnijmy w tym miejscu pewne istotne informacje na ich temat. Ogólnie rozróżniamy dwa główne rodzaje plików: tekstowe oraz binarne. Plik tekstowy stanowi pewien zbiór, składający się z ciągu znaków ASCII. Poszczególne informacje w nim zawarte pogrupowane są w kolejnych wierszach, z których każdy zakończony jest parą znaków CR LF. W tego rodzaju plikach dane zapisywane są sekwencyjnie, co ma oczywiście swoje dobre i złe strony. Główną ich wadą jest utrudnienie wyszukiwania określonego fragmentu danych zawartych w takim pliku. Niemniej jednak z reguły dąży się do tego, by pracować z danymi uporządkowanymi sekwencyjnie — wówczas nie musimy wykonywać częstych przeszukiwań tekstu. Pliki binarne, zawierając informacje binarne zrozumiałe jedynie dla określonych programów, nie są przeznaczone do bezpośredniego oglądania. W większości wypadków pliki takie są po prostu skompilowanymi wykonywalnymi programami lub ich bibliotekami. Pewną odmianę plików binarnych stanowią tzw. pliki zdefiniowane (ang. typed files). Struktura informacji zawartych w takiego rodzaju zbiorach jest najczęściej typu rekordowego o zmiennej lub stałej długości, zawierającego różnego rodzaju pola.

Terminal umożliwia przesyłanie plików binarnych, przy czym posługuje się dwiema metodami:

  1. XModem/CRC, gdzie wykorzystuje się algorytmy liczenia sum kontrolnych CRC (ang. Cyclic Redundancy Code) dla bloków danych. W odróżnieniu od tradycyjnej sumy danych, posługującej się sumowaniem wszystkich bajtów lub słów w bloku danych, algorytm CRC może wykorzystywać różne odmiany tzw. wielomianów generacyjnych. Rozmiar sumy kontrolnej zależy od stopnia używanego wielomianu.

  2. Kermit jest specjalnym protokołem transmisji danych, opracowanym w 1981 roku na Uniwersytecie Columbia w Nowym Jorku. Jego nazwa pochodzi od imienia bardzo znanej i komunikatywnej postaci Kermita z równie znanego serialu Muppet Show. Protokół ten umożliwia swobodny transfer zarówno danych w postaci tekstowej jak i binarnej. Znalazł on zastosowanie między innymi w usługach oferowanych przez TCP-IP, X.25 oraz LAN.

Opis wyżej wymienionych protokołów znacznie przekracza rozmiary tej książki, dlatego ograniczymy się jedynie do zwięzłych informacji na ich temat. Czytelnicy, którzy interesowali się już tymi zagadnieniami bez większego problemu będą mogli zaadaptować je w programach przedstawionych w dalszej części niniejszego opracowania.

Przedmiotem naszego zainteresowania będą głównie tzw. pliki beztypowe lub amorficzne (ang. untyped files). Tego rodzaju zbiory umożliwiają swobodny dostęp do danych, bez potrzeby wnikania w ich budowę. Elementy plików beztypowych należy traktować jako ciągi pojedynczych bajtów o strukturze, która dla użytkownika jest nieistotna. Jeszcze inną ich zaletą jest fakt, że pozostają niesprzeczne, czyli kompatybilne z innymi zbiorami danych i doskonale nadają się do programowania wszelkich operacji wejścia-wyjścia. Dane w postaci tego rodzaju plików są obecnie powszechnie wykorzystywane w programach sterujących urządzeniami pomiarowymi.

Podsumowanie

Celem niniejszego rozdziału było dokonanie krótkiego przeglądu dostępnych programów, za pomocą których można testować poprawność transmisji szeregowej zarówno w MS DOS jak i w Windows. Szczególnie przydatny dla naszych celów okaże się Terminal, który równie dobrze działa w środowisku 16-, jak i 32-bitowym. Był on standardowo dostarczany wraz z Windows 3.x, dlatego z dotarciem to tego produktu Czytelnik nie powinien mieć większych trudności. Przed rozpoczęciem pracy z łączem szeregowym do dobrego zwyczaju należy wstępne przetestowanie jakości połączenia i to niezależnie od tego, czy posługujemy się kablem oryginalnym, czy też własnej konstrukcji. Do tego rodzaju testu najlepiej użyć jakiegoś standardowego programu. Unikniemy w ten sposób możliwości wystąpienia szeregu przykrych niespodzianek przy uruchamianiu samodzielnie napisanych programów.

Rozdział 4 RS 232C w MS DOS

Czytając ten rozdział, zapoznamy się z niektórymi sposobami realizacji transmisji szeregowej w środowisku MS DOS. Wbrew pozorom jest to bardzo ciekawe i kształcące zajęcie. Poznając zasady tworzenia takich algorytmów w DOS i Windows można się przekonać, jak wielki postęp został dokonany w tej dziedzinie programowania. Wiadomości tu przedstawione pomogą zrozumieć, że idea programowania w Windows nie powstała od razu. Powstała dzięki odpowiedniemu ulepszaniu i adaptacji najlepszych elementów środowisk programistycznych DOS-a.

Borland C++

Zaprezentujemy dwie bardzo użyteczne funkcje zdefiniowane w standardzie ANSI C, umożliwiające bardzo szybkie skonfigurowanie w trybie do transmisji asynchronicznej wybranego łącza szeregowego. Ich prototypy znajdują się w pliku bios.h. Będą nimi:

int bioscom(int cmd, char abyte, int port);

oraz

unsigned _bios_serialcom(int cmd, char abyte, int port);

W obu przypadkach parametr port określa dany port komunikacyjny, dla 0 = COM1, dla 1 = COM2, lub ogólnie (n-1) = COMn. Należy pamiętać, że nazwy COMn znajdują się na liście nazw zastrzeżonych, nie można ich zatem nadawać żadnemu plikowi. cmd określa rodzaj wykonywanej przez port szeregowy operacji. Poniżej przedstawiono wartości, jakie można przypisać parametrowi cmd.

bioscom()

_bios_serialcom()

znaczenie

wartość cmd

stała symboliczna

0

_COM_INIT

inicjalizacja i otwarcie portu

1

_COM_SEND

ustawienie łącza w trybie do wysyłania

2

_COM_RECEIVE

ustawienie łącza w trybie do odbioru

3

_COM_STATUS

pobranie aktualnego statusu portu

Sposób ustalenia wszystkich cech charakterystycznych ramki danych określa parametr abyte:

bioscom() _bios_serialcom() znaczenie

rozmiar pola bitów danych

0x02 _COM_CHR7 7 bitów danych

0x03 _COM_CHR8 8 bitów danych

bity stopu

0x00 _COM_STOP1 1 bit stopu

0x04 _COM_STOP2 2 bity stopu

bity parzystości

0x00 _COM_NOPARITY No parity (brak parzystości)

0x08 _COM_ODDPARITY Odd parity (nieparzysta)

0x18 _COM_EVENPARITY Even parity (parzysta)

prędkość transmisji

0x00 _COM_110 110 bitów/sek.

0x20 _COM_150 150

0x40 _COM_300 300

0x60 _COM_600 600

0x80 _COM_1200 1200

0xA0 _COM_2400 2400

0xC0 _COM_4800 4800

0xE0 _COM_9600 9600

Przykładowo, jeżeli chcemy ustalić: prędkość transmisji na 9600 b/s; sprawdzanie parzystości polegające na tym, że liczba jedynek w polu danych będzie uzupełniana do liczby nieparzystej; jeden bit stopu oraz długość słowa danych jako 8 bitów, to argumentowi abyte należy przypisać:

abyte = (0xE0 | 0x08 | 0x00 | 0x03)

w funkcji bioscom() lub

abyte = (_COM_9600 | _COM_ODDPARITY | _COM_STOP1 | _COM_CHR8)

jeżeli zechcemy użyć _bios_serialcom().

Z zapisów tych wynika, że przypisanie konkretnej wartości reprezentującej strukturę ramki danych odbywa się poprzez wykonanie operacji maskowania z zastosowaniem operatora bitowej alternatywy |. Powyższe ustawienie parametrów ramki równie dobrze można odczytać jako:

1 1 1 0 0 0 0 0 (0xE0) dziesiętnie 224

OR

0 0 0 0 1 0 0 0 (0x08) 8

OR

0 0 0 0 0 0 0 0 (0x00) 0

OR

0 0 0 0 0 0 1 1 (0x03) 3

__________________

abyte = 1 1 1 0 1 0 1 1 (0xEB) 235

Zarówno bioscom(), jak i _bios_serialcom() zwracają wartość 16-bitową. Bardziej znaczący bajt tej liczby zawiera bity opisujące aktualny stan transmisji.

Bardziej znaczący bajt:

bit 7 (Time out)

1 = błąd przekroczenia czasu nawiązania połączenia, tzw. błąd --> przeterminowania czasu [Author:RG]

operacji

bit 6 (Transmit shift register empty)

1 = rejestr przesuwny nadajnika jest pusty

bit 5 (Transmit holding register empty)

1 = rejestr wyjściowy nadajnika jest pusty

bit 4 (Break detect)

1 = połączenie zostało przerwane

bit 3 (Framing error)

1 = błąd protokołu ramki

bit 2 (Parity error)

1 = błąd parzystości

bit 1 (Overrun error)

1 = błąd przepełnienia bufora odbiornika

bit 0 (Data ready) — gotowe dane

1 = w buforze odbiornika znajduje się bajt danych

0 = bufor odbiornika jest pusty.

W przypadku gdy parametr cmd został ustawiony jako: _COM_INIT — (0), _COM_SEND — (1) lub _COM_STATUS — (3), poszczególne bity mniej znaczącego bajta reprezentują sobą informacje obrazujące stan linii sterujących łącza RS 232C:

Mniej znaczący bajt:

bit 0 (Change in clear to send)

1 = sygnał na linii CTS zmienił poziom

bit 1 (Change in data set ready)

1 = sygnał na linii DSR zmienił poziom

bit 2 (Trailing edge ring detector)

1 = sygnał na linii RI zmienił poziom

bit 3 (Change in receive line signal detector)

1 = sygnał na linii RLSD zmienił poziom

bit 4 (Clear to send)

1 = sygnał na linii CTS jest aktywny

0 = nieaktywny

bit 5 (Data set ready)

1 = sygnał na linii DSR jest aktywny

0 = nieaktywny

bit 6 (Ring indicator)

1 = sygnał na linii RI jest aktywny

0 = nieaktywny

bit 7 (Receive line signal detect)

1 = sygnał na linii RLSD jest aktywny

0 = nieaktywny.

Jeżeli w miejsce cmd wpisalibyśmy _COM_RECEIVE - (2), wówczas mniej znaczący bajt wartości zwracanej przez bioscom() oraz _bios_serialcom() będzie zawierać informację (bajt) odebraną przez port szeregowy.

Zobaczmy, jak w praktyce można wykorzystać funkcję bioscom(). Przedstawiony na wydruku 4.1 algorytm realizuje naprzemienną transmisję szeregową, emulując prosty terminal. Jego kod znajduje się na załączonym CD w katalogu \KODY\CPP\dos_rs_1.cpp. Przy jego projektowaniu w dużym stopniu wykorzystałem właściwości preprocesora. Działanie programu można testować, łącząc się z innym komputerem, na którym uruchomiony jest ten sam program lub inny, opisany w poprzednim rozdziale. Ekran podzielony jest na dwie części, aby ułatwić nam śledzenie zarówno danych odbieranych jak i wysyłanych. Wiadomości wpisujemy z klawiatury.

Rysunek 4.1. Plansza działającego programu dos_rs_1.cpp

0x01 graphic

Wydruk 4.1. Kod źródłowy programu napisanego w C++ realizującego naprzemienną transmisję szeregową

//-----------dos_rs_1.cpp------------------------------------

#include <iostream.h>

#include <conio.h>

#include <stdio.h>

#include <bios.h>

#include <string.h>

#define WINDOW_IN() window (1,3,80,12) // okno do odbioru

#define WINDOW_OUT() window (1,14,80,25) // okno do nadawania

// Prędkość transmisji

#define SPEED_110 0x00

#define SPEED_150 0x20

#define SPEED_300 0x40

#define SPEED_600 0x60

#define SPEED_1200 0x80

#define SPEED_2400 0xA0

#define SPEED_4800 0xC0

#define SPEED_9600 0xE0

// Parzystość

#define NOPARITY 0x00

#define ODDPARITY 0x08

#define EVENPARITY 0x18

// Bity stopu

#define STOP_1 0x00

#define STOP_2 0x04

// Długość słowa danych

#define ByteSize_7 0x02

#define ByteSize_8 0x03

// Numer portu

#define COM_1 0

#define COM_2 1

#define rs_status() bioscom(STATUS, 0, COM)

#define rs_init() bioscom(INIT, SPEED | PARITY | STOP | \

ByteSize, COM)

#define rs_send(output) bioscom(SEND, output, COM)

#define rs_receive() bioscom(RECEIVE, 0, COM)

int STATUS = 3;

int INIT = 0;

int SEND = 1;

int RECEIVE = 2;

// parametry transmisji

int COM = COM_2, SPEED =SPEED_9600, PARITY = ODDPARITY, STOP = STOP_1,

ByteSize = ByteSize_7;

main()

{

int i, j, m, k, n; // zmienne sterujące pozycją kursora

int in, out; // dane odbierane-nadawane

window(1,1,80,24);

clrscr();

cout<<" [Esc] - koniec programu";

WINDOW_IN();

cout<< " -- Nadawanie -- ";

WINDOW_OUT();

cout<< " -- Odbiór -- ";

rs_init(); // inicjalizacja portu

j = 2; m = 2; k = 1; n = 2;

while (i != 0)

{

rs_status();

if (kbhit())

{

WINDOW_IN ();

gotoxy(j, m);

out = getch();

j ++;

if (out == '\x0D')

{

m ++;

j = 1;

cprintf("\n");

}

gotoxy(j, m);

if (out == '\x08')

j = j - 2;

putch(out);

if (j == 80)

{

j = 1;

m ++;

cprintf("\n");

};

if (m >= 12)

m = 12;

if (out == '\x1B')

i = 0;

else

rs_send(out); // wysyłanie znaków

}// koniec if(kbhit())

if (rs_status() & 0x100)

if((in = rs_receive() & 0x7F) != 0) // odbiór

{

WINDOW_OUT ();

if (in == '\x08') k = k - 1;

if (k == 80)

{

k = 1;

n ++;

cprintf("\n");

}

if (n >= 12)

n = 12;

if (in == '\x0D')

{

n ++;

k = 1;

cprintf("\n");

}

if(char(in) > '\x1F')

{

k ++;

gotoxy(k, n);

putch(in);

}

}

}// koniec while

window(1,1,80,25);

clrscr();

return 0;

}

Najważniejszym fragmentem przedstawionego programu są dwie, na pozór niewinnie wyglądające instrukcje warunkowe:

if (rs_status() & 0x100)

if((in = rs_receive() & 0x7F) != 0)

{...

// odbierz znak

}

Rozpatrzmy najpierw pierwszą z nich. Użyliśmy operatora &, aby sprawdzić rezultat iloczynu bitowego makrowywołania rs_status() z wartością 256 (heksadecymalnie 0x100). Ktoś mógłby zapytać, w jakim celu? Otóż zastanówmy się, co reprezentuje sobą wartość 256. Aby ją otrzymać: wykonamy proste działanie: do 255 (binarnie 255 = 1 1 1 1 1 1 1 1 ) dodamy 1, w wyniku otrzymując 256, czyli 1 0 0 0 0 0 0 0 0. Dla naszego PC oznaczać to będzie, że jeżeli powyższy warunek ma być spełniony, to w ośmiobitowym rejestrze przechowującym mniej znaczący bajt musi pojawić się 0 0 0 0 0 0 0 0. Jedynka natomiast zostanie przeniesiona (carry) do dziewiątego, czyli zerowego bitu bardziej znaczącego bajta. Będzie to sygnałem, że w rejestrze buforowym odbiornika pojawił się jakiś bajt. W jednej linijce kodu wykonaliśmy więc dwie bardzo ważne operacje: wstępnie sprawdziliśmy, czy jest wyzerowany bajt, który w przyszłości będzie zawierał odebrany znak oraz wysłaliśmy do rejestru stanu transmisji sygnał o możliwości odbioru danych. Makrowywołanie rs_receive() jest niczym innym jak swego rodzaju wywołaniem funkcji bioscom() z cmd o wartości 2. Jeżeli rezultat iloczynu bitowego rs_receive() z maską 0x7F (0x7F dziesiętnie: 127 = 0 1 1 1 1 1 1 1 ) będzie różny od zera oznacza to, że mniej znaczący bajt wartości zwracanej przez bioscom() zawiera odebrany przez port szeregowy znak. Teraz wystarczy go już tylko wyświetlić na ekranie. Należy zwrócić uwagę, że używając warunku:

if((in = rs_receive() & 0xFF) != 0)

też otrzymamy prawidłową transmisję.

PRZYPOMNIJMY

Instrukcja w postaci:

#define identyfikator_1(identyfikator, ...) ciąg znaków

jest makrodefinicją. Użycie w programie pierwszego identyfikatora:

identyfikator_1(identyfikator,...)

jest makrowywołaniem. Makrowywołanie zastępowane jest ciągiem znaków podanym w definicji identyfikatora_1.

Oczywiście w analogiczny sposób ktoś mógłby zrealizować również transmisję plików, na przykład według przedstawionego schematu:

{

...

int out;

FILE *pstream;

pstream = fopen("plik.txt" , "r");

rs_init();

...

while((out = fgetc(pstream)) != EOF)

rs_send(out);

fclose(pstream);

...

}

Borland Pascal

Zapoznamy się teraz ze sposobem realizacji transmisji szeregowej właściwym dla Pascala. Niestety, w środowisku MS DOS kompilator ten nie jest tak przyjazy jak C++. Będziemy musieli trochę uwagi poświęcić przerwaniom i rejestrom. Opiszemy trzy podstawowe funkcje przerwania 14h BIOS-u, za pomocą których można w prosty sposób zrealizować obsługę wybranego portu szeregowego. Będziemy musieli odwołać się też do rejestrów. Spośród szesnastu rejestrów, które mogą być wykorzystywane przez programistów, dla nas najważniejsze będą dwa pierwsze rejestry ogólnego przeznaczenia, którymi posługują się interesujące nas funkcje BIOS-u. Czytelnikom, którzy nie interesowali się dotąd takimi zagadnieniami wyjaśnijmy, że rejestry ogólnego przeznaczenia procesora Pentium są 32-bitowe. Będą to: EAX, EDX, ECX, EBX, EBP, ESI, EDI oraz ESP. Nazwy ich pochodzą od nazw rejestrów procesora 8086: AX, BX itd. Rejestry te przechowują argumenty operacji (tzw. operandy) dla operacji arytmetycznych i logicznych. Mogą też zawierać operandy dla obliczania adresów.

Poniżej została przedstawiona budowa interesujących nas rejestrów oraz opisano funkcje przerwania 14h, realizujące programową obsługę portu szeregowego.

Dwa pierwsze rejestry ogólnego przeznaczenia:

16-bitowy AX

31

23

15 AH

7 AL 0

32-bitowy EAX

16-bitowy DX

31

23

15 DH

7 DL 0

32-bitowy EDX

Rejestr DX jest wykorzystywany w różnego rodzaju operacjach mnożenia i dzielenia, jest również jedynym, w którym można podać adres portu w operacjach wejścia-wyjścia. AX (tzw. akumulator) służy przede wszystkim do wykonywania przesłań oraz operacji arytmetyczno-logicznych. Ze względu na to, że operacje wykonywane na rejestrze AX są optymalizowane, wykonanie ich przebiega znacznie szybciej niż na pozostałych rejestrach.

Funkcja 00h

Funkcja 00h przerwania 14h umożliwia odpowiednie skonfigurowanie i inicjalizację wybranego portu szeregowego ustalając jego parametry transmisji. Dane wejściowe tej funkcji przedstawiają się następująco:

AH — 00h,

DX — przechowuje numer portu: 0 = COM1, 1 = COM2,

AL — określa parametry transmisji. Format zawartych tam danych można opisać jako:

bit 7

bit 6

bit 5

bit 4

bit 3

bit 2

bit 1

bit 0

prędkość transmisji kontrola parzystości bit stopu liczba bitów danych

110 b/s brak 1 bit 7 bitów

0

0

0

0

0

0

1

0

150 b/s parzysta 2 bity 8 bitów

0

0

1

0

1

1

1

1

300 b/s nieparzysta

0

1

0

1

1

600 b/s

0

1

1

1200 b/s

1

0

0

2400 b/s

1

0

1

4800 b/s

1

1

0

9600 b/s

1

1

1

Funkcja ta w rejestrze AH zwraca status łącza, zaś w AL status linii modemu.

Funkcja 01h

Wysyła znak do wybranego portu szeregowego. Danymi wejściowymi są:

AH — 01h,

DX — numer łącza,

AL — wysyłany znak.

W bajcie przechowywanym w rejestrze AH zwraca ona status łącza.

Funkcja 02h

Służy do odbioru znaku z określonego portu szeregowego. Danymi wejściowymi są:

AH — 02h,

DX — numer łącza szeregowego.

W AL zwracany jest znak odebrany w wyniku transmisji, zaś w AH zwracany jest status portu.

Funkcja 03h

Określa status danego portu szeregowego. Danymi wejściowymi są:

AH — 03h,

DX — numer łącza.

W rejestrze AX zwracany jest status portu: bardziej znaczący bajt (rejestr AH) zwraca bajt statusu łącza, mniej znaczący bajt (rejestr AL) zwraca bajt statusu modemu.

Jako ciekawostkę podajmy, że programy mogą obsłużyć: 256 8-bitowych portów wejścia-wyjścia ponumerowanych ze stałą jednobajtową od 0 do 255 lub 128 16-bitowych portów ponumerowanych od 0, 2, 4 do 254, lub 64 32-bitowe porty o numerach 0, 4, 8 do 252. Używając wartości rejestru DX, analogicznie możemy określić 8-bitowe porty oraz porty 16-bitowe o numeracji od 0, 2, 4 do 65534. Istnieje ponadto możliwość obsłużenia 32-bitowych portów ponumerowanych od 0, 4, 8 do 65532. Wynika to z faktu, iż procesor jest w stanie przesłać 8, 16 i 32 bity do urządzeń wejścia-wyjścia. 16-bitowe porty mają adresy będące wielokrotnością 2, zaś 32-bitowe porty są wyrównywane do adresów będących wielokrotnością 4.

Poniżej (na wydruku 4.2) został przedstawiony prosty program, wykorzystujący funkcje 01h oraz 02h przerwania 14h BIOS-u. Skorzystaliśmy tutaj z procedury Intr(), wykonującej określone przerwania programowe. Wygląda ona następująco:

procedure Intr(IntNo: Byte; var regs: Registers);

gdzie IntNo jest numerem przerwania, zaś regs jest jednym z rekordów typu Registers zdefiniowany w module Dos:

type

Registers = record

case Integer of

0: (AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags: Word);

1: (AL, AH, BL, BH, CL, CH, DL, DH: Byte);

end;

Wydruk 4.2. Kod źródłowy programu dos_rs_2.pas napisanego w Pascalu, realizującego transmisję szeregową

Program dos_rs_2;

uses

Crt, Dos;

var

regs : Registers;

mode: Char; {tryb nadawanie-odbiór}

out : Char; {wysyłane znaki}

Begin

ClrScr;

regs.AH := 0; {01h}

regs.DX := 1; {COM2}

regs.AL := 234; {9600 b/s, ODDPARITY, 7 bitów danych, 1 bit stopu}

Intr($14, regs);

WriteLN(' 1 - Nadawanie 2 - Odbiór [Esc] - koniec nadawania

i odbioru');

mode := ReadKey;

if(mode = '1') then

begin

Repeat {nadawanie}

out := ReadKey;

regs.AL := ord(out);

regs.AH := 1;

regs.DX := 1;

Intr($14, regs);

Write(char(regs.AL));

Until(out = #27);

end;

if(mode = '2') then

begin

Repeat {odbiór}

regs.AH := 2;

regs.DX := 1;

Intr($14, regs);

Write(char(regs.AL));

Until(regs.AL = 27);

end;

if(mode = #27) then exit;

Repeat Until KeyPressed;

End.

Program ten znajduje się w katalogu \KODY\Pascal\dos_rs_2.pas. Jego obsługa sprowadza się do wyboru kierunku transmisji znaków wpisywanych z klawiatury. Koniec przesyłania danych sygnalizujemy klawiszem Esc. Bez problemu można tym sposobem przesłać również plik. Można też, korzystając ze ściągawki w postaci wydruku programu dos_rs_1.cpp, pokusić się o sprawdzanie statusu portu i aktualnego stanu transmisji. Testowanie tego typu prostych algorytmów zawsze okazuje się wielce pouczające.

Podsumowanie

Pisząc ten krótki rozdział, starałem się nie zanudzić Czytelnika zbyt wieloma operacjami bitowymi stosowanymi w programach komunikacyjnych pisanych w MS DOS. Jednak już teraz pragnę uprzedzić, że chociaż może się to wydać komuś dziwne, to do „bitów” powrócimy jeszcze w Windows. Celem tego fragmentu książki było zaprezentowanie ogólnych zasad tworzenia oprogramowania sterującego transmisją szeregową w DOS. Poznaliśmy dwie wielce użyteczne funkcje oferowane przez C++. Ich znajomość pozwala całkiem szybko zbudować poprawnie działający program komunikacyjny. Garść informacji o rejestrach i przerwaniach pozwoli nam w przyszłości w pełni docenić zalety programowania obiektowo-zdarzeniowego. Aplikacje pisane dla Windows też z nich korzystają, co prawda w sposób nie tak jawny, ale warto zdawać sobie sprawę z tego faktu.

Ćwiczenia

1. Korzystając z funkcji _bios_serialcom(), napisz prosty program, realizujący transmisję plików.

2. Uruchom program dos_rs_1.cpp skonfigurowany na port szeregowy, do którego przyłączona jest Twoja mysza. Oglądając efekt na ekranie, zobaczysz pewien znajomy znak (patrz tab. 2.1). Postaraj się wyjaśnić, co się stało.

3. Traktując jako ściągawkę program dos_rs_2.pas Zmodyfikuj go tak, by parametry komunikacyjne danego portu szeregowego, takie jak: prędkość, liczbę bitów stopu, kontrolę parzystości, liczbę bitów danych można było wprowadzać z klawiatury. Postaraj się również uzupełnić go o opcję umożliwiającą sprawdzanie statusu łącza. Unikniesz wówczas odbioru przypadkowo generowanych znaków.

Niekiedy Universal Serial Bus próbuje się dosłownie tłumaczyć, utożsamiając go z uniwersalną szyną danych, co oczywiście nie jest prawdą.

Zgodnie z zaleceniami protokołu V.28 CCITT (Międzynarodowy Komitet Doradczy ds. Telefonii i Telegrafii) logicznemu zeru powinien odpowiadać potencjał dodatni +3V...+15V, zaś logicznej jedynce potencjał ujemny -3V... - 15V.

Interfejs ten nie był omawiany, gdyż oficjalnie przestał być rekomendowanym standardem przesyłania danych w końcu lat 80. XX wieku.

2 Część I Podstawy obsługi systemu WhizBang (Nagłówek strony)

H:\Książki\!Lukasz\RS 232. Praktyczne programowanie\4 po jezykowej\R_1do4.doc

2

Niespójność treści! (proponuję usunięcie tego fragmentu, zresztą bez szkody dla całości)

To pleonazm. Albo „przeterminowania operacji”, albo „przekroczenia czasu operacji”.



Wyszukiwarka

Podobne podstrony:
Praktyczne programowanie, R 5c-04, Szablon dla tlumaczy
Praktyczne programowanie, R 5b-04, Szablon dla tlumaczy
Praktyczne programowanie, R 6-04, Szablon dla tlumaczy
Praktyczne programowanie, R 8-04, Szablon dla tlumaczy
Praktyczne programowanie, R 8-04, Szablon dla tlumaczy
Linux Programming Professional, R-16-t, Szablon dla tlumaczy
ost str-04 , Szablon dla tlumaczy
Professional Linux Programming, R-12-01, Szablon dla tlumaczy
Linux Programming Professional, r-13-01, Szablon dla tlumaczy
Professional Linux Programming, R-08-t, Szablon dla tlumaczy
C++1 1, r00-05, Szablon dla tlumaczy
Dreamweaver 4 Dla Każdego, ROZDZ07, Szablon dla tlumaczy
Dreamweaver 4 Dla Każdego, ROZDZ03, Szablon dla tlumaczy
Doc20, Szablon dla tlumaczy
Doc04, Szablon dla tlumaczy
Doc17, Szablon dla tlumaczy
C++1 1, r01-06, Szablon dla tlumaczy
Dreamweaver 4 Dla Każdego, STR 788, Szablon dla tlumaczy

więcej podobnych podstron