C Programlama Dili'ne Giriş

  Dersler
* Ö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

  C/C++ Derleyicileri
* Dev-C++
* Salford (silversoft FTN95)
* GCC
* Turbo C
* Eclipse IDE
* NetBeans IDE

  Dış Bağlantılar
* 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ı
}


Powered by PHP