3.1- MicroPython ile Karakter LCD (HD44780) Uygulamaları

Uygulamalarımıza kullanıcı arayüzü katmak istediğimizde çıkış aygıtı olarak göstergeleri kullanmamız gerekir. Göstergeler basit bir LED olabileceği gibi, bir ibre, bir bar gösterge veya 7 segman LED’ler ile yapacağımız bir sayı göstergesi olabilir. Bunlar pek çok durumda oldukça düşük maliyetli ve pratik bir çözüm olsa da özellikle metin yazdıracağımız durumlarda işimizi zorlaştırmaktadır. Örneğin bir panoya çeşitli hata durumlarını etiket olarak koyup bunun olup olmadığını yanına koyacağımız LED’ler ile göstermek yerine tek bir ekran koyup bütün hata mesajlarını bu ekranda gösterebiliriz. Bu uygulamamızın albenisini artıran bir durumdur. Bazı zamanlar arka tarafta ne kadar iyi uygulama yazarsak yazalım kullanıcılar öncelikle uygulamanın görsel tarafıyla ilgilenmektedir. Kullanıcıyı ilgilendiren “Kullanıcı deneyimi” kısmını ise kullanımı kolay, yabancı gelmeyen ve kolayca öğrenilebilecek bir arayüz tasarımı ile iyileştirebiliriz.

Uzun yıllardır Hitachi HD44780 tabanlı karakter LCD ekranlar gömülü sistemler başta olmak üzere bilgisayarlar tarafından kullanılan ve bir nevi endüstri standardı haline gelen ekranlardır. Bu ekranlar 80’lerden itibaren pek çok elektronik cihazda kullanılmakla beraber günümüzde modern bir çözüm olarak görülmese dahi ucuz ve etkili bir çözüm olarak kullanıcıların görselliği çok fazla talep etmediği düşük maliyetli işlerde kullanılabilmektedir.

Resim:winstar.com

HD44780 tabanlı karakter LCD’lerin en büyük özelliği öğrenci dostu olmalarıdır. Hem kullanım kolaylığı hem öğreticilik hem de maliyet açısından öğrenci dostu olmasından dolayı eğitimde ve öğrencilerin ödevlerinde sıkça tercih edilmektedir. Bu kitapta bu avantajlarından dolayı uygulama yapma ve kütüphane yazma konusuna bu ekranla başlayacağız.

Karakter LCD ekranları kullanmak oldukça kolaydır ve pek çok bilgisayar sistemine adapte edilebilir. Örneğin bilgisayarların paralel portlarından kullanabileceğimiz gibi herhangi bir shift register çıkışı veya port çoklayıcı ile seri iletişim üzerinden de kullanabiliriz. Çoğu zaman bir mikrodenetleyiciye ihtiyaç duyulmayacak kadar kolay kullanılabilmektedir. Biz mikrodenetleyiciler ile kullanmak istediğimizde ise oldukça basit bir mikrodenetleyici kullanmamız için yeterli olacaktır. SPI, I2C gibi seri iletişim protokolleri yerine paralel iletişim kullanıldığı için bu özelliklerden yoksun mikrodenetleyiciler tarafından da kolayca kullanılabilmektedir. Hatta biraz daha uç bir örnek vermemiz gerekirse hiçbir mikrodenetleyici olmadan sadece anahtarları bağlayarak el ile de bu ekranı kullanmanız mümkündür. [1]

Pek çok farklı firma HD44780 uyumlu karakter LCD üretmektedir. Pek çoğunda ayak sıralaması değişse de modül üzerinde çoğu zaman 1. ayağın ve son ayağın (14 ya da 16) belirtilmiş olduğunu görürüz. Birinci ayağı bulduktan sonra sıralama değişmemektedir. Karakter LCD’nin ayakları ve işlevleri aşağıda açıklanmıştır.

Karakter LCD’yi kullanmak için en az 4 adet veri ayağı, EN ayağı ve RS ayağını kontrol etmemiz gerekmektedir. ESP32’nin çıkış veren herhangi bir ayağına bağlayabilirsiniz. Kitaptaki uygulamalarda ESP32 ile arasındaki bağlantı şu şekilde olacaktır.

Kullanacağımız örneklerdeki LCD bağlantı şemasını aşağıda görebilirsiniz.

KarakterLCDDevre.fzz

Kullanacağınız modülün ayak sıralaması değişebildiği için bağlantıları tekrar gözden geçirmekte fayda vardır. Burada pek çok modülün takip ettiği ayak şemasına göre bağlantı yapılmıştır. 15 ve 16. ayaklar arka plan aydınlatması için kullanıldığından bağlamak isteğe bağlıdır. Ayrıca ESP32’den bağladığınız beslemenin 5V sağladığına emin olunuz, eğer yetersiz kalırsa harici bir 5V besleme kullanabilirsiniz.

Bağlantıları yaptıktan sonra nasıl çalıştıracağımızı düşünelim. Öncelikle her zaman olduğu gibi bir parçayı kullanmadan önce ilk kaynak olarak datasheeti incelememiz gerekli.

https://www.sparkfun.com/datasheets/LCD/HD44780.pdf

Datasheet okumaya çok alışkın değilseniz ilk başlarda size bilmece gibi gelebilir. Aslında bazı datasheetlerde konuları takip etmek ve açık bir şekilde anlamak işin uzmanları için de zorlayıcı olabilmektedir. Datasheetin bir köşesinde bir satırda yer alan bir ifade diğer bir bölümünde oldukça önemli olabilir. Bunu da hatırlatmadıkları zaman sayfalar arası sürekli gezinip durmamız gerekebilir. Bazı datasheetler gerçekten muğlak ifadeler içermektedir. Böyle durumlarda kaliteli teknik yazarlığın önemi daha iyi anlaşılmaktadır.

Datasheette bizi ilgilendiren ilk kısım “Pin Functions” adıyla 8. sayfada yer almaktadır. Burada yukarısında açıklamasını yaptığımız ayakların işlevleri yazmaktadır. Geri kalan kısımda komutlardan ve karakter kodlarından bahsedilmekte ve iletişimde takip edeceğimiz zamanlama değerleri açıklanmaktadır.

Bu konuları burada daha açık bir şekilde anlatalım. Öncelikle biz LCD sürücü ile iki yazmaç üzerinden iletişime geçmekteyiz. Bu yazmaçlardan birisi komutları işlediği komut yazmacı, ötekisi ise ekrana karakter yazdırmak için kullanılan veri yazmacıdır. Komut yazmacı ile veri yazmacı arasında seçim yapmak için RS ayağını kullanırız. Bu ayağa 0 değeri verdiğimizde gönderdiğimiz verinin komut olduğu değerlendirilir, 1 değeri verdiğimizde ise gönderdiğimizin veri olduğu değerlendirilir ve yazdırma işlemi yapılır.

LCD’nin yeni veri gönderip göndermediğimizi görmesi için EN ayağı kullanılır. EN ayağının düşen kenarında (1’den 0’a geçişinde) LCD, RS ve veri ayaklarındaki sinyalleri okur ve değerlendirir.

LCD’yi kontrol etmek için bazı komutlara ihtiyacımız vardır. Örneğin ekranı temizlemek, imleci başa getirmek, ekranı açmak, imleci yanıp söner hale getirmek veya imlecin konumunu değiştirmek için komutlar kullanılır. Bu komutlar sayısal değerler olup datasheette açıklanmıştır. Burada örnek olarak 0x01 yani ekranı temizleme komutundan bahsedebiliriz. Bu komutu çalıştırmak için şu şekilde bir algoritma yazmamız gereklidir.

· RS’yi 0 yap.
· Veri ayaklarına komutu yazdır. (0x01)
· EN ayağını 1 yap.
· Belli bir süre bekle.
· EN ayağını 0 yap.

Komut yazdırma bu kadar kolaydır. Biz ekrana örneğin ‘a’ harfini yazdırmamız gerektiğinde ise şu algoritmayı takip etmemiz gerekir.

· RS’yi 1 yap.
· Veri ayaklarına veriyi yazdır. (‘a’)
· EN ayağını 1 yap.
· Belli bir süre bekle.
· EN ayağını 0 yap.

Görüldüğü gibi yapacağımız işlemler bu kadar kolay. Bu uygulamayı MicroPython’da gerçekleştirmek için dikkat etmemiz gereken sadece bir nokta vardır. Bu modül paralel iletişimi kullanmakta ve portlara yazılan değerler ile çalışmaktadır. Mikrodenetleyicilerin giriş çıkış işlemlerini yaptığı bit bit ele alınabileceği gibi paralel olarak da ele alınabilir. Örneğin A portuna 255 (0xFF) değerine yazdığımızda tüm ayaklar 1, 0xF0 değerini yazdığımızda yarısı 1, yarısı ise 0 olmaktadır. MicroPython’da ise giriş çıkışlar pin olarak ele alındığından bizim sayısal verileri paralel olarak ifade etmemiz gereklidir. Bunu kolay ve etkili yapabileceğiniz örnek kodlar aşağıda verilmiştir. Karakter LCD uygulamalarını yapmadan önce bu uygulamayı anlamamız gereklidir.

Öncelikle bizim port olarak paralel çıkış alacağımız ayak dizisini belirlememiz gereklidir. Bunu programda pin_numaralari listesinde belirledik. Sonrasında bu pin numaralarını Pin nesnelerine dönüştürüp bunu ayrı bir listede kaydettik. Pinlerin çıkışını sıfır yaptıktan sonra dört işlem için dört farklı fonksiyon tanımladık.

Bu fonksiyonların işlevleri şu şekildedir,

· paralel_yaz_msb(deger, pin_list) : Baştaki bit öncelikli olmak üzere deger argümanındaki değeri pin_list listesine sırayla yazdırmaktadır. pin_list’in genişliği kadar değer yazdırılmakta, taşan kısım yazdırılmamaktadır.
· paralel_yaz_msb(deger, pin_list): Sondaki bit öncelikli olmak üzere deger argümanındaki değeri pin_list listesine sırayla yazdırmaktadır.
· paralel_oku_msb(pin_list): pin_list listesinde yer alan ayakları baş bit (MSB) öncelikli olmak üzere sırayla okur ve bunu tamsayı değeri olarak geri döndürür.
· paralel_oku_lsb(pin_list): pin_list listesinde yer alan ayakları son bit (LSB) öncelikli olmak üzere sırayla okur ve bunu tamsayı değeri olarak geri döndürür.

Bu fonksiyonlarla mikrodenetleyicilerde ve dijital devrelerde olan port okuma ve yazma işlemlerini kolayca yapabiliriz. Genellikle güncel modüller SPI veya I2C protokolleri üzerinden iletişim sağlasa da temel mantık devreleri ve ilkel dijital entegreler paralel iletişimi desteklemektedir. Aynı zamanda eski bilgisayarlar ile de (örneğin Commodore 64) paralel iletişimle bağlantı sağlayabiliriz.

Yukarıdaki uygulamada yer alan paralel_yaz_msb() fonksiyonunu bölümün devamında karakter LCD uygulamalarında kullanacağız.

LCD’ye veri ve komut yazdırmanın mantığını size anlattık. Şimdi ise hangi komutları ne zaman kullanmamız gerektiğini açıklayalım.

Clear Display : Ekranı temizlemek için kullanılmaktadır. Aynı zamanda DDRAM adresini 0 yaparak imleci en başa döndürür.

Return home : DDRAM adresini 0 yapar ve imleci en başa döndürür.

Entry mode set: İmlecin hareket yönünü ve ekranın kaymasını belirler.

Display on/off control: Ekranın kapatılıp açılmasını, imlecin kapatılıp açılmasını ve yanıp sönmeyi belirler.

Cursor of display shift: DDRAM içeriğini değiştirmeksizin ekranı ya da imleci sola veya sağa kaydırır.

Function set: Arayüz genişliğini (4/8-bit), satır sayısını ve karakter fontunu belirler (5x8/5x10). Bu komut LCD’yi doğru kullanmak için en önemli komuttur.

Set CGRAM address: Özel karakterler için belirlenen CGRAM hafızasındaki adresi belirler.

Set DDRAM address: Ekranda gösterilecek karakterlerin olduğu DDRAM adresini belirler. Yani bir nevi imlecin (yazdıracağımız karakterin konumunun) adresini belirlemektedir.

Read busy flag & address : Kısa zamanlı yazdırmalarda LCD’nin meşgul olup olmadığı mikroişlemci tarafından takip edilebilir. Biz yeterince bekleme verdiğimiz için bunu kullanmamıza gerek yoktur.

Write data to CD or DDRAM: Hafızaya veri yazmak için kullanılır.

Read data from CG or DDRAM : Hafızadan veri okumak için kullanılmaktadır. Normalde ekrana veri yazdırmamız gerekse de ekranda neyin yazdığını okumak için bu komut kullanılır. Bunu da kullanmamıza gerek yoktur.

Bu komutların sayısal yapısını datasheetin 24. ve 25. sayfalarında bulabilirsiniz. Tek bir komut yazmacı kullansak da her bir komutun bir bit konumu bulunmakta ve komut yazmacındaki diğer bitlerin anlamı komuta göre değişmektedir. Dikkat ederseniz komutlar DB0 numaralı en sağdaki bitten başlamakta ve teker teker sola kayarak devam etmektedir. Bu süreçte kendi sağında bulunan bitleri argüman olarak kullanmaktadır. Burada tek bir yazmaçta pek çok farklı argümanlı komutu çalıştırmanın zekice bir yöntemini görebilirsiniz.

LCD sürücüdeki hafıza çeşitlerini daha iyi anlamanız için açıklayalım,

DDRAM: Ekranda görünen karakterlerin değerlerinin bulunduğu hafızadır. Her bir DDRAM adresi ekrandaki bir karaktere karşılık gelmektedir. Örneğin 0x00 adresi ilk satırın ilk karakterine karşılık gelir.

CGROM: Bu hafızayı üreticiler belirlemekte ve bizim DDRAM’a yazdığımız değere karşılık gelen şekli ekranda göstermek için kullanılmaktadır. Örneğin 65 desimal değerini yazdığımızda bu hafıza sayesinde ekranda “A” işaretini görmekteyiz. Bu hafızanın tablosu üreticiye göre değişebilmektedir.

CGRAM: Bu hafıza ise bizim özel karakter oluşturmamıza imkân tanımaktadır.

Buradan incelediğimiz kadarıyla LCD’yi temel özellikleriyle kullanmak için çok bir konfigürasyon yapmamıza gerek yoktur. Günümüzde pek çok uygulamada LCD 4-bit kullanıldığı için başlangıçta “Function set” komutunu çalıştırıp buna dikkat etmemiz gereklidir. Sonrasında ise yapmamız gereken imlecin yerini belirleme ve karakteri yazdırmadır.

Kullandığımız ekran 16x2 olacağı için imleç belirleme noktasında çok bir sıkıntı yaşamayacağız. Bazen 20x4 gibi büyük ekranlarda karakter adreslemesini doğru yapmak gerekebilir.[2]

Şimdi temel LCD fonksiyonlarını kullanabileceğimiz deneme programını çalıştıralım ve sonrasında inceleyelim.

Programı çalıştırdığımızda ekranda “Merhaba Dunya!” yazısını görmemiz gereklidir.

Eğer bir yazı göremiyorsanız büyük ihtimalle bağlantıların doğru yapılmaması veya kontrast ayarının tam yapılmamasından dolayıdır. Devre tahtası üzerinde çalışırken devre tahtasının kalitesi bizim deneyimlerimize doğrudan etki etmektedir. Düşük kalite bir devre tahtasında temassızlık yaşanabileceği için bazı zamanlar LCD kullanırken sorun yaşanmaktadır.

Şimdi bu uygulamayı ilerleyen uygulamalarda kullanmak üzere modül haline getirelim. Öncelikle biz burada lcd_init() dediğimizde sadece LCD’yi hazır hale getirmek için gerekli işleri yaptık. Ayak ayarları yukarıda tanımlanmış ve sabit olup bunları değiştirmek için koda müdahale etmemiz gereklidir. Biz bunları da init() fonksiyonu içerisine alıp argüman olarak aktardığımız ayak numaralarıyla bunları gerçekleştirelim.

Globalde tanımladığımız data_pinleri adlı boş liste, en ve rs değişkenlerini daha sonrasında yaz() fonksiyonu kullanacaktır. Ayrıca biz modül olarak kullandığımızda lcd.puts() veya lcd.home() şeklinde kullanmak istediğimizden fonksiyon adlarını ona göre düzenleyip başlarındaki lcd ibaresini kaldıralım. Bu ufak değişikliklerle artık yazdığımız uygulama modül haline gelmiştir. Bu modülü kitabın kod sayfasında Kütüphaneler/lcd.py dosyasından inceleyebilirsiniz.

MicroPython’da modülleri kullanmamız için bu modülleri ayrı bir dosya olarak mikrodenetleyicinin dosya sistemine yüklememiz gereklidir. Şimdi lcd modülünü kullanmak için Thonny’de bu dosyayı karta yükleyelim.

Öncelikle lcd.py dosyasını açtıktan sonra File -> Save Copy seçeneğini seçelim.

Sonrasında karşımıza çıkan “Where to save to?” menüsünde “MicroPython device seçeneğini seçelim.

En son olarak karşımıza kartın dosya sisteminde yer alan dosyalar çıkacaktır. Burada lcd.py ismiyle modülü kaydedelim.

Kayıt işlemini yaptıktan sonra yukarıdaki devreyi hiç bozmadan kütüphane ile beraber yeni bir uygulama yazalım.

Gördüğünüz gibi kütüphane yazmak bu kadar kolaydır. Bir geliştirici olarak mevcut kütüphanelere bağlı kalmamalı ve gerektiği zaman kendi kütüphanenizi yazabilmelisiniz.

Burada kütüphanemizi C dilinde yazar gibi fonksiyonlarla yazdık. Deneyimli C geliştiricilerinin yazdığı veya kullandığı kütüphanelerde bu tarz bir kullanımdan ziyade nesne-sınıf yapısına benzer struct-typedef yapılarını görebiliriz. Bu konuda daha fazla ayrıntıyı görmek isteyenler STM32 HAL kütüphanelerini inceleyebilir.

Python nesne tabanlı bir programlama dili olduğu için biz kütüphanelerimizi sınıf-nesne yapısına bağlı kalarak yazmamız daha iyi olacaktır. Python’da bunu yapmak oldukça kolaydır. Şimdi fonksiyonlardan ibaret olan kütüphanemizi bir sınıf haline getirelim. Bu dosya kitabın kodları içerisinde “Kütüphaneler” kısmında yer almaktadır.

Bu kütüphaneyi şöyle bir örnekle kullanabiliriz.

Sınıfları kullanmamızın en büyük avantajı kütüphaneyle beraber birden fazla LCD nesnesi oluşturup kullanabilmemizdir. Yazılımda birden fazla nesne oluşturmamız devremizde de birden fazla modül kullanacağımız anlamına gelmektedir. Artık lcd_init() fonksiyonu kullanmak yerine LCD sınıfında bir nesne oluştururken başlangıç için gerekli olan değerleri argüman olarak aktarıyoruz. Bu init işlemi ise artık sınıfta yapıcı (constructor) adı verilen __init__ metodu içerisinde gerçekleşmektedir. Sınıfın içerisinde nesneyle ilgili değerleri ve fonksiyonları kullanmak ve tanımlamak istediğimizde baş kısma self ibaresini eklememiz gereklidir. Ayrıca bütün sınıfta yer alan fonksiyonların ilk argümanı ilgili nesneyi gösteren “self” olmalıdır. Dikkat etmeniz gerekenler bunlar olup nesne tabanlı bir kütüphane yazmanın başlangıçta ek bir zorluğu yoktur. GitHub’da mevcut MicroPython kütüphanelerini incelediğinizde ve Python için yazılan diğer modüllere baktığınızda hemen hepsinin nesne tabanlı yazıldığını görebilirsiniz. Nesne tabanlı programlama Python için şart olmasa da yani isterseniz hiç sınıflara girmeden de programlarınızı yazabilseniz de Python büyük oranda nesne tabanlı olarak kullanılmaktadır.

--

--