Pic ile PS2 Klavye Kullanımı

| Mart 21, 2021 Tarihinde güncellendi
Pic ile PS2 Klavye Kullanımı

Pic ile PS2 klavye Kullanımı hakkında detaylı bir makale. Klavyenin çalışma prensibi bağlantı uçlarının açılımları data transferleri hakkında bilgiler ve C dili ile hazırlanmış kütüphane dosyaları örnek yazılım uygulama görüntüleri

Tarihçesi: İlk kez yazı makinesinin mucidi olan Christopher Latham Sholes tarafından 1867’de ortaya çıkan klavye birimi o günden günümüze kadar teknolojiye ayak uydurması dışında pek bir değişikliğe uğramadı. Bugün bir çok bilgisayarda kullanılan Q klavyenin de mucidi olan Sholes, bu kadar karmaşık harf dizilimini mühendisliğe aykırı olarak yazıların daha yavaş yazılması dolayısı ile makinelerinin daha az bozulması için oluşturdu.

Çalışması: Klavye çalışma mantığı oldukça basittir. Her tuş basımında klavye kendine has 8 bitlik özel tuş bilgilerini gönderir, bu kodlar çözülerek hangi tuşun basıldığı kararı alınır ve kullanılır. Basılan tuş dahilinde hangi bilgilerin bizlere gönderildiği aşağıdaki tablolardan görülebilir.

Şekil 1 – Klavye Özel Kodları

ps2-kilavye-ozel-kodlar

Bağlantı Şekli: Klavyeler çeşitli bağlantı şekillerine sahip olsalar da dünya çapında en çok kullanılan bağlantı şekillerinden biri DIN ya da PS/2’dir. Aşağıdaki şekilde PS/2 yapısının giriş birimi görülmektedir.

Şekil 2 – PS/2 Bağlantı Şekli

ps2-baglanti

Şekil-2’de de görüleceği üzere PS/2 yapısında 6 farklı bağlantı noktası bulunmaktadır. Sırasıyla kaç numaralı pinin ne işe yaradığını söyleyecek olursak;

1- Data hattıdır
2- Boş hat, bağlantı yapılmayacak
3- GND, toprak hat ucudur
4- VDD, güç ucudur, +5V verilecek hattır
5- Clk ucudur, iletişim saati buradan verilir
6- Boş hat, bağlantı yapılmayacak

Önemli not: Bu yapı giriş birimi olduğu için klavyeden direk hat çekilecekse, tam simetriğine göre işlem yapılmalıdır. Aksi takdirde klavyeniz zarar görebilir.

Klavye Zaman Diyagramı ve C Kodunun Yazılması

Öncelikle biz iletişimimizi klavyeden kaynağımıza doğru yapacağımız için aşağıdaki zaman diyagramını kullanacağız. Görüldüğü üzere klavye her bir tuş bilgisi için aşağıdaki şekilde 20 ile 30 Khz arasında saat darbesi ve data sinyali üretmektedir. Eğer bu sinyalleri düşen kenarda algılamayı sağlarsak iletişim birimimizi çok kolay yazabiliriz.

Şekil 3 – Kklavyeden Kaynağa

klavye-clock-data

Yukarıdaki zaman diyagramını yorumlayacak olursak;

– Klavyeden hiçbir tuşa basılmaz iken saat ve data yolu yüksek seviyede duracaktır.
– Klavyeden herhangi bir tuşa basıldığında ilk saat darbesinde data hattı sıfıra çekilir.
– Daha sonraki 8 saat darbesinde tuşa ait, şekil-1’deki özel kod gönderilir.
– Daha sonra parity biti gönderilir, klavye tek parity sistemini kullanır
– En sonda da iletişimin bittiği yönünde 11. Saat darbesinde bitiş bilgisi gönderilerek iletişim sonlandırılır.

Burada belirttiğimiz bu yapıyı anlamak için aşağıdaki C fonksiyonu kullanılabilir. Parity bizim için önemli olmadığından kontrol ihtiyacı duyulmamıştır. Fonksiyon geri dönüş olarak klavyeden algıladığı özel kodu gönderecektir.

Klavye Kodunu Alan Fonksiyon

unsigned char get_byte(void)
{
char i;
unsigned char veri=0;
 
for(i=0;i<11;i++)                //11 bitlik veri gelecek
{
while(Clock);               //İlk önce Clock=1 olmalı
if( (i0))           //2->9 bitler
{
veri=veri>>1;
if(Data==1)
veri=veri | 0x80;
}
while(!Clock);              //Son olarak Clock=0 olmalı
}
return veri;                    //Algılanan değer gönderiliyor
}

Klavye için yukarıdaki kodu yazmak başlı başına yeterli değildir. Klavyede her tuşa basıldığında o tuşun özel kodu, tuş bırakıldığında o tuşa ait başka bir kod ve tekrar o tuşun kendi kodu gönderilir. Mesela bazı tuşlara basılıp bırakıldığında aşağıdaki kodlar sırasıyla klavyeden gönderilecektir;

A: 0x1C -> 0xF0 -> 0x1C
H: 0x33 -> 0xF0 -> 0x33
1: 0x16 -> 0xF0 -> 0x16

Görüldüğü üzere 0xF0 burada kilit rol oynamaktadır. Eğer sadece yukarıdaki C kodunu kullanacak olursanız, tek tuşa bastığınızda sanki 3 ayrı tuşa basmış gibi olacaksınız. Bunu engellemek için aşağıdaki kod sistemini kullanabilirsiniz.

data=get_byte();
while(get_byte()==0xF0);

Burada algılama işlemini ister 0xF0’dan önce, isterseniz de sonda yapabilirsiniz. Daha sonrası ise algıladığınız kodun bildiğimiz ASCI karşılığını bulmaktan ibarettir. İsterseniz benim yaptığım gibi shift ve caps lock tuşlarını algılayarak büyük, küçük veya tuşların ikinci görevlerini kullanabilirsiniz. Ben papatya yayıncılığın sağladığı diziyi kullanmayı tercih ettim.

const unsigned char kucuk[67][2]={
{0x0d,0x7e},{0x0e,'"'},{0x15,'q'},{0x16,'1'},
{0x1a,'z'},{0x1b,'s'},{0x1c,'a'},{0x1d,'w'},
{0x1e,'2'},{0x21,'c'},{0x22,'x'},{0x23,'d'},
{0x24,'e'},{0x25,'4'},{0x26,'3'},{0x29,' '},
{0x2a,'v'},{0x2b,'f'},{0x2c,'t'},{0x2d,'r'},
{0x2e,'5'},{0x31,'n'},{0x32,'b'},{0x33,'h'},
{0x34,'g'},{0x35,'y'},{0x36,'6'},{0x39,','},
{0x3a,'m'},{0x3b,'j'},{0x3c,'u'},{0x3d,'7'},
{0x3e,'8'},{0x41,0xef},{0x42,'k'},{0x43,3},
{0x44,'o'},{0x45,'0'},{0x46,'9'},{0x49,7},
{0x4a,'.'},{0x4b,'l'},{0x4c,2},{0x4d,'p'},
{0x4e,'+'},{0x52,'i'},{0x54,5},{0x55,0x5f},
{0x5a,0xa3},{0x5b,0xf5},{0x5d,','},{0x61,''},
{0x69,'1'},{0x6b,'4'},{0x6c,'7'},{0x70,'0'},
{0x71,','},{0x72,'2'},{0x73,'5'},{0x74,'6'},
{0x75,'8'},{0x79,'+'},{0x7a,'3'},{0x7b,'-'},
{0x7c,'*'},{0x7d,'9'},{0,0}
};

Yukarıdaki gibi dizilerimizi de tanımladıktan sonra yapmamız gereken tek şey, bastığımız kodu bulmak, onun hangi diziden seçileceğini bulmak ve onu geri döndürmektir. Tüm bu işlemleri ise aşağıdaki C fonksiyonu yapmaktadır.

Klavye Kodunun Asci’sini Bulan Fonksiyon

unsigned char keyboard(void)
{
unsigned char data=0;
unsigned char shift=0, i;
 
data=get_byte();
while(get_byte()==0xF0);
 
if((data==0x12)||(data==0x59))          //Sağ ya da sol shifte mi basıldı
shift=!shift;               //Capslock gibi çalışacak

if(data==0x58)                  //Capslock'a basıldıysa
shift=!shift;
 
for(i=0;kucuk[i][0]!=data && kucuk[i][0]; i++); //Tuşun ascii karşılığı bulunuyor
 
if(kucuk[i][0]==data)               //Data ascii tablolarımızda var mı bakılıyor
{
if(shift==0)                //Capslock açık değilse küçük harf, açıksa büyük harfin ascii değeri geri gönderiliyor
return kucuk[i][1];
else
return buyuk[i][1];
}
}

Kütüphanemiz tamamlandıktan sonra sıra pic’imize kod yazmaya geliyor. Ben pic olarak dahili kristali nedeniyle 16f628a’yı tercih ettim. Çalışmama kendi 2×16 LCD kütüphanemi de ekledikten sonra main fonksiyonu aşağıdaki gibi şekil alıyor.

#include
#include "delay.h"
#include "lcd.h"
#include "keyboard.h"
 
__CONFIG( PROTECT & CPD & WDTDIS & INTIO & MCLRDIS & LVPDIS & BORDIS & PWRTDIS );
 
void main(void)
{
unsigned char i;
int j;
PORTB=0x00;
PORTA=0x00;
 
CMCON=0x07;
 
TRISA=0x03;
TRISB=0x00;

lcd_init();
lcd_komut(ImlecAltta);
 
for(;;)
{
i=keyboard();
j++;
 
if(j==17)
{
lcd_gotoxy(2,1);
}
else if(j==33)
{
lcd_clear();
lcd_gotoxy(1,1);
j=0;
}
veri_yolla(i);
}
}

Kendime ait LCD kütüphanem ise şöyle;

lcd.h Dosyası

/*                  www.FxDev.org
*               2x16 LCD Kullanım Klavuzu
* D4,D5,D6,D7 pinlerini kullanarak 4 bit iletişim kullanır.
* D4,D5,D6,D7 pinleri sırasıyla kullanılan portun 4.,5.,6. ve 7.
* RW/RS/EN pinleri ise sırasıyla kullanılan portun 0.,1. ve 2. pinlerine bağlanır.
* Cursor kapalıdır.
* RW kullanılmadığı için direk toprağa bağlanabilir.
*
* lcd_init(); ile LCD'nin ilk ayarlarını yap
* lcd_clear(); ile LCD'yi sil
* lcd_yaz("deneme"); şeklinde yazı yazdır.
* veri_yolla('F'); şeklinde tek ascii kodu yazdır.
* lcd_gotoxy(1,13); şeklinde LCD'nin istenilen yerine git.
*                   www.FxDev.org
*/
 
#define lcd_port  PORTB     //Pin tanımlamaları
 
/* LCD'de kullanilan komutlarin tanimlamasi*/
#define Sil          1      // Ekrani temizler
#define BasaDon      2      // Imleci sol üst köseye getirir
#define SolaYaz      4      // Imlecin belirttigi adres azalarak gider
#define SagaYaz      6      // Imlecin belirttigi adres artarak gider
#define ImlecGizle   12     // Göstergeyi ac, kursor görünmesin
#define ImlecAltta   14     // Yanip sönen blok kursor
#define ImlecYanSon  15     // Yanip sönen blok kursor
#define ImlecGeri    16     // Kursorü bir karakter geri kaydir
#define KaydirSaga   24     // Göstergeyi bir karakter saga kaydir
#define KaydirSola   28     // Göstergeyi bir karakter sola kaydir
#define EkraniKapat  8      // Göstergeyi kapat (veriler silinmez)
#define BirinciSatir 128    // LCD'nin ilk satir baslangic adresi
// (DDRAM adres)
#define IkinciSatir  192    // Ikinci satirin baslangic adresi
#define KarakUretAdres 64   // Karakter üreteci adresini belirle
// (CGRAM adres)
/* LCD'de Kullanilan Fonksiyon Seçimi */
#define CiftSatir8Bit  56    // 8 bit ara birim, 2 satir, 5*7 piksel
#define TekSatir8Bit   48    // 8 bit ara birim, 1 satir, 5*7 piksel
#define CiftSatir4Bit  40    // 4 bit ara birim, 2 satir, 5*7 piksel
#define TekSatir4Bit   32    // 4 bit ara birim, 1 satir, 5*7 piksel
 
extern void veri_yolla(unsigned char);
extern void lcd_clear(void);
extern void lcd_yaz(const char * s);
extern void lcd_gotoxy(unsigned char x, unsigned char y);
extern void lcd_init(void);
extern void lcd_komut(unsigned char c);

lcd.c Dosyası

#include
#include    "lcd.h"
#include    "delay.h"
 
void lcd_busy(void)
{
DelayUs(250);
}
 
void lcd_komut(unsigned char c)
{
unsigned char temp;
temp = 0x00;
temp |= 0x04;
lcd_port = temp;
temp |= ( c & 0xF0 );
lcd_port = temp;
temp &= 0xF0;
lcd_port = temp;
lcd_busy();
temp = 0x00;
temp |= 0x04;
lcd_port = temp;
temp |= ( (c & 0x0F)<<4 );
lcd_port = teap;
temp &= 0xF0;
lcd_port = temp;
lcd_busy();
}
 
void veri_yolla(unsigned char c)
{
unsigned char temp;
temp = 0x00;
temp |= 0x05;
lcd_port = temp;
temp |= ( c & 0xF0 );
lcd_port = temp;
temp &= 0xF1;
lcd_port = temp;
lcd_busy();
temp = 0x00;
temp |= 0x05;
lcd_port = temp;
temp |= ( (c & 0x0F)<<4 );
lcd_port = temp;
temp &= 0xF1;
lcd_port = temp;
lcd_busy();
}

void lcd_clear(void)
{
lcd_komut(0x1);
DelayMs(2);
}
 
void lcd_yaz(const char * s)
{
lcd_busy();
while(*s)
veri_yolla(*s++);
}
 
void lcd_gotoxy(unsigned char x,unsigned char y)
{
if(x==1)
lcd_komut(0x80+((y-1)%16));
else
lcd_komut(0xC0+((y-1)%16));
}
 
void lcd_init()
{
unsigned char temp=0;
 
temp &= 0xF0;
lcd_port=temp;
 
DelayMs(15);
lcd_komut(0x02);
lcd_busy();

lcd_komut(CiftSatir4Bit);
lcd_komut(SagaYaz);
lcd_komut(ImlecGizle);
lcd_clear();
lcd_komut(BirinciSatir);
}

Son olarak data hattını pic’in RA1, Clk hattını da RA0 bacağına bağlayıp, klavyenin enerjisini verip devreyi çalıştırdığımızda ekranda sadece altta duran imleci göreceksiniz, daha sonra klavyeden bastığınız her tuş ekrana küçük harf olarak yazılacaktır. Bir kez shift ya da caps lock’a basarsanız harflerin büyük hallerine ya da tuşların ikinci görevlerine ulaşabilirsiniz.

Test Görüntüsü

Keyboard.c ve Keyboard.h dosyaları: pic-ile-ps2-klavye-kullanimi

PicProje E-Dergi 2| Yazar: FxDev

Yayım tarihi: 2018/07/05 Etiketler: ,



Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir