[ Home ] [ Seitenende ]

 

 

 

Micropython mit ESP32, Teil 1

 

In der Lektion „Micropython mit ESP32“, Teil 5Das Display” geht es um die Bedienung, das Aufspielen des OLED-Treibers in Form des Micropython“-Programmsssd1306.py“, 

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

die Inbetriebnahme mittels des kleinen Micropython“-Programmsoled.py“ und die Programmierung des kleinen OLED‑Displays mit einer fünfzeiligen Textanzeige (siehe Micropython“-Programmsoled_demo.py“):

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Bei dem Sourcecode (= Quelltext) im obenstehenden Bild mit der fünfzeiligen Textanzeige (inkl. Rechteckrahmen „Micropython“) fällt sofort auf, dass jede im kleinen OLED-Display anzuzeigende Textzeile einzeln bezüglich Zeile „line“ und Spalte „pos“ positioniert und textlich programmiert wird. Hinzu kommt noch, dass zur späteren Darstellung einer jeden einzelnen Textzeile die Funktion text_line()“ zwecks Auffüllens des Pixelspeichers bemüht wird. Denn wie im YouTube-Video erklärt, erfolgt ja die Ausgabe/Anzeige auf das Display erst mit dem Aufruf des Statements oled.show()“.

 

Okay, bei dem obenstehenden Micropython“-Programmsoled_demo.py geht es ja nur darum, zu zeigen, wie sich auch Text auf dem kleinen OLED-Display darstellen lässt. Aber nichts desto trotz, möchte ich auf Dauer, d.h. beim Programmieren weiterer „Micropython“-Programme nicht jede Fehlermeldung, nicht jeden Bedienungshinweis usw. einzeln programmieren müssen. Deshalb machen wir uns an die Arbeit und „pimpen“ (= veredeln) das kleine Programm etwas. Mit dem Ziel, dass wir später nur einen einzigen Textstring programmieren, der dann automatisch auf die fünf Textzeilen umgebrochen und auf dem Display angezeigt wird.

 

Jede Schrift bzw. jeder Text in Form von zusammengesetzen Buchstaben und/oder Ziffern hat eine bestimmte Größe (= Schriftgrad bei Microsoft Word, Schriftgröße bei Writer von LibreOffice). Aber um welche Schriftgröße handelt es bei dem kleinen OLED-Display vom „HELTEC WiFi kit 32“ nebst dem „ssd1306“-Display-Treiber? Finden wir es heraus!

 

Wie man im obenstehenden Bild im roten Kasten sehen kann, verfügt das Display über die Pixel-/Bildpunktgröße von 128 x 64 Pixel. Und zwar horizontal 128 Pixel und vertikal 64 Pixel.

 

Mit einer Buchstabenbreite von 8 Pixel/Buchstabe lassen sich also pro Textzeile 128 Pixel / 8 Pixel / Buchstabe = 16 Buchstabe(n) je Textzeile horizontal darstellen!

 

Mit einer Buchstabenhöhe von 14 Pixel/Textzeile lassen sich vertikal 64 Pixel / 14 Pixel / ? Textzeile = 4,571 Textzeilen 5 Textzeilen vertikal darstellen!

 

Aber stimmt das wirklich? 5 Textzeilen vertikal, wo es doch nur ganze und eben nicht 4,6 „krumme“ Textzeilen gibt, oder? Was stimmt da nicht?

 

Was wir also als Ergebnis brauchen, ist ein ganzzahliger Quotient (= Bruch, Verhältnis) wie z.B. 60 vertikale Pixel / 12 vertikale Pixel / Textzeile = 5 Textzeilen vertikal!

 

Da wir es bei dem OLED-Display aber vertikal mit insgesamt 64 Pixel zu tun haben, verbleibt bei 60 vertikalen Pixel mit 5 vertikalen Textzeilen ein Rest von = 4 vertikalen Pixeln!

 

Weil es aber zwischen den n = 5 vertikalen Textzeilen zwecks besserer Lesbarkeit jeweils noch = ( n - 1) einpixelige Leerzeilen gibt, haben wir es mit ( n – 1 ) = ( 5 – 1 ) = 4 vertikalen, einpixeligen Leerzeilen zu tun. Für die Probe folgt dementsprechend: 5 Textzeilen * 12 Pixel/Textzeile + 4 Leerzeilen * 1 Pixel/Leerzeile = 60 Pixel (= 5 Textzeilen) + 4 Pixel (= 4 einpixelige Leerzeilen) = 64 Pixel in der Vertikalen!

 

Hier noch einmal die Zusammenfassung:

 

·       16 Buchstaben je Textzeile à 8 Pixel Buchstabenbreite

·       5 Textzeilen mit je 16 Buchstaben à 12 Pixel Buchstabenhöhe

·       4 Leerzeilen à 1 Pixel pro Leerzeile als Abstandszeile

 

Wenn wir jetzt nochmals einen Blick auf das Micropython“-Programmsoled_demo.py werfen, dann fallen in der Funktion text_line()“ zwei scheinbare Ungereimtheiten auf (siehe rote Kreise):

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Bei dem Statement „x = 10 * pos könnte z.B. meinen, dass es sich bei dem Wert „10“ um die Buchstabenbreite handelt, obwohl das rechnerisch bezüglich der Pixelzahl von 128 Pixel in horizontaler Richtung nicht stimmten kann: 16 Buchstaben * 10 Pixel Buchstabenbreite = 160 Pixel insgesamt für jede Textzeile!

 

In Wirklichkeit haben die 16 Buchstaben je Textzeile aber nur eine Buchstabenbreite von 8 Pixel/Buchstabe, was zusammen 16 * 8 = 128 Pixel in horizontaler Richtung ergibt!

 

Bei dem Statement „y = line * 11“ könnte z.B. meinen, dass es sich bei dem Wert „11“ um die Zeilenhöhe handelt (= Buchstabenhöhe + einzeilige Leerzeile), obwohl das rechnerisch bezüglich der Pixelzahl von 64 Pixel in vertikaler Richtung nicht stimmten kann: 5 Textzeilen * 11 Pixel Zeilenhöhe = 55 Pixel insgesamt!

 

Was also hat es mit diesen Angaben für die x- und y-Richtung zu tun, wozu werden diese gebraucht? Wenn man sich das weiter entwickelte Micropython“-Programmoled_demo-01-01.py anschaut, dann wird deutlich, wofür die

beiden x- und y-Angaben nützlich sind:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Diesbezüglich haben die beiden offset“-Angaben folgende Bewandnis:

 

·       Das Statement x_offset = 10“

führt zu einer Verschiebung aller Textzeilen

in horizontaler Richtung nach rechts!

 

·       Das Statement y_offset = 11“

führt zu einer Verschiebung aller Textzeilen in vertikaler Richtung mit der Folge einer Stauchung der Textzeilen für Werte < 11 an den oberen Rand des Displays

und zu einer Dehnung für Werte > 11 an den unteren Rand des Displays.

 

Die beiden offset“-Werte auf null zu setzen, macht mathematisch wenig Sinn, da die Multiplikation mit dem „pos“- oder „line“-Wert das Ergebnis null liefert.

 

Wenn man, wie im Micropython“-Programmoled_demo-01-02.py zu sehen, den offset“-Wert für das Statement y_offset = 0“ auf null setzt, dann werden alle anzuzeigenden Textzeilen in der ersten Zeile mit dem Zeilen-Index 0 übereinander angezeigt, sodass man einzelne Textstrings nicht mehr lesen kann:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Wenn man aber, wie im Micropython“-Programmoled_demo-01-03.py gezeigt, die einzeln übereinander angezeigten Textstrings so zur Anzeige bringen, dass man diese in Ruhe lesen kann, dann muss man zwischen der Anzeige zweier Textstrings eine entsprechende Pause einlegen, bevor der nächste Textstring angezeigt wird:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Während also das Statement oled.fill(0)“ dafür sorgt, dass der Bildspeicher auf null gesetzt, d.h. gelöscht wird, sorgt das nächste Statement text_line("Hallo! Ich bin",3,8)“ mittels des Funktionsaufrufs text_line(text, line, pos = 0)“ dafür, dass der Bildspeicher mit neuem Content (= Inhalt) gefüllt wird, wenn das entsprechende Statement oled.text(text,x,y)“ aufgerufen wird! Dabei wird der Bildspeicher aber erst ausgelesen und auf dem Display angezeigt, wenn das Statement oled.show()“ aufgerufen wird.

 

Demzufolge gibt es zwischen dem Befüllen des Bildspeichers mit neuem Content und dem Auslesen und Anzeigen des Bildspeichers auf dem Display eine strenge „Arbeitsteilung“ im Sinne der einzuhaltenden Reihenfolge (= Algorithmus)

 

oled.fill(0)                                  # Displayspeicher aktivieren

text_line("Hallo! Ich bin",3,8)    # Textstring in Displayspeicher

oled.show()                               # Textstring auf Display anzeigen

time.sleep(1.5)  # 1,5 s             # Pause, d.h. Anzeige stehenlassen

 

Wenn man sich den Sourcecode vom Micropython“-Programmoled_demo-01-03.py anschaut, dann sieht man, dass sich die vier im obenstehenden Kasten befindlichen Statements insgesamt fünfmal wiederholen und sich nur hinsichtlich der anzuzeigenden Textstrings wie z.B. beim Statement text_line("Hallo! Ich bin",3,8)“ unterscheiden:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Immer dann, wenn sich Dinge mehrfach wiederholen und sich praktisch nur in einem Detail, hier also der anzuzeigende Textstring, voneinander unterscheiden, bietet es sich an, eine while“- oder for“-Schleife zu programmieren (siehe Micropython“-Programmoled_demo-01-04.py:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Wie man im obenstehenden Ausschnitt des Quellkodes sieht, ändert sich in der while“-Schleife nur der Inhalt des jeweiligen Textstrings im Statement text_line(text_Str[i],3,8)“, während alles andere unverändert bleibt. Und, da sich der anzuzeigende Inhalt im Textstrings mit jeder Ausgabe/Anzeige auf dem Display ändert bzw. ändern soll, müssen wir für die Textanzeige und die Textstrings noch eine entsprechende Anzeige“-Liste namens text_Str[ ]“ in Form einer einfachen, d.h. eindimensionalen, einspaltigen Tabelle programmieren. Da wir später auch noch die anzuzeigenden Inhalte dynamisch ändern/verändern wollen, kommt ein Tabelle in Form eines Arrays zum Einsatz. Und zwar vom Typ „list“, d.h. umgangssprachlich „Liste“ im Sinne einer Aufstellung, Aufzählung oder einer Spalte einer Tabelle:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Ein ausführliches Python“-Tutorial zum Arbeiten mit Listen vom Typ tuple()“ und später auch vom Typ „list()“ findet sich hier im [ Teil 1 ].

 

Im [ Teil 2 ] des Tutorials wird ein Anwender freundliches [ Bedienmenü ] programmiert u.a. mit Funktionen, um eine Namensliste zu verändern oder zu erweitern.

 

Das dort erarbeitete und vermittelte Know-how wird später auch auf den „HELTEC WiFi kit 32“-Mikrorechner mit dem „ESP32“-Prozessor und dem OLED-Display angewendet.

 

Dabei lässt sich dann das Auswahlmenü mittels der beiden Taster direkt am Mikrorechner bedienen. Dabei blättert man mit einem Taster durch’s Menü, während man mit dem anderen den entsprechenden Menüpunkt ausführt, d.h. die dazugehörige Funktion startet.

 

Da sich mit dem mehrzeiligen,  5 x 16 großen OLED-Display nicht nur fünf Textzeilen zu je 16 Buchstaben und/oder Ziffern darstellen lässt, sondern z.B. auch Linien, Dreiecke, Rechtecke usw. darstellen lassen, kann man die Aufmerksamkeit des Anwenders oder Bedieners, die unser kleines Programm „bedienen“, auch dadurch erhöhen, indem man z.B. eine Textzeile mit einem Rahmen umhüllt und das Ganze dann auch noch blinken lässt:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Wie man im obenstehenden Quellkode sieht, wird beim Programmieren des blinkenden Rahmens um den Textstring „Micropython“ (= letzte Anzeigezeile auf dem Display) herum diesmal eine entsprechende for“-Schleife verwendet. Dabei hat man es im Schleifenkopf bei der Schleifenbedingung range(0, 9, 1)“ insgesamt mit drei Parametern zu tun.

 

Der erste Parameter „0“ legt den Startwert des Schleifenzählers n = 0 fest mit dem die Schleife beginnen soll.

 

Beim zweiten Parameter „9“ handelt es sich um den Endwert des Schleifenzählers n, d.h. genau genommen um die Abbruchbedingung! Aufgrund des Schleifenzählerbereichs, engl. „range“, von [ 0 … 9 ] könnte man meinen, dass die Schleife = n + 1 = 9  + 1 = 10 mal durchlaufen wird. Da aber die Schleifendurchläufe beim Erreichen des Schleifenzählers n = 9 abgebrochen werden, haben wir es nur mit = n + 1 = 8 + 1 = 9 Schleifendurchläufen zu tun (siehe Video)!

 

Der dritte Parameter „1“ legt fest, um welche Schrittweite, hier +1 nach oben, gezählt werden soll, sodass sich im vorliegenden Fall der Schleifenzähler stets um einen Schritt, d.h. n += 1, von einem Schleifendurchlauf zum nächsten erhöht.

 

Wie man ferner im obenstehenden Quellkode sieht, wird ganz zum Schluss des Programms noch das OLED-Display mittels des Statements „pin16.off()“ ausgeschaltet. -

 

Es soll ja im richtigen Leben auch Menschen mit einem weniger guten Kurzzeitgedächtnis geben oder auch Menschen, die sich, aus welchen Gründen auch immer, nicht so richtig konzentrieren können, weil sie eventuell zu hippelig, d.h. nervös sind (= Schilddrüsen-Überfunktion oder zu viele Energy Drinks zu sich genommen).

 

Neben dem mehr oder weniger gut ausgeprägten Kurzzeitgedächtnis gibt es bei den Menschen aber auch solche mit unterschiedlicher Lernauffassung. So müssen z.B. die Bastler und Praktiker die Dinge oftmals selbst anfassen oder von allen Seiten betrachten, um Dinge besser „begreifen“ zu können, während die Theoretiker bzw. weniger praktisch Begabten lieber einen Blick in die Bedienungs-/Aufbauanleitung werfen, ohne die sie sich stets unsicher fühlen.

 

Manche Lerntypen müssen Dinge hören, um sie besser zu verstehen. Da die Dinge bis jetzt noch nicht alle reden können, ich denke da an die Sprachausgabe z.B. der Kaffeemaschine, des Kühlschranks oder der Waschmaschine im Zeitalter des IoT, helfen sich die akustischen Lerntypen auf ihre Weise, indem sie die Dinge laut besprechen, d.h. vor sich hersagen, um was es geht. Erst wenn die Dinge akustisch wahrnehmbar sind und das Gehör beteiligt ist, fangen sie an, Dinge und Zusammenhänge (= Logik) besser zu verstehen und zu verinnerlichen.

 

Sei es wie es ist, während es die einen kurz und knackig mögen (= einzeilige Textanzeige evtl. mit Laufschriftanzeige), mögen es die anderen dafür umso geschwätziger (= mehrzeilige Textanzeige ohne Laufschrift).

 

Beim nächsten Micropython“-Programmoled_demo-01-05.py geht es deshalb darum, eine fünfzeilige Textstring-Anzeige auf das OLED-Display zu bringen, die sich übrigens (Text-) Zeile für (Text-) Zeile von oben nach unten aufbaut:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Dabei hilft uns das obengenannte Programm dabei, ein noch besseres Verständnis von der Arbeits- und Funktionsweise beim Programmieren einer Display-Anzeige zu bekommen:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Die Bildschirmanzeige auf dem Desktop-PC hat dann folgendes, selbsterklärendes Aussehen (siehe Micropython“-Programmoled_demo-01-05.py:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Als nächstes soll ein Anzeige-Programm für das OLED-Display programmiert werden, mit sich die nachfolgende Display-Anzeige anzeigen lässt:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Um das Micropython“-Programmoled_demo-01-06.py mit den richtigen Werten für die xy-Koordinaten (= 128 x 64 Pixel) im Bereich der x-Achse mit [ 0 … 127 ] = 128 Pixel und im Bereich der y-Achse mit [ 0 … 63 ] = 64 Pixel programmieren zu können, müssen wir zuvor noch entsprechende Überlegungen anstellen, wie groß der Platzbedarf in x- und y-Richtung in Form der Pixel tatsächlich ist.

 

Unschwer zu erkennen ist im obenstehenden Bild, dass fünf Zeilen Text mit einem entsprechendem Rahm außen herum für die Displayanzeige programmiert werden sollen. Bei genauerem Hinsehen erkennt man auch, dass sich die Rahm um den Text herum berühren, aber nicht überlappen! Deshalb ist die Linienstärke, dort wo sich die Rahmen berühren, doppelt so dick wie bei der äußeren Umrandung aller Rahmen.

 

Für das gesamte Display und dessen Pixelgröße folgt für den Pixelverbrauch in vertikaler Richtung, d.h. von oben nach unten: 2 * 1 Pixel * 4 Zeilen = 2 Pixel * 4 Zeilen = 8 Zeilen insgesamt, sodass für den äußeren Gesamtrahmen nur noch 64 Pixel – 8 Pixel = 56 Pixel übrig bleiben.

 

Von den 56 verbleibenden Pixel müssen dann noch 2 äußere Rahmenlinien oben und unten der Linienstärke 1 Pixel subtrahiert werden: 56 Pixel - 2 Pixel = 54 Pixel, sodass pro Textzeile jetzt nur noch = 54 Pixel / 5 Zeilen = 10,8 Pixel/Zeile = abgerundet 10 Pixel/Textzeile für den Innenrahmen übrig bleiben! Dadurch aber, dass sich die 5 Rahmen im Inneren berühren, aber eben nicht überlappen, werden wie berechnet 4 Pixel bzgl. der Gesamtpixelzahl von 64 Pixel verschenkt, verschlechtert sich die Auflösung der Darstellung, weil wir 4 Pixel für die Doppel-Innenrahmen + 1 Rundungspixel = 5 Pixel insgesamt verschenken, die sich für die max. mögliche Rahmenhöhe selbst nicht nutzen lassen, sodass sich die Lesbarkeit entsprechend verschlechtert (siehe Bild oben)!

 

Wenn wir also keinen Platz, d.h. keine Pixel bei der Darstellung der Rahmen verschwenden wollen, dann müssen wir dafür sorgen, dass sich die 5 Pixel-Rahmen um die Schrift herum eben Erwarten nicht berühren, sondern überlappen:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Sehr deutlich sieht man das im Micropython“-Programmoled_demo-01-07.py (siehe Bild oben). Und zwar wenn man das Programm startet und sich in der zweiten Textzeile der Rahmen um den Text legt, sieht man sehr deutlich, dass sich der Rahmen mit seiner Oberkante über die untere Linie des darüber befindlichen Rahmens der ersten Textzeile legt, sodass die sich überlappenden Rahmen nur noch eine Linienstärke von einem Pixel (bisher waren es zwei Pixel) ausmachen, man also insgesamt bei fünf Textzeilen insgesamt vier Pixel hinzugewinnt!

 

Für das gesamte Display und dessen Pixelgröße folgt nun für den Pixelverbrauch in vertikaler Richtung, d.h. von oben nach unten: 1 Pixel * 4 Zeilen = 4 Zeilen (vormals 8 Pixel), sodass für den äußeren Gesamtrahmen jetzt wieder 64 Pixel - 4 Pixel = 60 Pixel übrig bleiben.

 

Von den jetzt noch 60 verbleibenden Pixel müssen dann noch 2 äußere Rahmenlinien oben und unten der Linienstärke 1 Pixel subtrahiert werden: 60 Pixel - 2 Pixel = 58 Pixel, sodass pro Textzeile jetzt wieder = 58 Pixel / 5 Zeilen = 11,6 Pixel/Zeile = abgerundet 11 Pixel/Textzeile für den Innenrahmen übrig sind! Dadurch aber, dass sich jetzt die 5 Rahmen im Inneren überlappen, werden wie berechnet 4 Pixel hinzugewonnen, sodass sich die Auflösung der Darstellung entsprechend verbessert, weil wir jetzt 4 * 1 Pixel für den einfachen, und nicht mehr doppelten Innenrahmen, hinzugewonnen haben! Die dadurch verbesserte Lesbarkeit im Rahmeninneren lässt sich sogar gut erkennen! Vergleichen Sie z.B. in der letzten, d.h. fünften Textzeile „Micropython“ die beiden Buchstaben py, deren Unterlängen nun nicht mehr die untere Umrandung berühren! -

 

Abschließend bleibt noch die Frage zu klären, ob sich der sogenannte y_offset, d.h. ob sich das Dehnen, Auseinanderziehen oder Zusammenstauchen von Textzeilen auch auf die Rahmen auswirkt. Kurz und knapp, probieren wir es im Micropython“-Programmoled_demo-01-08.py einfach aus, indem wir den y_offset“-Wert z.B. im Intervall von [ 8 … 16 ] entsprechend abändern. –

 

Als nächstes geht es darum, dass wir die fünfzeilige OLED-Anzeige noch attraktiver gestalten, indem wir einen optisch ansprechenden Effekt einbauen, z.B. so wie wir es von den noch mechanischen Anzeigetafeln bei den Ankünften oder Abflügen vom Flughafen her kennen. Mich hat dabei immer fasziniert, wenn neue Flugankünfte angekündigt wurden und dabei alle Anzeigefelder und -zeilen der ganzen Tafel auf einmal durchgeblättert wurden und das mechanische Geräusch beim Umblättern der einzelnen Buchstabenblätter nicht zu überhören war. Man nennt diese inzwischen veralteten, aber an Flughäfen noch immer zu sehenden Anzeigetafeln übrigens „Faltblattanzeige“.

 

Ähnlich einer solchen Faltblattanzeige programmieren wir die Textstring-Umrandung unseres OLED-Displays, indem wir zum Schluss der Textanzeige den einzelnen Rahmen ein- bis zweimal komplett von oben nach unten „durchrattern“ lassen, um dann am Ende auf einer Textzeile stehen zu bleiben, die uns besonders wichtig ist und die wir deswegen besonders hervorheben wollen (siehe Video):

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Im obenstehenden Bild ist der Sourcecode zu sehen, nachdem der fünfzeilige Text bereits komplett angezeigt wurde und nun die einzelnen Textumrandungen in Form eines Rahmes zeilenweise von oben nach unten durchscrollen, um dann bei der siebten Zeile beim Statement if stop > 7“ zu stoppen.

 

Was bedeutet es aber, wenn es keine sieben anzuzeigenden Textzeilen gibt, sondern nur vier?

 

Da es sich bei der while“-Schleife wegen der Bedingung True um eine Endlosschleife handelt, wird diese fortwährend durchlaufen bis die Abbruchbedingung im Statement if stop > 7“ erfüllt ist, das Programm dann wegen des Statements break einfach abbricht bzw. beendet wird, die Displayanzeige wegen des auskommentierten Statements „pin16.off()“ aber eingeschaltet bleibt.

 

Da die Endlosschleife mit dem anzuzeigenden Text und den Textumrandungen fortwährend durchlaufen wird, muss der Textzeilenzähler zeile nach Erreichen der vierten, anzuzeigenden Textzeile wieder auf Anfang, d.h. den Wert 1 gesetzt werden.

 

Wenn man nun aber erreichen will, dass die Textumrandung bei der dritten Textzeile stehen bleibt, dann muss man gemäß dem Statement if stop > 7“ die Textzeilen wie folgt berechnen: 7 Textzeilen - 4 bereits angezeigte Textzeilen = 3 verbleibende Textzeilen als Rest nach dem ersten Bilddurchlauf, sodass die Textumrandung die dritte Textzeile Kit ESP32,“ umschließt.

 

Praktisch bedeutet die Abbruchbedingung im Statement if stop > 7“, dass man das Durchnummerieren der Textzeilen fortwährend weiter laufen bzw. durchrechnen lässt, so als ob es keinen Bildwechsel gäbe. Mit der Folge dass die Textanzeige mit je vier anzuzeigenden Textzeilen quasi 1 ½ Bilddurchläufe bzw. Bildwechsel erfährt.

 

Bei einer Abbruchbedingung mit dem Statement if stop > 11“ bekämen wir z.B. 11 Textzeilen / ( 4 Textzeilen/Bild ) = 2,75 Bildwechsel, d.h. zwei vollständige Bildwechsel und eine 2/3 Bildanzeige mit der Textumrandung bei der Textzeile = 11 Textzeilen / ( 4 Textzeilen/Bild ) = 2 * 4 Textzeilen + 3 restliche Textzeilen = 2 Volltextbilder + 3 restliche Textzeilen, sodass die Textumrandung den Schriftzug Kit ESP32,“ umranden würde.

 

Wenn man das Ganze ausprobiert, dann stellt man aber erstaunt fest, dass nicht der Schriftzug der dritten Textzeile angezeigt wird, sondern nur der Schriftzug „ein HELTEC WiFi der zweiten Textzeile! Der Grund dafür ist ganz einfach der, dass die Bedingung im Statement if stop > 11“ für den Wert = 11 bis dato noch nicht erfüllt wurde, sondern erst noch erfüllt werden muss, nämlich beim nächsten Schleifendurchlauf. Wenn dann aber die Abbruchbedingung erfüllt wird, bricht das Programm sofort ab, sodass die rechnerisch dritte Textzeile nicht mehr angezeigt werden kann.

 

Demzufolge werden bis zur Erfüllung der Abbruchbedingung nur 10 Textzeilen angezeigt, sodass folgt: 10 Textzeilen / ( 4 Textzeilen/Bild ) = 2 * 4 Textzeilen + 2 restliche Textzeilen = 2 Volltextbilder + 2 restliche Textzeilen, sodass die Textumrandung mit dem Schriftzug „ein HELTEC WiFi der zweiten Textzeile angezeigt wird. -

 

Aber so wie es aussieht, liegt der logische Denkfehler bei der Berechnung darin begründet, dass die anzuzeigenden Textzeilen in der Texttabelle text_Str vom Typ „list“ eben nicht bei „1“ beginnen, sondern bei „0“, während hingegen der Zeilenzähler zeile bei „1“ beginnt.

 

Im Zweifelsfall geht „Probieren“ über „Studieren“, lassen sich die Dinge ja mit dem kleinen Mikrorechner und dem Micropython“-Programmoled_demo-01-09.py praktisch ausprobieren! –

 

Dass man, wie nachfolgend im Sourcecode von Bild „01_17“ gezeigt, bei der Textanzeige im

 

 

if stop > 7: # alternativ auch den Wert 11 verwenden (siehe Tutorial)

        oled.rect(0,zeile * y_offset-1,128,11,1)

        oled.show()

        break

stop += 1

 

 

OLED-Display mittels des Statements „if stop > 7:“ auswählen kann, dass die Textanzeige mit dem Textstring Kit ESP32,“ mittels Rahmen umrandet werden soll, ist zwar sehr interessant, aber programmiertechnisch zu umständlich, da man den Wert „7“ zwecks Änderung im Quellkode erst mal finden muss.

 

Aber wenn man es dann früher oder später auch noch mit einem sehr umfangreichen Programm mit vielen Programmzeilen zu tun hat, dann ist das Motto „Wer sucht, der findet!“ nicht wirklich hilfreich, weil man sich erst wieder in das Programm einlesen muss und der Zeitaufwand für das Einlesen und die Suche unverhältnismäßig zu groß ist.

 

Viel praktischer und ergonomischer wäre es, wenn man dem anzuzeigenden Textstring auch gleich noch das Attribut “1“ stellvertretend für „Umranden“ mit auf den Weg geben könnte! Das aber wiederum bedeutet, dass wir es bei kleinen Datenbank vom Typ „list“ mit einer zweidimensionalen Tabelle, die nicht nur aus Tabellenzeilen, sondern jetzt auch aus zwei Tabellenspalten besteht, zu tun haben:

 

 

text_Str = list()

text_Str = [  ["Hallo! Ich bin",             "0"],

["ein HELTEC WiFi",     "0"],

["Kit ESP32,",               "1"],

["programmiert in",        "0"],

["Micropython",              "0"]

]

 

 

Während dabei das Deklarieren mit dem Statement text_Str = list()“ und das anschließende Initialisieren mit dem Statement text_Str = [ … ]“ eine der leichteren Übungen ist, müssen wir uns an das Handling, d.h. den Umgang mit einer zweispaltigen Tabelle erst noch schrittweise herantasten! Zu diesem Zweck wird das bisherige Micropython“-Programmoled_demo-01-09.py erst mal abgespeckt und quasi bis auf die Dinge, die mit der Tabelle zu tun haben, entkernt:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Der im obenstehenden Bild gezeigt Sourcecode lässt sich natürlich auch im Micropython“-Programmoled_demo-01-10.py selbst ausprobieren.

 

An dieser Stelle noch ein Tipp: Kopieren Sie sich die (Hyper-) Link-Adresse in die (Windows‑) Zwischenablage, indem Sie den Mauszeiger auf den blau markierten Link „oled_demo-01-10.py positionieren, mit der rechten Maustaste klicken und im Kontextmenü auf <Adresse des Links kopieren> klicken, sodass der Link in die Zwischenablage kopiert wird. Wechseln Sie anschließend in das Programm  mit der Thonny“-Entwicklungsumgebung für das Programmieren mit Micropython und Python. Klicken Sie in der Thonny“-Menüleiste auf <File>, <Open>, fügen Sie den Link aus der (Windows-) Zwischenablage wieder mittels der Tastenfolge <Strg>, <V> ein in die Eingabezeile <Dateiname> und bestätigen Sie die „Eingabe“ mit der Taste <Return/Enter>, sodass das Micropython“-Programmoled_demo-01-10.py aus dem Hinternet vom Webserver heruntergeladen und in der Thonny“-Entwicklungsumgebung angezeigt wird!

 

Nachfolgend also der maßgebliche Ausschnitt vom Quellkode zur zweispaltigen Tabelle (siehe Micropython“-Programmoled_demo-01-11.py):

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Kennen Sie den Unterschied zwischen der analogen Welt und der digitalen? In der analogen Welt gibt es z.B. abends im Sommer oftmals einen wunderschönen Sonnenuntergang bei dem die Sonne kurz vor dem Verschwinden noch als rot glühender Feuerball zu sehen ist, obwohl sie eigentlich schon seit knapp sechs Minuten hinter dem Horizont verschwunden ist, weil eben das Licht wegen der großen Entfernung zwischen Sonne und Erde trotz der Lichtgeschwindigkeit von rund c = 300 000 km/s so lange braucht, bis es die Erde erreicht. Wäre die Sonne digital, gäbe es keinen Sonnenuntergang, weil sich beim Sonnenuntergang von jetzt auf gleich ausschalten würde. In der Digitaltechnik und Informatik wird das Einschalten mit einer „1“ (auf manchen Elektro-/Elektronikgeräten mit „I“ symbolisiert) und das Ausschalten mit einer „0“.

 

Das Umschalten von „0“ auf „1“ bzw. der Schaltzustand „0“ (= „aus“) oder „1“ (= „ein“) lässt sich mit zwei Transistoren als sogenannte „bistabile Kippstufe“ oder „RS-Flipflop“ realisieren, die dabei in der Lage sind jeweils einen der beiden Schaltzustände zu speichern. Und zwar solange bis die Batterie leer ist oder der Strom ausfällt. In der Digitaltechnik und Informatik bezeichnet man den gespeicherten Schaltzustand als 1 Bit. Dabei ergeben 8 Bit = 1 Byte und 1024 Bits = 1 Kilobyte (KByte).

 

Wenn Sie jemanden beleidigen wollen, ohne eine Strafanzeige zu riskieren, dann sagen Sie zu Ihrem Gegenüber: „Du dummer 45054!“ Informatiker, die im Informatikunterricht gut aufgepasst haben, wissen, dass sich die dezimalen Zahl 45054 ins hexadezimale Zahlensystem zur Basis 16 umrechnen lässt und dann den hexadezimalen Wert „AFFE16“ ergibt. Eine einstellige, hexadezimale Zahl erstreckt sich über den Zahlenbereich [0…F]. Bei hexadezimalen Zahl rechnet man also dezimal von [0…9]10 und dann weiter mit den Buchstaben, die aber hexadezimale Zahlen sind wie z.B. [A, B, C, D, E und F]16, wobei F16 = 1510 entspricht! Starten Sie den (Windows-) Taschenrechner, schalten Sie ihn im Menü um auf „wissenschaftlich“ ( </> ), tasten Sie die hexadezimale (= engl. „HEX“) Zahl AFFE ein, und lassen Sie sich diese dezimal (= engl. „DEC“) anzeigen!

 

Jetzt sind Sie soweit sensibilisiert, dass Sie den Unterschied der ansonsten identischen Micropython“-Programmeoled_demo-01-11.py und oled_demo-01-12.py herausfinden können. Aber können Sie den Unterschied auch erklären? Versuchen Sie es, indem Sie beide Programme der Reihe nach im Mikrorechner „HELTEC WiFi kit 32“ mit dem ESP32-Prozessor laufen lassen.

 

Noch deutlicher, aufschlussreicher und erfolgsversprechender wird die Detektivarbeit, wenn man sich die beiden Micropython“-Programmeoled_demo-01-13.py und oled_demo-01-14.py anschaut und diese ausprobiert. Dann stellt man nämlich fest, dass der Programmaufruf des Programms „oled_demo-01-13.py“ zu einer Fehlermeldung in der Programmzeile 47 mit dem Statement oled.text(text_Str[2][1],zeile,spalte)“ führt. Was aber passiert in dem Statement? Tritt der Fehler im Statement auf? Ist das Statement selbst der Fehler oder liegt der Fehler ganz wo anders?

 

Mit dem Statement oled.text(text_Str[2][1],zeile,spalte)“ soll bewirkt werden, dass der Text bzw. Textstring text_Str[2][1]auf dem OLED-Display angezeigt wird. Dabei fällt auf, dass es sich bei dem Textstring nicht um einen einzelnen Textstring handelt, sondern dass sich dieser aus den beiden Teilen „[2][1]“ zusammensetzt.

 

Wenn man sich dazu den Quellkode des Programms „oled_demo-01-13.py“ anschaut, dann stellt man fest, dass es sich bei dem Textstring text_Str[2][1] um zwei Datenfelder des zweiten Datensatzes „["Kit ESP32,",      1]“ der kleinen Datenbank in Form einer 5 x 2 Matrix großen Tabelle handelt, die sich aus 5 Zeilen und 2 Spalten zusammensetzt.

 

Weiter fällt auf, dass es sich beim ersten Datenfeld mit dem Content "Kit ESP32," um einen alphanumerischen Content in Form eines Textstrings handelt, während es beim zweiten Datenfeld um einen numerischen Content in Form der Zahl = 1 geht.

 

Dazu muss man wissen, dass sich in einer Datenbank in Form einer Tabelle vom Typ „list“ nicht nur gemischte Contents (= Dateninhalte) unterbringen lassen, sondern z.B. auch Funktions-/Methodenaufrufe (siehe dazu auch im Tutorial „Micropython, Teil 1).

 

Im Vergleich zum Micropython“-Programmeoled_demo-01-14.py fällt auf, dass man bei diesem keine Fehlermeldung angezeigt bekommt, dass sich dieses fehlerfrei ausführen lässt. Im weiteren Vergleich dazu fällt auf, dass es auch bei diesem Programm einen Textstring text_Str[2][1] mit zwei Datenfeldern im zweiten Datensatzes „["Kit ESP32,",      "1"]“ gibt.

 

Allerdings, und das scheint wesentlich zu sein(!), handelt es sich bei dem zweiten Datenfeld mit dem Content "1" um einen alphanumerischen Content, d.h. um die Ziffer 1 und nicht wie im Micropython“-Programmeoled_demo-01-13.py um die Zahl 1 !!!

 

Offensichtlich lassen sich mit dem Statement oled.text(text,zeile,spalte)“ wider Erwarten keine Zahlen, sondern nur Ziffern, auf dem OLED-Display darstellen:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Quelle:

Der Hobbyelektroniker, Tutorial „Micropython mit ESP32 - 5: Das Display

 

 

Es bleibt weiterhin spannend, wenn wir der Frage nachgehen, wie der dritte Datensatz, erstes Datenfeld mit dem Content Kit ESP32,“ mittels des Statements oled.text(text_Str[2][0],zeile,spalte)“ an das OLED-Display übertragen wird.

 

Doch zunächst bleiben wir bei dem inzwischen umbenannten Funktionsaufruf text_zeile(text_Str[2][0],zeile,spalte)“ im Programm „oled_demo-01-15.py

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

und lassen uns zwecks besseren Verständnisses sowohl im Hauptprogramm als auch in der Funktion text_zeile()“ hilfsweise die unterschiedlichen Typen von Klassen wie folgt anzeigen:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Dass es sich bei dem Statement oled.text()“ um eine Funktion bzw. ein Modul der importierten Klasse „SSD1306_I2C“ handelt, lässt sich leicht nachvollziehen; dass der Funktionsaufruf „text(text,x,y)“ selbst vom Typ str ist, schon weniger!

 

Dazu muss man als Programmier-Einsteiger bzw. -Anfänger wissen, dass sich bereits im Funktionskopf(!) entsprechende Variablen, gern auch als Tabelle vom Typ „list“ mit eckigen Klammern [ ] bzw. tuple mit runden Klammern ( ) oder vom Typ bool, einrichten, d.h. deklarieren und/oder initialisieren lassen, die wiederum für den gesamten Quellkode der Funktion, aber eben nur für diese, gültig sind!

 

Dabei hindert einen niemanden daran, innerhalb der Funktion die selben Variablennamen zu verwenden wie im Hauptprogramm, obwohl deren Variableninhalte strikt von einander getrennt sind und nichts, aber auch wirklich absolut nichts, miteinander zu tun haben! Deshalb sollte man tunlichst in der Funktion prinzipiell andere, aber sinnverwandte Variablennamen verwenden!

 

Das Programm „oled_demo-01-16.py ähnelt dem Programm „oled_demo-01-15.py nur mit dem Unterschied, dass beim Ersteren jetzt das Statement oled.text(text_Str[2][0],zeile,spalte)“ direkt, d.h. ohne die Funktion text_zeile(text, zeile, spalte : int())“ an das OLED-Display übertragen wird:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Jetzt steht endgültig fest, dass die Funktion text_zeile(text, zeile, spalte : int())“ tatsächlich nur der „Bequemlichkeit“ dient bzw. in dieser nur der sogenannte Offset der „x“- und „y“-Koordinaten umgesetzt wird. Dabei lässt sich die Darstellung der Textzeilen in y“-Richtung, d.h. auf dem OLED-Display von oben nach unten, entsprechend stauchen oder dehnen! -

 

Aber bei dem Programm „oled_demo-01-16.py kommt der Offset nicht zum Einsatz, da die dazugehörige Funktion text_zeile(text, zeile, spalte : int())“ nicht verwendet wird (siehe Bild oben). –

 

So, jetzt sind wir an einem Punkt angekommen, wo wir alles analysiert und ausführlich untersucht haben, was sich untersuchen lässt. Und das Verblüffende dabei ist, dass das eigentliche Problem bzw. die Fragestellung, ob es ein funktionelles Zusammenwirken zwischen der zeilenorientierten Textdarstellung auf dem OLED-Display und der grafischen Darstellung der Umrandung mittels eines Rechtecks, das sich wiederum aus einzelnen Pixeln zusammensetzt, nicht gelöst bzw. beantwortet wurde, eben weil es zwischen der grafischen Darstellung wie bei der rechteckigen Umrandung und der zeilenorientierten Textdarstellung keinen Zusammenhang gibt: die Pixeldarstellung wie beim Zeichnen eines Rechtecks als Umrandung hat mit der zeilenorientierten Textdarstellung überhaupt nichts tun! Beide, d.h. Text und Grafik haben nichts miteinander zu tun! Die einzige Gemeinsamkeit zwischen Text und Grafik ist die, dass sich beide das gleiche Koordinatensystem teilen.

 

Im Nachhinein erscheint das einfach nur logisch zu sein. Und, wer als erfahrener Programmierer oder Mathematiker schon öfters Grafiken programmieren musste, weiß das eben!

 

Wenn man aber in ein- und demselben Programm sowohl Text als auch Grafik quasi synchron programmieren und ein an sich simpler Rahmen einen Textstring umranden soll, dann wünscht man sich eben, dass sich die Rahmengröße ganz einfach von der Text- bzw. Schriftgröße ableitet. Aber wenn man eben nicht weiß, mit welcher Schriftgröße man es bei Darstellung von Text zu tun hat und anfangs auch nicht weiß, ob sich die Schriftgröße verändern, d.h. skalieren lässt oder nicht, dann ist man mangels entsprechender Erfahrung als „digitaler Schriftsetzer“ oder grafischer Layouter schnell überfordert oder eben anfangs ziemlich ratlos. Aber das hat sich ja jetzt geklärt, sodass wir unser kombiniertes Programm „oled_demo-01-17.py mit Text- und Grafikanwendung endlich fertigstellen können:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Werfen wir abschließend noch kurz einen Blick auf das if“-Statement im obenstehenden Quellkode (siehe roter Kasten ganz oben):

 

·       if  text_Str[zeile-1][1] == "1":

 

Bei einfachen if“-Abfage ohneelse“, d.h. „Nur wenn die Bedingung xy“ erfüllt ist, wird der nachfolgende Programmkode ausgeführt, ansonsten (= „else“) passiert nichts!

 

In der if“-Abfage wird das Statement „text_Str[zeile-1][1], konkret die zweidimensionale Tabelle „text_Str[zeile-1][1] mit den zwei Parametern „[zeile-1] und [1] quasi für „Zeile“ und „Spalte“, aufgerufen und bezüglich der Inhalte, engl. „contents“, abgefragt. Dabei wird mit dem ersten Parameter konkret die „zeile-1“ = 1 - 1 = 0 aus der Tabelle text_Str ausgelesen.

 

Man höre und staune: Die Tabelle text_Str beginnt in der rauen Wirklichkeit der Programmierung tatsächlich beim Index „0“, aber das wussten wir ja eigentlich schon. Aber gerade deswegen, weil die Textzeilen stets bei „1“ beginnen und nicht bei „0“ und gleichzeitig die Grafikpixel für die Umrandung stets bei „0“ für die x- und y-Achse, gab es anfangs, auch und gerade mit dem y-Offset für das Stauchen und Dehnen der Textzeilen entsprechende Verständnisschwierigkeiten!

 

Mit dem zweiten Parametern „[1], der übrigens immer auf „1“ stehen muss, weil es sich um die zweite Spalte der Tabelle text_Str handelt, wird dann ausgelesen, ob der in der Tabelle zugewiesene Wert auf „0“ oder „1“ steht. Dabei steht „0“ für „false“, d.h. falsch, nicht zutreffend und „1“ für „true“, d.h. richtig, zutreffend.

 

Im Programm „oled_demo-01-18.py ersetzen wir die in der Tabelle text_Str enthaltenen („Wahrheits“-) Werte „0“ durch False und „1“ durch True, da die booleschen Wahrheitswerte aussagekräftiger sind und die Verwechselungsgefahr verringern. Außerdem werden die Display-Anzeigen für Text und Textumrandung in eigene Funktionen wie folgt ausgelagert:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Da wir in den obenstehenden Funktionen mit globalen Variablen aus dem Hauptprogramm arbeiten und zwar deswegen, weil wir diese zuvor mittels des Statements „from ssd1306 import SSD1306_I2C durch Importieren verfügbar gemacht haben, müssen wir diese nicht explizit über den Funktionskopf der beiden Funktionen anzeigen_Textzeile()“ und anzeigen_Textrahmen()“ einlesen! Demzufolge haben die beiden Funktionen nur die Funktion, das Hauptprogramm kompakter und übersichtlicher zu machen.

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Wie man im obenstehenden Quellkode des Hauptprogramms sieht, wird die Tabelle text_Str im

 

·       Statement if  text_Str[zeile-1][1] == "True"

 

Zeile für Zeile abgefragt, ob der zweite Parameter vom Typ bool den Wert True hat, und falls dies der Fall ist, dann wird die entsprechende Textzeile abschließend mit einem Rahmen umrandet und der Anzeigevorgang mittels des Statements break abgebrochen, da der Anzeigevorgang vollständig umgesetzt wurde (siehe Programm „oled_demo-01-18.py). –

 

 

Faltblattanzeige“ jetzt mit „exec“-Programmausführung 

 

Beim Programm „oled_demo-01-19.py wurden der Quellkode für das Anzeigen der Textzeilen sowie der Textumrandungen in die Funktionen anzeigen_Textzeile()“ und anzeigen_Textumrandung()“ ausgelagert. Da den Funktionen im Funktionskopf keine Parameter mit auf den Weg gegeben und auch keine Werte mittels „return“ zurückgegeben werden gibt es mit der Auslagerung keinerlei Probleme. Darüber hinaus wurde noch die Funktion arbeite_mit_oled()“ neu in das Programm aufgenommen. Dabei handelt es sich um das kleine OLED-Programm oled.py mit dem man sich ein „Hallo“, ein leeres und ein gefülltes Reckteck auf dem OLED-Display anzeigen lassen kann. Im Programm selbst wird das kleine OLED-Programm oled.py automatisch aufgerufen und zwar nachdem der Text Kit ESP32,“ im Display angezeigt wurde:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Wie man im obenstehenden Quellkode sieht, lässt sich mit dem Statement exec("text_auf_OLED_Display.arbeite_mit_oled()")“ die Funktion arbeite_mit_oled()“ aufrufen und ausführen. Anschließend springt das Programm an die Stelle im Quellkode zurück, von es ursprünglich aufgerufen und gestartet wurde. -

 

Das Programm „oled_demo-01-20.py ist eine Weiterentwicklung des vorhergehenden Programms mit dem Unterschied, dass das Statement break (= Abbruch des laufenden Programms) entfernt wurde, so dass die „Endlosschleife“ mit dem Statement while True weiter ausgeführt wird! Darüber hinaus gibt es in der Endlosschleife noch die neu hinzugefügte Statements text_Str[2][1] = False und text_Str[3][1] = True, sodass das extern aufgerufene Programm text_auf_OLED_Display.arbeite_mit_oled()“ nun nicht mehr ausgeführt wird und der Cursor mit dem Textstring-Anzeigerahmen als Nächstes die Anzeige „programmiert in“ anzeigt. Dabei erneuert sich die fünfzeilige Anzeige im OLED-Display fortlaufend alle fünf Sekunden! Damit wird demonstriert, dass sich die Anzeige im OLED-Display inhaltlich, d.h. bezüglich der anzuzeigenden Textstrings text_Str[?][?]“, während des laufenden Betriebs jederzeit ändern lässt:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Da die „Endlosschleife“ mit dem Statement while True nun endlos ausgeführt wird, lässt sich das Programm „oled_demo-01-20.py im Moment nur durch Unterbrechung der Stromzufuhr des kleinen „HELTEC WiFi kit 32“-Mikrorechners oder durch Mausklick auf den Button „Rotes Stop!“-Schild in der Menüleiste der Thonny“-Entwicklungsumgebung beenden! –

 

Jetzt wissen wir und schätzen es, dass sich über die fünfzeilige OLED-Displayanzeige nicht nur Contents wie z.B. Textstrings komfortabel und effektvoll darstellen lassen, sondern dass sich jetzt auch Anwendungen, wie z.B. das kleine Grafik-Testprogramm „oled.py“,  mittels des exec()“-Statements starten und ausführen lassen (siehe im Bild oben). Der Nachteil dabei ist aber noch der, dass das automatische, d.h. das Menü gesteuerte Starten und Ausführen eines anderen Programms wie z.B. die Funktion arbeite_mit_oled()“ noch manuell veranlasst bzw. extra programmiert werden musse (siehe im Bild oben). Aber genau das lässt mit geringem Programmieraufwand problemlos verbessern. Allerdings muss man dazu einen kleinen Trick anwenden bzw. wissen, wie man mit einer dreidimensionalen Tabelle umgeht, wie sich diese handhaben lässt. Doch zunächst erweitern wie die zweidimensionale Tabelle wie folgt zu einer dreidimensionalen:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Aber handelt es sich bei der oben im Bild stehenden fünfzeiligen Tabelle wirklich um eine dreidimensionale Tabelle? Dies ist natürlich eine rhetorische Frage, die einem die Antwort quasi in den Mund legt: nein. Was aber ist der Grund dafür, dass es sich nicht wirklich um eine dreidimensionale Tabelle handelt?

 

Im Bereich der grafischen Datenverarbeitung bzw. der Programmierung von Grafiken, aber auch der Abbildung/Darstellungen von Gleichungen zweiten ( f(x) = x2 ) und dritten Grades ( f(x) = x3 ) wie z.B. bei der Kurvendiskussion, haben wir es mit zwei Dimensionen, d.h. mit x- und y-Koordinaten und bei drei Dimensionen mit x-, y- und z-Koordinaten zu tun.

 

Lässt man z.B. eine zweidimensionale Hyperbel der Funktion y = f(x) = x2 um die y-Achse rotieren, dann entsteht ein dreidimensionales Gebilde ähnlich einem Sektglas in das man von oben Sekt hineinfüllen kann. Würde man die rotierende Hyperbel nach oben abschließen, d.h. auf das Sektglas einen Deckel auflegen, dann ließe sich das (dreidimensionale) Volumen wegen der Form des Sektglases bzw. der Hyperbel nur durch Integration (= Umkehrung der Differentiation) berechnen. Für die grafische Darstellung bräuchte es dann eine echte dreidimensionale Tabelle im Sinne einer dreidimensionalen Wertetabelle. Ob sich eine solche dann mit einer Tabelle vom Typ „list“, wie oben im Bild zu sehen, programmieren lässt, müsste noch geklärt, d.h. ausprobiert werden. Falls nicht, müssten wir in Python ein externes Modul importieren, um tatsächlich zwei-, drei- und vierdimensionale Arrays programmieren zu können. Apropos vierte Dimension. Wissen Sie, was allgemein als vierte Dimension bezeichnet wird? Richtig, die Zeit!

 

Was wir bezüglich unserer „dreidimensionalen“ Tabelle (siehe im Bild oben) mit Sicherheit sagen können, ist, dass es sich bei dieser um eine Tabelle mit fünf Zeilen, engl. „rows“, d.h. Reihen und drei Spalten, engl. „columns“, d.h. Spalten, handelt.

 

Ausgehend von einer dreispaltigen Tabelle müsste also eine fünfspaltige Tabelle z.B. wie folgt aussehen:

 

 

"Hallo! Ich bin"

False

""

 

 

 

"ein HELTEC WiFi"

False

""

 

 

 

"Kit ESP32,"

True

"… arbeite_mit_oled()"

param_1 *)

param_2 *)

 

"programmiert in"

False

""

 

 

 

"Micropython"

False

""

 

 

 

*) Anmerkung:

 

Bei den Parametern handelt es sich z.B. um Parameter, die der Funktion arbeite_mit_oled(param_1, param_2)“ mit auf den Weg gegeben werden können.

 

Nehmen wir einmal an, wir müssten den Parameter „param_1“ aus der Tabelle, d.h. aus der dritten Zeile und vierten Spalte auslesen und den Wert im Programm entsprechend verarbeiten bzw. programmieren. Wie müsste das dazugehörige exec()“-Statement aussehen?

 

So vielleicht:

 

param_1 = text_Str( [2][True][ ][3][ ] )

exec( text_Str( [2][True][ ][param_1][ ] ) )

 

Oder so:

 

param_1 = text_Str( [2][True][“”][3][“”] )

exec( text_Str( [2][True][“”][param_1][“”] ) )

 

Oder eventuell so:

 

param_1 = text_Str( [2][True], [3],  )

exec( text_Str( [2][True], [param_1],  ) )

 

Vielleicht sollten wir aber zunächst unsere fünfspaltige Tabelle doch etwas vereinfachen und diese wie folgt auf drei Spalten reduzieren:

 

 

"Hallo! Ich bin"

False

""

 

"ein HELTEC WiFi"

False

""

 

"Kit ESP32,"

True

"… arbeite_mit_oled()"

 

"programmiert in"

False

""

 

"Micropython"

False

""

 

Wie müsste jetzt das dazugehörige exec()“-Statement aussehen?

 

So vielleicht:

 

exec( text_Str( [2][True]["… arbeite_mit_oled()"] ) )

 

Oder so:

 

exec( text_Str( [2][ "… arbeite_mit_oled()"] ) )

 

Oder eventuell so:

 

exec( text_Str( [2][2] ) )

 

Oder wie wäre es damit:

 

exec( text_Str[2][2] )

 

Kennen Sie den Unterschied zwischen einem (Elektronik-) Bastler und einem Ingenieur der Elektotechnik/Elektronik?

 

Der Bastler bastelt, indem er z.B. Widerstände nicht zuvor berechnet, bevor er sie in einer Schaltung verwendet, sondern tauscht sie einfach gegeneinander aus. Wenn dann der Widerstand abraucht, dann war er zu klein.

 

Aber es war eben nicht der Widerstand mit seinem ohmschen Widerstandwert(!) zu klein, sondern die zulässige (Wärme-) Verlustleistung des Widerstandes!

 

Es gibt nämlich Widerstände mit z.B. 1/8, 1/4 oder 1/2 Watt zulässiger Verlustleistung. Widerstände mit einer größeren Verlustleistung von 1 bis 5 Watt sind dann wegen der Hitzeentwicklung in einem Keramikgehäuse untergebracht und Widerstände mit noch höherer Verlustleistung sind z.B. als gewickelte Spule auf einem Porzellankörper aufgebracht.

 

Der Ingenieur („Einem Ingenör ist nichts zu schwör!“, „Gestern wusste ich noch nicht, wie ‚Ingenieur’ geschrieben wird, heute bin ich schon einer!“) hingegen, bemüht erst seine grauen Zellen und versucht den Widerstand hinsichtlich seines ohmschen Wertes und seiner Verlustleistung richtig zu berechnen, bevor er diesen in die Schaltung einbaut und verlötet bzw. verdrahtet (Widerstände können nämlich so heiß werden, dass das Lötzinn schmilzt! Branntgefahr!).

 

Und was macht der Programmierer? Er wendet das Prinzip „Banane“ an: das Produkt reift beim Kunden, wird also erst mit dem dritten oder vierten Update zuverlässig funktionieren. Aber das kennt man ja z.B. von Microsoft Windows oder Google Android Betriebssystemen.

 

Was also tun? Starten Sie ganz einfach das Programm „oled_demo-01-21.py, lassen Sie sich überraschen, und schauen Sie sich den Sourcecode an:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Obwohl wir mit einer „dreidimensionalen“, pardon dreispaltigen(!) Tabelle vom Typ „list“  - die Inhalte lassen sich im laufenden Betrieb ändern! -  arbeiten, haben wir es bei dem Statement exec(text_Str[2][2])“ nur mit zwei(!) Übergabeparametern [2][2] zu tun! Wahnsinn! Da muss man erst mal drauf kommen!

 

Dabei legt der erste Parameter [2] fest, welche Tabellenzeile aus dem Indexbereich [ 0 … 4 ] im OLED-Display angezeigt werden soll und der zweite Parameter [2] (= 3. Tabellenspalte) aus dem Indexbereich [ 0 … 2 ] gibt an, dass das exec()“-Statement nebst der Funktion arbeite_mit_oled()“ aus der Klasse text_auf_OLED_Display ausgeführt werden soll:

 

 

"Hallo! Ich bin"

False

""

 

"ein HELTEC WiFi"

False

""

 

"Kit ESP32,"

True

"… arbeite_mit_oled()"

 

"programmiert in"

False

""

 

"Micropython"

False

""

 

Das exec()“-Statement nebst der Funktion arbeite_mit_oled()“ aus der Klasse text_auf_OLED_Display selbst wird aber nur dann ausgeführt, wenn die if“-Abfrage mit dem Statement „if text_Str[zeile-1][1] == True:“ den Wert True hat! -

 

Mit den beiden Statements

 

text_Str[2][1] = False

text_Str[3][1] = True

 

innerhalb des Programmblocks der if-Abfrage wird demonstriert, dass sich die OLED-Displayanzeige während des Betriebs, d.h. im laufenden Programm, jederzeit ändern lässt (siehe im obenstehenden Bild)!

 

Damit haben wir es erstmals mit der Möglichkeit einer Ereignis gesteuerten Programmierung zu tun. Vorausgesetzt natürlich, dass wir es bei der entsprechenden while“-Schleife nach wie vor mit einer Endlosschleife zu tun haben und dies bei der weiteren Programmierung nicht ändern! -

 

Wir entwickeln das Programm „oled_demo-01-21.py weiter, indem wir die Funktion text_zeile(text, zeile, spalte : int())“ in die Klasse text_auf_OLED_Display verschieben und dabei entsprechend anpassen:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Auch die Funktion anzeigen_Textzeile()“ muss wie folgt angepasst werden:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Jetzt sind alle Funktionen „unter Dach und Fach“, d.h. innerhalb der Klasse text_auf_OLED_Display vereint (siehe Programm „oled_demo-01-22.py).

 

Wie wir gleich sehen werden, lassen sich die Funktionen der Klasse text_auf_OLED_Display nicht nur vom Hauptprogramm aus steuern, sondern auch direkt vom Programmblock der Klasse aus. Und zwar ganz ohne irgendeinen Funktionsaufruf! Das funktioniert tatsächlich, weil der Python“-Interpreter vor dem Programmstart alle Klassen nach darin enthaltenden Variablen, Funktionen usw. durchsucht, nach Abhängigkeiten von anderen Klassen, Funktionen usw. durchforstet, um diese später beim Interpretieren des Programmkodes und dessen Ausführung in der richtigen Reihenfolge zu berücksichtigen. Dabei wird dann auch der in der jeweiligen Klasse vorhandene Programmkode ohne Zutun von außen gestartet und abgearbeitet (siehe Programm „oled_demo-01-23.py):

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Wenn es also darum geht, dass wir systematisch, effizient und gut lesbar programmieren, dann sollte man den Programmkode zur Ansteuerung des OLED-Displays früher oder später vom Hauptprogramm aus in den Programmblock der Klasse text_auf_OLED_Display verschieben, sodass das Hauptprogramm entrümpelt wird und im Endeffekt tatsächlich nur den zentralen, übergeordneten Quellkode enthält, während gleichzeitig jede Klasse ihre eigene Programmierung bezüglich der Funktionen usw. erhält. Auf diese Weise wird sichergestellt, dass sich innerhalb der Klasse stets nur der Quellkode befindet, der mit der Klasse und deren Programmierung zu tun hat (siehe obenstehendes Bild).

 

Nur so vermeidet man, dass sich im Hauptprogramm im Laufe der Zeit teils unterschiedlicher „Spaghetti“-Programmkode ansammelt, der mit verschiedenen Aufgaben, Funktionen und deren Klassen zu tun hat, gleichzeitig aber die Lesbarkeit und das Verständis über die Funktionsweise des Programms erschwert, weil man sich im Hauptprogramm erst mal durch das Dickicht und das Gestrüpp schlagen muss, um zu erkennen, worum es beim Programm wirklich geht. Wer sich aber im Unterholz im Wald verirrt hat und umher irrt, der darf sich nicht wundern, dass er den Wald vor lauter Bäumen nicht sieht!

 

Wie man anhand des Quellkodes im obenstehenden Bild sieht, gibt es in der Klasse text_auf_OLED_Display insgesamt vier Funktiononen von denen drei in den Funktionsköpfen mit den Parametern zeile, y_offset, oled und zwei mit dem Parameter „time“ zu tun haben:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Wenn man also den Programmblock der Klasse text_auf_OLED_Display vom Hauptprogramm des Programms „oled_demo-01-22.py ans untere Ende der Klasse text_auf_OLED_Display des Programm „oled_demo-01-23.py verschiebt (siehe grüner Kasten),

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

dann muss man zwangsläufig die bisherigen Funktionsköpfe, wie bereits weiter oben gezeigt, um die entsprechenden Parameter zeile, y_offset, oled und „time“ erweitern, damit diese auf die globalen Variablen zugreifen können. Das gilt dann auch insbesondere für die entsprechenden Aufrufe der Funktionen (siehe grüne Kästen):

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Beim Anpassen des Programmkodes vom Programm „oled_demo-01-22.py ans untere Ende der Klasse text_auf_OLED_Display im Programm „oled_demo-01-23.py fällt auf, das der Präfix auf die Klasse text_auf_OLED_Display entfällt,

 

·       text_auf_OLED_Display.anzeigen_Textzeile(zeile, y_offset, time, oled)

·       text_auf_OLED_Display.anzeigen_Textrahmen()

·       text_auf_OLED_Display.anzeigen_Textzeile(zeile, y_offset, time, oled)

 

da sich die entsprechenden Funktionsaufrufe wegen der Verschiebung nun selbst in der zugehörigen Klasse text_auf_OLED_Display befinden!

 

Abschließend muss noch beachtet werden, dass das Statement y_offset = 10“ ebenfalls in die Klasse text_auf_OLED_Display verschoben werden muss. -

 

Wenn das Programm „oled_demo-01-23.py einwandfrei läuft und sich im Hauptprogramm keinerlei Programmkode mehr befindet, haben wir es geschafft, können wir das Programm mit dem Programm „micro_python-hallo_3-2.py zwecks Verwaltung der Namensliste verheiraten, d.h. zum Programm „oled_demo-01-24.py zusammenfügen!

 

Neben den bereits beschriebenen Änderungen am Programmkode muss im Programm „oled_demo-01-24.py noch der Funktionskopf der Funktion arbeite_mit_oled()“ auf arbeite_mit_oled(oled)“ geändert werden! Dies betrifft dann auch den Funktionsaufruf arbeite_mit_oled(oled)“ in der nachfolgenden OLED-Anzeigetabelle text_Str:

 

text_Str = list([ ["Hallo! Ich bin",        False,  ““],

                         ["ein HELTEC WiFi", False,   ““],

                         ["Kit ESP32,",            True,    arbeite_mit_oled(oled)“],

                         ["programmiert in",   False,  ““],

                         ["Micropython",         False,  ““]

                       ])

 

Ziel der Zusammenführung der beiden Programme „oled_demo-01-23.py und „micro_python-hallo_3-2.py“ zum neuen Programm „oled_demo-01-24.py ist es nämlich, den später im OLED-Display anzuzeigenden Text der Tabellen-Variablen text_Str vom Programm, d.h. der Klasse verwalte_Namensliste, dynamisch generieren zu lassen:

 

Bin in der Klasse 'verwalte_Textanzeigeliste'

 

Treffen Sie Ihre Menüauswahl im Bereich [0 ... 6]:

 

         (0) einlesen_ Textanzeigeliste

         (1) ausgabe_ Textanzeigeliste

         (2) einzelne_ Textanzeige

         (3) korrigieren_Textanzeige

         (4) anzeigen_ Textanzeigenliste

         (5) hinzufuegen_Textanzeige

 

         (6) Menüauswahl verlassen

 

Treffen Sie jetzt Ihre Menüauswahl: …

 

Zu diesem Zweck wird dann die Klasse verwalte_Namensliste in Klasse verwalte_Textanzeigeliste umbenannt und aus den Vornamen wird dann Textanzeigezeile (siehe Programm „oled_demo-01-25.py). -

 

Wird demnächst fortgesetzt …

… deshalb diese Webseite als Lesezeichen/Favorit abspeichern!

 

 

 

[ Home ] [ Seitenanfang ]