Proteus simülasyonu

 

Standart HD44780 sürücülü LCD’ler, Türkçe karakterlere destek vermezler. Ancak bize kendi karakter setlerine ilave olarak 8 adet karakter tanımlama imkanı verirler. Bu yazıda MSP430G2231 denetleyicisi kullanarak LCD ile bağlantı kuracağız, ve LCD’ye tanımladığımız Türkçe karakterleri gönderip, daha sonra bunları ekranda bastıracağız. Bunu yaparken şu yazımda hazırladığımız LCD kütüphanesine bazı eklemeler yaparak, Türkçe karakterleri tüm uygulamalarımızda kullanabileceğiz.

LCD’de bir karakter için 5 sütun, 8 satırlık alan bulunuyor. Ancak en alt satır imleç için ayrılmış durumda. Bu yüzden karakterlerimizi tasarlarken 5×7 boyutuna sığacak şekilde tanımlamalıyız. Aşağıdaki şekilde ‘b’ karakteri için datasheette (sayfa 15) verilmiş olan tasarımı görebilirsiniz.

'b' karakteri

‘b’ karakteri

Biz de karakterlerimizi bu şekilde tasarlayacağız. Yanmasını istediğimiz yerler için 1, sönmesini istediğimiz yerler için 0’lardan oluşan verileri LCD’nin CGRAM’ine göndereceğiz. Daha sonra bunları çağırarak ekrana bastırmış olacağız.

Öncelikle Türkçe karakterlerimizi belirleyelim :
ı, ğ, Ğ, ü, Ü, ş, Ş, İ, ö, Ö, ç, Ç
olmak üzere 12 farklı karakterimiz var. Ancak LCD bizim 8 karakter oluşturmamıza imkan sağlıyor. Bu yüzden bunların sayısınız 8’e indirmemiz gerekiyor. Şöyle bir yol izledim : ç – Ç, ş – Ş, ü – Ü, ö – Ö harflerinin yazılışları benzer olduğundan bu harflerin büyük – küçük halleri için tek karakter tanımladım. Geriye kalan ı, İ, ğ, Ğ için de birer karakter tanımladım. Böylece toplam 8 farklı karakter elde ettim.

Aşağıda ‘ş’ karakteri için nasıl bir tanımlama yolu izlediğimi görebilirsiniz. Görsel açıdan kolaylık olsun diye MS Excel programından faydalandım.

Adsiz12

‘ş’ karakteri

Karakterlerimizi bu şekilde tanımladıktan sonra elimizde 8 adet karakter için toplam 64 tane integer değer olacak.

Gelelim bu karakterleri LCD’ye nasıl tanıtacağımıza. Bildiğimiz gibi LCD’ye komut veya veri gönderebiliyorduk. HD44780, bizim eklediğimiz karakterleri 64 adresinden itibaren eklememize izin veriyor. O zaman LCD’ye karakterlerimizi tanıtmak için tek yapmamız gereken önce komut olarak 64 göndermek, ki bu şekilde CGRAM’in 64. adresine gitmiş olacağız, daha sonra 8 karakter için oluşturduğumuz 64 integeri ardarda veri olarak göndermek. Aşağıda Türkçe karakterleri LCD’ye tanıtan fonksiyonu görüyorsunuz. Aslında bu işi tek tek göndermek yerine bir dizi oluşturup döngüyle göndermek daha mantıklı, ancak MSP430G2231’in hafızası yetmediği için bu yönteme başvurmak zorunda kaldım.

void lcdTurkceKarakter(void)
{
/*int karakterler[8][8] = {
{0, 14, 16, 14, 1, 30, 4, 0},     // Ş - ş
{0, 14, 17, 16, 17, 14, 4, 0},    // Ç - ç
{0, 0, 12, 4, 4, 4, 14, 0},       // ı
{4, 0, 14, 4, 4, 4, 14, 0},       // İ
{0, 10, 0, 17, 17, 17, 14, 0},    // Ü - ü
{10, 0, 14, 17, 17, 17, 14, 0},   // Ö - ö
{14, 0, 14, 18, 14, 2, 28, 0},    // ğ
{14, 0, 14, 16, 22, 18, 14, 0}};  // Ğ*/
 
// Türkçe karakter atamayı üstteki dizi ile yapacaktım, fakat MSP430'un hafızası yetmediği için verileri tek tek gönderdim. 🙂
 
  lcdGonder('k', 64);   // Bellekte 64 adresinden itibaren,
  lcdGonder('v', 0);    // 1. harfin başlangıcı (8 veri)
  lcdGonder('v', 14);
  lcdGonder('v', 16);
  lcdGonder('v', 14);
  lcdGonder('v', 1);
  lcdGonder('v', 30);
  lcdGonder('v', 4);
  lcdGonder('v', 0);    // 1. harfin sonu
  lcdGonder('v', 0);    // 2. harfin başlangıcı...
  lcdGonder('v', 14);
  lcdGonder('v', 17);
  lcdGonder('v', 16);
  lcdGonder('v', 17);
  lcdGonder('v', 14);
  lcdGonder('v', 4);
  lcdGonder('v', 0);
  lcdGonder('v', 0);
  lcdGonder('v', 0);
  lcdGonder('v', 12);
  lcdGonder('v', 4);
  lcdGonder('v', 4);
  lcdGonder('v', 4);
  lcdGonder('v', 14);
  lcdGonder('v', 0);
  lcdGonder('v', 4);
  lcdGonder('v', 0);
  lcdGonder('v', 14);
  lcdGonder('v', 4);
  lcdGonder('v', 4);
  lcdGonder('v', 4);
  lcdGonder('v', 14);
  lcdGonder('v', 0);
  lcdGonder('v', 0);
  lcdGonder('v', 10);
  lcdGonder('v', 0);
  lcdGonder('v', 17);
  lcdGonder('v', 17);
  lcdGonder('v', 17);
  lcdGonder('v', 14);
  lcdGonder('v', 0);
  lcdGonder('v', 10);
  lcdGonder('v', 0);
  lcdGonder('v', 14);
  lcdGonder('v', 17);
  lcdGonder('v', 17);
  lcdGonder('v', 17);
  lcdGonder('v', 14);
  lcdGonder('v', 0);
  lcdGonder('v', 14);
  lcdGonder('v', 0);
  lcdGonder('v', 14);
  lcdGonder('v', 18);
  lcdGonder('v', 14);
  lcdGonder('v', 2);
  lcdGonder('v', 28);
  lcdGonder('v', 0);
  lcdGonder('v', 14);
  lcdGonder('v', 0);
  lcdGonder('v', 14);
  lcdGonder('v', 16);
  lcdGonder('v', 22);
  lcdGonder('v', 18);
  lcdGonder('v', 14);
  lcdGonder('v', 0);
}

Bu fonksiyonu kütüphane dosyamda “lcdGonder” ve “lcdHazirla” fonksiyonlarımın arasına ekliyorum. Yer önemli. Çünkü bu fonksiyonumda lcdGonder kullanılıyor, bu yüzden lcdGonder’in altında olmalı. lcdHazirla fonksiyonunda da bu fonksiyonu çağıracağımız için bu fonksiyonun da tanımlı olması açısından lcdHazirla’nın üstünde olmalı. C, satır satır işlenen bir dil olduğu için böyle bir şey yapmamız gerekiyor. Tabii en üstte fonksiyon prototiplerini tanımlasaydık bu yerleştirme işlemine gerek kalmayabilirdi.

Fonksiyonumuzu oluşturduk. Şimdi LCD hazırlanırken bu fonksiyonu çağıracağız, böylece karakterlerimizi LCD’ye tanıtmış olacağız. O zaman lcdHazirla fonksiyonumuzun sonuna küçük bir ekleme yapıyoruz ve şu hali alıyor :

void lcdHazirla(void)
{
  lcdBekle(15);                   // Bir süre beklendi.
  lcdGonder('k', 0x02);           // "00000010" yani imleç en başa gidecek.
  lcdGonder('k', 0x28);           // "00101000" yani 4 pin, 2 satır, 5x7 karakter kullanılacak.
  lcdGonder('k', 0x0C);           // "00001000" yani imleç gizlenecek.
  lcdGonder('k', 0x06);           // "00000110" yani imleç yazılan her karakterden sonra sağa doğru kayacak.
  lcdGonder('k', 0x01);           // "00000001" yani LCD temizlenecek.
  lcdBekle(10);                   // Bir süre beklendi.
 
  lcdTurkceKarakter();            // LCD'ye Türkçe karakterlerimizi gönderiyoruz.
}

Artık LCD’de Türkçe karakterlerimizi bastırabiliriz. O zaman hızlıca karakter bastırma olayını inceleyelim. Uluslararası karakterlerin belirli ASCII kodları vardır. Örneğin biz karakter olarak ‘A’ kullanırız, ama mikrodenetleyici onu arkaplanda 65 sayısına dönüştürerek işlem yapar. ASCII karakterleri standart olduğu için şöyle bir sırada işler ilerler :

Yine ‘A’ karakterini ele alalım. Biz ‘A’ karakterini kullandığımızda mikrodenetleyici onu 1 ve 0’lardan oluşan 65 sayısına dönüştürür. Oluşan bu “1000001” bitlerini LCD’ye gönderir. LCD bunu alır ve artık LCD’nin elinde 65 verisi vardır. LCD karakter setine bakar, 65’in karşılığı ne diye. Bu da ‘A’ karakteridir. ASCII standardında olaylar böyle gelişir. Aşağıda LCD’nin karakter setini göreceksiniz (datasheet sayfa : 17).

LCD karakter seti

LCD karakter seti

İşte bizim oluşturduğumuz karakterler sol üstten (CGRAM(1) yazan yerden) başlayarak 8 satırlık yere yerleşiyor. Bu tabloya göre ‘A’ karakterine bakarsanız “01000001” yani 65 adresinde olduğunu göreceksiniz. Bizim karakterlerimiz de bu durumda 0 ile 7 arasına yerleşecek. Yani örneğin LCD’ye veri olarak integer 0 gönderdiğimizde ‘Ş’ karakterini göreceğiz.

Metnimizin içindeki Türkçe karakterleri görüntüleyebilmek için de “lcdYaziYaz” fonksiyonumuzda bir değişiklik yapalım. Böylece ana programda uğraşmadan kütüphane dosyamızda olayı bitireceğiz. Bir switch – case yapısı koyacağım. Bastırılacak karakter Türkçe karakterlerden biriyse ona uygun veriyi gönderecek. Değilse, zaten eski halindeki gibi karakterin ASCII kodunu göndermeye devam edecek. Yeni lcdYaziYaz fonksiyonumuz aşağıdaki gibi oluyor :

void lcdYaziYaz (char* yazi)      // Bir string bastırmak için fonksiyon.
{
  lcdBekle(1);                    // Bir süre beklendi.
  int i = 0;
  while(yazi[i])                  // Yazının sonuna gelene kadar,
  {
    switch(yazi[i])
    {
    case 'ş':
      lcdGonder('v', 0);
      i++;
      break;
    case 'Ş':
      lcdGonder('v', 0);
      i++;
      break;
    case 'ç':
      lcdGonder('v', 1);
      i++;
      break;
    case 'Ç':
      lcdGonder('v', 1);
      i++;
      break;
    case 'ı':
      lcdGonder('v', 2);
      i++;
      break;
    case 'İ':
      lcdGonder('v', 3);
      i++;
      break;
    case 'ü':
      lcdGonder('v', 4);
      i++;
      break;
    case 'Ü':
      lcdGonder('v', 4);
      i++;
      break;
    case 'ö':
      lcdGonder('v', 5);
      i++;
      break;
    case 'Ö':
      lcdGonder('v', 5);
      i++;
      break;
    case 'ğ':
      lcdGonder('v', 6);
      i++;
      break;
    case 'Ğ':
      lcdGonder('v', 7);
      i++;
      break;
 
    default:
    lcdGonder('v', yazi[i++]);      // Veriyi gönder ve bir sonraki veriye geç.
    }
  }
}

Şimdi ana programımızda içinde Türkçe karakter bulunan bir stringi lcdYaziYaz fonksiyonuna gönderdiğimizde karakterlerin sorunsuz olarak çıkması lazım. Aşağıda kütüphane dosyamızın son halinin tamamını, onun altında da bu dosyayı kullandığım esas programın kodlarını bulacaksınız.

/*-------------------------------
Pin Bilgileri
 
P1.7  =   D7
P1.6  =   D6
P1.5  =   D5
P1.4  =   D4
P2.6  =   RS
P2.7  =   E
 
--------------------------------*/
 
#define    RS P2OUT_bit.P2OUT_6   // LCD'nin RS pini MCU'nun P2.6 pinine bağlandı.
#define    E  P2OUT_bit.P2OUT_7   // LCD'nin E pini MCU'nun P2.7 pinine bağlandı.
 
/*int karakterler[8][8] = {
{0, 14, 16, 14, 1, 30, 4, 0},        // Ş - ş
{0, 14, 17, 16, 17, 14, 4, 0},    // Ç - ç
{0, 0, 12, 4, 4, 4, 14, 0},       // ı
{4, 0, 14, 4, 4, 4, 14, 0},       // İ
{0, 10, 0, 17, 17, 17, 14, 0},    // Ü - ü
{10, 0, 14, 17, 17, 17, 14, 0},   // Ö - ö
{14, 0, 14, 18, 14, 2, 28, 0},    // ğ
{14, 0, 14, 16, 22, 18, 14, 0}};  // Ğ*/
 
// Türkçe karakter atamayı üstteki dizi ile yapacaktım, fakat MSP430'un hafızası yetmediği için verileri tek tek gönderdim. 🙂
 
void lcdBekle(int ms)             // Bekleme fonksiyonu
{
  unsigned int i, j;
  i = ms;
  for(j = 0 ; j < 250 ; j++)
  {
    for( ; i > 0 ; i--);
    i = ms;
  }
}
 
void lcdEDegistir(void)           // E pini düşen kenar tetiklemeli.
{                                 // Bu yüzden gönderdiğimiz bilginin LCD üzerinde
  E = 1;                          // işlem görmesi için E ucuna düşen kenar uyguluyoruz.
  E = 0;                          // Bunu da E'yi önce "1", sonra "0" yaparak hallediyoruz.
}
 
void lcdNeYazilacak(char ne)      // LCD'ye giden bilgimiz veri ya da komut olabilir.
{
  if(ne == 'k')                   // Komut ise;
    RS = 0;                       // RS pini "0" yapılır.
  else if(ne == 'v')              // Veri ise;
    RS = 1;                       // RS pini "1" yapılır.
}
 
void lcdGonder(char ne, int veri) // Gidecek bilginin türünü ve bilgiyi aldık.
{
  P1OUT = veri;                   // Bilgiyi P1OUT'a bastık. Böylece LCD ile bağlantılı kısım en değerlikli dört bit oluyor.
  lcdNeYazilacak(ne);             // Fonksiyona gelen bilgi türünü diğer fonksiyona aktarıp RS pinini ayarladık.
  lcdEDegistir();                 // Bilginin aktif olması için E pinine düşen kenar uyguladık.
 
  veri = (veri << 4);             // Şimdi değerliksiz dört biti göndereceğiz. Veriyi dört bit sola kaydırdık.
                                  // Bu şekilde verinin değerliksiz bitleri, artık değerlikli kısımda.
  P1OUT = veri;                   // Değişen veriyi P1OUT'a bastık.
  lcdNeYazilacak(ne);             // RS pinini ayarladık.
  lcdEDegistir();                 // E pinine düşen kenar uyguladık.
}
 
void lcdTurkceKarakter(void)
{
  lcdGonder('k', 64);   // Bellekte 64 adresinden itibaren,
  lcdGonder('v', 0);    // 1. harfin başlangıcı (8 veri)
  lcdGonder('v', 14);
  lcdGonder('v', 16);
  lcdGonder('v', 14);
  lcdGonder('v', 1);
  lcdGonder('v', 30);
  lcdGonder('v', 4);
  lcdGonder('v', 0);    // 1. harfin sonu
  lcdGonder('v', 0);    // 2. harfin başlangıcı...
  lcdGonder('v', 14);
  lcdGonder('v', 17);
  lcdGonder('v', 16);
  lcdGonder('v', 17);
  lcdGonder('v', 14);
  lcdGonder('v', 4);
  lcdGonder('v', 0);
  lcdGonder('v', 0);
  lcdGonder('v', 0);
  lcdGonder('v', 12);
  lcdGonder('v', 4);
  lcdGonder('v', 4);
  lcdGonder('v', 4);
  lcdGonder('v', 14);
  lcdGonder('v', 0);
  lcdGonder('v', 4);
  lcdGonder('v', 0);
  lcdGonder('v', 14);
  lcdGonder('v', 4);
  lcdGonder('v', 4);
  lcdGonder('v', 4);
  lcdGonder('v', 14);
  lcdGonder('v', 0);
  lcdGonder('v', 0);
  lcdGonder('v', 10);
  lcdGonder('v', 0);
  lcdGonder('v', 17);
  lcdGonder('v', 17);
  lcdGonder('v', 17);
  lcdGonder('v', 14);
  lcdGonder('v', 0);
  lcdGonder('v', 10);
  lcdGonder('v', 0);
  lcdGonder('v', 14);
  lcdGonder('v', 17);
  lcdGonder('v', 17);
  lcdGonder('v', 17);
  lcdGonder('v', 14);
  lcdGonder('v', 0);
  lcdGonder('v', 14);
  lcdGonder('v', 0);
  lcdGonder('v', 14);
  lcdGonder('v', 18);
  lcdGonder('v', 14);
  lcdGonder('v', 2);
  lcdGonder('v', 28);
  lcdGonder('v', 0);
  lcdGonder('v', 14);
  lcdGonder('v', 0);
  lcdGonder('v', 14);
  lcdGonder('v', 16);
  lcdGonder('v', 22);
  lcdGonder('v', 18);
  lcdGonder('v', 14);
  lcdGonder('v', 0);
}
 
void lcdHazirla(void)
{
  lcdBekle(15);                   // Bir süre beklendi.
  lcdGonder('k', 0x02);           // "00000010" yani imleç en başa gidecek.
  lcdGonder('k', 0x28);           // "00101000" yani 4 pin, 2 satır, 5x7 karakter kullanılacak.
  lcdGonder('k', 0x0C);           // "00001000" yani imleç gizlenecek.
  lcdGonder('k', 0x06);           // "00000110" yani imleç yazılan her karakterden sonra sağa doğru kayacak.
  lcdGonder('k', 0x01);           // "00000001" yani LCD temizlenecek.
  lcdBekle(10);                   // Bir süre beklendi.
 
  lcdTurkceKarakter();
}
 
void lcdHucreyeGit(unsigned int satir, unsigned int sutun)
{
  if(satir == 1)
  {
    sutun--;                      // 1-16 arasında giriş için 0-15 arası değer gelecek.
    lcdGonder('k', 0x80 + sutun); // Komut tablosuna göre 80-8F arasında değer gönderiliyor.
  }
 
  else if(satir == 2)
  {
    sutun--;                      // 0-15 arasında bir değer elde etmek için.
    lcdGonder('k', 0xC0 + sutun); // C0 - CF arası değer gönderiliyor.
  }
}
 
void lcdYaziYaz (char* yazi)      // Bir string bastırmak için fonksiyon.
{
  lcdBekle(1);                    // Bir süre beklendi.
  int i = 0;
  while(yazi[i])                  // Yazının sonuna gelene kadar,
  {
    switch(yazi[i])
    {
    case 'ş':
      lcdGonder('v', 0);
      i++;
      break;
    case 'Ş':
      lcdGonder('v', 0);
      i++;
      break;
    case 'ç':
      lcdGonder('v', 1);
      i++;
      break;
    case 'Ç':
      lcdGonder('v', 1);
      i++;
      break;
    case 'ı':
      lcdGonder('v', 2);
      i++;
      break;
    case 'İ':
      lcdGonder('v', 3);
      i++;
      break;
    case 'ü':
      lcdGonder('v', 4);
      i++;
      break;
    case 'Ü':
      lcdGonder('v', 4);
      i++;
      break;
    case 'ö':
      lcdGonder('v', 5);
      i++;
      break;
    case 'Ö':
      lcdGonder('v', 5);
      i++;
      break;
    case 'ğ':
      lcdGonder('v', 6);
      i++;
      break;
    case 'Ğ':
      lcdGonder('v', 7);
      i++;
      break;
 
    default:
    lcdGonder('v', yazi[i++]);      // Veriyi gönder ve bir sonraki veriye geç.
    }
  }
}
 
void lcdHarfYaz (char harf)       // Tek harf bastırmak için fonksiyon.
{
  lcdBekle(1);                    // Bir süre beklendi.
  lcdGonder('v', harf);           // Veriyi gönder.
}
 
void lcdTemizle(void)
{
  lcdGonder('k', 0x01);           // LCD temizlendi.
  lcdHucreyeGit(1, 1);            // 1. satır, 1. sütuna gidildi.
  lcdBekle(10);                   // Bir süre beklendi.
}
#include "io430.h"
#include "lcdFonksiyonlar.h"            // LCD için kullanacağımız fonksiyonlar
 
void main( void )
{
  WDTCTL = WDTPW + WDTHOLD;             // WDT kapatıldı.
 
  P1DIR = 0xF0;                         // P1.4 - P1.7 arası çıkış yapıldı.
  P2DIR = 0xFF;                         // Port 2 çıkış yapıldı.
  P2SEL = 0x00;                         // Port 2, i/o olarak kullanılacak.
 
  lcdHazirla();                         // LCD hazırlanıyor.
  lcdBekle(20);                         // Bir süre beklendi.
 
  lcdHucreyeGit(1, 1);                  // 1. satır, 1. sütuna git.
  lcdYaziYaz("Türkçe Karakter");
 
  lcdHucreyeGit(2, 1);
  lcdYaziYaz("ı ğ Ğ ü ş İ ö ç");
 
  while(1);                             // Sonsuz döngüde bekle.
}

Aşağıda devrenin Proteus simülasyonunu ve gerçek LCD üzerindeki görüntüyü inceleyebilirsiniz.

Proteus simülasyonu

Proteus simülasyonu

LCD görüntüsü

LCD görüntüsü

Son olarak IAR proje dosyalarına ve simülasyon için ISIS dosyasına buradan ulaşabilirsiniz.