Bessere Ansichten:

Grafik-LCD an Arduino


Features:

  • Grafik-LCD statt Text-LCD
  • 128 x 64 Pixel
  • Mehr Möglichkeiten der Gestaltung
  • einfach anzuwenden dank GLCD-Library
  • Beispielprogramme

Bild 1: Die Zutaten: Steckbrett, Arduino und ein grafisches LCD: Erfolge sind garantiert dank GLCD-Programmbibliothek und Beispielprogrammen.

Bessere Ansichten:

Grafik-LCD mit Arduino steuern

Eine grafikfähige LCD-Anzeige wertet ein Selbstbauprojekt auf. Statt der Text-LCD kommt beispielsweise ein Grafik-LCD mit 128 x 64 Pixel zur Anwendung. Arduino unterstützt Grafik-LCD (GLCD) vorbildlich - dank einer hervorragenden Library.

Wir steuern ein grafisches LC-Display (GLCD) mit einem Arduino-Board an. Das GLCD hat bereits einige Zeit in der Schublade verbracht, doch so recht habe ich mich nicht getraut, es einzusetzen. Die Ansteuerung erschien recht aufwändig. Dank der enormen Vorarbeit der beiden Autoren der GLCD-Programmbibliothek für Arduino, Michael Margolis und Bill Perry, lässt sich ein GLCD leicht anschließen und mit leistungsfähigen Befehlen auf hohem Niveau programmieren.

Verkabeln

Textbasierte LCD sind sehr preiswert. Bezahlbar sind GLCD mit geringer Auflösung, also beispielsweise 128 x 64 Pixel mit zwei Farben. Legt man Wert auf höhere Auflösungen, größere Displays oder mehr Farben, wird es schnell kostspielig. Wir begnügen uns mit je einer Hintergrund- und Schriftfarbe. Diese GLCD sind in schwarz / grün oder weiß / blau erhältlich. Der LCD-Controller trägt die Bezeichnung KS0108.

Beim Anschluss des GLCD an ein Arduino-Board, hier kommt ein Duemilanove mit einem Atmel Mege328-Prozessor zum Einsatz, ist auf die Pinbelegung des GLCD besonderes Augenmerk zu richten, da mehrere Anschlussbelegungen existieren. Dabei hilft die Dokumentation zur GLCD-Programmbibliothek, die im Verzeichnis libraries\glcd\doc der Arduino-IDE verfügbar ist. Daraus stammt auch das folgende Bild.

Vielen Lesern wird bekannt sein, dass der Kontrast eines Text-LCD meist mittels Potentiometers eingestellt wird. Dazu wird eine Spannung von 0 bis 5 Volt auf den Kontrast-Eingang des Text-LCD gegeben. Auch bei einem GLCD kann man den Kontrast mittels Poti einstellen, jedoch wird eine negative Kontrastspannung benötigt, die - wie praktisch - vom GLCD zur Verfügung gestellt wird. Der zuständige Anschluss auf dem verwendeten GLCD ist mit VEE bezeichnet.

Bild 2: Diese Tabelle zeigt alle Verbindungen zum Anschluss eines GLCD an den Arduino. Quelle: www.arduino.cc.

Für den Anschluss an einen Prozessor ist die hohe Zahl der notwendigen Verbindungen nachteilig. Neben dem 8-Bit-Datenbuss müssen eine Reihe von Steuerleitungen bedient werden. Die D/I-Leitung beispielsweise entscheidet darüber, ob am Datenbus anliegende Informationen als Befehl (Instruction) oder als Daten interpretiert werden. Hinzu kommen zwei Chip-Select-Leitungen, weil das 128x64-Display intern aus zwei 64x64-Anzeigen zusammengesetzt ist. Je nachdem, ob man auf die rechte oder die linken Seite der Anzeigefläche etwas zeichnen möchte, muss man die Leitung CS1, ein anderes Mal CS2 ansteuern. Alles zusammen sind es 14 Verbindungen zwischen Prozessor und GLCD.

Bild 3: Dieser Plan zeigt die Verdrahtung eines GLCD (Typ B) mit dem Arduino. Die Kontrasteinstellung erfolgt über ein 10k-Poti. Quelle: arduino.cc.

Die Library

Ist die Verkabelung gelungen, wie im Aufmacherbild auf einem Steckbrett geschehen, kommt die Programmierung an die Reihe. Für die ersten Erfolgserlebnisse und zur Überprüfung der Verkabelung sowie zur Einstellung des LCD-Kontrastes bringt die GLCD-Programmbibliothek (Library) einige Beispielprogramme mit. Die sind schnell kompiliert und auf den Prozessor kopiert. Starten die Beispiele, staunt der Anwender, was mit einer doch recht simplen Grafikanzeige machbar ist.

Zwei Klassen

Die GLCD Library bietet zwei Klassen: GLCD und gText. GLCD verfügt über einen beträchtlichen Satz von Methoden, z. B. zur Initialisierung, zur Auswahl von Schriftarten, zum Löschen der Anzeige und natürlich zum Zeichnen allerlei Figuren wie vertikale und horizontale Linien, gefüllte und offene Kreise und vieles mehr (siehe Tabelle). gText dagegen vereinfacht - wie der Name vermuten lässt - allerlei Textausgaben auf dem grafischen LC-Display. Dabei kann die verfügbare Anzeigefläche in verschiedene autonome Textbereiche (TextAreas) aufgeteilt werden. Befehle, denen die Bezeichnung einer TextArea vorangestellt, beziehen sich auf genau diese. Das erleichtert die Programmierung, wie das folgende Beispiel zeigt.

Die wichtigesten GLCD-Befehle:

Textfunktionen aus der Klasse gText:

Beispiel:

// Einbinden der GLCD
#include "glcd.h"

// und einige Schriftarten
#include "fonts/allFonts.h"

// Hier werden vier Textbereiche (TextAreas) definiert
gText t1;
gText t2;

…

// Dieser Textbereich nutzt die obere Hälfte der Anzeigefläche
// mittel vordefinierten Bereich und bestimmt die Schriftart
t1.DefineArea(textAreaTOP);
t1.SelectFont(fixednums15x31);

// Noch ein Textbereich
t2.DefineArea(0, GLCD.CenterY, 8, 2, fixednums7x15);

// und die Schriftfarbe soll weiß sein
t2.SetFontColor(WHITE);

// Textbereich t2 löschen
t2.ClearArea();

// Im Textbereich t1 etwas anzeigen
t1.Printf_P(PSTR("%02d:%02d.%02d"), hr, min, sec);

// Befehle für Textbereich t2,
// Cursor auf 0,0 des Textbereiches setzen
t2.CursorTo(0,0);

t2.Printf("%02d:%02d.%02d", hr, min, sec);

Bild 4: Grafisch aufbereitet: Temperaturanzeige mit Thermometer.

Grafische Temperatur-Anzeige

Richtig interessant ist es, eine kleine Anwendung mit der GLCD-Library zu programmieren. Für kleine Anwendungen wie beispielsweise eine Temperaturanzeige sind nur wenige Zeilen zu schreiben. Da wir nun eine grafische Anzeige haben, soll die Temperatur nicht nur als Ziffernfolge dargestellt werden, sondern zudem auch in Form eines Thermometer mit Skala (Bild 4).

Bild 5: Der Ursprung der Bildschirmkoordinaten beginnt oben links.

Bild 5 beschreibt das Koordinatensystem des "Bildschirms", in dem wir uns bewegen. Oben links ist der Nullpunkt, die X-Koordinate wächst von Null an bis zu einem Wert von 127 nach rechts, die Y-Koordinate dem entsprechend nach unten bis 63. Werden Textbereich definiert, schaffen wir damit eigene, relative Koordinaten. Betrachten wir einige Zeilen des Sourcecodes, um die Leistungsfähigkeit dieser Arduino-Programmbibliothek zu erfassen:

Bild 6: Die Arduino-Entwicklungsumgebung zeigt das Programm zur Temperaturanzeige.

Zuerst laden wir die Definitionen der beiden Bibliotheken die wir benutzen möchten. Für den Temperaturfühler LM335 existiert eine prima Bibliothek, welche den Umgang mit dem Sensor kinderleicht macht.

#include "glcd.h"
#include 
LM335A InsideTemp(5);     // LM335 an Analog-Eingang 5

Nun laden wir einige Schriftarten, hier könnte man noch etwas Platz sparen, wenn nur die benötigten Fonts geladen werden.

// Einige Fonts laden für Anzeige der Uhrzeit
#include "fonts/allFonts.h"
//#include "fonts/fixednums15x31.h"
//#include "fonts/fixednums8x16.h"
//#include "fonts/fixednums7x15.h"
//#include "fonts/SystemFont5x7.h"

In der Setup-Routine werden Variablen initialisiert, hier ist es nur die für das GLCD.

void setup()
{
        GLCD.Init(NON_INVERTED);
}

Einen Textbereich für die Uhrzeit definieren:

gText t1;

Nun folgt die Hauptschleife mit der Initialisierung weiterer Variablen. In dieser Hauptschleife gibt es eine weitere Endlosschleife, die später aufgerufen wird, um jede Sekunde die Zeit anzuzeigen.

void loop()
{
int hr, min, sec;
int counter = 0;;
int tcount = 0;
float t;          // Temperatur
float einGrad = 0.75;    // einGrad = 30 pixel / 40 Grad Temp Diff
float yhoehe;     // Höhe der Quecksilbersäule auf dem Display

Der Textbereich für die Uhrzeit soll die rechte Seite des Display einnehmen. Dazu nutzen wir die bereits definierte Angabe textAreaRIGHT.

t1.DefineArea(textAreaRIGHT);    // Display für die Uhrzeit
t1.SelectFont(fixednums7x15);   // Große Ziffern

Nun ist es Zeit, die Umrisse des Thermometers zu zeichnen. Es besteht aus einem gefüllten Kreis und zwei vertikalen Linien. Die Füllung zwischen den Linien, welche die Temperatur anzeigt, wird später in der zweiten Endlosschleife berechnet.

GLCD.FillCircle(10,54,6,BLACK);           // x,y,radius,Color
// GLCD zeichnet VLines von oben nach untern, abso x,y oben anfangen
GLCD.DrawVLine(8,6,46,BLACK);            // x,y,height,Color
GLCD.DrawVLine(12,6,46,BLACK);           // x,y,height,Color

Und nun die Skala, damit der Anwender die Temperatur abschätzen kann. Es beginnt mit dem 40-Grad-Strich ganz oben.

// 40-Grad-Strich
GLCD.DrawHLine(13,14,8,BLACK);           // x,y,length,Color

// 20-Grad-Strich
GLCD.DrawHLine(13,30,8,BLACK);           // x,y,length,Color

// Null Graf-Strich
GLCD.DrawHLine(13,44,8,BLACK);           // x,y,length,Color

Hier merke ich mir die wichtigen Werte zur späteren Berechnung (als Kommentar)

// Zur Berechnung des Quecksilberpegels:
// Null Grad: y = 44, 40 Grad = 14 (Diff. 30 Pixel für 40 Grad

Der Font für die Skala soll nicht so groß sein wie die Uhrzeit, sondern passend zum Thermometer

GLCD.SelectFont(SystemFont5x7,BLACK);
GLCD.DrawString("40",24,11); // Beschriftung 40 Grad
GLCD.DrawString("20",24,27); // Beschriftung 20 Grad
GLCD.DrawString("0",24,41); // Beschriftung Null Grad

Die Temperaturanzeige in Ziffern soll fett angezeigt werden.

// Temperatur anzeigen in Arial Bold
GLCD.SelectFont(Arial_bold_14, BLACK);   // Font und Schriftfarbe

Nochmals einige Variablen für Stunde, Minute und Sekunde auf Null setzen, danach geht es in die Endlosschleife, in der die Uhrzeit angezeigt wird und die Anzeige der Temperatur erfolgt.

hr = 0;
min = 0;
sec = 0;

while(1)
  {

Es reicht, die Temperatur alle 5 Sekunden zu lesen.

        if(tcount == 0)
        {
          InsideTemp.ReadTemp();
        }
        tcount++;
        if (tcount > 6)
        {
          tcount = 0;
        }

Hier wird mit nur zwei Zeilen jede Sekunde die Zeit im Textfeld t1 angezeigt

        t1.CursorToXY(0,0); // column & row is relative to text area
        t1.Printf_P(PSTR("%02d:%02d.%02d"), hr, min, sec);

Darunter sollen die Temperaturen angezeigt werden, in Celsius und Fahrenheit.

        // Celsius anzeigen
        GLCD.CursorToXY(64,33);
        GLCD.print(InsideTemp.Celsius(),1);
        GLCD.print(" C  ");

        // Fahrenheit darunter anzeigen
        GLCD.CursorToXY(64,49);
        GLCD.print(InsideTemp.Fahrenheit(),1);
        GLCD.print(" F  ");

Ab hier wird der Füllstand des Thermometers berechnet: Zunächst die Berechnung der Höhe des Striches, der den Füllstand des Thermometers bestimmt. Das Abrufen der Temperatur in Celsius oder Fahrenheit geschieht sehr elegant mit jeweils einer Zeile.

        if(InsideTemp.Celsius() > 0.00)
        {
// y-Höhe des Quecksilbers = einGrad * Temperatur
            yhoehe = einGrad * InsideTemp.Celsius();
        }
        else
        {
            yhoehe = 1;
        }

Korrektur zwischen Nullstrich und Quecksilbervorratsbehälter berücksichtigen (4 Pixel)

        int y = (int) 44-yhoehe-4;      // Oberste Px in Q-Säule
        int yh = (int)yhoehe+8;       // unteres Px in Qsäule (Höhe + 2 mal Korrektur, damit geht der Strich bis zum Behälter (Kreis)
        int loesch = y - 1;            // Löschbereich 1 px über oberstem Pixel in Quecksilbersäule und darüber

Nun ist alles berechnet, also den Füllstand anzeigen. Das geschieht durch drei vertikale Linien. Weiterhin wird der Platz über dem Füllstand gelöscht, damit auch bei fallender Temperatur der korrekte Stand zu erkennen ist, sonst würden gesetzte Pixel schwarz bleiben.

        GLCD.DrawVLine(9,y,yh,BLACK);            // x,y,height,Color
        GLCD.DrawVLine(9,6,loesch,WHITE);            // oben bis 1 px über Säule löschen

        GLCD.DrawVLine(10,y,yh,BLACK);            // x,y,height,Color
        GLCD.DrawVLine(10,6,loesch,WHITE);            // oben bis 1 px über Säule löschen

        GLCD.DrawVLine(11,y,yh,BLACK);            // x,y,height,Color
        GLCD.DrawVLine(11,6,loesch,WHITE);            // oben bis 1 px über Säule löschen

Was noch bleibt, ist, die Uhrzeit zu berechnen:

        sec++;
        if(sec > 59)
        {
                sec = 0;
                min++;
                if(min>59)
                {
                        min = 0;
                        hr++;
                        if(hr>11)
                                hr = 0;
                }
        }

Die Uhr läuft noch nicht genau. Falls sie zu langsam ist, wird die Pausenzeit vermindert, läuft die Uhr zu schnell. Ist der Wert zu erhöhen.

        delay(996);    // eine Sekunde Pause, abzüglich Rechenzeit
    }
}
//Programm-Ende

Erweiterungen des Programms sind denkbar: Ein Relais könnte bei Überschreiten einer definierten Temperatur ein- und bei Unterschreiten wieder ausschalten. Dann wäre es möglich, z. B. eine PA vor Überhitzung zu schützen oder einen Lüfter zu steuern. Es gibt noch keine Möglichkeit, die Zeit zu stellen. Dazu müssten einige Taster ergänzt werden. Nach dem Einschalten läuft die Uhr bei Null los - zur Demonstration der GLCD-Bibliothek reicht das aus. Weil das Programmieren mit der Grafik-Bibliothek für das Grafik-LCD so viel Freude bereitet hat, habe ich die genannten Erweiterungen realisiert.


Download von Dateien zu diesem Projekt

Arduino-Sourcecode und andere nützliche Dateien stehen zum Download bereit. Und hier geht es zum Download.