ESP32 ile LVGL Kullanarak Arayüz Oluşturma

Merhabalar,

Bu konuda ESP32 ve bir TFT ekran kullanarak nasıl grafik kullanıcı arayüzü oluşturabileceğimize değineceğiz. Gömülü sistemleri bir ekran ile grafik ekran ile kontrol etmek istediğimizde grafik kullanıcı arayüzlerine ihtiyaç duyarız. Bir çok farklı ücretli ve ücretsiz grafik kullanıcı arayüzü kütüphaneleri oluşturulmuştur. Yaygın bilinen grafik arayüz kütüphaneleri arasında Embeded Wizard, TouchGFX, LVGL ve QT bulunmaktadır. Bunların LVGL ve TouchGFX’ in kullanımı tamamen ücretsizdir. TouchGFX, STM32 firması tarafından satın alındıktan sonra tasarım arayüzü ile birlikte STM32 MCU’ lar için ücretsiz hale getirilmiştir. Ancak diğer MCU üreticilerinin sağladığı MCU’ lar tarafından doğrudan kullanılamamaktadır. LVGL ise bir çok MCU modeli için kullanım dökümanları paylaşmıştır. LVGL, günümüzde yaygın ve maliyeti düşük olan ESP32 modüllerini doğrudan desteklemektedir. Oldukça detaylı bir dökümantasyona sahip olan LVGL’ in dökümantasyon sayfasına bağlantıdan ulaşabilirsiniz. Genel olarak C ve Micropython için yazılmış kütüphaneler içermektedir ve LVGL kullanarak oldukça modern görünen arayüzleri kısa sürede oluştrabilirsiniz. Verilen dökümantasyonu incelediğinizde görebileceğiniz üzere LVGL fonksiyonlarının kullanımı son derece basittir ve oluşturmak istediğiniz tasarımı orta karmaşıklıkta olsa bile hızlıca oluşturabilirsiniz. Ancak LVGL’ in en büyük dezavantajı bir tasarım arayüzüne doğrudan sahip değildir. LVGL kullanarak tasarım yapmak için bir tasarım arayüzü istiyorsanız SquareLine Studio kullanabilirsiniz. Ancak bu yazılım ücretsiz sürümde en fazla 50 widget kullanmanıza ve 5 sayfa oluşturmanıza izin verir. Hobi amaçlı yapacağınız işler için verilen bu limit fazlası ile yeterli olabilir ancak profesyenel bir iş yapıyorsanız lisans ücretsiz lisans ticari ürünleri kapsamadığından lisans satın alınmalıdır.

SquareLine Studio kullanarak tasarladığınız bir arayüzü MCU’ ya yüklemek için kaynak kodu üretim işlemini arayüzden rahatlıkla gerçekleştirebilirsiniz. Ayrıca arayüzden üretilen kaynak kodu da açık olduğundan üzerinden sonradan düzenlemeler yapabilrisiniz. Bizde yapacağımız uygulamada bu yolu tercih edeceğiz. Aslında yapacağımız uygulama 3 sayfa içeren basit bir uygulama olacak ancak SquareLine Studio’ nun da kullanarak LVGL içerisindeki bir çok şeyi denemek daha hızlı ve kolay olduğu için bu yazılımı da göstermeyi tercih ettim. ESP32′ yi programlamak için ise Arduino kullanacağız. Ardino ile LVGL kullanırken, kullanılan ekranı sürmek (kontrol etmek) için ara bir kütüphaneye ihtiyaç duyulmaktadır. Ekran sürücü kütüphanesi olarak LVGL ile uyumlu olan TFT_eSPI kütüphanesini kullanacağız. Bu kütüphanenin Github sayfasından desteklenen ekran sürücüleri ve mikrodenetleyicler görüntülenebilmektedir. Şimdi projeyi oluşturmaya başlayalım. Projemizde 3 adet ekran olacak. İlk ekranda bulunan butonlar ile diğer iki ekrana geçiş olacak. İkinci ekranda iki LED’ in yakıp söndürebileceğimiz switch butonlar olacak. Üçüncü ekranda ise bir slider ve progress bar olacak. Arayüz tasarımında kullanacağımız SquareLine Studio’ yu bağlantıdan işletim sisteminize uygun sürümünü indirip kurabilirsiniz.

SquareLine Studio’ yu açtığınızda yeni proje oluşturacağımız için öncelikle üstteki ekrandan kırmızı ile işaretli “Create” butonunu seçerek turuncu ile işaretli “Arduino” seçeneğini seçmelisiniz. Burada farklı alternatifler de mevcut. Yapacağınız seçim tasarım aşamasında bir şeyi değiştirmemektedir. Ancak daha sonra proje oluşturma aşamasında burada yapılan seçime göre proje dosyaları üretilmektedir. Biz Arduino kullanarak yükleme yapacağımız için bu menüden bu seçimi yaptık. Sağda yeşil ile işaretli kısımdan ekranınız ile ilgili ayarları seçmelisiniz. Benim kullanacağım ekran 2.8 inch boyutunda ve 320×240 çözünürlükte ILI9341 sürücülü ekran olduğu için gösterdiğim ayarları yaptım. Sizde elinizdeki ekrana uygun şekilde bu seçimleri yapmalısınız. Aşağıdaki resimde proje oluşturduktan sonraki açılan ekran gösterilmektedir.

Açılan sayfada sol üstte kırmızı ile işaretli kısımda ekrana eklenen araçların hiyerarşisi verilmektedir. Şu an sayfamız boş olduğundan sadece bir sayfa görünmektedir. Hemen altındaki turuncu kısımda ekrana ekleyebileceğiniz araçlar görüntülenmektedir. Tasarımınıza daha fazla sayfa eklemek isterseniz de bu kısmın en altından eklemelisiniz. Yeşil ile verilen kısmı kullanarak projenize resimler ekleyebilirsiniz. Sağ üstte mavi ile verilen kısım seçilen aracın özelliklerini belirleyebildiğimiz kısım olup aracın ismi konumu boyutu gibi özellikleri bu kısmı kullanarak düzenleyebiliriz. Sarı olan kısım daha çok renk ve yazı boyutu gibi özelliklerin ayarlarının yapılmasını sağlayan kısımdır. Sağ en alttaki mor ile işaretli kısım ise ekrana ekleyeceğimiz araçlara ile tıklama sürükleme gibi etkileşimler gerçekleştirildiğinde yapılmasını istediğimiz bir işlem ya da çağrılmasını istediğimiz bir fonksiyon varsa onları belirleyecebileceğimiz kısımdır. Şimdi 1. sayfayı oluşturup butonlarımı ve bu butonlara tıklandığında ne yapılmasını istediğimiz işlemleri ekleyelim. SqaureLine Studio Kullanarak araçları yerleştirmek olukça kolaydır. AŞağıdaki resimde de gösterildiği üzere Sol alt kısımda verilen araçları tıklayıp ekranın üzerine sürükleyip bırakarak ekrana araç ekleyebilirsiniz. Ancak ekleyeceğiniz araçlar ham görünümdedir. Yani Buton eklediğinizde sadece buton gelir. Üzerine yazı eklemek isterseniz bir de Label eklemelisiniz. Ancak ekleyeceğiniz yazı butonun yazısı olması için hiyerarşik olarak onun altında olmalıdır. Hiyerarşik yerleştirmeyi sol tarafta kırmızı ile işaretli alan içerisinde gerçekleştirebiliriz. Sayfaya eklenen her araç bu kırmızı ile işaretli alan içerine eklenir ve her araç birbirine hiyerarşik olarak eklenebilir. Hiyerarşik olarak eklenen araçların en üstteki hareket ettirildiğinde alttaki araçlarda onun ile bağlı bir şekilde harekret eder.

Bu kısımda bahsedeceğim son kısım da butona bastığımız zaman meydana gelecek olayı eklemek. Arayüzde buton üzerine tıkladıktan sonra sağ taraftaki Events kısmından istediğimiz olayı ekleyebiliriz. Event ekleme için “Add Event” butonuna bastığımızda Action kısmından “Change Screen” seçerek “Add” butonuna basmalısınız. Böylece sayfa geçişisi için gerekli event eklenmiş olacaktır. Event’de varsayılan olarak Trigger kısmında “Clikced” seçili olduğu için butona tıkladığınız zaman bu işlem gerçekleşmektedir. İhtiyacınıza duruma göre Trigger seçenekleri arasındaki farklı Event’ leri seçebilirsiniz.

İlk sayfayı oluşturduktan sonra benzer şekilde 2 sayfa daha ekleyeceğiz. Projenin son görünümü aşağıdaki gibi olacaktır. Proje dosyalarını paylaşacağım için yaptığım değişikliklere proje dosyalarından da bakabilirsiniz. Yaptığım eklemeleri basit bir şekilde sizde yapabilirsiniz. Konunun çok fazla uzamaması için her sayfayı detaylı anlatmayacağım. Eklediğim araçların isimlerini kullanım amaçlarına göre belirlemeye çalıştım. Böylece yazılım içerisinde gerekli bağlantıları yapmak daha kolay olacaktır. Hazırlanan projeyi dışarı aktarmak için sol üstteki menü butonlarından “Export -> Create Template Project” diyerek oluşturduğunuz tasarımı proje halinde dışarı aktarabilirsiniz.

Proje oluşturma kısmını tamamladık. Şimdi oluşturduğumuz projeyi düzenleyelim. Ben oluşturulan proje dosyalarını düzenlemek ve yükleme için Platform.io kullanacağım. İsterseniz Arduino IDE’ sini kullanarak da bu derleme ve düzenleme işlemini gerçekleştirebilirsiniz. Ancak şunu belirtmeliyim ki özellikle Windows işletim sistemi kullanıyorsanız Arduino IDE’ sinde ESP32′ ye bir şey derlemek oldukça uzun sürmektedir. Bu sebeple Platform.io kullanmak derleme ve yükleme işlemini hızlandırdığından proje geliştirme sürecini de hızlandırmaktadır. Projeyi SquareLine Studio üzerinden dışarı aktardığınız zaman gerekli kütüphane dosyaları da proje içerisindeki “libraries” klasöründe gelmektedir. Arduino IDE’ si kullanacaksanız bu klasör içerisindeki her şeyi Arduino kütüphaneleri arasına eklemelisiniz. Şimdi de bu kütüphane dosyalarında neler var onlara bakalım.

Yukarıdaki resimde kütüphane dosyasının içerisinde bulunan klasörler ve dosyalar gösterilmiştir. Turuncu ile işaretli klasörler içerisinde LVGL kütüphaneleri ve kullanacağımız ekranı LVGL tarafından kontrol edecek sürücü kütüphaneleri mevcuttur. Bunların içerisinde sadece “TFT_eSPI” klasörü içerisinde “User_Setup.h” dosyası içerisinde değişiklik yapılmalıdır. Yapılacak değişiklikler kullanılan LCD’nin pin tanımları olup ileride daha detaylı bahsedeceğim. Mor ile işaretli kısımda arayüzde tasarladığımız sayfaların içerisindeki araçlar mevcuttur. Kırmızı ile işaretli kısımda arayüzde etkileşime girmek istediğimiz araçların fonksiyonları mevcuttur. Ancak bu dosyalar içerisinde sayfa geçisişi gibi bizim sonradan müdehale etmemiz gerekmeyen fonksiyonlar bulunmaz. Örneğin LED yakma için oluşturduğumuz butonların fonksiyonları bu dosyaların içerisindedir. Yeşil ile işaretli kısımda ayrı ayrı tanımlanan sayfa fonksiyonları burada birleştirilir ve “ui_init” fonksiyonu içerisinde sıra ile çağrılır. Bizim ana yazılımımız içerisinde bu “ui_init” fonksiyonunu çağırırak tasarladığımız arayüzün ekran içerisinde görüntülenmesini sağlayacağız. Mavi ile işaretli dosya “lv_conf.h” dosyası içerisinde ise LVGL kütüphanesinin ayarları mevcuttur. Örneğin LVGL de kullanacağınız temanın karanlık mı yoksa aydınlık mı olmasını ya da kullandığınız ekranın renk derinliğini bu dosya içerisinde ayarlayabilirsiniz. Yapmamız gereken değişikliklerden de birazdan bahsedeceğiz.

Dışarı aktarılan dosyalar arasındaki bir diğer dosya da ui klasörü altındaki ui.ino dosyası. Bu dosya içerisinde Arduino’ da kullandığımız “setup” ve “loop” fonkisyonları mevcut. “setup” fonksiyonu içerisinde ekran sürücü ayarları, ekran yenileme kullanılan buffer’ ların tanımları gibi işlemler gerçekleştirilmektedir. “loop” içerisinde ise sadece LVGL arayüzünün yenilenmesi için task handler fonksiyonu çağrılmaktadır. Proje dosyasını ESP32′ ye yüklemek için yapılması gereken sadece bir ayar bulunmaktadır. Bu ayar TFT ekran sürücü kütüphanesi olan TFT_eSPI kütüphanesi içerisindeki pin tanımlarıdır. TFT_eSPI kütüphanesi içerisindeki User_Setup.h dosyası içerisinde bir çok pin tanım kombinasyonu bulunmaktadır. Bu kombinasyonlar Arduino, ESP8266 ya da RP2040 gibi mikrodenetleyiciler kullanabilmenin yanı sıra ST7735, ILI9481 gibi ekran sürücülerinin de desteklenmesini sağlar. Benim kullandığım ekranın sürücüsü ILI9341 ve mikrodenetleyici olarak ESP32 kullanacağım için ayarlamaları da buna göre yapacağım. Proje dosyaları içerisinde ESP32 için yapılacak pin tanımlamalarını 212. satırda verilen pin atamalarını değiştirerek gerçekleştirebiliriz. ESP32 ile ekran arasındaki pin bağlantılarını ben aşağıdaki gibi gerçekleştirdim.

#define TFT_MISO 19
#define TFT_MOSI 23
#define TFT_SCLK 18
#define TFT_CS    5  
#define TFT_DC   16  
#define TFT_RST  17

#define TOUCH_CS 22

Pin bağlantılarını belirken ben ESP32′ nin default SPI pinlerine bağlamayı tercih ettim. Ancak ESP32′ de GPIO matrix olduğundan SPI’ ı neredeyse tüm dijital pinlerde kullanabilirsiniz. Burada dikkat edilmesi gereken önemli nokta bulunmakta. Kullandığımız ekran bir dokunmatik arayüze de sahip. ILI9341 ekran modülü üzerinde “xpt2046” dokunmatik ekran sürücüsü bulunur. Bu sürücü de mikrodenetleyici ile SPI arayüzü ile haberleşir. SPI haberleşme protokolü bir çok cihazın paralel şekilde bağlanmasına izin verir. Ancak SPI haberleşme için hatta bağlanan her donanım ayrı bir CS (Chip Select) pini kullanmalıdır. Bu sebeple dokunmatik ekran kullanacaksak “User_Setup.h” dosyası içerisindeki TOUCH_CS pinini yorum satırından çıkarmalı ve ESP32 üzerindeki bir pine atamalıyız. SPI hattına bu şekilde iki donanım bağlamak avantaj sağlasa da cihazların çalışabildiği SPI saat frekansları farklı olabilir ki bu ILI9341 80Mhz’ e kadar saat frekansı desteklerken, XPT2046 en fazla 2.5Mhz saat frekansı desteklemektedir. Bu sebeple “User_Setup.h” dosyası içerisinde bu frekansları da ayrı ayrı olarak belirlemeliyiz. Benim kullandığım dosyada 364. (SPI_FREQUENCY) ve 372. (SPI_TOUCH_FREQUENCY) satırlarda bu ayarlar gerçekleştirilmektedir. Unutmayın bu isimlerde birden fazla ön işlemci direktifi tanımlarsanız en son tanımladığınız geçerli olacaktır. Ben SPI_FREQUENCY değerini 40000000, SPI_TOUCH_FREQUENCY değerini ise 2500000 olarak girdim.

Bu değişiklikleri doğru şekilde yapıp ESP32′ ye yüklemeniz halinde ekran üzerinde tasarladığınız arayüz ekran üzerinde görüntülenip kontrol edilebilir olacaktır. Eğer bir sorun yaşarsanız önce pin bağlantılarınızı daha sonra yazılımınızı kontrol etmelisiniz. Eğer dokunmatik ekran kontrolü simetrik olursa yazılım içerisindeki TFT_eSPI constructor tanımını şu şekilde değiştirebilirsiniz.

TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); // SquareLine tarafından oluşturulan
TFT_eSPI tft = TFT_eSPI(screenHeight, screenWidth); // Bu şekilde düzeltilmeli

Şimdi de tasarladığımız ekranın istediğimiz fonksiyonları yapması için gereken işlemleri yapalım. LVGL ekran yenilmeme hızını saniyede 30 kare yapabilmek için arka planda belirli periyotlarda ekran yenileme işlemi gerçekleştirmelidir. Bu işlem için gereki yazılım loop içerisinde SquareLine tarafından oluşturulmuştur. Yapmak istediğimiz diğer işlemleri de loop kısmına eklersek ve yapacağımız işlemler bloklayıcı işlemler olursa sayfa yenileme hızının düşebilir ve akıcı bir sistem elde edemeyiz. Bu sebeple yapacağınız diğer işlemler için farklı bir task oluşturmanızı tavsiye ederim. Ben bu işlemleri aşağıdaki task içerisinde gerçekleştirdim.

void task1(void *pvParameters)
{
  while (1)
  {
    // led durumlarını değiştir
    digitalWrite(led1_pin, led1_stat);
    digitalWrite(led2_pin, led2_stat);

    // her 10 milisaniyede 1 ADC' den 1 örnek oku ve okunan değerleri topla
    if (millis() - adcTime > 10)
    {
      adcSum += analogRead(pot_pin);
      sampleCnt++;
      adcTime = millis();
    }

    // her 100 milisaniyede bir
    // toplanan adc değerlerinin ortalamasını alıp ekranda göster
    // slider ın değerini oku
    // slider dan alınan değeri pwm olarak led e aktar
    if (millis() - tt > 100)
    {
      adcVal = adcSum / sampleCnt;
      sampleCnt = 0;
      adcVal = map(adcVal, 0, 4096, 0, 100);
      adcSum = 0;

      // ADC den okunan değeri progress bar a ve yanındaki text box a yazdır
      lv_bar_set_value(ui_pgLed1, adcVal, LV_ANIM_ON);
      lv_label_set_text(ui_txtPgVal1, (String("%") + String(adcVal)).c_str());

      Serial.printf("Slider Val :%d\n", sliderVal);

      // slider değerini oku ve yanındaki text box a yazdır
      sliderVal = lv_slider_get_value(ui_sliderLed3);
      lv_label_set_text(ui_txtSliderVal, (String("%") + String(sliderVal)).c_str());
      
      // slider dan okunan değeri 0 ile 255 arasına getirip led e aktar
      sliderVal = map(sliderVal, 0, 100, 0, 255);
      ledcWrite(ledChannel, sliderVal);

      tt = millis();
    }

    vTaskDelay(10 / portTICK_PERIOD_MS);
  }
}

Burada tanımlanan ui_pgLed1, ui_txtPgVal1 gibi değişkenler ui.c dosyasında tanımlıdır ve oluşturduğumuz arayüzde verdiğimiz araçların isimlerine ui_ eklenerek SquareLine tarafından oluşturulmuştur. Sizde oluşturduğunuz araçları ararken önüne ui_ eklendiğine dikkat etmelisiniz. LED’ ler potansiyometre için kullandığım pinlerin tanımlarını bu şekilde yaptım.

const uint8_t led1_pin = 15;
const uint8_t led2_pin = 2;
const uint8_t pot_pin = 34;
const uint8_t pwmPin = 0; 

Son olarak da yazılımda bahsetmem gereken kısım LED’ ler için tanımladığımız switchlere basıldığı zaman LED durumlarını nasıl değiştireceğimiz. Switch’ lere basıldığı zaman çalışan “led1_toggle_func” ve “led2_toggle_func” isimli fonksiyonlar ui_events.h dosyasında tanımlanmışlar. Bu sebeple bu fonksiyonlara ana yazılım dosyamızdan erişemeyiz. Bu iki dosya arasınd bağlantı kurmak için farklı yöntemler mevcut. Ben gerçekleştirilmesi basit olan extern değişken kullanma yöntemini gerçekleştirdim. Bunun için ana yazılımın bulunduğu dosyada kullanmak istediğimiz değişkenleri tanımlayıp diğer yazılım dosyası içerisinde bu değişkenleri başına “extern” ekleyerek tekrar tanımlıyoruz. Bu tanımlama işlemini şu şekilde gerçekleştirilmiştir.

uint8_t led1_stat, led2_stat;     // defined in ui.ino

extern uint8_t led1_stat, led2_stat; //defined in ui_events.c

Bir değişken extern olarak tanımlandığı zaman derleyici bu değişkenin aynı isimle projenin başka bir yerde tanımlı olduğunu bilerek derlemesini sağlamaktadır. Böylece farklı dosyada aynı isimle tanımlanan değişkenin değerini okuyabiliyor ya da değiştirebiliyoruz. Değişkenler ui_events dosyası içerisinde extern olarak tanımlandıktan sonra butonlara basıldığı zaman buton değerlerinin okunup bu değişkene atanmasını aşağıdaki şekilde gerçekleştirebiliriz.

void led1_toggle_func(lv_event_t * e) 
{ 
    // Your code here 
    led1_stat = lv_obj_has_state(e->target, LV_STATE_CHECKED);
}
    
void led2_toggle_func(lv_event_t * e) 
{ 
    // Your code here 
    led2_stat = lv_obj_has_state(e->target, LV_STATE_CHECKED); 
}

Buton eventlerini de tanımladıktan sonra yazılım içerisinde bahsedebileceğim çok fazla detay kalmadı. Geri kalan şeyler bunlara göre daha basit denemeler ile çözülebilecek şeyler. LVGL ve SqaureLine Studio aslında başlı başına birer konu olarak ele alınabilir. Ancak LVGL konusunda belirtmem gereken en büyük problem son bir kaç yıl içerisinde 3 büyük güncelleme almış olmasıdır. Bu güncellemeler her ne kadar çok şey katmış olsa da internette bulunan örnekler açısından bir çok farklılık yaratmakta. Özellikle kendi dökümantasyon sayfasından bile bir şey bakarken kullandığınız LVLG sürümü ile dökümantasyonda anlatılanın aynı olduğunu kontrol etmelisiniz. Versiyonlar arasında fonksiyonların tanımları ve yazılım yapısı gibi konularda çok büyük değişiklikler bulunmaktadır. İnternette en çok kaynak bulabileceğiniz LVGL sürücümü 7x sürümleridir. Şu an 8x sürümleri master olarak yayınlanmakta ancak 9x sürümü de beta olarak yayınlandı ve yakında ona geçilecek. Projeyi geliştirmeye başlarken hangisini kullanmanız gerektiğine iyi karar verip öyle yola çıkmalısınız. Yoksa yarı yolda değiştirme kararı aldığınızda çok üzülebilirsiniz. Ben bu aralar proje geliştirme için 8x sürümü kullanıyorum ki bu projede de LVGL’ in 8.3.7 sürümünü kullandık.

Son olarak projeyi gerçekleştirirken ESP32 için kullandığım bağlantı şemasını ve projenin tamamının kaynak kodunun olduğu github sayfasını vererek konuyu tamamlayayım. Umarım eksik bir yer kalmamıştır. Konu ile ilgili sormak istediğiniz diğer soruları mail üzerinden gönderebilirsiniz.

Proje dosyalarının tamamına aşağıdaki bağlantılardan ulaşabilirsiniz.

2 Comments

Add a Comment

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir