Fatih Sarıkoç

PARALEL PORT UYGULAMALARI

Takdim

Bu sayfayı 1999-2000 yıllarında mühendislik fakültesinin kontrol labarutuarında yaptığım staj sonrasında hazırladım. Stajımda, adım motorlarını sürecek arabirim devreleri üzerinde çalışmış ve labaraturda bulunan bir robot kolun belirli bir yörünge hareket etmesini sağlayan programlar yazmıştım. Makinaları programlayabilmek fikri bana heyecan vermişti. Bu sevinci başkalarıyla paylaşmak ve hiç olmazsa Türkçe bir sayfa yaparak bemimle aynı dili konuşan öğrenci arkadaşlarıma küçük bir katkıda bulunmak istedim. Bügun, yaklaşık 8 yıl sonra, artık benzer konularda hem Türkçe'de hemde yabancı dilde sayısız kaynak bulunuyor. Yine de bu sayfanın okuyanlarına, özellikle lise öğrencilerine, faydalı olacağını umuyorum. (Fatih Sarıkoç, 28/07/2007)

Paralel Port Özellikleri

Bilindiği gibi bilgisayarlar yazıcı, tarayıcı, fare, klavye v.b. çeşitli çevre birimlerine sahiptir. Bilgisayar bu cihazlara dijital olarak bilgi gönderir ve bu cihazlardan dijital olarak bilgi alır. Bilgisayar çevre üniteleriyle haberleşmek için seri veya paralel portları kullanır. İletişim cihaza göre seri veya paralel olabilir. Her portun bilgisayar belleğinde bir adresi bulunur ve her açılışta BIOS bu adres değerlerini RAM belleğe yeniden yükler. Yazıcı portunun da belirli bir adres dğeri vardır. Bu adres değeri kontrol edilerek yazıcı portuna bağlı olan aygıtın kontrolü sağlanır. Yazıcı bilgisayara yakın olduğundan aradaki iletişim paraleldir ve bu sebeble yazıcı portuna paralel port adı verilir.

Paralel Port Adresleri

IBM uymlu PC/XT/AT bilgisayarlarda en fazla üç adet paralel port adaptörü bulunur. Kurulum adresine bağlı olarak paralel portun işlemci I/O haritasındaki adresi 278h, 378h veya 3BCh olabilir. Bilindiği üzere adresleme heksadesimal sayılarla yapılır. Bu sebeble kullanılan sayıları heksadesimal olduğunu ifade etmek içinde sonda “h” harfi kulllanılır. Her yazıcı portu data, status ve control olamak üzere üç ayrı port adresinden oluşur. Bunlara paralel port yazmaçları da denir. Yazıcı portunun yazmaç adresleri paralel portun taban adresine göre sıralıdır. Eğer paralel port(yazıcı portu) BIOS tarafından LPT1’e tahsis edilmişse data portu 378h adresinde, status portu 379h adresinde ve control portu 37Ah adresinde bulunur. Paralel port adresleri tipik olarak aşağıdaki listede gösterildiği gibidir.
 

 Yazıcı      Data Portu        Status       Control 

  LPT1         378h             379h         37Ah

  LPT2         278h             279h         27Ah

  LPT3         3BCh             3BDh         3BEh

Paralel Port Adreslerinin Tespiti

Hangi adresin hangi yazıcı portuna tahsis edildiğini bulmanın birkaç farklı yolu vardır. Bunlardan en kolay olanı debug kullanmaktır. DOS tabanlı işletim sistemlerinde bulunan debug programında dump komutu kullanılarak belleğin 0040:0008 nolu adres içeriği ekrana yazdırılır. Kullanım aşağıda görüldüğü şelildedir.
>debug      
-d 0040:0008 L8      
0040:0008       78 03 78 02 00 00 00 00    
Bu örneğin çalıştırıldığı makinada LPT1 378h, LPT2 278h adresindedir. Diğer tafaftan LPT3 ve LPT4 için bir adres tahsisi yapılmamıştır. Dos tabanlı makinalar için bir başka alternatif komut satırında Microsoft Diagnostics (MSD.EXE) programını çalıştırmaktır. Bu program sayesinde bilgisayarın diğer donanım birimleri hakkında da bilgi almak mümkündür.

Paralel Port Yazmaçları ve Bağlantılar

Daha önceden belirtildiği üzere yazıcı portu üç ayrı yazmaçtan yada bir başka deyişle üç ayrı port adresinden oluşur.

Data portu: Data portu aracılığıyla erişilen 8 sayısal çıkış terminali vardır.
Status portu : Status portu aracılığıyla erişilen biri ters çevrilmiş(inverted) 5 sayısal giriş terminali vardır.
Control portu : Control portu aracılığıyla erişilen üçü ters çevrilmiş 4 sayısal çıkış terminali vardır.

Şekil-1 de bir PC’nin yazıcı portu ve yukarıda sözü edilen yazmaçların bacak bağlantıları gösterimiştir. (D=Data,S=Status,C=Control, 18..25 nolu uçlar toprak uçlarıdır.)

Şekil-1 : PC’nin yazıcı çıkışı ve pin-port bağlantıları.
Kaynak : http://www.doc.ic.ac.uk/~ih/doc/par/index.html


Tablo-1 : Paralel port yazmaçları ve bunların terminalleri
Kaynak : Gökhan Dinçer ve Sinan Gürkan, PC Tabanlı Kontrol ve Otomasyon
76543210
dataxxxxxxxx
status~x xxxx---
control----~x x ~x ~x
~x : negatif lojik(inverted), x : positif lojik

Tablo-1’de görüldüğü üzere status portunun 7. biti olan S7 biti ters çevrilmiştir. Ayrıca C3,C1 ve C0 için de aynı durum geçerlidir. Uygulamada data portunun D0,D1,D2 ve D3 bitleri çıkış terminalleri olarak, diğer taraftan status portunun S6,S5,S4 ve S3 bitleri de giriş terminalleri olarak kullanılmıştır.

Paralel Port Terminalleri

Data portu 74LS374 olarak bilinen yüksek empedans durumlu oktal D-tipi flip-flop tarafından sürülür. Bu entegre 2.6 mA akım verelebilir(source) ve 24 mA’e kadar akım çekebilir(sink). Bu sebeble kullanılacak ara birim devresi için data terminallerinden alınan zayıf akım ihtiyaca göre kuvvetlendirilir. Data portundaki bilgiyi geri beslemeyle okumak için anakart üzerinde 74244 olarak bilinen yüksek empedans durumlu tampon(buffer) entegresi kullanılır.

Control portu pinleri 7405 invertör entegresi tarafından sürülür. C2 hariç bütün veri yolları terslenmiş haldedir. C2 yolu 16 nolu terminal ucuna verilmeden evvel iki defa terslendiği için aktif lojik mantığına göre çalışır. Control pinleri dışarı ancak 1 mA akım verebilir ve en fazla 7 mA akım çekebilir.

Uygulamada özellikle eğer harici bir güç kayanağı kullanılıyorsa terminallerin toprağa çekmemesine özen gösterilmiştir. Aksi halde paralel port adaptörünün olması gerekenden fazla akım çekerek yanması ve anakarta zarar vermesi kaçınılmaz olur.

Kaynaklar :

  1. Derleyen: Gökhan Dinçer ve Sinan Gürkan, PC Tabanlı Kontrol ve Otomasyon, Bilişim Yayıncılık Aş. 1999.
  2. Murray Sargent III and Richard L. Shoemaker, The IBM PC From Inside Out, Addison-Wesley Publishing Company, Inc. Eighth printing 1990. (Erc. Ünv. Kütüph. QA-76.8-S.73-1986)

Step Motor

Adım(step) motorları basitçe rotor adı verilen mıknatıslardan veya metalden yapılan bir parça ile bu parça çevreleyen ve onu indüklenme sayesinde hareket ettirebilen bobinlerden oluşur. Bobin uçları belli bir sıraya göre elektiriklendirildiğinde motorun adım adım dönmesini sağlanır. Motorun hassayitine göre bir devir için kaç adım atması gerektiği belirlidir. Bu sayede adım motorları geribeslemeye ihtiyaç duyulmaksızın açık çevrim kontrol (open loop control ) uygulamalarında ve hassas konumlanma gerektiren makinalarda kullanılabilir.

Şekil-2 : Bir step motorun içini gösteren ön kesit
Kaynak : http://www.doc.ic.ac.uk/~ih/doc/par/index.html

Sürülme(çalıştırılma) metoduna göre temelde tek kutuplu (unipolar) ve çift kutuplu–çok kutuplu(bipolar) olmak üzere iki çeşit step motor vardır. Bu iki çeşit motorun çalışma mantığı birbirine benzer fakat arabirim devreleri(interface circuıit) tamamen farklıdır. Step motorlar daha bir çok başlık altında sınıflandırılabilir. Burada motorlar hakkında daha önceden bilgi sahibi olduğunuz kabul edilerek sadece tek kutuplu ( bir faz/sargı , one phace/winding) step motor için kullanılacak arabirim devresi açıklanacaktır.

Tek Kutuplu Step Motor Arabirim Devresi

Bu tip motorlarda genelde motor içindeki sargıları besleyen 5 uç(coil) bulunur. Bunlardan biri gerilim (VCC) girişidir . Diğer dört uç motor içindeki yük bobinleri içindir. Hareket elde etmek için sargı uçlarının sırayla enerjilenmesi gerekir.

İleri geri hareket elde etmek üzere bir IBM PC ‘nin paralel portunun dört data çıkışı ( D0 D1 D2 ve D3 ) kullanılabilir. Bir yönde hareketi sağlamak için bu uçlar sırayla enerjilenir. Ters yönde hareket elde etmek için elektiriklendirme sırası terslenir.

        D0 D1 D2 D3

adım1   1  0  0  0    
adım2   0  1  0  0 
adım3   0  0  1  0 
adım4   0  0  0  1 
        >>-------->> Hareket

Port çıkışlarının sırası, data yazmacının ilk dört çıkışı programlanarak değiştirilebilir. Tabiki bu çıkışlar doğrudan motora verilmez çünkü her bir data ucu dışarı yaklaşık 20 mA akım verebilir. Bu düzey vasat bir motoru sürmek için bile çok yetersizdir. Bu sebeble akım düzeyini yükseltmek üzere transistörler gibi bir akım yükseltme katı kullanılır.

Sözü edilen yükeseltme katı olarak ayrı ayrı transistörler kullanmak yerine transistör dizisi ( Darlington Array ) denen türden TTL IC’ler de kullanılabilir. Fakat bu tür ticari entegrelerin 500mA-800mA aralığında akım üretebildiğini dikkate alınmalıdır çünkü sadece küçük ve fazla güç üretmeyen motorlar bu akım aralığında sürülebilir. Aşağıda bir PC’nin dört data çıkışını kullanan basit bir arabirim devresi gösterilmiştir.

Şekil -3 : Tek kutuplu step motor için sadece yükseltme katından oluşan arabirim devresi
Hazırlayan F.Sarıkoç, Electronics Workbench EDA şeması

Şekildeki V1 güç kaynağı motorun VCC(gerilim) ucuna bağlıdır. Yukarıdaki devrede bobin olarak gösterilen herbir yük motor içindeki sargıları ifade etmektedir. Bir başka deyişle tek kutuplu motorun her bir yük ucu, transistörlerin kollektörüne verilmiştir. Yükün kollektörde olması transistörlerin daha geç ve daha az ısınmasını sağlar.

Yukarıdaki devrenin çalışması için bilgisayarın paralel portundaki toprak ucuyla (D18-D25 nolu uçlardan herhangi birisi) arabirim devresini besleyen güç kaynağının toprağı birleştirilmelidir.

Transistörlerin ne tipte olacağı elde etmek istediğiniz akıma bağlıdır. Düşük akımlar için ULN2003 gibi bir TTL IC kullanabilirsiniz. 2 Amper’e varan düzeyde akım için BDX53C gibi bir transistör kullananbilirsiniz. Eğer elinizde akım kazanci daha düşük olan transistörler varsa Darlington bağlantı yöntemiyle akım kazancını yükselterek onlardan faydalanabilirsiniz

Uyarı : Kullandığız arabirim devresinde paralel port terminallerin toprağa çekmemesine(devrenin toprağı durumunda olmamasına) dikkat etmelisiniz. Emin olmadığınız durumu denemeyiniz. Yapacağınız yanlışlıklardan dolayı sorumluluk almayacağımı belirtmek isterim.

Step Motorun Programlanması

Step motoru programlamak için arabirim devresini programlamak, arabirim devresini programlamak için de bilgisayarın çıkış portlarından birini programlamak gerekir. Burada çıkış portu olarak paralel port anlatılacak ve programlar Şekil-3’teki arabirim devresi dikkate alınarak hazırlanacaktır.

Programlama dili olarak Turbo C++ kullanılacaktır. Basic, Pascal, Delphi gibi başka dilleri tercih edenler için de ÖZET BİLGİ hazırlanmıştır. C dilinde portlara veri göndermek için outportb fonksiyonu, portlardan veri okumak için inportb fonksiyonu kullanılır. Fonksiyonların genel kullanım biçimi aşağıdaki gibidir.

# include <stdio.h>
# include <dos.h>
        # define      data    0x378
        # define    status    0x379
        # define  control    0x37A 

        unsigned char veri ;

outportb(data,veri);
veri = inportb(status);

Yukarıda bahsedilen fonksiyonların pratiğini yapabilmak için aşağıdaki basitpar.c isimli küçük bir program gösterilmiştir Bu program Şekil-3’teki arabirim kullanılmak kaydıyla tek kutuplu(unipolar) step motoru 100 ms'lik bir periyotla tek bir yönde sabit hızla hareket ettirir. Klavyede herhangi bir tuşa basıldığında program sonlanır.

Örnek -1 :

 
/*  basitpar.c */

#include <dos.h>
#include<conio.h>

#define port 0x378

main(){        
     do {                                  //                D3 D2 D1 D0
            outportb(port,1); delay(100);  // birinci adım   0  0  0  1
            outportb(port,2); delay(100);  // ikinci adım    0  0  1  0 
            outportb(port,4); delay(100);  // üçüncü adım    0  1  0  0 
            outportb(port,8); delay(100);  // dördüncü adım  1  0  0  0
      }while(!kbhit());
  return 0;
};

Eğer basirpar.c programını tecrübe ettiyseniz elektirik enerjisini programlanabilir halde kinetik enerjiye dönüştürdünüz demektir. Bu size keyif verdiyse şimdi işe yarar bir program yapmaya hazır olmalısınız. Daha ileri bir uygulamaya başlamadan evvel gitmotor.c isimli programa bakınız. Bu program bir tek motorun istenen yönde ve istenen hızda kontrolünü sağlar. Git fonksiyonu (göreceli olarak) ileri yön hareket için , tersgit fonksiyonu yön terslemek için ve delay fonksiyonu hız değiştirmek için kullanılmaktadır.

Örnek-2 :

/* Fatih Sarıkoç, Haziran 2000*/
/* Kont&Bil. Müh. Kontrol Lab.*/
       /* gitmotor.c */

#include   <stdio.h>
#include     <dos.h>
#include   <conio.h>
#include  <stdlib.h>

#define dataport  0x378

void git(int x);
void tersgit(int x);

int opsiyon,periyot;
 
void main(void)
{  periyot=300;

  do{  clrscr();
       printf("[8] Daha Hızlı\n");
       printf("[4],[6] Yön Tersle\n");
       printf("[2] Daha Yavaş\n");
       printf("[5] Çıkış\n");
       while(!kbhit()){git(periyot);};

       opsiyon=getch();

       switch(opsiyon){
        case 50:{ periyot=1.5*periyot;gotoxy(1,11);
                printf("yavaşlatıldı  periyot :%d    ",periyot);
                git(periyot);break;};
        case 56:{ periyot=periyot/1.5;gotoxy(1,11);
                printf("hızlandırıldı periyot :%d    ",periyot);
                git(periyot);break;};
        case 54:{ git(periyot);break;};
        case 52:{ tersgit(periyot);break;};
        case 53:{ outportb(dataport,0); exit(0);};
      }; /* switch‘in sonu*/
    }while(1); /*do’nun sonu*/
}; /* main’in sonu*/

 

void git(int x)
{  
 do{
       gotoxy(1,12);printf("ileri yönde gidiyor");
       outportb(dataport,1);delay(x);
       outportb(dataport,2);delay(x);
       outportb(dataport,4);delay(x);
       outportb(dataport,8);delay(x);
       }while(!kbhit());

       opsiyon=getch();

       switch(opsiyon){
        case 50:{ periyot=1.5*periyot;gotoxy(1,11);
                printf("yavaslatıldı  periyot :%d   ms ",periyot);
                git(periyot);break;};
        case 56:{ periyot=periyot/1.5;gotoxy(1,11);
                printf("hızlandırıldı periyot :%d   ms ",periyot);
                git(periyot);break;};
        case 52:{ tersgit(periyot);break;};
        case 53:{ outportb(dataport,0);exit(0);};
        default:{ git(periyot);}; 
 };
};

 

void tersgit(int x)
{ 
 do {
       gotoxy(1,12);printf("geri yönde gidiyor  ");
       outportb(dataport,8);delay(x);
       outportb(dataport,4);delay(x);
       outportb(dataport,2);delay(x);
       outportb(dataport,1);delay(x);
      }while(!kbhit()); /* do’nun sonu*/

       opsiyon=getch();
 
       switch(opsiyon){
        case 50:{ periyot=1.5*periyot;gotoxy(1,11);
                printf("yavaslatıldı  periyot :%d   ms ",periyot);
                tersgit(periyot);break;};
        case 56:{ periyot=periyot/1.5;gotoxy(1,11);
                printf("hızlandırıldı periyot :%d   ms ",periyot);
                tersgit(periyot);break;};
        case 54:{ git(periyot);break;};
        case 53:{ outportb(dataport,0);exit(0);};
        default:{ tersgit(periyot);};
            }; /* switch’in sonu*/
}; /* programın sonu */

Çok Sayıda Motor İçin Arabirim Devresi

Buraya kadar sadece tek bir motorun programlanması ve arabirim devresinin yapımı üzerinde duruldu. Yukarıda açıklanan yöntemle paralel port üzerinden ikinci bir motoru programlayarak çalıştırmak mümkündür. Fakat üç yada daha fazla motoru aynı anda sürmek gerektiğinde sadece yükseltme katından oluşan arabirim devresi yetersiz kalır çünkü paralel portun 12 tane data terminali yoktur. Terminal sayısı arttıralamayacağına göre arabirim devresi daha az sayıda giriş ucuyla daha çok sayıda motoru kontrol edebilecek şekilde dizayn edilmelidir.

Bu aşamada işin içine biraz lojik giriyor. Arabirim devresine ayrıca bir lojik katman eklemelidir. Şimdi son durumu toparlamak gerekirse genel yapı şu biçimde olamalıdır ;

Paralel Port >> Lojik Kat >> Yükseltme Katı >> Motor
Size fikir verecek birkaç farklı çözüm alternatifi aşağıda sıralanmıştır.

CLK >> Ring Sayıcı >> Transistörler >> Motor
CLK >> Flip-Flop ve Lojik Kapılar >> Transistörler >> Motor
CLK >> 2 bit sayıcı >> 2x4 Decoder >> Transistörler >> Motor

Son modeli açıklamakta fayda var. Bu çözüm modeli data portundam alınan ve saat darbesi ( CLK ) üreten tek bir uç ile bir motorun tek yöde hareket ettirilmesini sağlayabilir. İkinci bir data çıkışı yön tayin etmek üzere kullanılabilir. Bu durumda bir paralel port terminalinden alınan yön çıkışı 2 bit sayıcı çıkışı ile EX-OR ‘lanarak 2x4 Decoder girişine verildiğinde motor yönü (yön ucu =1) için rahatlıkla terslenebilir. Bu modelde normalde (yön ucu = 0) olmalıdır.

Yukarıda CLK olarak ifade edilen tek bitlik (arabirim devresi için) giriş ucu data portunun herhangi bir çıkış terminalinden alınabilir. CLK frekansı C dilinin Delay( ) komutu sayesinde istenen değere ayarlanabilir. Netice olarak bu yöntemle yapılan bir arabirim devresi sayesinde paralel portun data terminalleri(8 adet) kullanılarak 4 ayrı step motor aynı anda kontrol edilebilir. Bu miktar bir çok iş için yeterlidir örneğin 4 mafsalla bir robot kol bile yapabilir. ( Tabiki mekanik aksamın zahmetine katlananabilenler için.)

Robot Kol Programlama

Bu konu kapsamında İ.Atabaş ve S.Ökdem adlı öğrenciler tarafından tasarlanıp yapılan bir robot kolun (Tasarlayanlarına Tubitak Başarı Ödülü kazandıran bu makine Erciyes Ünv. Bilg. Mühendisliğine bağlı kontrol labaratuarında bulunuyor.) programlanması incelenecektir. Sözü edilen robot gövde, omuz, dirsek olarak adlandırılan üç mafsaldan oluşur ve her mafsalda step motor kullanılarak yapılmıştır.

Aslında robot dört mafsallıdır fakat şu anda sadece üç mafsalı kullanıldığı için dördüncüsü burada gözardı edilecektir. Yine burada arabirim devresi gözardı edilecektir programcılık açısından paralel portun hangi terminalinin robot kulon hangi uzvuyla ne yönde ilgili olduğunu bilmek yeterli olacaktır. Bu bilgiler aşağıdaki örnek program içerisinde verilecektir.

Şekil-4’te üç mafsallı bir robot kol sembolize ediliyor. Robot kolun uç noktasının üç boyutlu koordinat ekseninde belli bir hedef noktayı bulmasını sağlamak istersek bu nasıl yapılabilir ? Bu tabiki sadece üç motoru programlayıp sürmek kadar basit değildir çünkü biz koordinatları dorusal olarak düşünürüz oysa makine koordinatları açısal olarak bulur.

Bu yüzden hedef x, y ve z koordinatlarının herbir mafsalın dönmesi gereken ø1 ,ø2 ve ø3 açılarına dönüştürmek gerekir. Burada işin içine matematik giriyor. Herkes kendine göre formüller üretebilir ve eğer bu kunuda zahmet eden olursa farklı çözümleri öğrenmekten büyük memnuniyet duyarım.

Şekil-4 : Üç mafsallı bir robot kolun hareketini sembolize eden resim
Hazırlayan : F.Sarıkoç


Bir robot kolun istenen koordinatı bulmasını sağlamak için sadece açıları hesaplamak yeterli değil. Mafsalda meydana gelen net dönme miktarını etkileyen başka faktörler de vardır. Kullanılan mekanik aksam örneğin dişliler motordan alınan açısal hareketi belirli bir oranda değiştirir. Bu yüzden her mafsalda step motorun bir adım darbesine karşılık olarak kaç derece dönme hareketi yaptığı ve bu hareketin dişli çarklara bağımlı olarak her mafsalda ne kadar net dönme hareketi oluşturduğu bilinmelidir. Bu bağıntıları katsayılarla ifade etmek gerekir. Örnek -3’teki programda kullanılan katsayi_1 ve katsayi_2 sabitleri bu türden katsayılardır.

Aşağıdaki program sadece koordinat ekseninde bir tek nokatayı bulmaya yarar. Eğer robot kolun bir dosyadan okunan girişlere göre belirli bir yörüngeyi takip etmesi istenirse o zaman yörüngeyi ayrık noktalardan oluşan bir bütün olarak ele almak gerekir.

Her bir adımla gelinen koordinat kendinden bir sonraki adım için referanstır ve bir önceki adım için hedeftir. Referans konum, hedef noktaya doğru yapılacak harekete başlamadam evvel makinanın içinde bulunduğu koordinatlardır.

Referans konumdan hedef konuma ulaşabilmek için saat yönünde mi yoksa tersi yöndemi hareket edileceği ve bu hareketin kaç derece olacağı ve bütün bunlara bağlı olarak paralel portun hangi terminaline kaç adım darbesi gönderileceği hesaplamalıdır. Bu nedenle yörünge takibi sözkonusu olduğunda referans konum ve hedef konum kavramları çok önemlidir.

Şimdi programı incelemekte fayda var. Anlatılamayan veya bahsedilmeyen bir çok husus program içerisindeki açıklamalarla netlik kazanabilir. Programı satır satır anlamaya çalışmayınız. Burada sadece kullanılan fonksiyonların işlevini göstermek ve robot kolun programlanması hakkında size fikir vermek amaçlanmıştır.

Örnek 3 :

/* F.Sarikoç, Haziran 2000,Kontrol Lab. */
  /* Ölçüler santim olarak düşünüldü */
            /* Robkol0.c */

 
#include  <stdio.h>
#include  <conio.h>
#include   <math.h>
#include    <dos.h>
#include<process.h>

#define p 3.142857

/* gövde-omuz,omuz-dirsek arası uzunluklar */
#define kol1 25.5
#define kol2 19.0


/* kullanılan motora ve o motorun dişli çarklarına bağlı dönme katsayıları */
#define katsayi_1  25.72016461         
#define katsayi_2   7.72


/* paralel port taban adresi-data portu */
#define port 0x378


/* manevra için data terminallerine gönderilmesi gereken değerler */
/* dirsek motoru ileri = 000100, geri = 100000 */
/* omuz motoru   ileri = 000010, geri = 010010 */
/* gövde motoru  ileri = 000001, geri = 001001 */
#define dirsek_ileri  4
#define dirsek_geri   36
#define omuz_ileri    2
#define omuz_geri     18
#define govde_ileri   1
#define govde_geri    9

 

/* prototip tanımlamaları */
void bul(int,int,int);
void git(int,int,int,int,int,int);

int x,y,z,
    a,b,c;

 
main()
{
  clrscr();
  scanf("%d %d %d",&a,&b,&c); /* gidilecek koordinatlar okunuyor x,y,z */

 
/* robotun verilen koordinata uzanıp uzanamayacağı yoklanıyor */
      if (   (a*a+b*b+c*c) > ((kol1+kol2)*(kol1+kol2))  )
            {printf("olmaz\n");getch();exit(0);};

 

/* Alınan koordinatlar bul fonksiyonuna aktarılıyor. Bu fonksiyon 
programın matematiğinden sorumludur. Aldığı koordinatdeğerlerine göre 
motorları yönlendirecek sayısal sonuçlar üretir ve sonuçları motorları 
hareket ettirmekle yükümlü olan git fonksiyonuna transfer eder.  */ 

  bul(a,b,c);
  return 0;

};

 

void bul(int x,int y,int z)
{
/* govdeaci,omuzaci,dirsekaci hedef koordinatlarına göre sırayla gövde,omuz 
ve dirsek  motorlarının dönmesi gereken açısal değerlerdir. */

/* m1yon,m2yon,m3yon değişkenleri referans ve hedef konuma göre hangi motorun 
hangi yönde dönmesi gerktiğini gösterir.m1adim,m2adim ve m3adim hangi adım
motoruna kaç sinyal darbesi gönderileceğini belirler.*/

  double      t,tetaA,tetaB,teta1,teta2,teta3,
              govdeaci,omuzaci,dirsekaci;
  int         m1yon,m2yon,m3yon,
              m1adim,m2adim,m3adim;


/* alınan doğrusal koordinatlardan açısal teta1,teta2,teta3 koordinatlarını 
üreten formüller burada başlıyor. Programcılık açısından bakıldığında burada 
yazılan formülleri anlamak zorunda değilsiniz*/


  teta3=acos(((kol1*kol1+kol2*kol2)-(x*x+y*y+z*z ))/(2*kol1*kol2));
  teta3=teta3*180/p;
  tetaA=atan2(z,sqrt(x*x+y*y)); 
  t=(sqrt(x*x+y*y+z*z));
  tetaB=acos( (t*t+kol1*kol1-kol2*kol2)/(2*kol1*t) );
  teta2=tetaA+tetaB;teta2=teta2*180/p;

    if ((x==0)&&(y==0)) teta1=90;
    else teta1=atan2(x,y);teta1=teta1*180/p;       



/* bu kısımda elde edilen açısal koordinatlara ve motorlara ait aci değerlerine 
göre her bir motora gönderilecek yön ve adım değikenleri tespit edilir. */

 

  if (teta3>180){ dirsekaci=teta3-180; m3adim=katsayi_1*dirsekaci;m3yon=dirsek_geri;}
  else  {dirsekaci=180-teta3;m3adim=katsayi_1*dirsekaci;m3yon=dirsek_ileri;};

  if (teta2>0){ omuzaci=teta2; m2adim=katsayi_1*omuzaci;m2yon=omuz_geri;}
  else  {yng2=0-teta2;m2adim=katsayi_1*yng2;m2yon=omuz_ileri;};

  if (teta1<90){ govdeaci=90-teta1; m1adim=katsayi_2*govdeaci;m1yon=govde_geri;}
  else  {govdeaci=teta1-90;m1adim=katsayi_2*govdeaci;m1yon=govde_ileri;};



/* elde edilen yon ve adım değişkenleri motorları hareket ettirmek için paralel 
portu programlamakla görevli git fonksiyonuna aktarılır. */

  git(m1adim,m2adim,m3adim,m1yon,m2yon,m3yon);

 

  printf("\n\nteta1 :%f \nteta2  :%f\nteta3 :%f\n",teta1,teta2,teta3);

  printf("\ngovdeaci :%f \nomuzaci  :%f\ndirsekaci :%f\n",govdeaci,omuzaci,dirsekaci);

  printf("\nm1adim :%d \nm2adim  :%d\nm3adim :%d\n",m1adim,m2adim,m3adim);

  printf("\nx :%d \ny  :%d\nz :%d\n",x,y,z);

  printf("\ntetaB :%f \ntetaA  :%f\n",tetaB,tetaA);

  getch();

}

 

/* Bu foksiyon data terminallerinden hangisine kaç adet saat darbesi göndereceğini
hesaplar. Bunu yaparken bir sayaç kullanır ve adım sayısı sayaca eşitlenen motoru
durdurmak için o motora ait yon değişkenini sıfırlar. Sayaç bütün motorlar için
gerekli adım darbesini ürettiği anda prosedür sonlanır. */

 

void git(int a,int b,int c ,int d,int e,int f)

{  int veri=0;
   int i=0;

     do
       { if ( i >= a ) d=0;

          if  ( i >= b ) e=0;

            if  (i >= c )  f=0;

                   veri= d|e|f;

                           outportb(port,veri);
                           delay(10);
                           outportb(port,0);

      }while(!((i>=a)&&(i>=b)&&(i>=c)));

};

/* programın sonu */

İnternet Üzerinden Paralel Port Kontrol

Bu konu kapsamında internette veya nerwork içinde bir başka bilgisayara bağlantı kurulması ve bağlanılan bilgisayarın paralel portlarının programlaması incelenecektir. Bu çalışmada Delphi programlama dili ve bu dilin soket bileşenleri kullanılmıştır. Ayrıca Delphi içinde paralel porta erişim sağlayabilmek için (inline) Assembly kodlaması yapılmıştır. Bu çalışmayı okumadan evvel TCP/IP ve Internet kavramlarına en azından aşina olmak gerekmektedir.

Burada sizlerin daha önceden Delphi bildiği kabul edilerek Delphi içinde paralel portu kontrol etmek üzere Assembly komutlarının nasıl kullanıldığı bir sonraki başlık altında anlatılacak ve ayrıca Delphi’de soket bileşenlerinin kullanımı kısaca hatırlatılacaktır. Son olarak uzaktaki bilgisayarın data portunun dört terminaline veri göderen ve status portunun dört terminalinden de veri okuyabilen İSTEMCİ adlı bir Delphi programı ve buna hizmet veren SUNUCU isimli bir program örnek olarak gösterilecektir.

Delphi İçinde Assembly Kullanımı

Delphi içinde portlara doğrudan erişim için kullanılabilecek hazır bir bileşen yoktur. Bunun yerine shareware bileşenlerden faydalanmak mümkündür. Fakat hazırlanması sayfalar dolusu yer işgal eden bu tür bileşenlerden yapmak veya yapılmış olanını hazırlamak yerine yarım sayfalık (inline) Assembly kodu kullanmak yeterli olacaktır.

Delphi içinde bir Assembly yordamı kullanmak için aşağıdaki gibi bir asm bildirimi ile başlayan ve end bildirimi ile biten bir asm bloğu kullanılır. Bu blok içerisinde sadece asm komutları kullanılır.

asm

/* assembly kodları */

end

Paralel Porta Okuma ve Yazma

Port mikroişlemciyi dış dünyaya bağlayan bir cihazdır. Her port, bir adres değeri ile tanımlansa da geleneksel yöntemle bir bellek adresini kullanır gibi işleme tabi tutulmaz. Kullanıcı bu ayrımı işletim sistemine göre farkedemeyebilir. Örneğin bir Unix kullanıcısı PC’ye bağlı bütün cihazlara adeta bir dosyaya yazma yada okuma yapar gibi erişim sağlayabilir. Fakat Intel işlemci bütün işletim sistemlerinde arka planda giriş çıkış için aynı Assembly dili komutlarını (IN ve OUT) kullanır.

Port adreslerine doğrudan değer göndermek ve okumak mümkün değildir. Daha önce mutlaka akümülatör yazmaçlarını kullanmak zorundayız. Örneğin porta göndermek istediğimiz veri değerini daha önceden aku_rec olarak gösterilen AX veya AL yazmaçlarından birine yüklemeliyiz. Göndermek istediğimiz değer 1 word büyüklüğünde ise AX, 1 bayt büyüklüğünde ise AL yazmacını kullanırız. Okuma işlemi için de aynı durum geçerlidir. Aşağıda okuma ve yazma işleminin genel kullanım şekli gösterilmiştir.

in  aku_rec, port   ; aku_rec:akümülatör yazmacı

out port,aku-rec

Port adreslerini statik ve dinamik olarak belirleyip kullanmak mümkündür. Statik olarak in ve out komutları yukarıda gösterildiği gibi kullanılır. Dinamik olarak kullanmak gerektiğinde DX yazmacına ihtiyaç duyulur. Kullanılacak port numarası önce DX yazmacına yüklenir. Bu metod DX’i program içerisinde değiştirmek suretiyle aynı yordamla farklı portlara erişim sağlamaya imkan verir. Aşağıda port adreslerinin dinamik olarak kullanımı gösterilmiştir.

mov dx,port

in  aku_rec,dx

out dx,aku-rec

Delphi içinde standart paketler arasında portlara doğrudan erişimi sağlamak için tanımlanmış herhangi bir yordam ve bileşen yoktur. Ayrıca bit düzeyli işlemler için yüksek seviyeli programlama dilleri yetersiz kalmaktadır. Bu sebeble Delphi kodları içerisinde gerektikçe Assembly komutları kullanılmıştır. Delphi’de Assembly komutları doğrudan asm ve end bloğu arasında kullanılabilir. Örneğin istemci programında data portuna veri göndermek için aşağıdaki asm bloğu kullanılmıştır.

   asm
     mov al,veri
     mov dx,378h
     out dx,al
   end;
Status portundan veri okumak için aşağıdaki asm bloğu kullanılmıştır.
   asm
      mov dx,379h
      in  al,dx
      xor al,80h  // s7’yi tersle
      mov cl,3 // cl’yi 3 yap
      shr al,cl  // al’yi 3 bit kaydır
      and al,00001111b //s7’yi kırp,4 bit okuyoruz
      mov &sonuc,al
  end ;             

Her iki yordamda da tercihen dinamik port adresleme kullanılmıştır. Yukarıdaki blokta dikkat edilirse SHR, XOR ve AND gibi Assembly komutları vardır.

SHR(shift riğht) işleme aldığı değeri bit düzeyinde kaydırmaya yarar ve CL yazmacı ile birlikte kullanılır. Kaç bit kaydırma yapmak istiyorsak bu değeri SHR kullanılmadan önce CL yazmacına atarız . Status portunun ilk üç biti kullanılmadığından bu porttan okunan değeri üç bit kaydırmak için SHR komutu ve CL yazmacı kullanıldı.

XOR komutu status portunun terslenmiş S7 bitini aktif lojik mantığına göre okumak için , diğer taraftan AND komutu status portunun dört bitini kırparak maskeleme yapmak için kullanılmıştır. Aslında bu iki komut statusten 4 bit okumak için zorunlu değildir fakat prensip olarak kullanılmıştır.

Kaynaklar :

  1. KIP R. IRVINE : Assembly Language for Intel-Based Computers Third Edition, ©1998,1995 Prentice Hall Inc. Upper Saddle River, NJ 07458 Miami-Dade Community College-Kendall
  2. PETER ABEL : IBM PC Assembly Language And Programming (Third Edition), Printice Hall International Editions.
  3. JULIO SANCHEZ and MARAIA P. CANTON: Programming Solutions Handbook For IBM Microcomputers , McGraw-Hill, Inc. 1991. (Erc. Ünv. Kütüph. QA-76.8-S.55-1991)

Dephi Soket Bileşenleri

Soketler sayesinde iki bilgisayar arsında bağlantı kurulabilir. Burada kullanılan soket fiziksel bir kavram değildir. Bağlantı kurulacak diğer makinanaın IP numarası ile bağlantı port numarasını ifade eden sayısal bir kavramdır. Bir bakıma iki bilgisayar arasında iletişimin başladığı ve bittiği uç noktadır.

Delphi’de internet bileşenleri arasında iki çeşit soket bileşeni vardır. Bunlardan birisi TclientSocket bileşenidir ve istemci olarak hizmet verir. Diğeri de TserverSocket bileşenidir ve sunucu olarak kullanılır.

Soket Bileşenlerinin Kullanımı

TclientSocket İSTEMCİ isimli programda, TserverSocket SUNUCU isimli programda kullanılmıştır. Bilindiği gibi Delphi nesne tabanlı görsel bir dildir. Her bileşen aslında bir nesnedir ve her nesneye ait bir takım özellikler ve olaylar tanımlıdır.

İstemci ve sunucu programlarında da iki adet soket bileşeni kullanılmıştır. Bunlardan birisi portlara iletilecek veya portlardan alınacak bilgi için kullanılır. Diğeri mesaj alış verişi için ayrılmıştır.

Aşağıdaki alıntıda ctext adındaki TclientSocket türü bileşenin kullanımı gösterilmiştir ve bazı özellikleri açıklanmıştır.

ctext.Address:=(edthostadr.text);

Adres özelliğine bağlantı kurulacak hedef bilgisayarın sayısal internet adresi yani IP adresi atanır. Bu '192.0.10.35' gibi parçalı gösterimde bir string ifade olmalıdır.

ctext.Host:=(edthostadi.text);

Host özelliğine hedef bilgisayarın ağda tanımlı olan adı atanır. Eğer hedef bilgisayar aynı ağ içinde bulunmuyorsa o takdirde eng.erciyes.edu.tr gibi string tipinde bir domain adresi bu özelliğe atanabilir.

ctext.Port:=strtoint64(edtuzaktport.text);

Port özelliği bağlantı kurulacak port numarasını tanımlamak için kullanılır ve integer tipinde değer alır. Program kodu içerisinde keyfi olarak 1024 ve 1032 numaraları kullanılmıştır.

Sunucu programın hizmet port numarası 23 olarak kurulduğunda sunucu telnet programlarına hizmet verebilir. Fakat bu her durum için güvenli bir iletişim sağlayamaz. Çünkü sunucu sadece string tipinde gelen karakter bilgilerine göre hizmet verebilir. Oysa telnet klavyeden gelen her türlü kontrol karakterini iletir. Bu da hata oluşmasına sebeb olur.

ctext.Active:=true;

Yukarıda açıklanan değer atamaları yapıldıktan sonra hedef bilgisayara bağlantı kurulabilir. Bunun için soketin active özelliği True yapmak gerekir. Kurulu bir bağlantıyı sonlandırmak için active özelliğine False değerini atanmalıdır.

Bağlantı kurulmuş bilgisayara string tipinde veri göndermek istediğimizde socket özelliğinin SendText metodu kullanılır.

ctext.Socket.SendText(edtmsg.text);

İstemci ve Sunucu’da sayısal veri alışverişi için aynı soket kullanılır. Hangi durumda veri okuma hangi durumda gönderme yapılacağı gönderilen string bilginin incelenmesi ile anlaşılırve bu prograncıya kalmış seçimlik bir durumdur. Ben kendi programımda sunucu cdata soketine ulaşan string bilginin ilk karakteri ‘O’ ve ‘o’ ise okuma yapaılacağına değilse gönderme(yazma) yapılacağına dair kodlama düzenledim.

Bağlantı kurulmuş olan bilgisayardan bize string tipinde veri geldiğinde OnRead olayı gerçekleşir. Gelen bilgi Socket özellğinin ReceiveText metoduyla ile işleme tabi tutulur.

edtuveri.text:=ctext.Socket.ReceiveText;

İstemci ve Sunucu programda kullanılan diğer bir bileşen de TServerSocket bileşenidir. Aynı özellikler, olaylar ve metodlar bu soket bileşeni için de geçerlidir.

procedure led(var sha,shb,shc,shd:tshape;str:string);

Ayrıca yukarıda önbildirimi gösterildiği üzere internet bileşenleriden farklı olarak program içerisinde led isimli bir prosedür kullanılmıştır. Bu prosedürde dört adet shape bileşeni ve bir string ifade parametre olarak alınmaktadır ve bu prosedür İstemci’de bulunan led animasyonları canlandırmak için gereklidir.

Kaynaklar :

  1. İhsan Karagülle ve Zeydin Pala : Borland Delphi 3, Türkmen Kitapevi Sahaflar Çarşısı No :19 34450-Beyazıt/İstanbul 1998
  2. Ruhver Barengi : Delphi 4’e Bakış, Seçkin Yayınevi Sağlık Sokak No : 19/B 06410-Sıhhıye/Ankara 1999