6 Text Ausgabe

Zifern und Buchstaben werden für unser Auge aus Dot-Anordnungen gebildet. Zu ihrer Darstellung definiert man in Variablen das Pixelabbild jedes gewünschten Zeichens. Über Textfunktionen liest man diese Variablen aus und setzt alle entsprechenden Dots auf dem Display. Im Beispiel wwFlipdot-clock-direct verdeutliche ich, wie man das "zu Fuß" mit direkten Dotbefehlen realisieren kann.

4x7 Ziffern-Font - <i>wwFont_4x7</i>

4x7 Ziffern-Font - wwFont_4x7

Text-Fonts

Text-Fonts sind Sammlungen von Pixelabbildern einzelner Zeichen, die man im Programm komfortabel nutzen kann. Vom PC her sind wir in 2020 bezüglich Font-Vielfalt und Darstellungsqualität sehr verwöhnt. Wegen des geringen Speichers im Arduino NANO und der kleinen Anzeigeaulösung bzw. -größe geht es auf unseren Flip-Dot-Modulen etwas spartanischer zu. Wir können aber auf einen reichen Erfahrungsschatz aus den Anfängen des Computer zurück greifen: 9-Nadel-Drucker oder 5x7 LED Anzeigen hatten früher das gleiche Problem.

Font-Strategie der wwFlipGFX

Meine Fonts sollten 1. für eine einfache Benutzung per ASCII Code ansprechbar sein und 2. aus Speicherplatzgründen nicht immer den vollen Zeichensatz enthalten müssen.

Dazu gibt es die Strategie des Jump Table bzw Look-Up-Tables = Nachschau-Tabelle. Bei dieser Struktur findet man am Anfang jeder Font-Datei eine Tabelle, in der für jedes ASCII Zeichen Anfangsposition und Byte-Anzahl notiert sind.

Gibt es für ein vom Benutzer verwendetes ASCII-Zeichen keine Dot-Daten, wird dies der aufrufenden Funktion über den Look-Up-Table mitgeteilt. Das beugt Fehlfunktionen im Programmablauf vor - man kann jeden ASCII Text an alle Textfunktionen senden, ohne das dadurch unzulässige Speicherzugriffe erfolgen würden.

Fonts der wwFlipGFX-Library

Um das Rad nicht neu erfinden zu müssen, habe ich mir verschiedene Font-Strukturen angeschaut. Mene Wahl fiel auf die ThingPulse ESP8266 OLED SSD1306 Library, da sie einen Look-Up-Table verwendet und sowohl einen Font Converter, als auch einen Font-Editor zur freien Verfügung stellt. Dazu mehr auf der nächsten Seite.

Die von mir erstellten und mit der Library ausgeliferten Fonts findet man im Unterordner Arduino\libraries\wwFlipGFX\src\fonts\. Die Ziffern im Dateinamen geben Breite und Höhe eines Fonts an. wwFont_4x7_fix.h ist somit ein 4 Dot breiter und 7 Dot hoher Font. fix bedeutet, dass er eine feste Zeichenbreite aufweist. Dieser Font hat einen geringen Speicherbedarf, da er nur die Ziffern 0-9 und wenige Buchstaben enthält, mit denen man eine Uhr darstellen kann.

Speicherort aller Fonts der wwFlipGFX-Library

Speicherort aller Fonts der wwFlipGFX-Library

Der wwFont_Xx7.h besitzt ebenfalls eine Zeichenhöhe von 7 Dots, ist aber in der breite variabel (X) und enthält einen vollen ASCII Zeichensatz incl. deutscher Umlaute. Er besitzt keine Ober- oder Unterlängen. Mit 7 Dot Höhe kann er auf jedem Flip-Dot-Modul ausgegeben werden. Auf 16 Dot hohen Displays ist 2-zeiligiger Text möglich. In deutschem Text unübliche ASCII Zeichen fehlen zur Speicherplatzersparnis. Fehlende Zeichen können ergänzt werden - siehe nächste Seite. Im Beispiel wwFlipGFX-01-lauftext wird die Verwendung dieses Fonts demonstriert.

Ziffernsätze für Uhren

Zur Darstellung der Uhrzeit benötigt man mindestens 4 Ziffern, einen Doppelpunkt und 4 Zwischenräume zwischen den Zeichen. Bei einem 4 Dot breiten Schriftsatz ergibt das eine Mindestbreite von 21 Dot.

4x7 Font für Uhren ab 21x7 Display - <i>wwFont_4x7</i>

4x7 Font für Uhren ab 21x7 Display - wwFont_4x7

4x9 Font. Für zweizeiligen Text sind 19 Dot hohe Module nötig - <i>wwFont_4x9</i>

4x9 Font. Für zweizeiligen Text sind 19 Dot hohe Module nötig - wwFont_4x9

4x9 Font für Uhren. Einzeilig ab 21x9 Dot großen Modulen darstellbar,<br>also auch auf KRUEGER 24x16 Modulen

4x9 Font für Uhren. Einzeilig ab 21x9 Dot großen Modulen darstellbar,
also auch auf KRUEGER 24x16 Modulen

Befehle zur Verwendung von Fonts

Bevor man einen Font benutzen kann, muss man ihn am Anfang des Programms per #include einbinden. Fonts werden im 32k Programm Memory des Arduino Nano gespeichert, belegen also nicht das knappe RAM. Wenn der Speicherplatz ausreicht, kann man auch mehrere Fonts parallel einbinden und im Programm abwechselnd verwenden.

#include "fonts/wwFont_4x7_fix.h"  //kopiert den Font in das Programm Memory 
#include "fonts/wwFont_4x9_fix.h"  //Fonts können parallel verwendet werden

Bevor man mit einem Font schreiben kann, muss er per mSetFont(wwFont_Xx7) ausgewählt werden. Das kann einmal am Anfang des Prorgamms im Setup() geschehen oder beliebig oft im Programmablauf. Alle Textfunktionen verwenden immer den zuletzt gesetzten Font zur Darstellung.

Da der Font zu Beginn des Programms 1x dauerhaft in das Programm Memory geladen wird, erhöht ein hin und her Schalten zwischen verschienden Fonts anschließen den Speicherbedarf nicht weiter.

mSetFont(wwFont_Xx7);  //wählt einen Font für alle folgenden Textbefehle aus
                       // hier ist die Dateiendung .h nicht mit anzugeben

Zur Speicherplatzersparnis kann man in der Zeichensatzdefinitionen die Leerspalten zum Trennen der Zeichen entfernen und erst später programmtechinsch wieder hinzu fügen. Die wwFlipGFX erlaubt das Einstellen eines beliebigen Zeichenabstands, was auch für Hervorhebungseffekte verwendet werden kann. Der Zeichenabstand kann beliebig oft umgestellt werden.

void mSetCharSpace(uint8_t charSpace); // Setzt den Zeichenabstand (0-255)
                                       // Default = 1 = ein Dot Abstand

Die Zeichenketten werden immer erst in die Matrix geschrieben und anschließend per mUpdate(); auf das Display gespielt - Erklärung dazu siehe eine Seite weiter vorne unter Grafikfunktionen. Alles zum Thema Koordinatenursprung (x/y) ist dort ebenfalls nachzulesen. Vor einem mUpdate(); können beliebig viele Text und Grafikfunktionen zur Erzeugung des Bildinhalts aufgerufen werden. Texte werden auf schwarzem Hintergrund dargestellt, darunterliegende Grafiken also gelöscht.

Der Textstart darf auch außerhalb des "sichtbaren" Flip-Dot-Displays liegen und positive wie negative Werte im Rahmen eines int16_t annehmen. Die außerhalb des Sichtfelds liegenden Dots eines jeden Zeichens werden ignoriert. So kann man sehr einfach Laufschriften erzeugen - siehe Beispiel unten.

Per mDrawDigit(); kann man eine Ziffer von 0-9 mit dem vorher gewählten Font ausgeben. Man übergibt die Zahl nicht als ASCII String, sondern direkt als Integer Wert bzw. per Variable im Bereich zwischen 0 und 9. Das spart z.B. bei einer Uhr Konvertierungsaufwand im eigenen Code.

void mDrawDigit(int16_t topLeftCornerX, int16_t topLeftCornerY, uint8_t digit);
//Schreibt die Ziffern 0-9. Übergabe als Integer. x/Y = linkes oberes Dot

Normalen Text übergibt man hingegen als String and die entsprechende Funktion. Es sind alle ASCII Zeichen erlaubt. Ist eins davon im aktuellen Zeichnesatz nicht definiert, wird es problemlos ausgelassen. Der übergebene Startpunkt x/y markiert die linke obere Position des ersten Dots im Text. Übergibt man z.B. für x negative Werte, wird der entsprechende Textanfang nicht mit ausgegeben.

void mDrawString(int16_t topLeftCornerX, int16_t topLeftCornerY, String text);
// Schreibt einen Text in die Matrix. x/y = linke obere Textecke

Wer bei Fonts mit variabler Zeichenlänge die Textbreite für eigene Berechnungen eines Zeilenumbruchs oder einer Scrolldauer benötigt, kann sie per getStringWidth(); abrufen. Der Text kann als String oder per Pointer und ASCII-String-Länge übergeben werden.

uint16_t getStringWidth(const char* text, uint16_t length);  
uint16_t getStringWidth(String text);	 
// Rückgabe = Stringbreite in Dots bei Ausgabe mit aktuellem Font

Fallblattsimulation

Immer wieder hört man von Menschen: "Die Flipdots klingen ja wie am Flughafen". Das ist so aber häufig nicht richtig, da am Flughafen oder am Bahnhof meist Fallblattanzeigen motiert waren. Fallblattanzeigen bestehen aus einem "Block" von Ziffern und Buchstaben, die auf Karten = Fallblätter gedruckt sind und ähnlich einem alten Telefonregister drehbar um eine Achse angeordnet sind. Dreht man diese Achse, springt ein Fallblatt nach dem anderen zur Vorderseite hin sichtbar um, was ein charakteristisches Geräusch des Durchscrollens erzeugt.

Um diesen Effekt einfach simulieren zu können, habe ich die Funktion mScrollDigit(); entwickelt. Es sollten möglichst nur Fonts mit fester Breite verwendet werden - sonst kann es "komische" Effekte geben. Aktuell können die Ziffern 0-9 angezeigt werden. Die Übergabe des Werts 10 entspricht einem leeren Feld. Damit kann man eine Ziffer neu aufbauen oder löschen.

void mScrollDigit(uint8_t x0, uint8_t y0, uint8_t digitOld, uint8_t digitNew);
//Funktion zum Simulieren einer Fallblattanzeige
//Wechselt eine Ziffer (zwischen 0 und 9) digitOld in digitNew 
//Übergabe als integer Wert; Wert 10 entspricht einem leeren Feld

Die Funktion mScrollDigit(); berücksichtigt einige Parameter zur Ausgabegestaltung, die man vor dem Funktionsaufruf nach eigenem Geschmack einstellen kann.

void mScrollSpace(uint8_t scrollSpace);
// Abstand zwischen einlaufendem und auslaufendem Zeichen in Dots

void mScrollDirection(uint8_t scrollDirection);  
// Scrollrichtung hoch oder runtern: UP/DOWN

Um den Scrollefekt zu erzeugen, "blättert" die Funktion die Ziffern in der Matrix jeweils um ein Dot nach oben/unten, bevor sie ein mUpdate(); ausführt. Die Scrollgeschwindigkeit wird durch ein internes delay(); realisiert, dessen Länge man frei wählen kann.

void mScrollDelay(uint16_t scrollDelay);
// Verzögerung zwischen jedem einzelnen Scrollschritt in ms (1 Sekunde = 1000 ms)

Der folgende Code verwendet den Font wwFont_4x7_fix.h. Die Ziffern 1 und 2 scrollen langsam von unten nach oben und schnell wieder zurück nach unten.

// ==========================================================================
#include "wwFlipGFX.h"
#include "fonts/wwFont_4x7_fix.h"   // Enthält nur die Zeichen +-0123456789:C°
wwFlipGFX ww;
// ==========================================================================
void setup() {
  ww.begin();
  ww.dotPowerOn();  // schaltet die Flipspannung auf die Treiberbausteine
  ww.setCoilFlipDuration(1000);
  ww.resetAll(0);   // lösche alle Dots so schnell es geht, also ohne Verzögerung
  delay(500);
  ww.mSetFont(wwFont_4x7_fix);
}
// ==========================================================================
void loop() {
  uint8_t x0 = 3;          //Linke obere Ecke der Ziffer
  uint8_t y0 = 1;

  ww.mScrollDirection(UP); //Voreinstellung der Scrollrichtung auf Up = nach oben
  ww.mScrollDelay(200);    //200 ms = 0,2 Sekunden Anzeigezeit pro Scrollschritt 
  ww.mScrollSpace(2);      //2 Dot Abstand zwischen den scrollenden Ziffern

  ww.mScrollDigit(x0, y0, 1, 2); //Ziffer 1 zu Ziffer 2 an Position x0/y0 wechseln
  delay(2000);                   //2 Sekunden warten

  ww.mScrollDirection(DOWN);
  ww.mScrollDelay(80);
  ww.mScrollSpace(4);

  ww.mScrollDigit(x0, y0, 2, 1);
  delay(1000);
}
// ===========================================================================

keine Verfolgung durch soziale Medien

Deprecated: Directive 'allow_url_include' is deprecated in Unknown on line 0