1.1l 🚧 LCD Anzeige

Für kleines Geld gibt es LCD-Displays auf Basis des HD44780 Treiberchips. Um sie bequem an einem µC betreiben zu können werden sie mit einem Portexpander-Chip HLF8574 über I2C angeschlossen. Eine Library macht die Ansteuerung zum Kinderspiel.

  1. LiquidCrystal_PCF8574 installieren und Beispielcode
  2. LCD-Chip HD44780
  3. Anschluss an SturmBoard mit Hardware-Brücken
  4. Anschluss an SturmBoard mit Software Lösung
LCD (16*2) mit HD44780 über HLF8574 an I2C anschließen
LCD (16*2) mit HD44780 über HLF8574 an I2C anschließen

LiquidCrystal_PCF8574 Library

Arduino Library for LiquidCrystal displays with I2C PCF8574 adapter🔗

ToDo: Wie kann der Insert-Modus des Displays eingeschaltet werden?

LiquidCrystal_PCF8574 Library von Matthias Hertel
LiquidCrystal_PCF8574 Library von Matthias Hertel

Testprogramm

#include <Wire.h> // Wire Bibliothek einbinden
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd (0x27); // LCD-Adresse auf 0x27 für 16 Zeichen und 2 Zeilen ein

byte herz[] = {0b00000,0b01010,0b11011,0b11111,0b01110,0b00100,0b00000,0b00000};
byte dotOff[] = {0b00000,0b01110,0b10001,0b10001,0b10001,0b01110,0b00000,0b00000};
byte dotOn[] = {0b00000,0b01110,0b11111,0b11111,0b11111,0b01110,0b00000,0b00000};

void setup() {
  lcd.begin(16, 2);      // LCD initialisieren
  lcd.clear();           // Displaypuffer löschen
  lcd.setBacklight(255); // Hintergrundbeleuchtung einschalten
  lcd.setCursor(0,0);    // Cursor auf erstes Zeichen, erste Zeile setzen
  lcd.print("MezMedia.de"); // Text ausgeben
  lcd.setCursor(0,1);    // erstes Zeichen, zweite Zeile
  lcd.print("Viel Erfolg!");
  delay(2000);
  lcd.createChar(0, herz); // eigene Zeichen definieren
  lcd.createChar(2, dotOff);
  lcd.createChar(7, dotOn);
}
int show = -1;
void loop() {
  int i;
  switch(show){
    case 0: // Raus rein scrollen
      for(i=0;i<16;i++){
        lcd.scrollDisplayRight();
         delay(200);
      }
      for(i=0;i<16;i++){
        lcd.scrollDisplayLeft();
        delay(70);
      }
      delay(1000);
      break;
    case 1: // Cursor
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Cursor On");
      lcd.cursor();
      delay(1000);
      for(i=8;i>0;i--){
        lcd.setCursor(i, 0);
        delay(200);
      }
      delay(1000);
      lcd.blink();
      for(i=1;i<9;i++){
        lcd.setCursor(i, 0);
        delay(300);
      }
      delay(1000);
      lcd.noBlink();
      lcd.noCursor();
      delay(1000);
      break;
    case 2: // eigene Zeichen
      lcd.clear();
      //lcd.print("Herz:<\00>"); // funktioniert nicht 
      lcd.write(0); // RAM-Position 0 für Herz funktioniert
      lcd.setCursor(0, 1);
      lcd.print("Punkt:<\02><\07>");
      delay(2000);
      break;
    case 3: // verschiedene Zeichen ausgeben
      lcd.clear();
      for(i=0xe0;i<0xe0+16;i++){
        lcd.write(i);
        delay(50);
      }
      lcd.setCursor(0, 1);
      for(i=0xf0;i<0xf0+16;i++){
        lcd.write(i);
        delay(50);
      }
      delay(4000);
      break;
    case 4: // Autoscroll
      lcd.clear();
      lcd.print("Autoscroll-Test:");
      delay(1000);
      lcd.autoscroll(); // einschalten
      for(i=1;i<=9;i++){
        lcd.print(i);
        delay(400);
      }
      lcd.noAutoscroll(); // ausschalten
      delay(2000);
      break;
    default:
      show=-1;  
  }
    show++;
}

Funktionen

Befehl / BeispielErklärung
LiquidCrystal_PCF8574 lcd (0x27);Initialisierung für LCD auf Adresse 0x27
lcd.begin(16, 2);LCD hat 2 Zeilen mit 16 Zeichen
lcd.clear();Den Pufferspeicher löschen und Cursor auf 0,0
lcd.home();Cursor auf 0,0
lcd.setBacklight(255);Die Hintergrundbeleuchtung einschalten.
Faktisch ist 0 aus und alle anderen Werte an
lcd.setCursor(0,0);
lcd.setCursor(0,1);
Cursor auf erstes Zeichen, erste Zeile setzen
Cursor auf erstes Zeichen, zweite Zeile setzen
lcd.print("MezMedia.de");Text auf LCD ausgeben
lcd.write(0xe1);Byte zu LCD schicken, hier Code Buchstabe ‘ä’
lcd.cursor();Den Cursor einschalten
lcd.noCursor();Den Cursor ausschalten
lcd.blink();Am Cursor blinken lassen
lcd.noBlink();Blinken ausschalten
lcd.display();Display wieder einschalten
lcd.noDisplay();Display ausschalten
lcd.scrollDisplayLeft();Anzeige nach Links scrollen
lcd.scrollDisplayRight();Anzeige nach Rechts scrollen
lcd.autoscroll();Anzeige scrollt automatisch nach links bei Eingabe nach Zeilenende
lcd.noAutoscroll();Autoscroll wieder ausschalten
lcd.leftToRight();Anzeige von Links nach Rechts
lcd.rightToLeft();Anzeige von Rechts nach Links
lcd.createChar(1, dotOff);Ein eigenes Zeichen im RAM-Speicher auf Adresse 1 ablegen

LCD-Chip HD44780

Synopsis: HD44780📖 Sonderzeichen LCD HD44780 kompatibel🔗 Dot-Matrix LCD-Displays🔗

  • Ein Zeichen ist 5×8 (Breite x Höhe) Pixel groß
  • Hat einen 80 Zeichen langen Textpuffer (wird beim Scrollen interessant)
  • Kann 8 “Kundenzeichen” im RAM ablegen, Zeichen 0..7

HD44780 Displaycode Tabelle

Für ASCII funktioniert es noch gut, aber bei Umlauten und Sonderzeichen muss man sich die Code-Tabelle📖 anschauen und den entsprechenden Displaycode senden Beispiele:

ZeichenUnicodeLCD-Code
U+20AC\xd3
°U+0080\xdf
𝛼U+03B1\xe0
äU+00E4\xe1
ßU+00DF\xe2
εU+03B5\xe3
µU+00B5\xe4
𝜎U+03C3\xe5
öU+00F6\xef
ΩU+03A9\xf4
üU+00FC\xf5
ΣU+03A3\xf6
πU+03C0\xf7
HD44780 Zeichensatz

💊 Umlaute und Sonderzeichen ersetzen

#include <Wire.h> // Wire Bibliothek einbinden
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd (0x27);

String text="Für 20° -> 30µV";

void setup() {
  lcd.begin(16, 2);      // LCD initialisieren
  lcd.clear();           // Displaypuffer löschen
  lcd.setBacklight(255); // Hintergrundbeleuchtung ein
  Serial.begin(9600);
  Serial.println(text);
  lcd.print(text);       // Text direkt ausgeben
  lcd.setCursor(0,1); 
  lcd.print("F\xf5r 20\xdf \x7e 30\xe4V"); // Codiert
}

void loop() {}

Die Ausgabe von UTF-8 auf dem seriellen Monitor klappt problemlos. Die LCD-Anzeige gibt aber Unsinn aus. Erst durch händisches Ersetzten mit den richtigen LCD-Codes wird die Anzeige sinnvoll.

Sonderzeichen auf LCD ausgeben
Sonderzeichen auf LCD ausgeben

🚧 Aufgabenidee: Erstellen Sie eine Funktion void ausgebenLCD(String s), die sinnvolle Ersetzungen für diese Zeichen vornimmt: \~°µßäöü-><-

Vergleichen Sie die Zeichen in den Listen: Unicodeblock Basis-Lateinisch📖 Unicodeblock Lateinisch-1, Ergänzung📖 mit der Tabelle der LCD-Codes und erstellen Sie eine Tabelle mit den zu ersetzenden Zeichen. Gegebenenfalls müssen eigene Zeichen im RAM hinterlegt werden.

😵‍💫 Noch keine Lösung, bin über UTF-8 und Strings gestolpert. Scheint kompliziert zu werden. Z.B. String utf=”\\~°µßäöü”; utf.length() ergibt 14 🤷…

UTF\ 0x5c~ 0x7e° 0xb0µ 0xb5ß 0xdfä 0xe4ö 0xf6ü 0xfc
LCDRAM 0x00RAM 0x010xdf0xe40xe20xe10xef0xf5

LCD an SturmBoard anschließen mit Drahtbrücken

Das I2C-LCD-Display ist an PA11 (SCL) und PA12 (SDA) angeschlossen. Beim Assembler und bei MBED hat Herr Sturm eine Software I2C-Lösung zur Anbindung verwendet, d.h. es wird nicht die I2C-Hardware des Controllers genutzt, sondern die Schnittstelle ist per Software realisiert.
Die Arduino I2C-Library Wire benutzt standardmässig D15 = PB8 (SCL) und D14 = PB9 (SDA). Meine einfache Lösung sind zwei Drahtbrücken:

  • Serial Clock SCL: D15 = PB8 -> PA11
  • Serial Data SDA: D14 = PB9 -> PA12
#include <Wire.h> // Wire Bibliothek einbinden
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd (0x27); // LCD-Adresse auf 0x27 für 16 Zeichen und 2 Zeilen ein

void setup() {
   lcd.begin(16, 2); // initialize the lcd
   lcd.clear();
   lcd.setBacklight(255);
   lcd.setCursor(0,0); // erstes Zeichen, erste Zeile
   lcd.print("MezMedia.de");
}

void loop() { 
  delay(1000);
  lcd.setBacklight(255);
  lcd.setCursor(0,1); // erstes Zeichen, zweite Zeile
  lcd.print("Viel Erfolg!"); 
  delay(1000);
  for (int i= 255;i>=0;i--){
    lcd.setBacklight(i);
    lcd.setCursor(0, 1);
    lcd.printf("Backlight: %d    ",i); 
    delay(50);
  }
}

Mit dem Testprogramm erkannt: Die Hintergrundbeleuchtung geht nur an und aus. 😕
Beim STM32L152RE gibt es zwei I2C Schnittstellen, die über eine interne Verdrahtungsmatrix auf unterschiedliche Ports geschaltet werden können. Im Datenblatt ab Seite 47 sind die möglichen Anschluss-Pins für I2C zu finden.
PA11 und PA12 sind leider nicht dabei. 😭
Nach der API-Beschreibung kann die zweite Schnittstelle recht leicht eingerichtet werden, auch dort könnte das LCD-Display mit Drahtbrücken von PB10 und PB11 angeschlossen werden. Leider wird dies mit der BlueTooth Schnittstelle kollidieren.

I2C Drahtbrücken für LCD bei SturmBoard
I2C Drahtbrücken für LCD bei SturmBoard
I2C Drahtbrücken für LCD bei SturmBoard
I2C Drahtbrücken für LCD bei SturmBoard
PinI2C
PB5 (D4)I2C1_SMBA
PB6 (D10)I2C1_SCL
PB7I2C1_SDC
PB8 (D15)I2C1_SCL
PB9 (D14)I2C1_SDA
PB10 (D6)I2C2_SCL
PB11I2C2_SDA
PB12I2C2_SMBA
Mögliche Pins für I2C
Verkabelung bei externem LCD
Verkabelung bei externem LCD

LCD an SturmBoard anschließen mit Software Lösung

Ein Kollege hat eine Softwarelösung entwickelt, die ohne Drahtbrücken auskommt: https://github.com/schreger/LiquidCrystal_PCF8574_SoftWire/tree/main
Dazu muss eine Bibliothek eingefügt werden, Perplexity:

Arduino Bibliothek hinzufügen: Schritt-für-Schritt-Anleitung

Es gibt zwei Hauptmethoden, um eine Bibliothek zur Arduino IDE hinzuzufügen:

1. Über den Bibliotheksmanager (empfohlen)
  • Öffne die Arduino IDE.
  • Gehe zu Sketch > Bibliothek einbinden > Bibliotheken verwalten….
  • Im Bibliotheksmanager kannst du nach dem Namen der gewünschten Bibliothek suchen.
  • Wähle die gewünschte Bibliothek aus und klicke auf Installieren.
  • Die IDE lädt die Bibliothek automatisch herunter und installiert sie.

😔 Geht nicht, weil Bibliothek nicht auftaucht.

2. Manuelle Installation einer ZIP-Bibliothek
  • Lade die gewünschte Bibliothek als ZIP-Datei (z.B. von GitHub) herunter.
  • Öffne die Arduino IDE.
  • Gehe zu Sketch > Bibliothek einbinden > .ZIP-Bibliothek hinzufügen….
  • Wähle die heruntergeladene ZIP-Datei aus und bestätige mit Öffnen.
  • Die Bibliothek wird installiert und steht anschließend zur Verfügung.

😉 Geht nicht, weil die JSON-Dateien fehlen.

.ZIP-Bibliothek hinzufügen...
.ZIP-Bibliothek hinzufügen…
.ZIP-Bibliothek Fehler
.ZIP-Bibliothek Fehler

👋 Manuelles Hinzufügen zum Sketch

1. Sketch erstellen:
#include <Arduino.h>
#include <SoftWire.h>
#include <LiquidCrystal_PCF8574_SoftWire.h>

SoftWire wire(PA12, PA11);

LiquidCrystal_PCF8574_SoftWire lcd(0x27); // set the LCD address to 0x27

void setup() {
  wire.begin(); 
  wire.setClock(100000); // I2C speed 100kHz 
  lcd.begin(16, 2,wire); // initialize the lcd for a 16 chars and 2 line
  lcd.clear();
  lcd.setBacklight(255);
  lcd.setCursor(0,0); // erstes Zeichen, erste Zeile
  lcd.print("MezMedia.de");
}

void loop() {
  delay(1000);
  lcd.setBacklight(255);
  lcd.setCursor(0,1); // erstes Zeichen, zweite Zeile
  lcd.print("Viel Erfolg!"); 
  delay(1000);
  for (int i= 255;i>=0;i--){
    lcd.setBacklight(i);
    lcd.setCursor(0, 1);
    lcd.printf("Backlight: %d    ",i); 
    delay(50);
  }
}
2. Library laden und entpacken

https://github.com/schreger/LiquidCrystal_PCF8574_SoftWire/tree/main

3. Mit Copy & Paste zum Sketch hinzufügen

Taucht dann im Sketch auf und wird mit kompiliert.

Manuell hinzufügen: Copy & Paste
Manuell hinzufügen: Copy & Paste