Zeichen auf LCD invertieren

Ich habe mir eine kleine Uhr geschrieben, die auf einem 16x2 LCD angezeigt wird und die man mit einem Dreh-Encoder stellen kann. Soweit funktioniert auch alles!
Aber es besteht noch ein kleiner Schönheits-“fehler”. Beim stellen der Uhr setze ich den Cursor auf blinken, so dass ich sehe, was ich einstelle. Ich kann aber immer nur eine Stelle blinken lassen.
Also zum Beispiel beim Jahr nur die “2” von “2016”. Hier mal als Beispiel-Sketch:

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // setze die I2C-Addresse fuer das LCD auf 0x27 (16 Zeichen, 2 Zeilen)

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print(2016);
  lcd.setCursor(0, 0);
  lcd.blink();
}

void loop() {

}

Nun, vielleicht geht das hardwaremäßig nicht anders!?
Also bin ich auf die Idee gekommen, man könnte doch die CustomChars “missbrauchen” und die Zahlen invertiert darstellen. Aber wie komme ich an die nicht-invertierten Zahlen?
Kann man irgendwie das Character-ROM auslesen?
Oder muss ich mir für jede Zahl ein eigenes Zeichen erstellen?

Ja, du müsstest jedes Zeichen einzeln definieren. Allerdings: die üblichen Displays können maximal acht eigene Zeichen handlen...somit wird das bei einer Uhr nicht klappen. Was aber geht (und auch noch ausreichend schnell sein dürfte): einfach die normalen Zeichen blinken lassen, indem du sie abwechselnd schreibst oder nen Leerzeichen.

Ich hab's befürchtet! Aber eigentlich müsste ich doch mit den 8 Zeichen auskommen. Ich brauche doch nur max. 4 Zeichen gleichzeitig (Jahr ist 4stellig, alle anderen (Monat, Tag, Stunden, Minuten, Sekunden) sind nur 2stellig). Ich müsste dann die jeweils benötigten mit createChar dynamisch erstellen. Oder dauert das zu lange? Muss ich mal testen...

Sofern du nur 8 unterschiedliche (eigene) Zeichen gleichzeig im Display brauchst kann das klappen. Aber dann ist das eine recht verschachtelte Umkopier-Aktion… Erst letztens hatten wir hier so ein Fall von Doc_Arduino, der damit hantiert hatte -und anschließend recht ernüchtert war. :confused:

Ob es zeitlich schnell genug ist kann ich nicht sagen.
Versuch macht kluch…

*Nachsatz:
Gerade ist mir noch etwas eingefallen, wodurch du dir das Umkopieren komplett ersparen könntest:

Vor ein paar Monaten hatte ich kurzfristig ebenfalls “lcd.blink()” im Einsatz, jedoch aus obigen Gründen wieder verworfen. Dann aber hatte ich an Stelle dessen die Funktion “lcd.cursor()” genommen. Das ist der Unterstrich der die nächste Schreibstelle zeigt - aber auch unter ein bestehendes Zeichen gezeichnet wird.

Was spricht dagegen, genau dieses “lcd.cursor()” über eine (unabhängige) Routine im Halbsekunden-Takt ein- und auszuschalten? Das zeigt dann ebenso die Cursor-Position, blinkt lustig vor sich hin und spart viel Kopier-Code. Trägt zwar nicht so “dick auf” wie .blink(), erfüllt aber ebenso genau diesen Zweck. Voraussetzung ist natürlich, dass dann nirgends delay(x) im Programm vorhanden ist.

Hallo,

was heißt hier ernüchtert? Rudi. Der Thread und der Weg war lang und steinig, führte aber mit Whandall genau zum Ziel. Funktioniert wie es soll und ist im Einsatz. Man muß nur einmal wirklich hinter die Methode gestiegen sein. Ist aber sicherlich hierfür Overkill, auch wenn es cool ist. Außer man möchte unbedingt den invers Effekt. Dann geht das nur so.

Genauso gut würde hier neben der Blink-Funktion auch ausreichend sein im Wechseltakt die Ziffer darzustellen und wieder die Zelle mit leer überschreiben. Dann blinkt das auch oder hat eben den Effekt.

Am einfachsten finde ich die Display eigene Cursor Blink Funktion. Zelle beschreiben und Cursor wieder um eine Stelle zurücksetzen. Damit er wieder in der richtigen Zelle blinkt, solange du im Modify-Mode bist für die Stelle.

Wenn eine zweistellige Ziffer gemeinsam blinken soll, dann schreiben, leeren im gewünschten Takt. Blinking without delay läßt hier grüßen.

Hi Doc_ wie auch immer, irgendwie hatte ich noch im Kopf, dass die "Auflösung" etwa differenzierter sein sollte als 5 px je Zelle. Ich habe dein kleines Video gesehen, es zeigt dann wohl genau das, was du erreichen wolltest. Supi!

Was das lcd.blink() betrifft, bevorzuge ich meine "Unterstrich-Variante", das sieht m.E. etwas filigraner aus als die fette Blink-Marke. Das Zurücksetzen auf die Edit-Position ist bei meiner Methode genau so nötig wie bei lcd.blink(). Das komplette Überschreiben bzw. Blinken mehrer Zeichen würde mir nicht so sehr gefallen. Auf jeden Fall lässt "blink without delay" dabei sogar ganz laut grüßen. ;) LG, Rudi

Vielen Dank für eure guten Ratschläge! :slight_smile:

Ich habe es jetzt mit den invertierten Zeichen hinbekommen. Das ist auch schnell genug!

Genau genommen ist es sogar so schnell, dass ich die Zahl jetzt auch noch blinken lasse (sieht noch besser aus, als wenn sie nur invertiert ist).
Hier der Beispiel-Sketch:

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // setze die I2C-Addresse fuer das LCD auf 0x27 (16 Zeichen, 2 Zeilen)

byte invNumber[10][8] =
{
  { B10001, B01110, B01100, B01010, B00110, B01110, B10001, B11111 },
  { B11011, B10011, B11011, B11011, B11011, B11011, B10001, B11111 },
  { B10001, B01110, B11110, B11101, B11011, B10111, B00000, B11111 },
  { B00000, B11101, B11011, B11101, B11110, B01110, B10001, B11111 },
  { B11101, B11001, B10101, B01101, B00000, B11101, B11101, B11111 },
  { B00000, B01111, B00001, B11110, B11110, B01110, B10001, B11111 },
  { B11101, B11011, B10111, B00001, B01110, B01110, B10001, B11111 },
  { B00000, B11110, B11101, B11011, B10111, B10111, B10111, B11111 },
  { B10001, B01110, B01110, B10001, B01110, B01110, B10001, B11111 },
  { B10001, B01110, B01110, B10000, B11110, B11101, B10011, B11111 }
};

int num, tmp;
int delayms = 500;

void setup() {
  Serial.begin(115200);
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("0123456789");
}

void loop() {
  for (int iYear = 2000; iYear < 2050; iYear++) {
    lcd.setCursor(0, 1);
    lcd.print(iYear);
    tmp = iYear;
    for (byte i = 0; i < 4; i++) {
      num = int(tmp / pow(10, 3 - i));
      tmp -= num * pow(10, 3 - i);
      lcd.createChar(i, invNumber[num]);
      lcd.setCursor(i, 1);
      lcd.write(i);
    }
    delay(delayms);
    lcd.setCursor(0, 1);
    lcd.print(iYear);
    delay(delayms);
  }
}

In meine Uhr übernehme ich das natürlich ohne die delays. :slight_smile:

Nachtrag: Die Pixel der Buschstaben findest Du im Datenblatt. Grüße Uwe

Hallo, vielleich ist das ja etwas. Gruß und Spaß Andreas