rs232_linux-win32_cz3.pdf
(
392 KB
)
Pobierz
106-107_rs232_cz3.indd
K U R S
Programowanie portu szeregowego
w systemach operacyjnych
Linux i Windows, część 3
Umiejętność programowej obsługi interfejsu
RS232 od strony komputera PC jest dziś
istotnym elementem elektronicznego rzemiosła.
W niniejszym kursie piszemy jak w praktyce
oprogramować port szeregowy w środowiskach
Linux i Windows. Wiele miejsca poświęcamy
pisaniu przenośnych aplikacji GUI, które
korzystają z interfejsu szeregowego i zachowują
się tak samo w systemach Windows jak
i Linux. Wszystkie omawiane zagadnienia
poparte są szczegółowo opisanymi praktycznymi
przykładami.
Aplikacja konsolowa używająca
portu szeregowego
Aplikacja konsolowa została napi-
sana w języku C i skompilowana za
pomocą kompilatora GCC, który spo-
tkamy w każdej dystrybucji Linuksa.
Składa się ona z trzech plików:
–
main.c
– główny plik aplikacji od-
powiedzialny za jej funkcjonalność
(
list. 6
);
–
LinuxRS232.h
– plik nagłówkowy
zawierający deklaracje funkcji ob-
sługi interfejsu RS232 (
list. 7)
;
–
LinuxRS232.c
– plik źródłowy za-
wierający definicje (ciała) funk-
cji obsługi interfejsu RS232
(
list. 8...11
).
Na list. 6 zamieściłem zawartość
pliku
main.c
. Działanie programu po-
lega na pobraniu jednej cyfry (je-
den znak+Enter) z klawiatury i wysła-
niu przez port szeregowy /dev/ttyS0
(COM1) bajta o wartości równej poda-
nej cyfrze (0...9). Jeśli wpiszemy znak
inny niż 0...9 to przez port zostanie
wysłany bajt o wartości równej kodo-
wi ASCII tego znaku pomniejszonemu
o 0x30. Następnie program zasypia na
czas ok. 1 sekundy (
break time
), po
czym sprawdza czy w buforze wej-
ściowym portu znajdują się jakiekol-
wiek dane (odpowiedź zestawu). Jeśli
tak jest są one odczytywane i w kon-
soli pojawia się zarówno ich interpre-
tacja ASCII jak i wartości kolejnych
bajtów zapisane dziesiętnie. Pokazu-
je to
rys. 4
zawierający zrzut z ekra-
nu zrobiony podczas pracy aplikacji,
gdy użytkownik jako daną do wysła-
nia wpisał liczbę 3. Zmienna
InQue
zawiera odczytaną za pomocą funkcji
CheckCommInput
liczbę bajtów ocze-
kujących w buforze wejściowym, zaś
zmienna
BytesRead
zawiera liczbę baj-
tów faktycznie wyjętych z tego bufora
za pomocą funkcji
Read
.
List. 8 przedstawia implementację
funkcji
Open
i
Close
. Funkcja
Open
otwiera port, po czym ustawia żąda-
ną przez użytkownika prędkość trans-
misji oraz wyłącza co tylko można
z funkcjonalności obróbki danych wej-
ściowych i wyjściowych. Innymi sło-
wy, wybieramy wejście
raw input
i wyjście
raw output
wyłączając wszel-
kie funkcje mapowania jednych zna-
ków na drugie, sprzętową i programo-
wą kontrolę przepływu, itp..
List. 9 zawiera ciało funkcji
Write
służącej do wysłania do portu
Num-
berOfBytesToWrite
bajtów, począwszy
od miejsca w pamięci określonego
wskaźnikiem
Buffer
. Funkcja ta zwra-
ca liczbę faktycznie wysłanych baj-
tów. W przypadku błędu zwraca 0.
List. 10 zawiera ciało funk-
cji
Read
, za pomocą której możemy
wybrać z bufora wejściowego portu
NumberOfBytesToRead
bajtów. Specy-
fikujemy przy tym pewne ogranicze-
nie określone stałą
cbInQueue
zdefi-
niowaną w pliku
LinuxRS232.h
. Ogra-
niczenie to zapobiega próbie odczy-
tu wielu bajtów z portu. Wartość
cbI-
nQueue
powinna być dobrana tak,
aby podczas normalnej pracy aplika-
cji w żadnym momencie nie zacho-
dziła potrzeba odczytu z portu liczby
bajtów większej od
cbInQueue
. Funk-
cja
Read
zwraca 0 w przypadku błę-
du i 1, gdy odczyt zakończył się suk-
cesem. Za pośrednictwem wskaźnika
lpNumberOfBytesRead
zwracana jest
liczba faktycznie odczytanych bajtów.
List. 7. Plik nagłówkowy LinuxRS232.h
//---------------------------------------------------------------------------
// File: LinuxRS232.h
// Description: Linux RS232 header file
// Compiler: gcc
// Author: Arkadiusz Antoniak, 2005
//---------------------------------------------------------------------------
#ifndef LinuxRS232H
#define LinuxRS232H
#define cbInQueue 1024
#define cbOutQueue 16
int Open(char *Port, unsigned long Baud);
void Close(void);
unsigned long Write(const void* Buffer, unsigned long NumberOfBytesToWrite);
int Read(void * Buffer, unsigned long * lpNumberOfBytesRead, unsigned long NumberO-
fBytesToRead);
void CheckCommInput(unsigned long * lpInQue);
//---------------------------------------------------------------------------
#endif
Uwaga!
Ze wzgledu na objętość tekstu listingów 6 i 8, publikujemy je wyłącznie na CD-EP5/2006B oraz na stronie internetowej
w dziale Download.
106
Elektronika Praktyczna 5/2006
K U R S
List. 9. Funkcja Write
unsigned long Write(const void* Buffer, unsigned long NumberOfBytesToWrite)
{
int iOutWrite;
if (fd<1) return 0;
iOutWrite = write(fd, Buffer, NumberOfBytesToWrite);
if (iOutWrite<0) return 0;
return iOutWrite;
}
dzeniem czy część sprzętowa na to
pytanie odpowiedziała, program od-
czekuje pewien czas – w naszym
przykładzie jest to 1 sekunda. Czas
taki nazywany jest
break time
. Na-
leży w tym miejscu zwrócić uwagę
na różnicę w znaczeniu pojęć
bre-
ak time
i
timeout
używanych czę-
sto w opisach aplikacji komunika-
cyjnych.
Otóż
break time
jest minimalnym
czasem jaki aplikacja musi odczekać
na wystąpienie pewnego zdarzenia.
Jeśli zdarzeniem tym jest odpowiedź
układu pomiarowego dołączonego do
komputera przez RS232, to
break
time
jest wyznaczony przez czas do-
konania pomiaru i czas potrzebny na
przesłanie przez port szeregowy wy-
niku tego pomiaru. W naszym przy-
padku
break time
jest wyznaczony je-
dynie przez czas odpowiedzi – oczy-
wiście 1 s jest czasem znacznie dłuż-
szym niż minimalny czas jaki należa-
łoby tutaj odczekać.
Czas
timeout
jest czasem przeter-
minowania (przedawnienia) pewnej
operacji. Jeśli po upływie tego czasu
chcemy ponownie wywołać tą opera-
cję, to musimy powtórzyć całą proce-
durę związaną z jej wywołaniem.
List. 10. Funkcja Read
int Read(void * Buffer, unsigned long * lpNumberOfBytesRead, unsigned long Numbe-
rOfBytesToRead)
{
unsigned long nNumberOfBytesToRead;
int iInRead;
if (NumberOfBytesToRead>cbInQueue)
nNumberOfBytesToRead=cbInQueue;
else
nNumberOfBytesToRead=NumberOfBytesToRead;
if(fd<1) return 0;
iInRead=read(fd, Buffer, nNumberOfBytesToRead);
if(iInRead<0)
return 0;
else
*lpNumberOfBytesRead=iInRead;
return 1;
}
Rys. 4. Okno aplikacji konsolowej
Podsumowanie
W tej części kursu pragnąłem za-
prezentować wykorzystanie omówio-
nych poprzednio funkcji na prostym
przykładzie, tak aby bez wgłębiania
się w szczegóły pokazać że „to dzia-
ła”. Proponuję Czytelnikom poekspe-
rymentować z opisanym zestawem
i oprogramowaniem – ludzie wszak
uczą się najlepiej i najszybciej na
przykładach. W następnej części zmie-
nimy nieco tematykę i zobaczymy jak
oprogramowanie portu szeregowego
wygląda w systemie Windows. Skupi-
my się przy tym na tych cechach,
które są takie same lub podobne do
ich odpowiedników występujących
w Linuksie. Wszystko to ma na celu
stworzenie klasy obsługi RS232 w ję-
zyku C++ identycznej w obu syste-
mach co do interfejsu, więc przeno-
śnej. Klasę tą – w wersji dla Win-
dows – stworzymy w następnej części
cyklu. Oprócz tego, opiszemy też pro-
stą aplikację GUI dla Windows, której
funkcjonalność będzie taka sama jak
funkcjonalność opisanego dziś proste-
go programu konsolowego. W dalszych
częściach kursu aplikację tą przenie-
siemy na Linuksa.
Arkadiusz Antoniak, EP
arkadiusz.antoniak@ep.com.pl
Wskaźnik
Buffer
określa miejsce w pa-
mięci, gdzie zostaną zapisane odczy-
tane bajty.
List. 11 przedstawia funk-
cję
CheckCommInput,
która pozwa-
la zapytać sterownik portu szerego-
wego ile bajtów aktualnie znajdu-
je się w buforze wejściowym. Ich
liczba zwracana jest przez wskaźnik
lpInQue
.
Oczywiście, funkcje przedstawio-
ne na list. 8...11 (plik
LinuxRS232.c
)
to tylko moja propozycja wykorzysta-
nia funkcji systemowych, a Czytelnicy
zechcą zapewne napisać własne funk-
cje obsługi portu szeregowego (byłoby
to nawet wskazane ze względów edu-
kacyjnych).
Całość kompilujemy za pomocą
GCC używając standardowo programu
make
. Przykładowy plik
makefile
za-
mieściłem na
list. 12.
Jest to bardzo
prosty plik, mówiący kompilatorowi
jedynie co kompilować, zaś linkerowi
– z jakich plików *.o stworzyć plik
wykonywalny o nazwie
main
. Aby
otrzymać ten plik wystarczy wpi-
sać „make” będąc w katalogu zawie-
rającym pliki źródłowe aplikacji i plik
makefile
. Program uruchamiamy wpi-
sując w konsoli „./main”.
Jeśli do portu COM1 komputera
dołączony jest nasz zestaw, to bę-
dziemy mogli obserwować działanie
całości. Polega ono na zadaniu py-
tania (wpisana przez użytkownika
wartość) i obserwacji odpowiedzi.
Pomiędzy zadaniem pytania a spraw-
List. 11. Funkcja CheckCommInput
void CheckCommInput(unsigned long *
lpInQue)
{
ioctl(fd, FIONREAD, lpInQue);
}
List. 12. Plik makefile
main: main.c LinuxRS232.c
gcc -g -c -Wall main.c -o main.o
gcc -g -c -Wall LinuxRS232.c -o
LinuxRS232.o
gcc LinuxRS232.o main.o -o main
Elektronika Praktyczna 5/2006
107
Plik z chomika:
mtx32
Inne pliki z tego folderu:
rs232_linux-win32_cz8.pdf
(628 KB)
rs232_linux-win32_cz7.pdf
(190 KB)
rs232_linux-win32_cz6.pdf
(799 KB)
rs232_linux-win32_cz5.pdf
(467 KB)
rs232_linux-win32_cz4.pdf
(277 KB)
Inne foldery tego chomika:
Audio i akustyka hasło nick
Dyskretne przekształcenie Fouriera
Elektronika hasło nick
filmy
FPGA
Zgłoś jeśli
naruszono regulamin