Bir çok GLCD kütüphanesi bulunmakta ve bunları kendi uygulamalarımız içerisine dahil etmekte güçlük çekeriz.
http://en.radzio.dxp.pl/ks0108/
Üstteki linkte bulunan GLCD kütüphanesi kullanarak basit bir uygulama yapmak istiyorum.
Elimde hazır olarak bulunan bir kart var. Üzerindeki mcu PIC18F452. Kart eski ama böyle basit uygulamaları denemek için ideal. Hatta ilgili mcuda, epey fazla hata bulunmakta ve üreticisi tarafından başka mcular önerilmekte. Hata kayıtlarına ve diğer belgelerine alttaki linkten ulaşabilirsiniz, ancak bu konumuzla alakalı değil.
https://www.microchip.com/en-us/product/PIC18F452
GLCD ise; Winstar WG12864B-YYH-V8N. Piyasada kolayca bulunabilen KS0108 uyumlu bir grafik ekran.
Bu GLCD kütüphanesini seçmemin özel bir nedeni yok. Bir çok başka kütüphane var. Daha kapsamlı olanları var, ancak bunlar mcunun; hem FLASH alanını, hem de RAM alanını fazlaca kaplıyor.
Elimdeki kart hazır olunca buna uymak zorundaydım. Buna göre GLCD port tanımlamalarım alttaki gibi oldu. Bu tanımlamalar “KS0108-PIC16.c” dosyasının başında yer almaktadır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#define KS0108_DATA_PORT PORTD #define KS0108_DATA_DIR TRISD #define KS0108_DATA_PIN PORTD #define KS0108_CTRL_PORT PORTB #define KS0108_CTRL_DIR TRISB #define KS0108_RS (1 << 4) #define KS0108_RW (1 << 3) #define KS0108_EN (1 << 5) #define KS0108_CS1 (1 << 0) #define KS0108_CS2 (1 << 1) #define KS0108_CS3 (1 << 2) |
Bunun haricinde bu katta, iki adet ADC kullanılmış. Birine pot, diğerine de LM35 bağladım. Pot değeri ve ekran tazelemesi 200mS, sıcaklık okuması da 1000mS aralıklarla olmaktadır. Bunun bir kuralı yok, sadece ben bu şekilde olmasını istedim. Malum, ADC okuma kısıtlaması mcuya göre değişmekte. Zaten bu kadar sık okuma yapmayacağız bu uygulamada.
ADC yapılandırma fonksiyonunu; basit uygulamalarda ve test uygulamalarında genel bir yapılandırma kullanıyorum. Proje ciddileşirse; o zaman başka kısıtlamalar veya tanımlamalar yaparak, daha özel hale getirmeye çalışıyorum.
Burada A0 ve A1, ADC kanallarında okuma yapılıyor. ADC yapılandırma ve ADC kanal okuma fonksiyonu:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/*-------------------------------------------------*/ void initMcu(void) { //ADC yapılandırması ADCON0bits.ADCS = 0b11; // Frc //ADCON0bits.CHS = 0b000; // Okurken seçim yapılacak ADCON1bits.ADFM = 1; // Sağa yasla ADCON1bits.ADCS2 = 0b0; // Frc 2 ADCON1bits.PCFG = 0b0010; // C/R -> 5/0 } /*-------------------------------------------------*/ uint16_t adcOku(uint8_t kanal) { kanal = kanal > 7 ? 7 : kanal; ADCON0bits.CHS = kanal; ADCON0bits.ADON = 0b1; // ADC cevrimi başlat __delay_ms(1); ADCON0bits.GO_nDONE = 1; while(ADCON0bits.GO_nDONE); // Çevrim bitene kadar bekle ADCON0bits.ADON = 0b0; // ADC cevrimi kapalı // Bu mcuda ADC 10-bit, buna göre dönüş değeri 16-bit return(uint16_t) ((ADRESH << 8) + ADRESL); } |
Burada kritik bir durum yok. Kendi uygulamalarınızda basit değişiklikler ile daha konforlu hale getirebilirsiniz.
Ana fonksiyon ise aşağıdaki gibi:
1 2 3 4 5 6 7 8 9 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 |
/*-----------------------------------------------------------*/ void main(void) { double derecef; uint8_t d1, d2; uint16_t p1; uint8_t LM35_oku_sayac = 5; //200ms*5 = 1000mS 'de bir sıcaklık okunur unsigned char buf[22]; __delay_ms(1000); // PLL otuması için bekle initMcu(); GLCD_Initialize(); GLCD_ClearScreen(); GLCD_GoTo(0, 0); GLCD_WriteString((char *) "+-------------------+"); GLCD_GoTo(0, 1); GLCD_WriteString((char *) "| Universal |"); GLCD_GoTo(0, 2); GLCD_WriteString((char *) "| KS0108 library |"); GLCD_GoTo(0, 3); GLCD_WriteString((char *) "| Mehmet Bilgi |"); GLCD_GoTo(0, 4); GLCD_WriteString((char *) "| en.radzio.dxp.pl |"); GLCD_GoTo(0, 5); GLCD_WriteString((char *) "| PIC18F452 |"); GLCD_GoTo(0, 6); GLCD_WriteString((char *) "| microcontrollers |"); GLCD_GoTo(0, 7); GLCD_WriteString((char *) "+-------------------+"); __delay_ms(3000); GLCD_ClearScreen(); GLCD_Rectangle(0, 0, 127, 63); GLCD_Rectangle(2, 2, 123, 59); while(1) { //Sıcaklık ekranda çok hızlı değişim göstermemesi için 1000ms de bir okunuyor if(++LM35_oku_sayac >= 5) { derecef = adcOku(0) * 500.0 / 1023.0; d1 = (uint8_t) (derecef); d2 = (uint8_t) ((derecef - d1) * 100); LM35_oku_sayac = 0; } p1 = adcOku(1); strcpy(string1, itoa_strudel((int) d1, (char *) buf, 10)); strcat(string1, "."); strcat(string1, itoa_strudel((int) d2, (char *) buf, 10)); GLCD_GoTo(5, 1); strcpy(string2, "Ortam S\x82"); strcat(string2, "cakl\x82\x84\x82:"); GLCD_WriteString((char *) string2); GLCD_GoTo(5, 2); // 0123456789012345678 strcpy(string3, " "); GLCD_WriteString(string3); GLCD_GoTo(5, 2); strcat(string1, (char *) "\x80"); //° sembolünü 128. karakterde tanımladım. strcat(string1, (char *) "C."); GLCD_WriteString(string1); GLCD_GoTo(5, 3); //Türkçe ve Özel karakterler (font5x8.h dosyasından düzenlenebilir.) strcpy(string2, "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90"); GLCD_WriteString(string2); GLCD_GoTo(5, 4); strcpy(string2, "Pot de\x84"); strcat(string2, "eri:"); GLCD_WriteString((char *) string2); GLCD_GoTo(5, 5); // 0123456789012345678 strcpy(string3, " "); GLCD_WriteString(string3); GLCD_GoTo(5, 5); strcpy(string1, itoa_strudel((int) p1, (char *) buf, 10)); GLCD_WriteString(string1); __delay_ms(200); } } |
Sayıların ekrana belli formatlarda basılmasını sağlamak için; C içerisinde bir kaç kütüphane ve bunların fonksiyonları bulunmakta. Özellikle “sprintf” kullanıldığında; FLASH alanda çok fazla yer kaplamakta. Alttaki linkte bulunan “itoa” fonksiyonu bu konuda çok kolaylık sağladı.
http://www.strudel.org.uk/itoa/
Fonksiyon ise:
1 2 3 4 5 6 7 8 9 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 |
/** * C++ version 0.4 char* style "itoa": * Written by Lukás Chmela * Released under GPLv3. * http://www.strudel.org.uk/itoa/ * * char *itoa_strudel(int value, char *result, int base) * */ char *itoa_strudel(int value, char *result, int taban) //"base" kelimesi özel kelime olduğundan "taban" olarak değiştirdim { // check that the base if valid if(taban < 2 || taban > 36) { *result = '\0'; return result; } char* ptr = result, *ptr1 = result, tmp_char; int tmp_value; do { tmp_value = value; value /= taban; *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * taban)]; } while(value); // Apply negative sign if(tmp_value < 0) *ptr++ = '-'; *ptr-- = '\0'; while(ptr1 < ptr) { tmp_char = *ptr; *ptr-- = *ptr1; *ptr1++ = tmp_char; } return result; } |
Normalde fonksiyon bu şekilde tanımlanmış: “char *itoa_strudel(int value, char *result, int base)”. Ancak “base” tanımlaması XC8 içerisinde özel bir kelime olduğu için; sadece uyarı verip, hatalı yerlerin altını kırmızı ile çiziyor. Ama sorunsuz derleniyor ve çalışıyor. Bu durum gözüme takılmaması için “base” kelimesini “taban” kelimesi ile değiştirdim.
Daha önceden yaptığım başka projelerden alıntı yaptığım için; yapılandırma içinde PLL kullanılmış. Kart üzerinde 10MHz lik bir kristal mcuya bağlı. Yapılandırma dosyası(config.h) içerisinden size uygun olan hız ve diğer değişiklikler yapılabilir.
Türkçe ve bazı özel karakterler için font5x8.h dosyasına ilaveler yaptım. Siz de kendinize gerekli olan karakterler için istediğiniz değişikliği yapabilirsiniz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
0x00, 0x06, 0x09, 0x09, 0x06, // ° \x80 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, //dolgu \x81 0x00, 0x44, 0x7C, 0x40, 0x00, // ı \x82 0x00, 0x44, 0x7D, 0x44, 0x00, // İ \x83 0x08, 0x15, 0x56, 0x56, 0x3D, // ğ \x84 0x3c, 0x43, 0x42, 0x53, 0x34, // Ğ \x85 0x3D, 0x40, 0x40, 0x20, 0x7D, // ü \x86 0x3D, 0x40, 0x40, 0x40, 0x3D, // Ü \x87 0x48, 0x54, 0xD4, 0x54, 0x20, // ş \x88 0x46, 0x49, 0xC9, 0x49, 0x31, // Ş \x89 0x38, 0x45, 0x44, 0x45, 0x38, // ö \x8A 0x3C, 0x43, 0x42, 0x43, 0x3C, // Ö \x8B 0x38, 0x44, 0xC4, 0x44, 0x20, // ç \x8C 0x3E, 0x41, 0xC1, 0x41, 0x22, // Ç \x8D |
GLCD_WriteString() fonksiyonu içerisinde gönderilen yazı; GLCD_WriteString() fonksiyonu içerisinde basılacak font seçimi yaparak, GLCD_WriteData() fonksiyonu ile ekrana basılmasını sağlamakta. Bu uygulamada 5×8 piksel fontlar kullanılmıştır. Farklı fontları ve farklı piksel boyutlarını basabilmek mümkün. Yukarıda bahsettiğim fontXXX.h dosyasında ve GLCD_WriteString(), vb. fonksiyonlarda değişiklik yapmak gerekmekte.
Ayrıca bu GLCD kütüphanesinde 128×64 tek renk resimleri ve/veya şekilleri gösterebilecek fonksiyonlarda bulunmakta. Bunlarla ilgili olan dosya da “bitmap.h”.
Uygulamanın videosu ve proje dosyaları ektedir.
Proje dosyaları: