Arduino: Deutsche Umlaute und Sonderzeichen am LCD (Liquid Crystal Library)

LCDs ermöglichen die einfache Darstellung von Zeichen mit dem Arduino. Bei Verwendung der I2C Schnittstelle werden nur zwei Pins vom Arduino benötigt. Üblicherweise wird dazu die Liquid Crystal I2C verwendet. Leider ist die Ausgabe der deutschen Umlaute (ä ö ü) oder dem scharfen s (ß) nicht ganz einfach.

Prinzipiell gibt es für die Anzeige folgende Möglichkeiten:

  • Umlaute als Custom Characters erstellen
  • Spezielle Steuersequenzen für die Umlaute verwenden
  • Man passt die Liquid Crystal Library so an, dass Sonderzeichen (deutsche Umlaute, scharfes s, ...) ordnungsgemäß am LCD angezeigt wird

Die ersten beiden Möglichkeiten findet man leicht im Internet. Hier stelle ich meine Noiasca Liquid Crystal vor die alles im Hintergrund erledigt.

Umlaute als Custom Characters am LCD

Man könnte die Umlaute als "Custom Characters" definieren. Mit den 8 zur Verfügung stehenden Custom Characters kann man die großen und kleinen Umlaute sowie das ß darstellen. Leider löst das noch nicht das Problem einer einfachen Ausgabe. Ich wollte daher eine neue Library erstellen, die in der Lage ist mit den bekannten .print Anweisungen Umlaute und Sonderzeichen darzustellen. Die Verwendung der Octal-Codes war mir zur unhandlich, daher habe ich eine neue LCD Library erstellt.

Teaser: Das kann die neue LCD Library mit deutschen Umlauten

Deutsche Umlaute und das scharfe-S (ß) werden im Fließtext dargestellt. Große Umlaute stehen mit einem speziellen Konstruktor auch zur Verfügung. Dazu gibt es am Ende mehr:

LCD mit deutschen Umlauten für Arduino

Die Ausgabe erfolgt mit einem normalen .print()

lcd.print("ÄäÖöÜüß");

Wir haben jetzt einen einfachen Zugriff auf einige griechische Buchstaben, wie man Sie in der Mathematik benötigt. Beispielsweise das µ (mu) oder Σ (Sigma) ist enthalten:

LCD mit griechischen Buchstaben für Arduino

(alpha, beta, epsilon, pi, mu, rho, Sigma)

Weiters gibt es eine Menge an Sonderzeichen, die im ROM des LC-Displays vorhanden sind. Das ° Grad Zeichen am LCD und die Pfeile finden sicher eine Verwendung:

Sonderzeichen (z.b. ° Grad, µ micro) am Arduino LCD

(Degree, Division, middle Point, n with tilde, Pound, Yen, Tilde, Sqareroot, Proportional to, Infinity, Left Arrow, Right Arrow, Backslash)

Hintergründe zur "Noiasca LCD Library"

Am Ende der Seite (bei den Links) steht die neue LCD Library zum Download zur Verfügung. Ich will aber auch für den interessierten Leser erklären, was dazu notwendig war.

Die Vorliegende LCD Library ist eine komplette Neuentwicklung und ist auf Basis der Datahsheets für den HD44870 entstanden. Arduino gibt für LCD ein API vor, and das sich diese Library überwiegend hält. Daher ist das Interface (das API) dieser Library mit bekannten Libraries wie z. B. die "Adafruit Liquid Crystal I2C"  oder der "Liquid Crystal" kompatibel.

Der LCD Zeichensatz

Eigentlich findet man im Zeichensatz (ROM Code A00) eines Hitachi HD44780U kompatiblen LCDs viele Sonderzeichen. Es gibt dabei drei Herausforderungen:

  • Im unteren Bereich (bis 127) weichen 3 Zeichen von ASCII ab (in der Zeichensatztabelle rot markiert). Statt dem Backslash ist ein Yen Zeichen, die Tilde musste einem "Pfeil nach Rechts" weichen. Außerdem gibt es noch einen Pfeil nach Links.
  • Die für uns interessanten Sonderzeichen (ä, ö, ü, ß) sind zwar im ROM vorhanden, liegen aber an anderen Adressen (am Bild grün markiert). Die Großbuchstaben Ä Ö Ü sind nicht vorhanden
  • "Sonderzeichen" werden als UTF-8 gesendet. Das heißt ein Zeichen kann aus bis zu 4 Bytes bestehen. Dazu unten noch mehr.

Auf Basis des Zeichensatzes im Datenblatt ergeben sich somit für uns folgende relevante Abweichungen von UTF-8:

Alle Sonderzeichen inkl. deutscher Umlaute am LCD für Arduino

Übrigens, es gibt im Datenblatt noch einen Zeichensatz ROM A02. Der Schwerpunkt von ROM A02 sind kyrillische Zeichen und europäische Sonderzeichen - auch große Umlaute gäbe es darin. Meine bisher gekauften LC-Displays haben jedoch alle das ROM A00, weshalb meine Änderungen nur für diese LCDs entstanden sind.

Hier gibt es weitere Informationen zu LCD mit kyrillischen Zeichen: Noiasca Liquid Crystal Library: Russian - Cyrillic Letters

Die UTF-8 Zeichencodierung

UTF-8 ist eine weit verbreitete Zeichencodierung. UTF-8 ist in den ersten 128 Zeichen (Indizes 0–127) deckungsgleich mit ASCII.

Die Zeichen können mit bis zu 4 Byte kodiert sein. Das ist auch der Grund, warum bei der Ausgabe von beispielsweise ä zwei "japanische" Zeichen am Display dargestellt werden. Genauer: es sind Katakana Schriftzeichen halber Breite aus dem UTF-8 Bereich 0xFF65-0xFF9F. ä wird in UTF-8 als 0xC3A4 codiert. Es ist ein zwei Byte Zeichen. Daher erfolgt die Ausgabe des Zeichens 0xC3 (das tanzende Männchen) und 0xA4 (der kurze schräge Strich).

In der nachfolgenen Tabelle sind exemplarisch einige Zeichen aus der neuen Library angeführt inklusive dem Mapping auf den ROM A00 Zeichensatz des LCD Treibers.

char UTF-8 A00 Name
\ 5C 7C REVERSE SOLIDUS ("Backslash")
~ 7E 2D TILDE
£ C2 A3 ED POUND SIGN
¥ C2 A5 5C YEN SIGN
° C2 B0 DF DEGREE SIGN
µ C2 B5 E4 MICRO SIGN
· C2 B7 A5 MIDDLE DOT
ä C3 A4 E1 LATIN SMALL LETTER A WITH DIAERESIS
ö C3 B6 EF LATIN SMALL LETTER O WITH DIAERESIS
ü C3 BC F5 LATIN SMALL LETTER U WITH DIAERESIS
Ä C3 84 E1 LATIN CAPITAL LETTER A WITH DIAERESIS
Ö C3 96 EF LATIN CAPITAL LETTER O WITH DIAERESIS
Ü C3 9C F5 LATIN CAPITAL LETTER U WITH DIAERESIS
ß C3 9F E2 LATIN SMALL LETTER SHARP S
ñ C3 B1 EE LATIN SMALL LETTER N WITH TILDE
÷ C3 B7 FD DIVISION SIGN
ñ C6 9F F2 LATIN CAPITAL LETTER O WITH MIDDLE TILDE
Σ CE A3 F6 GREEK CAPITAL LETTER SIGMA
α CE B1 E0 GREEK SMALL LETTER ALPHA
β CE B2 E2 GREEK SMALL LETTER BETA
ε CE B5 E3 GREEK SMALL LETTER EPSILON
μ CE BC E4 GREEK SMALL LETTER MU
π CF 80 F7 GREEK SMALL LETTER PI
ρ CF 80 E6 GREEK SMALL LETTER RHO
E2 86 90 7F LEFTWARDS ARROW
E2 86 92 7E RIGHTWARDS ARROW
E2 88 E8 E8 SQUARE ROOT
E2 88 9D E0 PROPORTIONAL TO
E2 88 9E F3 INFINITY

Letztere Zeichen sind Beispiele für 3 Byte Zeichen.

  • Beginnt ein Zeichen mit 0b11xxxxxx (0xC0 aufwärts), ist generell mit Folgezeichen zu rechnen.
  • 0b110xxxxx Startbyte und ein Folgezeichen, die deutschen Umlaute sind z.B. derartige Sonderzeichen
  • 0b1110xxxx (0xE0 und höher) Startbyte und zwei Folgezeichen (z.B. das Wurzelzeichen)
  • 0b11110xxx (0xF0 und höher) Startbyte und drei Folgezeichen

Das klingt jetzt komplizierter als es ist. Im Wikipedia Link (Verlinkt am Ende der Seite) ist es gut beschrieben.

Adaptierung der .write Methode für einwandfreies .print

Ich musste die Library derartig ändern, dass die .write Methode, mit Multi-Byte Zeichen korrekt umgehen kann. Warum die .write Methode? Lange Geschichte ganz kurz: die LCD Library erbt von der Print Klasse die .write() Methode. Die .write() Methode druckt ein Zeichen. Die .print() Methode ruft die .write() Methode für jedes benötigte Zeichen auf bzw. kümmert sich auch um die formatierte Ausgabe (z.B. mit zusätzlichen Parameter für Zahlen in HEX oder BIN).

Da .write() immer nur ein Zeichen von .print() bekommt, merkt sich die Library in einer Variable special, dass ein Steuerzeichen (z.B. 0xC2) gesendet wurde. Derartige Steuerzeichen werden nicht ausgegeben (zumindest wenn es als erstes Byte ankommt). Beim nächsten Aufruf von .write(), ermittelt die Library dann das entsprechende Sonderzeichen. Im Prinzip hat die neue .write() Methode nur viele If und Switch-Case Anweisungen um dieses Mapping zu ermöglichen. Damit erklärt sich auch der größere Programmspeicherbedarf der Library.

Zugriff auf Sonderzeichen mit .writeOld()

Wenn du heute schon einzelne ROM-Sonderzeichen mit der .write() Methode schreibst, so müssen diese Aufrufe auf .writeOld() geändert werde. Mit .writeOld() wird die neue Logik umgangen und die Ausgabe des Sonderzeichens erfolgt wie in der originalen Library. Die Verwendung ist einfach:

lcd.writeOld(0xE1); // Ausgabe eines ä

Betroffen sind alle Sonderzeichen im ROM ab 0xC0. Darunter fallen auch die manchmal verwendeten 0xE1 (ä), 0xEF (ö), 0xF5 (ü) und 0xE2 (ß). Mit Einsatz der neuen Library wäre aber ohnehin das direkte Schreiben der Umlaute unterstützt.

Nicht davon betroffen ist die Ausgabe von Special Characters / Custom Characters. Diese können weiterhin mit lcd.write(0) bis lcd.write(7) ausgegeben werden. Der Grund ist einfach erklärt: 0 - 7 liegt unter 0xC0 und wird somit auch von .write() unverändert ausgegeben.

Darstellungsvarianten der großen Umlaute Ä Ö Ü

Die Library unterstützt mehrere Darstellungsvarianten für die großen Umlaute. Die Auswahl der jeweiligen Variante geschieht durch die Übergabe unterschiedlicher Zeichensatz Konverter. Dazu dient der letzte optionale Parameter.

Für die I2C Libraries stehen zur Vereinfachung bzw aus historischen Gründen auch separate Konstruktoren zur Verfügung

Das Beispiel "0x05 German Umlauts" enthält alle verfügbaren Konstruktoren und zeigt, wie die unterschiedlichen Varianten verwendet werden können.

LiquidCrystal_I2C_Large lcd(addr, cols, rows);       // Ä --> A

Der Standard Konstruktor benötigt wenig Programmspeicher und ist gut lesbar. Die Umlaute Ä Ö Ü werden durch die einfachen Zeichen A O U ersetzt. Die Variante ist verwendbar, wenn man die Unterscheidung groß/klein Benötigt, aber nicht zu viel Speicher verwenden möchte.

LiquidCrystal_I2C_Small lcd(addr, cols, rows);             // Ä --> ä

Der Small Konstruktor ersetzt die großen Umlaute gegen kleine Umlaute. Das kleine ö auf einem LC Display ist gerade einmal ein Pixel niedriger als für ein großes Ö zur Verfügung stehen würde. Ähnlich beim ü - Ü. Nur beim Ä /ä fällt der Unterschied deutlicher auf. Bei 446 gelisteten Wörtern die mit Ä beginnen ist das aber verschmerzbar.

LiquidCrystal_I2C_Ae lcd(addr, cols, rows);          // Ä --> Ae

Mit dem _Ae Konstruktor werden die großen Umlaute gegen Ae, Oe, Ue substituiert. Bei dieser Variante muss man beachten, dass durch die Ersetzung je großem Umlaut zwei Zeichen dargestellt werden.

LiquidCrystal_I2C_Special lcd(addr, cols, rows);   // Ä --> Ä 

Mit dem _Special Konstruktor werden die großen Umlaute mit Hilfe von "Custom Characters" korrekt dargestellt. Dafür werden die drei letzten "Special Characters" (auch Custom Characters) 5, 6 und 7 verwendet und stehen für eigene Sketche nicht mehr zur Verfügung. Diese Variante sieht zwar am besten aus, benötigt aber auch am meisten Programmspeicher.

LiquidCrystal_I2C_ST7070 lcd(addr, cols, rows);   // Ä --> Ä 

Einige Displays verwenden statt einen HD44780 einen SPLC780D1 oder ST7070 Treiber IC. Diese Displays haben einen sehr viel umfangreicheren Zeichensatz und haben eine native Unterstützung für Ä Ö Ü, das heißt es werden keine Custom Characters benötigt und diese können weiterhin für eigene Zwecke verwendet werden. Am Ende der Seite findest weitere Informationenzu zum SPLC780D1 und ST7070

LiquidCrystal_I2C_ST7070_Ext lcd(addr, cols, rows);   // Ä --> Ä 

Mit diesem Konstruktor werden weitere Zeichen des ST7070 unterstützt. Damit ist die Darstellung aller europäischen Sprachen die auf Latin-1 oder Latin-2 benötigen möglich.

Unterstütze Hardware

Bezüglich dem Hardware Interface unterstützt die Noiasca Liquid Crystal

  • Direkt (parallel) angeschlossene Displays sowie "LCD Keyboard" Shields im 4bit Modus, also mit 6 (bzw. 7) GPIOs. Sie ersetzt z.B. die Library "Liquid Crystal"
  • I2C Expander PCF8574, wahrscheinlich die häufigst verwendete Variante und ersetzt somit die "Liquid Crystall I2C"
  • I2C Expander MCP23017 wie sie z.B. am LCD RGB KEYPAD for RPi oder am Adafruit RGB LCD verwendet werden
  • Displays mit nativer I2C Schnittstelle. Z.B. das Grove RGB, das Sureeno RGB Display oder auch das OLED LEC1621 Display
  • SPI Expander MCP23S08: SPI benötigt zwar einen Pin mehr für den Chip Select, aber wesentlich weniger Resourcen als I2C. SPI ist ideal für Projekte, bei denen SPI bereits für andere Sensoren oder Shields verwendet wird.

Bezüglich der Zeichensätze der Character ROMs unterstützt die Noiasca Liquid Crystal

Bezüglich der LCD Hardware

  • Es werden alle üblichen Formfaktoren von 1x8, 2x8, 2x16, 4x16, 2x20, 4x20 unterstützt. Hier haben einige Libraries Schwierigkeiten mit dem Zeilenanfang.
  • Das 1x16 in der Ausprägung einer logischen Zeile mit 16 Zeichen (es gibt auch welche die als 2x8 angesprochen werden müssen).
  • Als Besonderheit wird auch 4x40 unterstützt das eigentlich zwei 2x20 Displays entspricht. Damit wird auch die Library "Liquid Crystal 440" abgedeckt. Siehe: Noiasca Liquid Crystal Library 40 characters 4 rows LCD

Die Auswahl der Hardware muss über entsprechende Includes sowie entsprechende Konstruktoren bei der Anlage des LCD Objektes erfolgen. Für jeden Hardwartyp gibt es entsprechende Beispiele um die Parameter für die Konstruktoren richtig zu befüllen.

Parallel angeschlossene Displays (4bit)

#include <NoiascaLiquidCrystal.h> 
#include <NoiascaHW/lcd_4bit.h>
LiquidCrystal_4bit lcd(rs, en, d4, d5, d6, d7, bl, cols, rows);
//LiquidCrystal_4bit lcd(rs, en, d4, d5, d6, d7, bl, blType, cols, rows);

I2C Expander PCF8574P

Die häufigste Variante ist vermutlich der Anschluss des LCD mit einem PCF8574P I2C Portexpander:

#include <Wire.h>
#include <NoiascaLiquidCrystal.h>
#include <NoiascaHW/lcd_i2c.h>
LiquidCrystal_PCF8574 lcd(addr, cols, rows);

Für die Verwendung von Displays mit ST7070 Driver Chip gibt es zwei Zeichenkonverter:

#include <Wire.h>
#include <NoiascaLiquidCrystal.h>
#include <NoiascaHW/lcd_i2c.h>
LiquidCrystal_PCF8574 lcd(addr, cols, rows, convert_ST7070); // support of Latin-1 on the ST7070

Der convert_ST7070_ext unterstützt fast alle Zeichen aus dem zweiten Zeichensatz und eignet sich für die Darstellung vieler Süd- und Osteuropäischer Sprachen:

#include <Wire.h>
#include <NoiascaLiquidCrystal.h>
#include <NoiascaHW/lcd_i2c.h>
LiquidCrystal_PCF8574 lcd(addr, cols, rows, convert_ST7070_ext); // support of Latin-1 on the ST7070

SPI Expander MCP23S08

Der MCP23S08 ist ein Portexpander mit SPI Schnittstelle und eignet sich ausgezeichnet zum Ansteuern von LCDs. SPI benötigt in der Regel wesentlich weniger Programmspeicher als I2C.

#include <SPI.h>
#include <NoiascaLiquidCrystal.h>  
#include <NoiascaHW/lcd_MCP23S08.h> 
LiquidCrystal_MCP23S08 lcd(addr, csPin, cols, rows);

Mehr informationen dazu auf englisch.

Wire

Darunter fallen Displays mit nativem I2C Support, z. B. das RGB LCD von Sureeno oder von Grove bzw. auch eine Reihe von OLED Character Displays.

Das Sureeno Display:

#include <Wire.h>
#include <NoiascaLiquidCrystal.h>
#include <NoiascaHW/lcd_wire.h>
LiquidCrystal_Wire_RGB lcd(lcdAddr, cols, rows);

Das Grove Display benötigt eine andere I2C Adresse für den RGB Chip, daher muss man die RGB Adresse 0x62 übergeben:

#include <NoiascaLiquidCrystal.h>  
#include <NoiascaHW/lcd_wire.h>     
LiquidCrystal_Wire_RGB lcd(lcdAddr, rgbAddr, cols, rows);

Mehr Details und Hinweise zum Sureeno und Grove Display findest du auf der englischen Seite: Surenoo RGB and Grove RGB Display.

Die OLED Displays sind hier näher beschrieben: LCD Library for the OLED LEC1621 Display.

Einsatz der neuen Noiasca Liquid Crystal Library

Der Einsatz der neuen Noiasca Liquid Crystal ist einfach:

  • ZIP downloaden und Inhalt in das eigene Library Verzeichnis entpacken.
  • Arduino IDE neu starten.
  • Hello World Beispiel aus der Library ausprobieren, evtl. muss die Adresse des Displays angepasst werden.
  • Bestehende Sketche die bisher mit der Liquid Crystal I2C Library 1.2.1 funktioniert haben, müssen auch mit der neuen Library funktionieren. Im Regelfall ist nur die Änderung der #includes notwendig:
m, 
#include <NoiascaLiquidCrystal.h>
#include <NoiascaHW/lcd_i2c.h>
  • In das setup() kommt noch vor dem lcd.begin() der Start der I2C Wire Library
Wire.begin();
lcd.begin();
  • Hast du heute bereits Sonderbehandlungen für Umlaute im Fließtext oder gibst du Umlaute mit einzelnen .write() aus, so müssen diese Codeteile angepasst werden.
  • Wenn sonstige Sonderzeichen mittels .write() ausgegeben wurden und diese nicht in echte UTF-8 Texte geändert werden können, so sind diese Aufrufe auf .writeOld() zu ändern.

Exkurs: Die LCD I2C Adressen 0x27 vs. 0x3F

Gibt es Schwierigkeiten mit der generellen Anzeige auf einem I2C LCD, empfiehlt es sich, mit einem I2C Scanner zu überprüfen, auf welcher Adresse das Display reagiert. In den Beispielen im Internet finden sich sowohl die Adresse 0x27 sowie 0x3F. Hintergrund sind zwei kompatible Chips. Die ICs PCF8574P, PCF8574T, PCF8574TS unterstützen die Adressen 0x20 - 0x27. Die ICs PCF8574AP, PCF8574AT und 8574A - also jene mit A in der Gehäusebezeichnung - verwenden die Adressen 0x38 - 0x3F. Bis auf die abweichenden Adressen sind die Chips kompatibel und bei den Bestellungen aus China ist es reiner Zufall welcher Chip (und somit welche I2C Adresse) kommt. Verwendet man zwei verschiedene Chips könnte man also bis zu 16 I2C Displays ansteuern.

Exkurs: Kleinbuchstaben mit Unterlängen (g j p q y)

Bei den Kleinbuchstaben mit Unterlängen g, j, p, q und y erreicht man durch addieren von 0x80 (quasi 8 Spalten nach rechts in der Zeichensatztabelle) die Anzeige von Varianten die in die Unterlänge reichen. Nach einigen Tests habe ich beschlossen, das in der Library nicht umzusetzen. Die Kleinbuchstaben g p q y mit Unterlängen sind nämlich höher. Diese Zeichen haben eine Höhe von 7 Pixel und trotz Ausnutzung der Unterlänge, überragen sie somit die anderen Kleinbuchstaben um ein Pixel. Da die meisten Displays nur 5x7 Pixel je Zeichen zur Verfügung stellen, ist die Darstellung nicht besser möglich. Hier ein Vergleichsbild: erste Zeile die Standard-Buchstaben - zweite Zeile mit Unterlängen:

Kleinbuchstaben mit Unterlängen am LCD Display

Wer es dennoch mal probieren will, der schreibt beispielsweise:

lcd.writeOld('g' + 0x80);

Arduino IDE 1.8.9 und höher

Damit deine Arduino IDE auch wirklich UTF-8 voll unterstützt, brauchst du mindestens die Arduino IDE 1.8.9. Davor kann es zu Problemen in der Darstellung der Umlaute geben (siehe Arduino Releasenote Eintrag "Fix UTF8 related bugs on Windows"). Sowohl in der Ansicht im Editor, wie auch bei der Ausgabe auf der seriellen Schnittstelle müssen die Umlaute korrekt dargestellt werden können damit auch die Ausgabe am LCD funktionieren kann.

Zusammenfassung

Die neue Noiasca Liquid Crystal eignet sehr gut für die Ausgabe von deutschen Texten. Sonderzeichen - wie auch deutsche Umlaute und das scharfe s - können einfach mit den gewohnten .print Methoden ausgegeben werden. Für den unveränderten Zugriff auf Zeichen im höheren ROM Bereich gibt es einen Aufruf der alten write Methode. Optimale Unterstützung erfährt man auf Displays mit SPLC780D1oder ST7070 Treiber IC. Abschließend noch der Hinweis, dass die neue Library wegen dem Zeichen-Mapping mehr Programmspeicher und auch 4 Byte mehr SRAM benötigt.

Links

Die mit Sternchen (*) gekennzeichneten Verweise sind sogenannte Affiliate/Provision-Links. Wenn du auf so einen Verweis klickst und über diesen Link einkaufst, bekomme ich von deinem Einkauf eine (kleine) Provision. Für dich verändert sich der Preis dadurch nicht. Ich empfehle nur Produkte die ich selber besitze und wenn ich überzeugt bin, dass sie für andere interesssant sind.


Protokoll

First upload: 2020-03-20 | Version: 2022-12-26