* Önsöz
* Giriş
* Veri Tipleri, Değişkenler
* Operatörler
* Temel G/Ç Fonksiyonları
* Temel Kütüphane Fonksiyonları
* Karşılaştırma Deyimleri
* Döngüler
* Fonksiyonlar I
* Fonksiyonlar II
* Diziler
* Gösterici (Pointer) Kavramı
* Katarlar (Stringler)
* Dinamik Bellek Yönetimi
* Gösterici Uygulamaları
* Yapılar ve Birlikler
* Dosya Yönetimi
* Bit Düzeyinde Çalışmak
* Port Denetimi
* Grafik Kullanımı
* C Makroları
* Kısaca C++
* Derleme Seçenekleri
* Tarih-Saat Fonksiyonları
* Monte-Carlo Yöntemleri
* Fortran ve C
* Yararlanılan Kaynaklar
* Dev-C++
* Salford (silversoft FTN95)
* GCC
* Turbo C
* Eclipse IDE
* NetBeans IDE
* programlama.com
* C Programcıları Derneği
* C (wikipedia)
* C++ (wikipedia)
* cplusplus.com
* koders.com
* Hot scripts
|
|
Ders 18: Port Denetimi
##################-- (%90)
|
En son güncelleme: Wed, 30 Nov 2011 13:22:02 +0200
Giriş
Bu kısımda, ağırlıklı olarak Windows işletim sistemlerinde çalışan (Turbo C, Dev-C++ gibi) derleyicilerin
bünyesinde bulunan port fonksiyonları ve kullanımları anlatılacaktır. Linux işletim sisteminde benzer
uygulamaların nasıl yapılacağı bölüm sonunda verilmiştir.
Bir program içerisinden donanımsal birimlere erişmek veya onları kullanmak
için birçok yol vardır. En basiti,
bu gibi birimlere aynı bellek gözüne erişilmiyormuş gibi gösterici kullanarak erişmektir;
ancak bu durum sistem mimarisinden dolayı her zaman mümkün olmayabilir.
Bu durumda, ilgili birimlere erişmek için derleyicilerin sahip olduğu hazır kütüphane fonksiyonları
kullanılır[1].
NOT
- Windows işletim sistemi, güvenlik nedeniyle, C derleyicilerine ait portlara erişim
fonksiyonlarını kullanmaya da izin vermeyebilir.
- Linux işletim sistemi kullanıcıları ana kullanıcı (root) olmadığı sürece, portlara erişim
izni yoktur.
|
18.1 Port Kavramı
Anakartın üzerinde bir bilgisayarın en önemli bileşenleri
(Veriyolları, Portlar, CPU, RAM, BIOS, ChipSet, ROM, I/O devrelerinin çoğu) bulunur.
Anakart, sistemin çalışmasını organize eder. Bu organizasyon anakart üzerinde bulunan yongalar (entegre devreler) sayesinde
gerçekleşir. Anakart üzerinde bilgisayara veri giriş/çıkış için kullanılan pinlere veya elektriksel bağlantı noktalarına
port denir. Örneğin: Paralel port (LPT), seri port (COM), AGP portu, PCI portları gibi.
Daha fazla bilgi için burayı tıklayın.
18.2 Port Giriş/Çıkış Fonksiyonları
Bir bilgisayarın portlarına erişmek için birçok fonksiyon vardır.
Tablo 18.1'de, Turbo C derleyicisinde bululunan ve bu konu ile ilgili birkaç fonksiyon tanıtılmıştır.
NOT
Turbo C derleyicisinde, port fonksiyonları kullanılabilmesi için dos.h başlık dosyası
programa ilave edilmelidir.
|
Tablo 18.1: dos.h'te tanımlı bazı port erişim fonksiyonları
Port Fonksiyonu |
Açıklama |
void outp(int port_adresi,int bayt_degeri); |
Porta bir baytlık veri yazar |
void outport(int port_adresi,int deger); |
Porta bir kelime* yazar |
void outportb(int port_adresi,unsigned char deger); |
Porta bir baytlık veri yazar |
int inp(int port_adresi); |
Porttan bir baytlık veri okur |
int inport(int port_adresi); |
Porttan bir kelime okur |
char inportb(int port_adresi); |
Porttan bir baytlık veri okur |
(*) kelime (word) : Porta yazılacak veya porttan okunacak, bir tamsayının
bellekte kaplayacağı alanı temsil eder. (Bu alan sizeof() operatörü
ile öğrenilebilir)
|
Port foksiyonlarının kullanımı, örnek programlar üzerinde, bir sonraki bölümlerde
incelenmiştir. Bütün programlar Turbo C derleyicisinde denemiştir.
Eger bu derleyiciye sahip degilseniz,
buradan inderbilirsiniz.
18.3 Paralel Port Örnekleri
Bu bölümde, bir önceki kısımda verilen port fonksiyonları ile, bir PC'nin
paralel portunun nasıl denetleneceği 6 tane örnek programda anlatılmıştır.
NOT
Standart bir PC'de LPT nin alt portlarının adresleri,
DATA için 0x378, STATUS için 0x379 ve
CONTROL 0x37A dır;
|
Program 18.1: outp fonksiyonunun kulanımı
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
|
/* 18prg01.c: outp örneği */
#include <stdio.h>
#include <dos.h>
#define DATA 0x0378
int main()
{
int deger = 25;
outp(DATA, deger);
printf("\n%X nolu adrese %d degeri yazildi.", DATA, deger);
return 0;
} |
ÇIKTI
378 adresine 25 degeri yazildi.
|
Program 18.1'de 6. satırda tanımlanan porta, 12.satırda 25 değeri yazılmaktadır.
Bu değer PC paralel portunun DATA uçlarına yazılır. Bu sebeple 25 değeri
ikili sistemde (binary) ifade edilip 8 bite bölünür, yani 25 = 00011001
şekinde DATA portuna yazılır. Burada 1 portun ilgili bacağına
+5V DC sinyalini gönderir. 0 olan bağlantı noktalarına ise sinyal gönderilmez.
Bu değerler basit bir voltmetre ile ölçülüp test edilebilir.
Porta yazılmak veya porttan okunmak istenen veriyi ikili (binary) olarak görüntülemek
yararlı olabilir. Program 18.2'de cevir_taban2 fonksiyonu bu amaçla yazılmıştır.
Program 18.2: outportb fonksiyonun kullanımı
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
|
/* 18prg02.c: outportb fonksiyonu */
#include <stdio.h>
#include <dos.h>
#include <math.h>
#define DATA 0x0378
long cevir_taban2(int);
int main()
{
int deger = 0x19; /* deger = 25 */
outportb(DATA,deger);
printf("\nDATA portuna gonderilen deger %d : %08ld",deger, cevir_taban2(deger));
return 0;
}
/* Bu fonksiyon 10 tabanındaki bir sayıyı
2 tabınındaki karşılığını hesaplar. */
long cevir_taban2(int x)
{
int i = 0, k;
long bin = 0;
while( x>0 )
{
if(x%2) k = 1;
else k = 0;
bin += k*pow(10,i++);
x /= 2;
}
return bin;
} |
ÇIKTI
DATA portuna gonderilen deger 25 : 00011001
|
9. satırdaki cevir_taban2 fonksiyonu, kendisine parametere olarak gelen
bir tamsayıyı iki tabana çevirir.
Ekranda porta yazılan değer ve onun iki tabanındaki karşılığı, uygun bir formatla,
8 bit halinde gösterilmiştir.
inp() ve inportb() fonksiyonları, PC bağlantı noktalarından sırasıyla
bir karakter ve bir baytlık veri okumak mümkündür. Program 18.3, bu fonksiyonlar
ile nasıl veri okunacağına dair iyi bir fikir verir.
Program 18.3: inp ve inportb fonksiyonlarıyla paralel porta atanan varsayılan değerleri öğrenme
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
|
/* 18prg03.c: inp ve inportb fonksiyonlarının kullanımı */
#include <dos.h>
#include <stdio.h>
#define DATA 0x0378
#define STATUS DATA+1
#define CONTROL DATA+2
int main()
{
int veri;
puts("Paralel porta atanan degerler (Hex):");
veri = inp(DATA);
printf( "Data portu : %X\n",veri );
veri = inp(STATUS);
printf( "Status portu : %X\n",veri );
veri = inportb(CONTROL);
printf( "Kontrol portu : %X\n",veri );
return 0;
} |
ÇIKTI
Paralel porta atanan degerler (Hex):
Data portu : 4
Status portu : 7F
Kontrol portu : CC
|
Programın elde ettiği değerler, porta hiç bir
müdehale olmadan elde edilmiştir ve her bilgisayarda başka bir sonuç verebilir.
Bu fonksiyonların tek parameteresi olduğuna dikkat ediniz.
Bir porta herhangi bir veri yazıldıktan sonra, bu veri o portun
saklayıcısına (register)
yazılır ve yeni bilgi yazılmadıkça orada kalır. Program 18.4 CONTROL
portuna ouportb ile yazılan bir verinin inportb fonksiyonu ile
okunması gösterilmiştir.
Program 18.4: inportb ve outportb fonksiyonlarının kullanımı
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
|
/* 18prg04.c: inportb ve outportb örneği */
#include <stdio.h>
#include <dos.h>
#define PORT 0x037A
int main()
{
int deger;
deger = inportb(PORT); /* varsayılan deger */
printf("\nPorta veri yazilmadan onceki deger : %X",deger);
deger = 0x0A; /* deger = 10 */
outportb(PORT, deger);
deger = inportb(PORT);
printf("\nPorta veri yazdiktan sonraki deger : %X",deger);
return 0;
} |
ÇIKTI
Porta veri yazilmadan onceki deger : CC
Porta veri yazdiktan sonraki deger : CA
|
Program 18.4'ün çıktısı incelendiğinde, portta varsayılan değerin
CCh, veri yazıldıktan sonraki değerin CAh olduğu görülmektedir.
CONTROL portunun ilk 4-bitine müdehale edilebildiği halde ikinci 4-biti değiştirilememiş. Neden?
18.4 Seri Port Örnekleri
Bu bölümde, yine Standart C'de olmayan
bilgisayarın seri portları üzerinden iletişim konu edilecektir.
NOT
Standart bir PC'de COM1 için ilk adres 0x3F8, COM2 için 0x2F8 dir;
|
Standart PC'lerin seri iletişim portlarına erişim UART olarak adlandırılan bir birim
üzerinden gerçekleştirilir. Bu birim anakat üzerindeki bir entegre devredir.
Ancak temel olarak bilinmesi gereken alma saklayıcısına ve gönderme saklayıcısına
nasıl erişileceği ve UART'ın ayarlarının nasıl yapılacağıdır.
Program 18.5'de bir dosya içeriğinin karakter karakter seri port üzerinden karşı tarafa
nasıl gönderileceği görülmektedir[1].
Program 18.5: Bir metin dosyasının içeriğini seri porta aktarır.
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
|
/* 18prg05.c: Bir metin dosyasının içeriğini seri porta aktarır */
#include <stdio.h>
#include <dos.h>
#include <stdlib.h>
int main()
{
char kr;
FILE *dosya;
/* UART'ın ayarlanması */
outportb(0x3FB,0x80);
outport (0x3F8,0x0C);
outportb(0x3FB,0x1B); /* 9600 bps.dur biti 1.cift eslik, 8 bit veri*/
/* dosya açılıyor */
if ( (dosya=fopen("deneme.txt", "r")) == NULL) {
puts ("Hata olustu! Dosya acilmadi.");
exit(1);
}
while( !feof(dosya) )
{
kr=getc(dosya); /* dosyadan bir karakter oku */
while ( (inportb(0x3FD) & 0x20)==0 ); /* gönderme saklayicisi sınanıyor */
ouportb(0x3F8,kr); /* porta gönderiliyor */
}
fclose(dosya); /* dosya kapatiliyor */
return 0;
} |
Bir UART iletişim işine geçmeden önce ayarlanmalıdır; yani,
iletişim hızı, hata biti kullanıp kullanılmayacağı gibi birtakım
bilgilerin yerleştirimi yapılmalıdır. UART'ın herhangi bir andaki durumu,
yani veri göndermeye hazır olup olmadığı, yeni veri gelip gelmediği gibi
bilgiler hat durum saklayıcısı üzerindeki bitlere bakılarak anlaşılır.
Örneğin, UART'a gönderilmesi için bir veri yazılmadan önce, göndermek için uygun
olup olmadığı sınanmalıdır. Program 18.6'de seri port üzerinden gelen karakterleri
alıp ekrana nasıl yazıldığı görülmektedir[1].
Program 18.6: Seri port üzerinden gelen karakterleri alıp ekrana yazar.
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
|
/* 18prg06.c: Seri port üzerinden gelen karakterleri alıp ekrana yazar */
#include <stdio.h>
#include <dos.h>
int main()
{
char kr;
/* UART'ın ayarlanması */
outportb(0x3FB,0x80);
outport (0x3F8,0x0C);
outportb(0x3FB,0x1B); /* 9600 bps.dur biti 1.cift eslik, 8 bit veri*/
while(1)
{
while( (inportb(0x3FD) & 0x01)==0 ); /* yeni karakter gelene kadar bekle */
kr=inportb(0x3F8); /* geleni al ve kr'ye yerleştir */
printf("%c", kr);
}
return 0;
} |
Soru: Son iki programı öyle değiştirin ki, birinin klavyesinden girilen, diğerinin ekranında görülsün.
18.5 Linux'de Portlara Erişim
Linux işletim sisteminde portlara erişmek için birkaç yol vardır. Burada,
gcc derleyicisinin içine gömülebilen assemble dili kullanılarak oluşturulan port
fonksiyonları gösterilecektir.
Linux'de ana kullanıcı (root) olmadıkça veya ana kullanıcı izin vermedikçe portlara erişmeniz mümkün değildir.
Bu yüzden, önce programın portlara erişim izni verip vermediği sınanmalıdır. Bunun için,
/usr/include/sys/io.h dosyası içinde tanımlı ioperm() fonksiyonu kullanılabilir.
Program 18.7 de basit bir port erişim programı verilmiştir.
Kullanıcıların, programın başına ilave edebileceği başlık dosyaları için ayrıca bkz.
Bölüm 20.
Program 18.7: Linux'de port erişimi
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
|
/* 18prg07.c
Linux işletim sisteminde portlara erişim */
#include <stdio.h>
#include <stdlib.h>
#include <sys/io.h>
#include "linuxPort.h"
int main()
{
int deger = 25;
/* porta erişim izni var mı?
sadece root ve onun izin verdiği kullanıcılar erişebilir ) */
if( port_erisim() ) exit(1);
outportb(DATA, deger);
printf("\n%X nolu adrese %d degeri yazildi.", DATA, deger);
return 0;
} |
17. satırdaki port_erisim() fonksiyonu ioperm() fonksiyonunu çağırıp erişim iznini denetler.
port_erisim(), aşağıda verilen linuxPort.h dosyası içinde tanımlanmıştır.
linuxPort.h bütün Linux tabanlı işletim sistemlerinde bulunan gcc derleyici ile kullanılabilir.
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
|
/*********************************************************************
** **
** linuxPort.h **
** **
** Linux işletim sisteminde kullanılabilecek port fonksiyonları **
** **
** Oluşturma tarihi: Haziran 2006 **
** Enson güncelleme: Kasım 2008 **
** **
*********************************************************************/
//
// Standart PC için Port adresleri ------------------------------------
//
#define DATA 0x378
#define STATUS 0x379
#define CONTROL 0x37A
#define COM1 0x3F8
#define COM2 0x2F8
#define MCR 0x3FC // Modem Control Register (8 bit)
#define MSR 0x3FE // Modem Status Register (8 bit)
#define KEYB1 0x060
#define KEYB2 0x064
//
// port erişim fonksiyonları ------------------------------------------
// Bu fonksiyonlar, gcc derleyicisinde <sys/io.h> dosyasında mevcuttur
//
void outportb(unsigned short port, unsigned char data)
{
__asm__ __volatile__ ("outb %1, %0"
:
: "dN" (port),
"a" (data));
}
void outport(unsigned short port, unsigned short data)
{
__asm__ __volatile__ ("outw %1, %0"
:
: "dN" (port),
"a" (data));
}
unsigned char inportb(unsigned short port)
{
unsigned char rv;
__asm__ __volatile__ ("inb %1, %0"
: "=a" (rv)
: "dN" (port));
return rv;
}
unsigned short inport(unsigned short port)
{
unsigned short rv;
__asm__ __volatile__ ("inw %1, %0"
: "=a" (rv)
: "dN" (port));
return rv;
}
//
// erisim izinlerini kontrol et -------------------------------------
//
int port_erisim(void)
{
int i, erisim = 0;
/* paralel porta erisim izni var mi? */
for(i=0; i<=2; i++){
if (ioperm(DATA+i,1,1) )
{
fprintf(stderr, "0x%X adresindeki porta erisim engellenmistir.\n", DATA+i);
erisim++;
}
}
/* seri porta erisim izni var mi? */
for(i=0; i<=6; i++){
if (ioperm(COM1+i,1,1) )
{
fprintf(stderr, "0x%X adresindeki porta erisim engellenmistir.\n", COM1+i);
erisim++;
}
}
/* klavye portuna erisim izni var mi? */
if (ioperm(KEYB1,1,1) )
{
fprintf(stderr, "0x%X adresindeki porta erisim engellenmistir.\n", KEYB1);
erisim++;
}
if (ioperm(KEYB2,1,1) )
{
fprintf(stderr, "0x%X adresindeki porta erisim engellenmistir.\n", KEYB2);
erisim++;
}
if(erisim) printf("erisim # = %d\n",erisim);
return erisim;
}
//
// Seri port Haberleşme Ayarları ------------------------------------
//
void com_ayarlari()
{
outportb(COM1 + 1 , 0x00); // Kesmeleri kapat - COM1
outportb(COM1 + 3 , 0x80); // DLAB açık
outportb(COM1 + 0 , 0x03); // Aktarım hızı - Divisor Latch Low Byte
outportb(COM1 + 1 , 0x00); // Aktarım hızı - Divisor Latch High Byte
outportb(COM1 + 3 , 0x03); // 8 bit, parity yok, 1 dur biti
outportb(COM1 + 2 , 0xC0); // FIFO Kontrol saklayıcısı
} |
|