Raspberry Pi Pico I2C OLED Ekran Kullanımı

Raspberry Pi Pico I2C OLED Ekran Kullanımı Pi Pico I2C OLED

Bu makalemizde, gömülü sistemlerin en popüler görsel geri bildirim araçlarından biri olan Pi Pico I2C OLED SSD1306 sürücülü ekran modülünü Raspberry Pi Pico ile kontrol etmeyi öğreneceğiz. Bu rehberin sonunda, RP2040 mikrodenetleyicisi üzerinde donanımsal I2C haberleşmesini yapılandırabilecek, MicroPython kullanarak ekranda metinler yazdırabilecek ve kendi tasarladığınız özel grafikleri/görselleri OLED ekrana yansıtabileceksiniz. devreyakan üzerinde daha önce hazırladığımız diğer OLED ekran projelerine ve temel çalışma prensiplerine göz atmak isterseniz OLED ekran makalelerimize ve rehberlerimize başvurabilirsiniz.

Gerekli Donanım Bileşenleri

  • 0.96 inç veya 1.3 inç I2C OLED Ekran Modülü (SSD1306 Kontrolcülü, 128×64 Piksel)
  • Raspberry Pi Pico veya Pico W
  • Deneysel Devre Tahtası (Breadboard)
  • Jumper Bağlantı Kabloları

Raspberry Pi Pico ve I2C OLED Bağlantı Şeması

Raspberry Pi Pico ile OLED ekran arasındaki fiziksel bağlantıları kurarken RP2040’ın esnek GPIO yapısından faydalanacağız. SSD1306 OLED ekranlar genellikle 3.3V gerilim seviyesinde çalışacak şekilde tasarlanmıştır. Devre kurulumunda ekran modülünün SDA pinini Pico’nun GPIO 16 (fiziksel Pin 21) hattına, SCL pinini ise GPIO 17 (fiziksel Pin 22) hattına bağlıyoruz. Ekranın çalışması için gerekli olan 3.3V enerjiyi Pico’nun 36 numaralı pini olan donanımsal 3V3(OUT) çıkışından alıyoruz. Ekranın GND hattını ise Pico’nun 38 numaralı donanımsal toprak (GND) pinine bağlayarak devremizi tamamlıyoruz.

Raspberry Pi Pico I2C OLED Ekran Kullanımı
Pi PicRaspberry Pi Pico I2C OLED Ekran Kullanımı

OLED Sürücüsü ve MicroPython Kütüphane Kurulumu

Projemizi programlamaya başlamadan önce, bilgisayarımızda düzenli bir çalışma dizini oluşturalım. MicroPython ortamında SSD1306 ekranı sürebilmek için optimize edilmiş olan açık kaynaklı sürücü kütüphanesine ihtiyacımız var. İlgili kütüphane ve örnek kod dosyalarına ulaşmak için GitHub deposunu ziyaret edebilirsiniz. Depo içerisindeki “T3_Interfacing_An_OLED” dizininde yer alan main.py ve ssd1306.py dosyalarını oluşturduğumuz yerel proje klasörünün içine kopyalayalım. Buradaki ssd1306.py dosyası, ekranın donanımsal register ayarlarını yöneten temel sürücü kütüphanesidir; main.py ise görsel çıktılarımızı ve animasyonlarımızı yazacağımız ana kod dosyamızdır. OLED ekranda kendi özel logomuzu veya bir resmi görüntülemek istiyorsak, öncelikle o resmi mikrosaniyeler içinde işlenebilecek monokrom (1-bit) bir bitmap formatına dönüştürmeliyiz. Bunun için aynı dizinde yer alan yardımcı img_to_bmp.py script’ini bilgisayarımızda çalıştıracağız.

Görsel Dönüştürücü (img_to_bmp.py) Çalışma Mekanizması

Bilgisayarınızda bu script’i çalıştırabilmek için öncelikle popüler Python görsel işleme kütüphanesi olan PIL (Pillow) paketini pip install Pillow komutuyla kurmalısınız. Dönüştürmek istediğiniz görseli (örneğin 32×32 piksel boyutlarında bir PNG) script ile aynı klasöre yerleştirin. Script içerisindeki donanımsal dönüştürme fonksiyonu resmi açar, ardından transpose() ve convert('1') metotlarını kullanarak resmi tam monokrom (siyah ve beyaz) bayt dizisine indirger. save() fonksiyonu ile dönüştürülen görsel diskimize “.bmp” olarak kaydedilirken, io.BytesIO() aracılığıyla da bu monokrom görselin bytearray verisi terminale yazdırılır. Elde ettiğimiz bu bayt dizisini kopyalayarak main.py dosyamızdaki görsel değişkenimize atayacağız. Görsel boyutunun OLED ekran sınırlarını (128×64) aşmadığından emin olmak için dönüşüm öncesinde görsellerinizi kırpıp yeniden boyutlandırmayı unutmayın.

Python img_to_bmp.py Çıktı Arayüzü

Yukarıdaki terminal çıktısında görüldüğü üzere, test amaçlı hazırladığımız 32×32 piksellik kaynak görsel, mikrodenetleyicimizin doğrudan bellekten okuyabileceği bayt dizisine kusursuz bir şekilde dönüştürülmüştür.

Şimdi, SSD1306’nın çalışma mekanizmasını ve Frame Buffer (Çerçeve Arabelleği) kavramını inceleyelim. SSD1306 OLED ekranlar, pikselleri tek tek doğrudan I2C üzerinden çizmek yerine, tüm ekran piksellerinin durumunu (açık veya kapalı) temsil eden yerel bir arabelleğe ihtiyaç duyar. 128×64 çözünürlüğündeki monokrom bir ekranda toplam 8192 piksel bulunur ve her piksel 1 bit (0 veya 1) yer kapladığı için toplam arabellek boyutu tam olarak 1024 bayttır (1 KB).

MicroPython’un yerleşik framebuf kütüphanesi, Pico’nun SRAM’i üzerinde bu 1024 baytlık çerçeve arabelleğini oluşturur. Ekranda yapacağımız tüm metin, çizgi veya bitmap çizimleri aslında bu RAM bloğunda gerçekleştirilir ve sonrasında oled.show() komutu çağrıldığında tüm arabellek tek bir I2C veri paketi olarak ekrana yollanır (flush edilir). Bu yöntem, her piksel için ayrı ayrı I2C yayını yapmanın getireceği devasa haberleşme gecikmelerini tamamen ortadan kaldırır.

from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
import utime
import framebuf,sys
WIDTH  = 128                                            # OLED Ekran Yatay Çözünürlüğü
HEIGHT = 64                                             # OLED Ekran Dikey Çözünürlüğü

Aşağıdaki image_byte_arr değişkeni, monokrom resmimizin bitmap bayt dizisini barındırır. Python script’inden kopyaladığımız bu veriyi kodumuza ekliyoruz. Resmin tam oturması için genişlik ve yükseklik parametrelerini de 32×32 olarak tanımlıyoruz:

image_byte_arr = b'BM\xbe\x00\x00\x00\x00\x00\x00\x00>\x00\x00\x00(\x00\x00\x00 \x00\x00\x00 \x00\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x80\x00\x00\x00\xc4\x0e\x00\x00\xc4\x0e\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xfc?\xff\xff\xfb\xcf\xff\xff\xe7\xf7\xff\xff\xc7\xf1\xff\xffs\xc6\x7f\xfe\xf1\xcf\xbf\xfd\xf7\xef\xbf\xfd\xf7\xf7\xdf\xff\xff\xf7\xdf\xfb\xef\xf3\xdf\xf9\xc7\xf1\x8f\xf6\x13\xeco\xf7|>w\xf7~\x7fw\xf7\xfe\x7fw\xf7\xff\x7fo\xfb\x7f\x7fo\xfc~~\x1f\xfd\xbc=\xff\xff\xe3\xe3\xbf\xfe\xf7\xf7\xbf\xff\x7f\xff\x7f\xff3\xe4\xff\xffx\x1f\x7f\xfe\xfc?\xbf\xfd\xfe?\xff\xfb\xff\x7f\xdf\xfb\xff\x7f\xdf\xfb\xfe\x7f\xef\xfb\xff\xbf\xef\xf9\xfb\xdf\x9f\xff\x0f\xf0\xff'
image_width = 32
image_height = 32

RP2040 mikrodenetleyicisi üzerinde iki adet bağımsız donanımsal I2C denetleyicisi (I2C0 ve I2C1) yer alır. Bunlar GPIO pin haritalamasına göre esnekçe atanabilir. Örneğimizde donanımsal I2C0 kanalını aktifleştiriyoruz ve haberleşme hızını standart 100 kHz yerine, ekranın çok daha akıcı tazelenmesini sağlayan 200 kHz (veya ekranın desteklediği durumlarda 400 kHz Fast Mode) frekans seviyesine ayarlıyoruz. i2c.scan() metodu, I2C hattına bağlı olan cihazları tarar ve SSD1306’nın genellikle `0x3C` (bazen `0x3D`) olan donanımsal hex adresini terminale basarak hattın elektriksel olarak çalıştığını doğrular.

i2c = I2C(0, scl=Pin(17), sda=Pin(16), freq=200000)
print("Bağlı I2C Aygıt Adresi : "+hex(i2c.scan()[0]).upper())
print("Donanımsal I2C Yapılandırması: "+str(i2c))  

OLED nesnemizi sürücü sınıfından türeterek ekran çözünürlüğümüzü ve yapılandırılmış I2C donanım hattımızı parametre olarak iletiyoruz. oled.fill(0) komutu, tüm yerel çerçeve arabelleğini sıfırlayarak (tüm bitleri siyah yaparak) ekranı tamamen temizler.

oled = SSD1306_I2C(WIDTH, HEIGHT, i2c)

Hazırladığımız yardımcı displayText() fonksiyonu, ekran üzerinde belirli koordinatlara metin yazdırmayı kolaylaştırır. Metin koordinatları x ve y piksel konumu olarak iletilir. Örneğin (0, 0) koordinatı ekranın sol üst köşesini temsil eder.

def displayText(text, position=(0,0),clear_oled=True,show_text=True):
    if clear_oled:
        oled.fill(0)
    oled.text(text,position[0],position[1])
    if show_text:
        oled.show() 

Bitmap resimlerimizi ekranda çizdirmek için tasarladığımız displayImage() fonksiyonu ise, donanımsal bayt dizisini alır, dikey/yatay piksel tarama yönlerini düzeltmek için ters çevirir (mirroring) ve MicroPython’un monokrom çerçeve arabelleği biçimi olan MONO_HMSB (Horizontal Monochrome MSB) modunda bir FrameBuffer nesnesi oluşturur. Sonrasında oled.blit() fonksiyonuyla bu görsel arabellek verisini ana ekran çerçevesinin istenen piksel koordinatına bindirerek yansıtır.

def displayImage(image_byte_array, image_resolution,position=(0,0),clear_oled=False,show_img=True): 
    img = bytearray(image_byte_array)
    img = bytearray([img[i] for i in range(len(img)-1,-1,-1)])
    frame = framebuf.FrameBuffer(img, image_resolution[0], image_resolution[1], framebuf.MONO_HMSB) 
    if clear_oled:
        oled.fill(0) 
        print("clear")
    if show_img:
        oled.blit(frame, position[0],position[1]) 
        oled.show()
        print("display")

Aşağıdaki kod bloğunda, ekrandaki yazıları sağa ve sola kaydırarak (scrolling) dinamik bir kayan yazı animasyonu gerçekleştiriyoruz. Çerçeve arabelleğinin her yenilenmesinde koordinat değerlerini değiştirerek akıcı bir görsel hareket elde ediyoruz:

text1 = "merhaba dunya"
text2 = "devreyakan"
for x in range(0, WIDTH):
    displayText(text1,(x,0),clear_oled=False,show_text=True)
    displayText(text2,(WIDTH-x,20),clear_oled=True, show_text=True)
    if x == WIDTH:
        break
    else:
        x+=5

Sonsuz `while` döngüsü içerisinde, hem dönüştürdüğümüz bitmap görseli hem de durum metnini eşzamanlı olarak ekran üzerinde hareket ettiren gelişmiş bir animasyon döngüsü koşturuyoruz. Her kare çiziminden önce oled.fill(0) çağırarak bir önceki kareye ait piksel kalıntılarını temizliyoruz:

while True:
    y=0
    text = "Interfacing OLED"
    oled.fill(0)
    for x in range(0,WIDTH-image_width):
        displayImage(image_byte_arr,(image_width,image_height),(x,y),clear_oled=False)
        displayText(text,(x,y+40),clear_oled=False,show_text=True)
        if x == (WIDTH-image_width)-1:
            break
        else:
            x+=2
            oled.fill(0)
    for x in range(WIDTH-image_width,-1,-1):
        displayImage(image_byte_arr,(image_width,image_height),(x,y),clear_oled=True)
        displayText(text,(x,y+40),clear_oled=False,show_text=True)
        if x == 0:
            break
        else:
            x-=2

Yazmış olduğunuz main.py ve ssd1306.py kod dosyalarını Thonny IDE üzerinde açın. Kartın her açılışta bu kodları otomatik olarak koşturabilmesi için, “Farklı Kaydet” seçeneğini kullanarak ve hedef olarak “Raspberry Pi Pico”yu belirterek dosyaları kartın dahili flash dosya sistemine kaydedin. Bu sayede Pico’yu harici bir pille veya USB adaptörüyle beslediğiniz anda bilgisayar bağlantısı gerekmeden projeniz otomatik olarak çalışmaya başlayacaktır.

Thonny IDE Pico Dosya Kayıt Ekranı

Projenin Tam Kod Dosyaları

Yorum yapma özelliği, forum tarafından gelen istek sebebiyle kapatılmıştır. Lütfen tartışmalar ve sorularınız için topluluk forumumuza katılın.