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
&
lt
;
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ı: