lcd.createChar für mehr als 8 Zeichen?

Guten Tag @ all.

Ich würde gerne auf meinem 20x4 LCD Display etwas künstlerisch aktiv werden. Hierzu hab ich die Funktion lcd.createChar gefunden und mir das gewünschte Bild schon in die byte-Blöcke umgeschrieben.
Habe jetzt nur das Problem das ich die createChar-Funktion nur 8 mal verwenden kann (wenn ich nicht ganz verkehrt bin, dann kann char 256 aufnehmen (ohne Vorzeichen).
Gehe ich hin und verwende die Funktion ein 9. mal, dann bekomme ich auf dem Display überall wo eigentlich das 1. Symbol hin soll ebenfalls das 9. → er überschreibt also mit 9 die 1.
Kann mir jemand sagen wieso - und insbesondere wie ich mehr Zeichen erstellen kann?

Habs mal damit versucht 7 Zeichen zu definieren, diese zu schreiben und danach wieder neue zu definieren, aber auch da überschreiben die höherzähligen Zeichen dann die niederzähligen …

#include <LiquidCrystal_I2C.h>
#include <Wire.h>

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// Zeichen erstellen
byte boden[8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
B11111
};
byte turm1[8] = {
B00000,
B00000,
B00000,
B11111,
B11111,
B11000,
B11001,
B11010
};
byte turm2[8] = {
B01110,
B01110,
B01110,
B11111,
B11111,
B10100,
B00100,
B00100
};
byte turm3[8] = {
B00000,
B00000,
B00000,
B11001,
B11000,
B11000,
B11000,
B11000
};
byte turm4[8] = {
B11100,
B11010,
B11001,
B11000,
B11000,
B11000,
B11000,
B11000
};
byte turm5[8] = {
B00100,
B00100,
B00100,
B10100,
B01100,
B00100,
B00110,
B00101
};
byte turm6[8] = {
B11011,
B11111,
B11011,
B11011,
B11011,
B11011,
B11111,
B11011,
};
byte turm7[8] = {
B00000,
B00000,
B00000,
B00001,
B00000,
B00000,
B00000,
B11111,
};
byte turm8[8] = {
B11000,
B11000,
B11000,
B11000,
B11001,
B11010,
B11100,
B11010,
};
byte turm9[8] = {
B00110,
B00100,
B01100,
B10100,
B00100,
B00100,
B00100,
B00100,
};
byte turm10[8] = {
B11000,
B11000,
B11000,
B11000,
B11000,
B11000,
B11000,
B11000,
};
byte turm11[8] = {
B11001,
B11000,
B11000,
B11000,
B11000,
B11000,
B11111,
B11111,
};
byte turm12[8] = {
B00100,
B10100,
B01100,
B00100,
B00110,
B00101,
B11111,
B11111,
};
byte turm13[8] = {
B11000,
B11000,
B11000,
B11000,
B11000,
B11000,
B11111,
B11111,
};
byte pfeil1[8] = {
B00000,
B01000,
B10000,
B11111,
B10000,
B01000,
B00000,
B00000,
};
byte pfeil2[8] = {
B00000,
B00000,
B00000,
B11111,
B00000,
B00000,
B00000,
B00000,
};
byte pfeil3[8] = {
B00000,
B00000,
B00010,
B11110,
B00010,
B00000,
B00000,
B00000,
};
byte pfeil4[8] = {
B00000,
B00000,
B00000,
B00111,
B00100,
B00100,
B00100,
B00100,
};
byte pfeil5[8] = {
B00100,
B00100,
B10101,
B01110,
B00100,
B00000,
B11111,
B11111,
};





void setup() {
 // I2C-Display initialisieren
    lcd.begin(20,4);
    lcd.backlight();
    
 // 1.Block
    lcd.createChar(0, boden);
    lcd.createChar(1, turm1);
    lcd.createChar(2, turm2);
    lcd.createChar(3, turm3);
    lcd.createChar(4, pfeil1);
    lcd.createChar(5, pfeil2);
    lcd.createChar(6, pfeil3);
    lcd.createChar(7, turm4);
    lcd.createChar(8, turm5);   // und ab hier wird 0 überschrieben .... :-(
    
    lcd.setCursor(0, 0);
    lcd.print((char)0);
    lcd.print((char)1);
    lcd.print((char)2);
    lcd.print((char)3);
    lcd.print((char)4);
    lcd.print((char)5);
    lcd.print((char)6);
    lcd.print((char)7);
    lcd.print((char)8);
    lcd.print("Ende");
lcd.setCursor(1, 1);
}

void loop() {}

Der Zeichensatz eines Text-Displays besteht aus 256 Zeichen.
Davon kannst Du 8 Zeichen selbst definieren und 248 Zeichen sind "fest" im Zeichenspeicher vorprogrammiert.

Die 8 Zeichen, die Du selbst definieren kannst, kannst Du beliebig oft ändern.

Du kannst z.B. mit einer neunten Definition eines Zeichens das erste früher selbstdefinierte Zeichen wieder mit einer anderen Definition überschreiben.

Aber Du hast zu jedem Zeitpunkt nur 8 selbstdefinierte Zeichen.

Wenn Du künstlerisch tätig werden möchtest, nimm ein Grafik-Display anstelle eines Text-Displays!

Schau dir mal das Datenblatt des Display Controllers an. Der Controller hat ein "character generator RAM" mit 64 Bytes. Also 8 Zeichen à 8 Zeilen. Mehr geht hardware-seitig nicht.

Ich hätte aber auch gedacht, dass man die Zeichen im RAM überschreiben kann nach dem sie auf dem Display dargestellt wurden und sie dann sichtbar bleiben.

Der Displaycontroller HD44890 https://www.sparkfun.com/datasheets/LCD/HD44780.pdf bzw seine Nachbauten haben RAM für 8 selbstdefinierte Zeichen. Diese werden 2x im unteren Berech für Zeichen eingeblendet ( von 0 bis 7 und von 8 bis 15) (Tabelle 4 auf Seite 17 des Datenblatts. ). In der Tabelle heisen sie CGRAM (Character Generator RAM)
Wie bereits vorgeschlagen kannst Du die Zeichen jederzeit ändern aber hast nur 8 verschiedene zur Verfügung die gleichzeitig auf dem Display dargestellt werden können.
Grüße Uwe

Danke - an die Sache mit den 8 Freien hatte ich garnet gedacht.

Wenn ich diese jedoch so oft wie ich will verändern kann, wieso wirkt sich dann eine Änderung nach dem print-Befehl auf beide aus?
z.B.:

#include <LiquidCrystal_I2C.h>
#include <Wire.h>

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// Zeichen erstellen
byte leer[8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000
};
byte voll[8] = {
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};


void setup() {
 // I2C-Display initialisieren
    lcd.begin(20,4);
    lcd.backlight();
    
    lcd.createChar(0, leer);
    lcd.setCursor(0, 0);
    lcd.print((char)0);
    
    lcd.createChar(0, voll);
    lcd.setCursor(0, 1);
    lcd.print((char)0);
}

void loop() {
}

Ich definiere das 1. Zeichen als “leer” - schreibe somit dies in die Zeile 1 - ändere das 1 freie Zeichen auf “voll” und schreibe dies in Zeile 2.
Somit sollte nur in Zeile 2 ein Block zu sehen sein - Ergebniss ist jedoch das in beide Zeilen ein voller Block zu sehen ist.

Ich schreibe die beiden ja nicht gleichzeitig sondern einzel … somit sollte der 2. print-Befehl den 1. doch garnet abändern können?!

Grafik-Display wäre vermutlich besser (hab noch keine Erfahrungen damit gemacht) aber hab eben das Display schon ins Projekt fest eingebaut … :wink:
Wenns auch mit dem Display ginge dann würds mich freuen - ansonsten wirds eben erst im nächsten Projekt mit eingeplant.

Scorch:
Ich definiere das 1. Zeichen als "leer" - schreibe somit dies in die Zeile 1 - ändere das 1 freie Zeichen auf "voll" und schreibe dies in Zeile 2.
Somit sollte nur in Zeile 2 ein Block zu sehen sein - Ergebniss ist jedoch das in beide Zeilen ein voller Block zu sehen ist.

Ich schreibe die beiden ja nicht gleichzeitig sondern einzel ... somit sollte der 2. print-Befehl den 1. doch garnet abändern können?!

Das Display wird vom HD44890 laufend aktualisiert (passiert z.B. mit 60 Hz, beim HD44890 weiß ichs grad nicht auswendig). Im Speicher des Displays stehen die Zeichencodes für jede Position; Wird das Display aktualisiert, läd der Controler das "Bild" des Zeichencodes als Pixeldaten auf das Display. Wenn du das Zeichen "1" ausgibst, dann wird das "Bild" das sich hinter dem Code 1 auf das Display geschrieben. Änderst du die Pixeldaten mit createChar, dann steht da halt das neue Bild. Es ist Hardwaremäßig nicht vorgesehen, dass du mehr als 8 selbstdefinierte Zeichen verwenden kannst. Es gibt einfach icht genug Speicher. Was Uwe gemeint hat ist, dass du Zeichen austauscht, wenn du sie nicht auf dem Display brauchst. So kannst du z. B. im ersten Bildschirm 8 Sonderzeichen haben, die ein Logo räpresentieren, eine Sekunde später ein anderes (nachdem du alle selbstdefinierten Zeichen ausgetauscht hast). Gleichzeitig mehr als 8 zu nutzen geht nie.
Einige Blockgrafikzeichen sind übrigens schon im festen Zeichensatz enthalten (z. B. komplett gefüllter Block).

Scorch:
... Wenn ich diese jedoch so oft wie ich will verändern kann, wieso wirkt sich dann eine Änderung nach dem print-Befehl auf beide aus?...

Hatte ich doch geschrieben:

uwefed:
Wie bereits vorgeschlagen kannst Du die Zeichen jederzeit ändern aber hast nur 8 verschiedene zur Verfügung, die gleichzeitig auf dem Display dargestellt werden können.

Grüße Uwe