Merhaba arkadaşlar, KS108 için driver yazıyorum. Lcd'de doğru çizen ve istediğim piksele nokta koyan fonksiyon yazmak istiyorum.
Nasıl yapabileceğim konusunda yardımcı olabilirmisiniz ? Bu konuda örnek var mı ?
Doğru çizmek için Bresenham algoritması kullanabilirsin.
http://tr.wikipedia.org/w/index.php?title=Bresenham%27%C4%B1n_%C3%A7izgi_algoritmas%C4%B1&oldid=1761138 (http://tr.wikipedia.org/wiki/Bresenham%27%C4%B1n_%C3%A7izgi_algoritmas%C4%B1)
adresinde algoritmanın detaylarını bulabilirsin.
Aşağıda da Picc ile yapılmış örnek var.
glcd_pixel() fonksiyonunu yazarsan bunu aynen bu şekilde kullanabilirsin.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
// Purpose: Draw a line on a graphic LCD using Bresenham's
// line drawing algorithm
// Inputs: (x1, y1) - the start coordinate
// (x2, y2) - the end coordinate
// color - ON or OFF
// Dependencies: glcd_pixel()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
void glcd_line(int x1, int y1, int x2, int y2, int1 color)
{
signed int x, y, addx, addy, dx, dy;
signed long P;
int i;
dx = abs((signed int)(x2 - x1));
dy = abs((signed int)(y2 - y1));
x = x1;
y = y1;
if(x1 > x2)
addx = -1;
else
addx = 1;
if(y1 > y2)
addy = -1;
else
addy = 1;
if(dx >= dy)
{
P = 2*dy - dx;
for(i=0; i<=dx; ++i)
{
glcd_pixel(x, y, color);
if(P < 0)
{
P += 2*dy;
x += addx;
}
else
{
P += 2*dy - 2*dx;
x += addx;
y += addy;
}
}
}
else
{
P = 2*dx - dy;
for(i=0; i<=dy; ++i)
{
glcd_pixel(x, y, color);
if(P < 0)
{
P += 2*dx;
y += addy;
}
else
{
P += 2*dx - 2*dy;
x += addx;
y += addy;
}
}
}
}
İlginiz için teşekkür ederim.
İstediğimiz X,Page piksel'ine ekrandaki görüntü üzerinden nasıl nokta koyabilirim?
Grafik LCD'nin RAM'ini belleğe kopyalayıp ( 1024 byte ) grafiksel bütün işlemleri bellekte yapsam ve grafik lcd'ye geri yazsam bu yöntem nasıl olur.
Ayrıca yatay ve dikey çizgileri nasıl çizebilirim. Yukarıdaki algoritmayı kullanmadan
Alıntı yapılan: "fatihvelid"Grafik LCD'nin RAM'ini belleğe kopyalayıp ( 1024 byte ) grafiksel bütün işlemleri bellekte yapsam ve grafik lcd'ye geri yazsam bu yöntem nasıl olur.
Ayrıca yatay ve dikey çizgileri nasıl çizebilirim. Yukarıdaki algoritmayı kullanmadan
Her seferinde 1024 byte veriyi LCD ye göndereceksen pek mantıklı değil gibi geldi bana. Sadece değişenleri göndereceksen olabilir ancak çarpışma testi vs yapmayacaksan neden RAM e kopyalamaya ihtiyacın olsun ki.
Yatay veya dikey çizgi çekmek kolay.
Yatay çizgi için
örneğin başlangıç koordinatları x1,y1 bitiş koordinatları x2,y2 olsun zaten y1 ve y2 eşit olmak zorunda bir döngü kuracaksın x1 den x2 ye kadar
for(i=x1; i<=x2; ++i)
{
glcd_pixel(i, y1, color);
}
diyeceksin burada x1 x2 den küçük olmalı. Değilse sıralarını değiştirirsin.
dikey çizgi çekmek içinse
for(i=y1; i<=y2; ++i)
{
glcd_pixel(x1, y, color);
}
diyeceksin. Burada da y1 < y2 olmalı.
@fatihvelid
GLCD'de 2 tane KS0108 var.
Her chip 8 sayfa,64 sutun'u kontrol eder.
Dolayısıyla 2 tanesi 8 sayfa,128 sutun'u kontrol eder.
Herhangi bir pixel'i yakmak istiyorsan, önce ilgili işlemciyi seçeceksin
sonra pixel sangi sayfadaysa, sayfa kodunu göndereceksin, pixel hangi sutundaysa sutun kodunu göndereceksin, ve son olarak pixel, hangi bit ise
onu 1 yapacaksın diğer 7 bit 0 olacak.
Sayfa ve sutun kodları nedir ve nasıldır diyorsan, GLCD'nin datasheet'ini incele. İçinde ks0108 bulunan tüm datashetlerden faydalanabilirsin.
Glcd'nin bacak bağlantıları dışında farklılık olmaz.
Kolay gelsin.
Alıntı yapılan: "fatihvelid"İlginiz için teşekkür ederim.
İstediğimiz X,Page piksel'ine ekrandaki görüntü üzerinden nasıl nokta koyabilirim?
GLCD'ler decimal 184 başlayıp 191 de biter ve toplam 8 sayfadır. senin yapacağın GLCD sayfa bilgisini gönderip daha sonra hangi pixel aftif olmasını istiyorsan hangi bölgede ise onun cipini on yapıp daha sonra pixel değerini gönderiyorsun.
İlk çalıştırdığımda çok kısa süre için ekran gidip geliyor. Nedendir acaba.
Ayrıca GLCD'nin RAM'ini okurken bir sorunla karşılaşıyorum. Okumuyor ve hep 0 dönüyor sanırım. Yazdığım kod aşağıda. Bir hata mı var?
BYTE GlcdRead(CS _cs)
{
BYTE Data;
if(_cs == CS2)
GLCD_CS2 = TRUE;
else
GLCD_CS1 = TRUE;
GLCD_Data_TRIS = 0xFF;
GLCD_RW = 1;
GLCD_E = 1;
Delay1KTCYx(1);
GLCD_E = 0;
Delay1KTCYx(1);
GLCD_E = 1;
Delay1KTCYx(1);
Data = GLCD_Data_PORT;
GLCD_E = 0;
GLCD_CS1 = FALSE;
GLCD_CS2 = FALSE;
GLCD_Data_TRIS = 0x00;
GLCD_RW = 0;
return Data;
}
CCS bilmediğim için vereceğim fikir belki işine yarar; KS0108 GLCD okurken dikkat etmen gereken kısım lcd ekran iki ayrı çipten oluştuğu için ilk önce birinci chip aktif yapıp okuyacaksın sonra ise birinci chip off yapıp ikinci chip okuyacaksın
CCS kullanmıyorum. Programı C18 ile geliştiriyorum.Kendi oluşturduğum yapıları kullanıyorum.
Yukarıdaki programda, BYTE GlcdRead(CS _cs) fonksiyonunu çağırmadan önce PAGE ve X eksenini ayarlıyor. Ve ardından CS'lerden sadece birisini aktif yapıyor.
RW = 1 olduğunda E'nin düşen kenarında veriyi almaya çalışıyor.
Okuma ve yazmada bilmen gereken en önemli noktalar şunlar
1) GLCD'ye Yazma yapacaksan E'nin düşen kenarında yazılır
GLCD'den bir data okuyacaksan E=1 iken okunur
2) Data okuyacakken veya yazacakken LCD meşgul mu değilmi bilmelisin yani ilk önce busy flag okunur.
Kolay gelsin
Alıntı yapılan: "eemkutay"Okuma ve yazmada bilmen gereken en önemli noktalar şunlar
1) GLCD'ye Yazma yapacaksan E'nin düşen kenarında yazılır
GLCD'den bir data okuyacaksan E=1 iken okunur
2) Data okuyacakken veya yazacakken LCD meşgul mu değilmi bilmelisin yani ilk önce busy flag okunur.
Kolay gelsin
Busy Flag'ı nasıl okuyabilirim. Ve işlemler arasına ne kadar gecikme koymam gerekiyor.
Aşağıdaki kod'da sorun olmasa gerek.
BYTE GlcdRead(CS _cs)
{
BYTE Data;
if(_cs == CS2)
GLCD_CS2 = TRUE;
else
GLCD_CS1 = TRUE;
GLCD_Data_TRIS = 0xFF;
GLCD_RW = 1;
GLCD_E = 1;
Delay1KTCYx(1);
GLCD_E = 0;
Delay1KTCYx(1);
GLCD_E = 1;
Delay1KTCYx(1);
Data = GLCD_Data_PORT;
GLCD_E = 0;
GLCD_CS1 = FALSE;
GLCD_CS2 = FALSE;
GLCD_Data_TRIS = 0x00;
GLCD_RW = 0;
return Data;
}
Kolay Gelsin
Karakter LCD'deki gibi araya delay koyarak bu iş çözülmez. Çünkü GLCD üreticisi, "GLCD'nin işlemleri şu kadar zaman alır " gibi kesin bilgiler vermiyorlar dolayısıyla glcd içindeki status registerinin 7 biti busy flag'dir. Bu flag kontrol edilir. Busy flag 0 ise data yazabilir veya okuyabilirsin.
Arada gereksiz enable'ların vardı kaldırdım
// Bu kod data okumak içindir status'u okumaz, statusu okumak için
// diğer kısımları kullanmalısın ( // ile yazdığım)
BYTE GlcdRead(CS _cs)
{
BYTE Data;
if(_cs == CS2)
GLCD_CS2 = TRUE;
else
GLCD_CS1 = TRUE;
// GLCD_RS=0; // busy için
GLCD_RS=1;
GLCD_RW = 1;
GLCD_E=1;
GLCD_Data_TRIS = 0xFF; // hem port ayarlıyorum hemde delay oluy.
// oku:
Data = GLCD_Data_PORT;
// if(Data&&0x80) // 7.bit testi yapıyoruz
// goto oku; // LCD meşgul
GLCD_E = 0;
GLCD_CS1 = FALSE;
GLCD_CS2 = FALSE;
GLCD_Data_TRIS = 0x00;
GLCD_RW = 0;
return Data;
}
Alıntı yapılan: "eemkutay"
// Bu kod data okumak içindir status'u okumaz, statusu okumak için
// diğer kısımları kullanmalısın ( // ile yazdığım)
BYTE GlcdRead(CS _cs)
{
BYTE Data;
if(_cs == CS2)
GLCD_CS2 = TRUE;
else
GLCD_CS1 = TRUE;
// GLCD_RS=0; // busy için
GLCD_RS=1;
GLCD_RW = 1;
GLCD_E=1;
GLCD_Data_TRIS = 0xFF; // hem port ayarlıyorum hemde delay oluy.
// oku:
Data = GLCD_Data_PORT;
// if(Data&&0x80) // 7.bit testi yapıyoruz
// goto oku; // LCD meşgul
GLCD_E = 0;
GLCD_CS1 = FALSE;
GLCD_CS2 = FALSE;
GLCD_Data_TRIS = 0x00;
GLCD_RW = 0;
return Data;
}
Düzenleyip aşağıdaki hale getirdim. Ama yine biryerlerde sorun var. PIC 40 MHZ'de çalışıyor. Hızdan kaynaklanan bir sorun olabilir mi ?
Yanlışım varsa düzeltirmisiniz ?
Alıntı Yap
BYTE GlcdRead(CS _cs)
{
BYTE Data;
if(_cs == CS2)
GLCD_CS2 = TRUE;
else
GLCD_CS1 = TRUE;
GLCD_RW = 1;
GLCD_DI = 1;
GLCD_E=1;
GLCD_Data_TRIS = 0xFF; // hem port ayarlıyorum hemde delay oluy.
Glcd_Wait_Busy();
_asm
nop
nop
nop
nop
nop
_endasm
Data = GLCD_Data_PORT;
GLCD_E = 0;
GLCD_CS1 = FALSE;
GLCD_CS2 = FALSE;
return Data;
}
void Glcd_Wait_Busy(void)
{
BYTE status;
GLCD_DI = 0;
GLCD_RW = 0;
GLCD_Data_TRIS = 0xff;
_asm
nop
nop
nop
_endasm
while(1)
{
GLCD_E = 1;
_asm
nop
nop
nop
_endasm
status = GLCD_Data_PORT;
if ((status & 0x80) == 0)
break;
_asm
nop
nop
nop
_endasm
}
GLCD_Data_TRIS = 0x00;
GLCD_RW = 0;
}
İlgileriniz için teşekkürler. Kolaya gelsin
Alıntı Yap
BYTE GlcdRead(CS _cs)
{
BYTE Data;
if(_cs == CS2)
GLCD_CS2 = TRUE;
else
GLCD_CS1 = TRUE;
GLCD_RW = 1;
GLCD_DI = 1;
GLCD_E=1;
GLCD_Data_TRIS = 0xFF; // hem port ayarlıyorum hemde delay oluy.
Glcd_Wait_Busy();
_asm
nop
nop
nop
nop
nop
_endasm
Data = GLCD_Data_PORT;
GLCD_E = 0;
GLCD_CS1 = FALSE;
GLCD_CS2 = FALSE;
return Data;
}
void Glcd_Wait_Busy(void)
{
BYTE status;
GLCD_DI = 0;
GLCD_RW = 0;
GLCD_Data_TRIS = 0xff;
_asm
nop
nop
nop
_endasm
while(1)
{
GLCD_E = 1;
_asm
nop
nop
nop
_endasm
status = GLCD_Data_PORT;
if ((status & 0x80) == 0)
break;
_asm
nop
nop
nop
_endasm
}
GLCD_Data_TRIS = 0x00;
GLCD_RW = 0;
}
İlgileriniz için teşekkürler. Kolaya gelsin[/quote]
Elindeki Glcd'nin datasheet'in deki zamanlama tablosunu ve diyagramını incelemelisin. 40Mhz çok yüksek hız, bir komut 100ns , programda hatalar var ve zamanlama problemin olmaması için dediğim gibi zaman haberleşme diyagramını incele , benim kullandığım glcd, hy12864 ve clock puls'i en az 450ns diyor ve ben 20mhz'de 3 tane nop atıyorum (600ns) herşey ok.
Zamanlama diyagramındaki zamanlardan biraz daha yavaş çalıştırırsan , sorun olmayacaktır.
Programında hatalar var, busy test fonksiyonun kullanım yeri hatalı,
ilk önce busy testi yapılır sonra read işlemi yapılır, aşağıdaki gibi
Glcd_Wait_Busy(); // lcd meşgul mu? meşgul değilse aşağı satıra geçer
Glcd_Read(1); // Daha önce girdiğin adresi 1. chip'ten okur
// read programında hata vardı düzeltildi, aşağıdaki gibi olacak ama yine
// datasheet'ten zamanlamaları kontrol etmelisin bu nedenle nop'lara
// dokunmadım
BYTE GlcdRead(CS _cs)
{
BYTE Data;
if(_cs == CS2)
GLCD_CS2 = TRUE;
else
GLCD_CS1 = TRUE;
GLCD_RW = 1; // datasheet'e göre bu seviye aralarına
GLCD_DI = 1; // nop'lar gerekebilir
GLCD_E=1;
GLCD_Data_TRIS = 0xFF; // hem port ayarlıyorum hemde delay oluy.
_asm
nop
nop
nop // en az nop için dahasheet'e bakmalısın
nop
nop
_endasm
Data = GLCD_Data_PORT;
GLCD_E = 0;
GLCD_CS1 = FALSE;
GLCD_CS2 = FALSE;
return Data;
}
// burada her iki chip busy mi test ediliyor istersen adrese göre
// yapabilirsin
void Glcd_Wait_Busy(void)
{
GLCD_CS1=1; //1.chip on, diğeri zaten off
busy_test( ); // busy flag=0 oluncaya kadar bekle
GLCD_CS1=0;
GLCD_CS2=1; //2.chip on, diğeri off
busy_test( ); // busy flag=0 oluncaya kadar bekle
}
// tek chip busy mi test ediyor
void busy_test(void)
{
BYTE status;
GLCD_DI = 0; // komut modu
GLCD_RW = 1; // okuma modu
GLCD_E = 1; // data okuyacağız, E=1
GLCD_Data_TRIS = 0xFF; // portlar giriş
_asm
nop
nop
nop
_endasm
while(1)
{
_asm
nop
nop
nop
_endasm
status = GLCD_Data_PORT; // portu oku
if (status & 0x80) // busy flag =0 ise çık
break;
_asm
nop
nop
nop
_endasm
}
GLCD_Data_TRIS = 0x00; // port çıkış
GLCD_E = 0; // E=0
}
Teşekkür ederim.
Lcd'de resim göstermek istiyorum. Fonksiyonuda yazdım. Resmi gösterdiğimde bazen resmin bir kısmı aşağı kayıyor. Bazende doğru gösteriyor.
Bir türlü çözemedim. Algoritmada bir hata olmadığına eminim. Bir bakabilirmisiniz ?
Alıntı Yap
void Glcd_Image(rom unsigned char *image)
{
BYTE x=0,y=0;
auto unsigned int i=0;
while(1)
{
GLCD_DI = 0;
_asm nop nop nop nop nop
_endasm
GlcdWrite(CS1,0x40);
GlcdWrite(CS1,0xB8 | y);
GLCD_DI = 1;
for(x=0;x<=63;x++,i++)
GlcdWrite(CS1,image);
GLCD_DI = 0;
GlcdWrite(CS2,0x40);
GlcdWrite(CS2,0xB8 | y);
_asm nop nop nop nop nop
_endasm
GLCD_DI = 1;
for(x=0;x<=63;x++,i++)
GlcdWrite(CS2,image);
if(i>1023)
break;
y++;
}
}
GLCD'ye data yazmayı ve okumayı başardın, bundan sonrası kolay ve gerisi sana kalmış.
Resimleri I2C 400Khz'de haberleşebilen eeprom'a yüklüyorum. Oradan 380Khz civarında bir hızla okuyorum ve ekrana yazdırıyorum. 32KB'lık bir eeproma 32 adet 128x64'lük full ekran yüklenebiliyor. Ayrıca karakter tablosunu da resim olarak gösteriyorum ve karaktere göre eepromda adres gösterip okutturuyorum. Böylece işlemcinin hafızasını gereksiz kodlarla doldurmuyorum.
Kolay gelsin.
Sorunları çözdüm. Yardımlarınız için teşekkürler.
PIC18F8722'nin flash kapasitesi 128kb olduğu için eeproma kaydetmeye gerek olmaz. Zaten birkaç tane resim kaydedeceğim.
C için istediğimiz fontu üreten bildiğiniz ücretsiz program var mı ?
Tekrar teşekkürler.