- Bild-Datei in eine Binär-Datei umwandeln, welche die Farbwerte der einzelnen Pixel im RGB565-Format (s. u.) durch jeweils zwei Bytes beschreibt
- Binär-Datei auf den ESP32 laden
- Mit einem Python-Programm diese Binär-Datei auslesen und damit auf dem Display die Farbwerte der Pixel festlegen
1. Bild-Datei in Binär-Datei konvertieren
Für diesen Schritt habe ich mit Delphi ein kleines Programm geschrieben. Dabei habe ich mich auf die Konvertierung von bmp-Dateien beschränkt. Andere Datei-Typen (wie etwa jpg) kann man ja leicht in dieses bmp-Format umwandeln (z. B. mit dem frei erhältlichen Programm Irfan View).
Mein Konvertierungs-Programm bmp2bytes565.exe finden Sie im Anhang bmp2bytes256.zip zusammen mit einem Testbild. Die Benutzung des Programms ist denkbar einfach: Starten Sie das Programm und öffnen Sie die gewünschte bmp-Datei. Achten Sie dabei darauf, dass das Bild maximal 240 Pixel breit und 135 Pixel hoch ist. Im nächsten Schritt führen Sie die Kodierung durch; falls im Code-Fenster noch Bytes von einer vorangegangenen Kodierung stehen, sollte der Inhalt des Code-Fenster zunächst gelöscht werden. Je nach Größe der Bild-Datei kann die Konvertierung einige Sekunden dauern. Die ersten beiden Bytes im Code-Fenster geben die Breite und Höhe des Bildes an, die restlichen Bytes geben die RGB565-Bytes (s. u.) in dezimaler Darstellung an. Im dritten Schritt muss der RGB565-Code gespeichert werden; die Extension ist 'bin'.
Im Rest dieses Abschnitts möchte ich kurz auf das RGB565-Format und die Konvertierung von RGB nach RGB565 eingehen. Diese Darlegungen sind für das Verständnis der restlichen Abschnitte aber nicht unbedingt erforderlich. Bei der meist verwendeten RGB-Codierung wird der Farbwert eines Pixels durch 3 Bytes beschrieben: ein Byte für den Rot-Anteil, ein Byte für den Grün-Anteil und ein Byte für den Blau-Anteil. Bei der RGB565-Codierung werden für den Rot-Anteil statt 8 Bit nur 5 Bit benutzt, für den Grün-Anteil 6 Bit und für den Blau-Anteil wieder nur 5 Bit; insgesamt werden für den Farbwert eines Pixels also nur 16 Bit, d. h. 2 Bytes benutzt:
Bei meinem Konvertierungs-Programm folgt die Umwandlung vom RGB- ins RGB565-Format dem folgenden Schema:
2. Binär-Datei auf den ESP32 laden
Öffnen Sie die Thonny-IDE und suchen Sie im This-Computer-Bereich des Datei-Fensters (s. Abb. 3) nach der Binär-Datei des Bildes (z. B. testbild.bin aus dem Anhang). Klicken Sie mit der rechten Maustaste auf diesen Dateinamen; es öffnet sich ein Kontext-Menü. Hier wählen Sie die Option 'upload to /' aus. Nun wird die Binär-Datei in den ESP32 geladen. Dies dauert einige Sekunden. Danach sehen Sie den Namen dieser Datei auch im MicroPython-device-Teil des Datei-Fensters.
3. Erstes MicroPython-Programm
In unserem ersten Programm werden die Farbwerte Pixel für Pixel zeilenweise aus der Bin-Datei gelesen und mit der Methode display.pixel ausgegeben; Details können den Programm-Kommentaren entnommen werden:
Code: Alles auswählen
# Bilder mit Hilfe des Delphi-Programms bmp2bytes565.exe in Binär-Format umwandeln:
# Die ersten beiden Bytes geben dabei die Breite und Höhe des Bildes an;
# die einzelnen Pixel werden zeilenweise mit ihren 2 Farbwerten rg und gb im Display-RAM gespeichert (RGB565).
from machine import Pin, SPI
import st7789
from time import sleep
spi = SPI(2, baudrate=20000000, polarity=1, sck=Pin(18), mosi=Pin(19))
display = st7789.ST7789(spi, 135, 240, reset=Pin(23, Pin.OUT), cs=Pin(5, Pin.OUT), dc=Pin(16, Pin.OUT), backlight=Pin(4, Pin.OUT), rotation=3)
# Landscape
display.init()
display.fill(0)
# Zeilenweise lesen
f = open('testbild.bin', 'rb') # öffnen mit "[r]eading as [b]inary"
# Breite und Höhe des Bildes...
data = f.read(2) # Breite und Höhe
data = list(data) # bytearray -> Liste von Zahlen
x_max = data[0]
y_max = data[1]
# Pixel-Daten holen und in Display-Speicher übertragen...
for y in range(0,y_max):
data = f.read(x_max*2) # 1 Zeile
data = list(data) # bytearray -> Liste von Zahlen
# Index des rg- und des gb-Werts vom 1. Pixels in der Zeile y:
rg = 0
gb = 1
for x in range(0,x_max):
c = (data[rg] << 8) + data[gb]
display.pixel(x,y,c)
# nächstes Pixel:
rg = rg + 2
gb = gb + 2
f.close()
4. Zweites Micropython-Programm
Unser zweites Programm ist kürzer und arbeitet deutlich schneller. Hier werden die Farbwerte mit der Methode display.blit_buffer übertragen; Details können den Programm-Kommentaren entnommen werden:
Code: Alles auswählen
# Bilder mit Hilfe des Delphi-Programms bmp2bytes565.exe in Binär-Format umwandeln:
# Die ersten beiden Bytes geben dabei die Breite und Höhe des Bildes an, die restlichen Bytes
# stellen für jedes Pixel jeweils das rg- und das gb-Byte dar.
# Die Pixel-Daten werden mit blit_buffer direkt in das Display-RAM geschrieben; sehr einfach und enorm schnell!!!
from machine import Pin, SPI
import st7789
spi = SPI(2, baudrate=20000000, polarity=1, sck=Pin(18), mosi=Pin(19))
display = st7789.ST7789(spi, 135, 240, reset=Pin(23, Pin.OUT), cs=Pin(5, Pin.OUT), dc=Pin(16, Pin.OUT), backlight=Pin(4, Pin.OUT), rotation=3)
# Landscape
display.init()
display.fill(st7789.YELLOW) # Hintergrund
# Breite und Höhe des Bildes...
f = open('testbild.bin', 'rb') # öffnen mit "[r]eading as [b]inary"
data = f.read(2) # Breite und Höhe
data = list(data) # bytearray -> Liste von Zahlen
x_max = data[0]
y_max = data[1]
# Pixel-Daten holen und in Display-Speicher übertragen...
data = f.read(x_max*y_max*2) # alle Pixel-Bytes
display.blit_buffer(data, 50, 10, x_max, y_max)
data = 0 # vermeidet "MemoryError: memory allocation failed, allocating ..." beim Beenden des Programms
f.close()
In der folgenden Abb. 4 ist das Testbild (aus dem Anhang) auf dem Display des TTGO zu sehen:
Zum Zeitbedarf:
Messungen zeigen, dass (bei einer SPI-Baudrate von 33 MHz) zum Löschen des Displays ca. 34 ms benötigt werden. Um unser Testbild aus der Datei zu lesen, braucht das Programm ca. 13 ms; um es mit blit_buffer auf dem Display darzustellen, sind ca. 18 ms nötig.
...