Der Winstar-Grafik- und Textmodus wird angezeigt

Grafikdisplays, einschließlich solcher vom Typ OLED, die auf unserem Markt am häufigsten von Winstar vertreten werden, haben eine viel geringere Nachfrage im Vergleich zu Kleinbuchstaben, und Veröffentlichungen über ihre Verwendung sind ebenfalls viel geringer. Mittlerweile sind es grafische OLED-Displays, die aufgrund der fehlenden Bindung an Schriftarten eines vordefinierten Musters den besten Weg bieten, ergonomische Anzeigegeräte für eine Vielzahl von Anforderungen zu erhalten. Darüber hinaus stellte sich heraus, dass der Grafikmodus im WS0010-Controller einfacher zu initiieren ist und stabiler arbeitet als der Textmodus.

Bevor wir mit der Betrachtung der tatsächlichen grafischen Anzeigen fortfahren, werden wir das immergrüne Problem mit den Problemen der Aktivierung des Textmodus des WS0010-Controllers betrachten, der eine unerwartete und offensichtliche Lösung erhalten hat (oh, wo waren meine Augen!).

Beheben von Problemen mit dem WS0010-Textmodus


Es ist bekannt, dass Winstar-Linienanzeigen während der Initialisierung Stabilitätsprobleme aufweisen. Übrigens stellte sich heraus, dass dies nicht nur für die „verdammten Chinesen“ gilt: Die Muster von Newhaven Display 16x2, die ich mit großer Schwierigkeit auf der anderen Seite der Welt erhalten habe, sind äußerlich eine vollständige Kopie von Winstar, mit Ausnahme der Position einiger Inschriften und des Firmennamens auf dem Fleck ( die gleiche Form und Schriftart):

Bild

Diese Anzeigen enthalten, wie in Datenblättern beschrieben, einen bestimmten "LCD-vergleichbaren" Controller. Sie verhalten sich völlig identisch mit den chinesischen und haben die gleichen Nachteile. Natürlich sollten Sie keine Zeit damit verbringen, andere Unternehmen wie Midas zu überprüfen: Nach dieser Veröffentlichung könnte es nicht ohne internationale Zusammenarbeit auskommen. Die globalisierte Wirtschaft herrscht!

Die Schwierigkeiten des Textmodus äußern sich darin, dass beim Starten (z. B. beim Neustart oder manuellen Zurücksetzen des Programms der Steuerungssteuerung) Müll auf den Anzeigen erscheinen kann und die Zeilen 0 und 1 zufällig die Stellen wechseln. Die Experimente zeigten, dass es nicht von der Einschlussmethode abhängt (8-Bit oder 4-Bit). Dieses Problem ist besonders akut, wenn regelmäßige Neustarts der Software erforderlich sind, z. B. durch den Watchdog-Timer.

Das Problem wird teilweise durch eine sorgfältige Einstellung zur Stromversorgung (von einer separaten Quelle und keinesfalls von einem USB-Arduino) und einen separaten Neustart durch Aus- und Einschalten des Displays nach dem Starten des Steuerungsprogramms gelöst (siehe vorherige Veröffentlichung des Autors). Wie sich herausstellte, war der Autor dieser Zeilen nicht der einzige, der eine ähnliche Lösung für das Problem vorschlug: Der Autor des LuquidCrystal-Add- Ons namens WinstarOLED enthielt auch einen speziellen pw_pin, mit dem die Anzeigeleistung zum Zeitpunkt des Programmstarts verzerrt ist.

Aber das ist natürlich alles Initiative und halbe Sachen. Jemand SeregaB ist auf einen radikalen Weg gestoßen (siehe seine Veröffentlichung auf easyelectronics.ru - danke an Tomasina für den Tipp). Tatsächlich stellte er eine ganz andere Aufgabe: zu lernen, wie man nur mit Grafik statt mit Text arbeitet. Beim Versuch, zwischen den Modi zu wechseln, stellte er schnell fest, dass "das Umschalten in den Grafikmodus normal und von Grafik zu" Text "- sehr ungeschickt " war. Dann erinnerte er sich daran, dass „ ich vor langer Zeit, als DShs noch auf Papier gedruckt waren, in einigen DShs des HD44780 gelesen habe, dass das Umschalten der Modi nur bei ausgeschaltetem Bildschirm erfolgen sollte .“ Und es hat funktioniert.

Aus der zitierten Veröffentlichung werde ich hier einfach zwei Schaltvorgänge reproduzieren und sie für die Verwendung mit LuquidCrystal leicht anpassen (die Klasseninstanz heißt hier OLED1).

In den Grafikmodus wechseln:
OLED1.command(0x08);//  OLED1.command(0x1F);//   OLED1.command(0x01);//    (..  clear()) OLED1.command(0x08|0x04);//  

In den Textmodus wechseln:
  OLED1.command(0x08);//  OLED1.command(0x17);//    OLED1.command(0x01);//    (..  clear()) OLED1.command(0x04 | 0x08);//  

Wie wir später sehen werden, ist das erste Verfahren nicht wirklich erforderlich: Der WS0010 wechselt nach einem halben Tritt in den Grafikmodus. Senden Sie einfach den Befehl 0x1F an ihn. Aber die zweite Folge von Befehlen war sehr wohl der Fall. Für das Beispiel wurde es mit LuquidCrystal in folgender Form direkt in die Skizze aufgenommen:
 void reset_textmode() //     { OLED1.command(0x08);//  OLED1.command(0x17);//    OLED1.command(0x01);//    OLED1.command(0x04 | 0x08);//  } 

Diese Funktion wurde dann direkt nach dem Start der Bibliothek im Setup aufgerufen:

  . . . . . OLED1.begin(16,2); //16  2  reset_textmode(); //  clear() . . . . . 

Wenn Sie zuvor eine Verzögerung (500) einfügen, wird die Demonstration sehr deutlich: Nach dem Drücken der Reset-Taste der Arduino-Karte wird normalerweise Müll auf dem Bildschirm angezeigt, jedoch nur für einen Moment: Nachdem die Funktion ausgelöst wurde, wird der Bildschirm gelöscht und alle Zeilen sind wieder vorhanden .

Die Funktion funktioniert so, aber der Einfachheit halber habe ich den Inhalt der Funktion LiquidCrystalRus :: clear () in der Datei der aktualisierten Bibliothek LiquidCrystalRus_OLED.cpp ersetzt, die zuvor mit dieser Befehlsfolge erläutert wurde (ich erinnere Sie daran, dass Sie sie von der Website des Autors herunterladen können ). Es wird nicht darauf gewartet, dass der Befehl in der Bibliothek ausgeführt wird. Aus Gründen der Zuverlässigkeit werden daher nach jedem Befehl Verzögerungen von 100 μs in den allgemeinen Stil der Bibliothek eingefügt. In Skizzen, die diese Variante von LiquidCrystalRus_OLED verwenden, muss zu Beginn des Setups die Funktion clear () aufgerufen werden, und gleichzeitig wird der Bildschirm gelöscht.
Hinweis
Es gibt ein Missverständnis im Zusammenhang mit der Bildschirmreinigung: Im Datenblatt der Befehlstabelle wird darauf hingewiesen, dass der Befehl 0x01 bis zu 6,2 ms dauern kann, „wenn fsp oder fosc = 250 kHz“. Welche Art von "fsp oder fosc" tatsächlich in bestimmten Controllern vorhanden ist, sie waren zu faul zum Schreiben, aber auf jeden Fall sollte die Verzögerung für diesen Befehl erheblich sein, selbst wenn es sich um Megahertz handelt (und der Autor von LiquidCrystal erwähnt dies). In der Praxis stellt sich jedoch heraus, dass das Reinigungsteam für sich selbst arbeitet, wenn es überhaupt keine Verzögerung gibt. Also habe ich nicht verstanden, sondern nach der bekannten Programmierregel gehandelt: "Es funktioniert - nicht anfassen!".

Lassen Sie uns nun endlich den Grafikmodus behandeln.

Der Grafikmodus im Text zeigt WEH001602 an


Zunächst habe ich versucht, die Textanzeige von WEH001602BG in den Grafikmodus zu schalten. Beachten Sie, dass die grafischen Anzeigen 100x16 und Text (20x2-Konfiguration, 16x2 haben nur weniger horizontale Punkte) identische Matrizen aufweisen. Nur Textanzeigen sind vertraute Intervalle. Dies schränkt die Verwendung des Grafikmodus in Textanzeigen und noch mehr des Textmodus in Grafiken stark ein. Aber um zu testen, wie es funktioniert, können Sie jeden von ihnen verwenden.

Das Display wurde zusammen mit dem DS1307 nach folgendem Schema mit dem Arduino Nano verbunden:
Bild

Nach dem gleichen Schema werden wir in Zukunft grafische Anzeigen anschließen. Die graue Farbe im Diagramm zeigt ggf. den Anschluss des zweiten Displays.

Um in den grafischen Modus zu wechseln, können Sie das verbesserte Verfahren aus dem vorherigen Abschnitt verwenden. Eine einfache Funktion mit einem einzigen Befehl funktioniert jedoch:
 . . . . . #define LCD_SETGRAPHICMODE 0x1f LiquidCrystal lcd(9, 4, 8, 7, 6, 5); void setGraphicMode(){ lcd.command(LCD_SETGRAPHICMODE); } . . . . . 

Wir brauchen hier keine russische Tabelle, daher wird der Standard-LiquidCrystal (nicht begradigt) verwendet, der im grafischen Modus einwandfrei funktioniert. Um nicht mit dem Debuggen aller Bibliotheksoptionen herumzuspielen, verwende ich für den Fall, dass Text und grafische Anzeigen parallel enthalten sind, für jede meine eigene Bibliothek (für Text, der Rus_OLED aktualisiert hat, für grafische Normalen). In diesem Fall kann mit Ausnahme der E-Ausgangspins gemäß dem obigen Diagramm immer noch eine Verbindung zu denselben Controller-Beinen hergestellt werden.

Außerdem habe ich teilweise die Leistungen des Autors der erwähnten WinstarOLED-Bibliothek genutzt (an sich ist dieses Add-On für LuquidCrystal meiner Meinung nach unvollständig und es ist nicht praktisch, es als zu verwenden). Er führte eine praktische Funktion zum Setzen des grafischen Cursors ein (der ursprüngliche Fehler bezüglich des maximalen x- Werts wurde hier behoben):
 void setGraphicCursor( uint8_t x, uint8_t y ){ if( 0 <= x && x <= 99 ){ lcd.command(LCD_SETDDRAMADDR | x); } if( 0 <= y && y <= 1 ){ lcd.command(LCD_SETCGRAMADDR | y); } } 

Die Konstante LCD_SETDDRAMADDR ist in der LiquidCrystal-Bibliothek definiert. Eine 100x16-Anzeige ist wie eine Textanzeige in zwei Zeilen unterteilt, 0 und 1, da y hier nur zwei Werte annehmen kann. Die horizontale Koordinate x variiert zwischen 0 und 99. Mit dem Befehl lcd.write () wird ein Byte gesendet, dessen einzelne Bits die Lichtpositionen der vertikalen Linie mit einer Länge von 8 Punkten bestimmen. Die Position ganz links in der oberen Zeile hat die Koordinaten 0,0, die Position ganz rechts in der unteren Zeile - 99,1. Darüber hinaus entspricht der niedrigste Punkt dem niedrigstwertigen Bit und der niedrigste Punkt dem höchsten.

Um das Codieren von Bildern zu vereinfachen, habe ich eine Platte gezeichnet, auf der Sie den gewünschten Code schnell manuell erstellen können. Für vollständige Schriftarten-Tabellen ist es natürlich ratsam, spezielle Editoren zu verwenden (von denen es mindestens eine Million verschiedene Grade an Amateuraktivität gibt), aber 10 Ziffern mit der gewünschten Bitreihenfolge lassen sich schneller manuell verarbeiten, zumal automatisch erstellte Schriftarten häufig noch von Hand fertiggestellt werden müssen. In Übereinstimmung mit dem Obigen wird eine Glyphe, beispielsweise die Schriftart Nummer 2, Schrift 10x16, wie folgt codiert:

Bild

All dies wird in ein zweidimensionales Array der Form geschrieben:
 const byte Data2[2][10]={{0x06,0x07,0x03,0x03,0x03,0x83,0xc3,0x63,0x3f,0x1e}, {0xf0,0xf8,0xcc,0xc6,0xc3,0xc1,0xc0,0xc0,0xc0,0xc0}}; 

Für jede Ziffer 0-9 wird ein separates solches Array erstellt: Daten0, Daten1, Daten2 usw. Für Uhren benötigen Sie neben Zahlen auch einen doppelten Punkt. Es kann kürzer gemacht werden:
 const byte DataDP[2][2]={{0x70,0x70}, {0x1c,0x1c}};//  

Da der Controller im Grafikmodus nicht weiß, wie er „blinken“ soll, muss der Doppelpunkt programmgesteuert blinken. Sie können einen Doppelpunkt einfach löschen, indem Sie Nullen an den entsprechenden Positionen anzeigen. Aus Gründen der Einheitlichkeit habe ich jedoch ein separates Array erstellt
 const byte DataDPclr[2][2]={{0x00,0x00}, {0x00,0x00}};// .  

Um jede Ziffer und separat für einen Doppelpunkt anzuzeigen, wird eine separate Funktion geschrieben:
 void draw2 (byte x/* */) // “2” { for (byte i = x; i<x+10; i++){ setGraphicCursor(i, 0); lcd.write(Data2[0][ix]); setGraphicCursor(i, 1); lcd.write(Data2[1][ix]);} } 

Alle Funktionen sind gleich, verwenden jedoch unterschiedliche Arrays. Für einen Doppelpunkt werden auch andere Grenzen der Schleife verwendet. Es stellte sich heraus, dass die Codemenge nicht zu sparsam ist (dazu später mehr), aber es ist klar und einfach, Fehler zu korrigieren. Die Lücken zwischen den Zeichen werden in der Ausgangsstufe berücksichtigt und geben die entsprechende Position an (die RTClib-Bibliothek wird zum Lesen der Uhr verwendet):
 void loop() { DateTime clock = RTC.now(); if (clock.second()!=old_second) { uint8_t values; values=clock.hour()/10; //  drawValPos(values,0); values=clock.hour()%10; //  drawValPos(values,12); values=clock.minute()/10; //  drawValPos(values,28); values=clock.minute()%10; //end   drawValPos(values,40); if (clock.second()%2) drawDP(24); else drawDPclr(24); old_second=clock.second(); }//end if clocksecond } 

Zehn Ziffern mit jeweils 20 Bytes belegen 200 Bytes im Speicher - etwa 10% des Volumens (und die breite Schrift ist 16 x 16, wie im folgenden Beispiel, und alle 16%). Eine vollständige einsprachige Schrift dieser Größe zusammen mit Zahlen, ohne Berücksichtigung aller Arten von Satzzeichen und Sonderzeichen. Zeichen, enthält 62 (Englisch) bis 74 (Russisch ohne E) Zeichen, der Wert nimmt fast die Hälfte des ATmega328 RAM ein. Daher müssen Tricks mit Arrays und Ausgabefunktionen für jedes Zeichen separat abgebrochen werden und wie erwartet ausgeführt werden. Das heißt, die Schriftarten sollten im Programmspeicher belassen und über PROGMEM heruntergeladen werden, und alle Glyphenmuster sollten als ein einziges Schriftartenarray angeordnet und zur Ausgabe nach Symbolnummer in eine einzige Tabelle geladen werden. Andernfalls ist nicht genügend Speicher vorhanden und der Programmcode wird auf ein unkontrollierbares Volume aufgeblasen. Hier werden wir nicht weiter darauf eingehen, da in unseren einfachen Beispielen all dies nicht erforderlich ist - jedes Mal werden wir auf eine kleine, unbedingt notwendige Anzahl von Zeichen beschränkt sein.

Aufgrund der Größe des Volltexts der GraphicOLED_DC1307-Skizze bringe ich sie nicht mit. Sie können sie hier herunterladen. Die Funktion resetOLED wird im Text gespeichert, wodurch die Anzeigeleistung beim Neustart des Controllers (über pwrPin D2) verzerrt wird. Sie wurde jedoch nie benötigt, sodass sie sicher entfernt werden kann. Das Ergebnis des Programms ist auf dem Foto dargestellt:

Bild

Leider ist ein gleichzeitiger Aufenthalt im Text- und Grafikmodus ausgeschlossen. Wenn Sie also den verbleibenden Speicherplatz verwenden möchten, müssen Sie Ihre eigenen Schriftarten zeichnen (in jeder Zeile bleibt Platz für ca. 7 Zeichen mit 5 x 7 Schriftarten).

Grafikdisplay WEG010016A


Als schließlich die bestellten Grafikdisplays WEG010016AL eintrafen, versuchte ich zunächst, sie in den Textmodus zu versetzen, um zu sehen, was daraus wurde.

Um den Textmodus zu überprüfen, wurde ein Programm zur Simulation einer Kalenderuhranzeige mit einem externen Temperatursensor heruntergeladen, das in einer früheren Veröffentlichung beschrieben wurde. Das Ergebnis hat mich daran erinnert, dass verschiedene Winstar-Anzeigen in Bezug auf den Anschluss unterschiedlich ausgerichtet sein können (in diesem Fall hat der WEG010016A oben einen Anschluss für den Text WEH001602B, den wir oben verwendet haben, unten und für Typ C an der Seite):

Bild

Wir werden uns weiter mit der Ausrichtung des Displays befassen, aber jetzt werden wir sehen, was passiert ist. Aber es hat sich als nicht gut herausgestellt: Der Textmodus (natürlich mit einer Krücke ausgestattet, der am Anfang des Artikels besprochen wurde) funktioniert einwandfrei, macht aber in der Praxis keinen Sinn, da zwischen den Zeichen keine Leerzeichen vorhanden sind. Daher werden wir nicht weiter darauf eingehen, sondern mit der Betrachtung des Grafikmodus fortfahren.

Die Installationsverfahren für den Grafikmodus selbst sind dieselben wie die oben für die Textversion beschriebenen. Es bleibt zu behandeln, wenn das Display umgedreht ist, wenn es oben auf dem Bildschirm einen Anschluss hat. Natürlich können Sie das Display einfach umdrehen, aber die Position mit dem Stecker nach unten erscheint mir natürlicher und bequemer. Wenn Sie einen Typ mit einem seitlichen Anschluss verwenden, müssen Sie den Anschluss möglicherweise nach rechts und nicht nach links ausrichten. Für die verkehrte Ausrichtung ist es erforderlich, das Bild zu transformieren, dh die erste und letzte horizontale Position und Linie zu vertauschen und auch die Reihenfolge der Bits in Bytes umzukehren, aus denen das Array besteht (in diesem Fall entspricht das niedrigstwertige Bit dem unteren Punkt).

Da ich für den vorherigen Fall bereits zehn Ziffern gemalt hatte, blieb es für die letzte Aufgabe, das Programmumkehrverfahren einzuführen:
 byte reverse(byte x) { byte result=0,i; for(i=0;i<8;i++) { if (x & (1 << i)) { result |= 1 << (7-i); } } return result; } 

Sie können die Reihenfolge der horizontalen Koordinaten und vertikalen Linien ändern, indem Sie Änderungen an der Funktion setGraphicCursor vornehmen:
 void setGraphicCursor( uint8_t x, uint8_t y ){ if( 0 <= x && x <= 99 ){ lcd.command(LCD_SETDDRAMADDR | (99-x)); } if( 0 <= y && y <= 1 ){ lcd.command(LCD_SETCGRAMADDR | (1-y)); } } 

Die Ausgabefunktionen des Arrays jeder Ziffer bleiben gleich, es wird nur die Bitumkehr hinzugefügt:
 void draw2 (byte x/* */) // 2 { for (byte i = x; i<x+10; i++){ setGraphicCursor(i, 0); byte b=reverse(Data2[0][ix]); lcd.write(b); setGraphicCursor(i, 1); b=reverse(Data2[1][ix]); lcd.write(b);} } 

Die vollständige Skizze der Ausgabe der Uhr GraphicOLED_DC1307_100x16 kann hier heruntergeladen werden . Das Ergebnis für die Anzeige WEG010016AL ist auf dem Foto dargestellt:

Bild

Aber auf diesem Foto eine andere Schriftart (16 x 16) auf dem WEG010016CG-Display (das Display steht ebenfalls auf dem Kopf):

Bild

Wenn Sie die Schriftart neu erstellen, indem Sie die Reihenfolge der Bits manuell ändern, müssen Sie nicht umgekehrt vorgehen, und das Programm wird schneller ausgeführt (obwohl es keine merklichen Verzögerungen im Auge gibt). Das angegebene Bit-Flip-Verfahren ist jedoch in jedem Fall nützlich, um verschiedene Bilder anzuzeigen. Beispielsweise können Sie von einem Pfeil nach oben und rechts programmgesteuert vier Richtungen gleichzeitig abrufen.
Pfeilzeichnung
Bild- und Pfeilcode (die Koordinaten und Bits in der Tabelle werden entsprechend der unteren Position des Anschlusses für die Anzeige WEG010016AL invertiert, siehe oben):

Bild
 const byte DataATR[2][8]={{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, {0x01,0x02,0x04,0x28,0x30,0x78,0x60,0x80}}; 

Funktionen zur Ausgabe von multidirektionalen Pfeilen:
 . . . . . void drawSW (byte x) //   (  ) { for (byte i = x; i<x+8; i++){ setGraphicCursor(i, 0); lcd.write(DataATR[0][ix]); setGraphicCursor(i, 1); lcd.write(DataATR[1][ix]);} } void drawNW (byte x) //   (  ) {//   : for (byte i = x; i<x+8; i++){ setGraphicCursor(i, 0); byte b=reverse(DataATR[1][ix]); lcd.write(b); setGraphicCursor(i, 1); b=reverse(DataATR[0][ix]); lcd.write(b);} } void drawNE (byte x) //   (  ) {//  ,    for (byte i = x; i<x+8; i++){ setGraphicCursor(i, 0); byte b=reverse(DataATR[1][7-(ix)]); lcd.write(b); setGraphicCursor(i, 1); b=reverse(DataATR[0][7-(ix)]); lcd.write(b);} } void drawSE (byte x) //   (  ) {//   for (byte i = x; i<x+8; i++){ setGraphicCursor(i, 0); lcd.write(DataATR[0][7-(ix)]); setGraphicCursor(i, 1); lcd.write(DataATR[1][7-(ix)]);} } . . . . . 

Das Foto unten zeigt das Ergebnis eines leeren Programms zur Anzeige des Geschwindigkeits- und Windrichtungssensors. Wie Sie sehen, hat es sich als sehr einfach herausgestellt, Schriftarten unterschiedlicher Größe zusammen mit Bildern in einer Zeile zu implementieren:

Bild

Abschließend möchte ich hinzufügen, dass hier eine sehr interessante Bibliothek für die Arbeit mit WS0010 im grafischen und textuellen Modus mit SPI ist. Im Text werden hauptsächlich Flüssigkristalle kopiert (und woran können Sie noch denken?). In der Grafik werden grafische Grundelemente, integrierte Schriftarten (dick wie meine und die üblichen 5 x 7) und vieles mehr gezeichnet.

Source: https://habr.com/ru/post/de402517/


All Articles