Proje Defteri

GIF'ten OLED Animasyon Dönüştürücü

Hareketli bir GIF bırakın, her kareyi C dizisi olarak ve SSD1306, SH1106 gibi tek renkli ekranlar için çalışır bir Arduino kodu olarak alın. Flash maliyeti siz ayar yaptıkça hesaplanır, yani animasyonun sığmadığını derlemenin sonunda değil burada öğrenirsiniz.

1. Animasyon seçin

GIF'i buraya bırakın ya da tıklayıp seçin. Ayrı ayrı PNG/JPG kareler de olur.

2. Ekran ayarları

3. Kareler

Bir kareye tıklayarak onu animasyondan çıkarın. Bellek çubuğu kırmızıya döndüğünde flash maliyetini yarıya indirmenin en hızlı yolu bir kare atlayarak silmektir.

4. Çıktı

OLED animasyonu aslında nasıl çalışır

Yaygın ekran kütüphanelerinin hiçbirinde animasyon desteği yoktur. SSD1306'nın o an gösterdiği tek ekranın ötesinde kendine ait bir kare tamponu ve zaman çizelgesi kavramı yoktur. Animasyon dediğiniz şey, kodunuzun bir durağan bitmap çizmesi, beklemesi, sonrakini çizmesi ve bunu tekrarlamasıdır. Bu aracın ürettiği her şey o döngüye hizmet eder: bir bitmap listesi ve aralarındaki gecikme.

Bu bakış, insanların takıldığı iki noktayı da açıklar. Birincisi bellek, çünkü her kare sıkıştırılmadan, tam boyutuyla saklanır. İkincisi hız, çünkü kareyi panele göndermek I2C hattında gerçek zaman harcar ve o süre saniyedeki kare sayınızın tavanını belirler.

Derlemeden önce bellek maliyetini hesaplamak

Tek renkli bir kare piksel başına bir bit tutar, yani tam ekran 128x64 bir animasyonda kare başına 128 × 64 ÷ 8 = 1024 bayt eder. Sonrası acımasız bir aritmetik:

Arduino Uno'da 32 KB flash var ve bootloader bunun yaklaşık 0,5 KB'ını alıyor. Adafruit_GFX ile birlikte Adafruit_SSD1306, metin de kullandığınızda kabaca 10 KB daha götürüyor. Geriye animasyonunuz ve programınızın kalanı için 20 KB civarı kalıyor; bu sayfadaki panelin teorik sınırdan çok önce uyarmasının sebebi bu.

En etkili tasarruf kare sayısını azaltmak değil, çizim alanını küçültmektir. İki boyutu da yarıya indirmek maliyeti dörtte bire düşürür. Hareketli bir robot göz çifti nadiren tüm paneli ister: ekranın ortasına yerleştirilmiş 64x32'lik bir alan aynı görünür ve dörtte biri kadar yer kaplar.

Dizilerin PROGMEM ile işaretlenmesi gerektiğini de not edin. O olmadan derleyici dizileri SRAM'e kopyalar; Uno'da toplam 2 KB SRAM olduğu için iki tam kare bile sığmaz. Yukarıdaki kutucuk varsayılan olarak işaretlidir ve üretilen kod kareleri pgm_read_ptr() ile geri okur, yani bu kararın diğer yarısını da halleder.

Kare hızı ve I2C darboğazı

128x64 bir kare 1024 bayttır ve varsayılan 100 kHz'deki I2C, protokol yükü de sayıldığında saniyede kabaca 10 KB taşır. Bu, kare başına yaklaşık 90 ms, yani saniyede 11 kare eder; üstelik daha sizin kodunuz hiçbir şey yapmadan. Animasyonunuz GIF'ten yavaş görünüyorsa sebep genellikle ayarladığınız gecikme değil, budur.

Hattı Wire.setClock(400000) ile yükseltmek saniyede 40 kare civarına çıkarır, bu da gözün ihtiyacının ötesindedir. SSD1306 modüllerinin çoğu 400 kHz'i sorunsuz kaldırır; bozulma görüyorsanız sınır denetleyici değil, pull-up dirençleriniz veya kablo uzunluğunuzdur. SPI ekran bu soruyu tümden ortadan kaldırır, çünkü SPI bir kat daha hızlı çalışır.

Doğru çıktı formatını seçmek

Aynı pikseller üç ayrı şekilde paketlenebilir ve yanlış olanı seçmek tanıdık bir bozulma üretir, bu da teşhisi kolaylaştırır.

Adafruit GFX pikselleri satır satır, baytta sekiz tane, en anlamlı bit solda olacak şekilde saklar. display.drawBitmap() ile kullanın. Varsayılan budur ve çoğu proje için doğru cevaptır.

U8g2 XBM aynı satır düzenini kullanır ama her baytın içindeki bit sırasını ters çevirir, çünkü X11 bitmap formatı böyle yapıyordu. u8g2.drawXBMP() ile kullanın. Görseliniz sekiz pikselllik yatay bloklar halinde aynalanmış çıkıyorsa, bu ikisinden yanlış olanı seçmişsiniz demektir.

Ham sayfa formatı SSD1306 denetleyicisinin kendi belleğini sakladığı düzenle aynıdır: sekiz satırlık dikey sayfalar, sütun başına bir bayt. Bir kareyi doğrudan kütüphanenin tamponuna memcpy ile yazıp piksel piksel çizim döngüsünü atlamanızı sağlar, gözle görülür şekilde hızlıdır. Bedeli ise yalnızca 0,0 konumunda ve panelin tam boyutunda çalışmasıdır. Görseliniz yatay şeritlere bölünmüş çıkıyorsa, yatay dizi beklenen yerde dikey dizi kullanmışsınızdır.

İyi görünen 1 bitlik görsel elde etmek

Tek renkli panelde gri yoktur. Her piksel ya açık ya kapalıdır, yani fotoğrafik bir kaynağın indirgenmesi gerekir ve nasıl indirgediğiniz, kaynağın çözünürlüğünden daha çok önem taşır.

Sert eşik kesme değerinin üstündeki her şeyi tutar, kalanı atar. Çizgi çalışması, logo, metin ve pixel art için doğru seçimdir; bu ekranlara girenlerin çoğu da zaten bunlardır. Şekil net okunana kadar eşik kaydırıcısını ayarlayın.

Floyd-Steinberg her pikselden kalan hatayı komşularına yayar ve fotoğrafları okunur kılan ince dokuyu üretir. Animasyonda tek bir dezavantajı vardır: doku kareler arasında tamamen değişir, göz de bunu gürültü olarak okur. Animasyonunuz kaynıyormuş gibi görünüyorsa sert eşiğe geçin.

Bayer sabit bir 4x4 matris kullanır, yani desen kareler arasında yerinde kalır. Bu da onu özellikle animasyon için daha iyi dithering seçeneği yapar; tek bir durağan kare genelde Floyd-Steinberg ile daha güzel görünse bile.

Sıkça sorulan sorular

image2cpp neden bana tek kare veriyor?

Çünkü dosyayı bir HTML canvas'a çiziyor ve canvas tek kare tutuyor. Bu image2cpp'nin hatası değil, tarayıcının bir özelliği. Bu sayfa GIF kabını doğrudan ayrıştırıyor: LZW ile sıkıştırılmış blokları, imha yöntemlerini ve her karenin gecikmesini okuyarak animasyonun tamamını çıkarıyor. Durağan görseller için image2cpp hâlâ kullanılacak araç ve TFT paneller için renkli çıktıyı da o veriyor.

Animasyonum Arduino Uno'ya sığmıyor, ne yapmalıyım?

Kazandırdıkları sırasıyla: çizim alanını küçültün, bir kare atlayarak silin, sonra döngüyü kısaltın. 64x32 bir animasyon tam ekranın dörtte biri kadar yer kaplar. Bunlar da yetmezse ESP32 veya Nano ESP32'de megabaytlarca flash var, soru ortadan kalkar. Kareleri SD kartta tutup akıtmak mümkün ama genelde ekranın çizebileceğinden zaten daha yavaş kalır.

Robot gözü için kullanabilir miyim?

Evet, bu sayfanın en yaygın kullanımı da bu. Göz kırpma ve etrafa bakma için bir GIF çizin ya da bulun, çizim alanını küçük tutun ve şekiller net kalsın diye dithering yerine sert eşik kullanın. Onar karelik iki adet 64x32 göz animasyonu, set başına 2,5 KB ile Uno'ya rahat sığar.

Araç SH1106 veya Nokia 5110 destekliyor mu?

Evet. Önemli olan denetleyici değil, bayt düzeni. SH1106 SSD1306 ile aynı formatları alır, tek farkı kütüphanenin hallettiği bir sütun kaymasıdır. 84x48'lik Nokia 5110 de çalışır: boyutu ayarlayın ve ham sayfa formatını kullanın, o denetleyicinin doğal düzeni de odur.

Kaç kare hızını hedeflemeliyim?

Karakter animasyonu için saniyede on iki ila on beş kare yeterlidir ve 400 kHz'deki bir I2C hattının başka işlerle birlikte sürdürebildiği hız da kabaca budur. Sekizin altı slayt gösterisi gibi okunmaya başlar. Yirminin üstüne çıkmak harcadığı flash'a nadiren değer, çünkü her ek kare bir bitmap daha demektir.

Bir şey yükleniyor mu?

Hayır. Çözme, dithering, paketleme ve kod üretiminin tamamı tarayıcınızda çalışır. Sayfa bir kez yüklendikten sonra çevrimdışı da çalışır.