Arduino LC-Display-Ansteuerung Seite 2

Ähnliche Dokumente
Starten Sie die Arduino IDE und geben Sie den folgenden Programmcode ein:

4 Vererbung, Polymorphie

Repetitorium Informatik (Java)

Projekt Nr. 15: Einen elektronischen Würfel erstellen

Erste Schritte. Das Arduino-Board. Ihr Fundino-Board. Programmieren für Ingenieure Sommer Andreas Zeller, Universität des Saarlandes

Kapitel 8. Programmierkurs. Methoden. 8.1 Methoden

Probeklausur: Programmierung WS04/05

Objektorientierte Programmierung mit C++ Zusammenfassung der wichtigsten Topics rund um die objektorientierte Programmierung mit C++11

Der I²C-Bus. Vorstellung des Inter-Integrated Circuit -Bus. Aufbau und Funktionsweise. Beispiel PortExpander am Arduino

Grundlagen. Kapitel 1

Die Programmiersprache C

ARDUINO Übung. Inhalt:

Überschreiben von Methoden

DOTMATRIXDISPLAYS 2x16

Folge 18 - Vererbung

Java, OO und UML Fortsetzung

Prof. W. Henrich Seite 1

Objektorientierung: Klassen und Objekte

GetName(), GetName(), GetGeschlecht() und AelterWerden().

Einstieg in die Programmierung mit Visual Basic.NET

Einen eigenen Arduino-Bootloader brennen Version 1.0 Created Erik Bartmann Internet

Objektorientiertes Programmieren für Ingenieure

Haftkünstler auf dem Prüfstand. Online Ergänzung HOLGER FLORIAN BOHN OLGA SPECK THOMAS SPECK

RN-Control ARDUINO Bibliothek ATMEL 32 Version 0.2

Grundlagen von Python

Programmieren in Java

Programmierung mit C Zeiger

Vererbung & Schnittstellen in C#

Qt-Projekte mit Visual Studio 2005

MySQL-Befehle. In diesem Tutorial möchte ich eine kurze Übersicht der wichtigsten Befehle von MySQL geben.

5.4 Klassen und Objekte

einfache PIC-Übungsprogramme

Handbuch Groupware - Mailserver

Modul Entscheidungsunterstützung in der Logistik. Einführung in die Programmierung mit C++ Übung 4

Übungsaufgaben: 1. Objektorientierte Programmierung - Teil 1

Java Kurs für Anfänger Einheit 4 Klassen und Objekte

Deklarationen in C. Prof. Dr. Margarita Esponda

Palm conduit Konfigurations-Guide

Software-Projekt: Mensch ärgere Dich nicht. Dokumentation Softwareprojekt: Mensch ärgere Dich nicht

Eine Einführung in C-Funktionen

Einrichten eines News-Systems in Typo3

Objektorientierte Programmierung mit Python Polymorphismus und Vererbung. Eltern

Kommunikation HOST TMC420 Controller

Zusatzinformation zum USB-Flashdrive mit ARM und RS232

DL100 Technisches Datenblatt - RS232 zu LCD-Konverter, Anzeigebaustein via RS232 (Nachfolger des LCDChipRS232)

SimpleOOP Opensource OOP Plugin

Ziel, Inhalt. Programmieren in C++ Wir lernen wie man Funktionen oder Klassen einmal schreibt, so dass sie für verschiedene Datentypen verwendbar sind

C++ - Operatoren. Eigene Klassen mit neuen Funktionen

Methoden. von Objekten definiert werden, Methoden,, Zugriffsmethoden und Read-Only

13 OOP MIT DELPHI. Records und Klassen Ein Vergleich

Erstellung von Bibliotheken in CoDeSys V3

Qt Programmierung Teil 1 Fenster erstellen by NBBN ( CrashKurs-Artig. Was brauche ich? -Einige C++ Kenntnisse

Ringlicht-v3 - Frei konfigurierbares Ringlicht mit RS232 Anbindung. Kurzbeschreibung

01. Grundprinzipien der Vererbung

Vorkurs C++ Programmierung

7. Objektorientierte Softwareentwicklung/3. Informatik II für Verkehrsingenieure

Grundlagen der Informatik - 6. Praktikum

Anwendung und Programmierung von Mikrocontrollern. Anwendung und Programmierung von Mikrocontrollern

Computernetzwerke. Von den Grundlagen zur Funktion und Anwendung. von Rüdiger Schreiner. 2., überarbeitete Auflage. Hanser München 2007

Access [basics] Aktionsabfragen per VBA ausführen. Beispieldatenbank. Aktionsabfragen. Die Execute-Methode. Datenzugriff per VBA

IT- Handbuch für Fachinformatiker, 7. Auflage: Text- Lösungen Sascha Kersken

Inhaltsüberblick. I. Grundbegriffe - Objekte und Klassen. Organisatorisches. I. Grundbegriffe - Objektorientierte Konzepte

Die Programmiersprache C99: Zusammenfassung

Java: Vererbung. Teil 3: super()

Microcontroller Kurs Programmieren Microcontroller Kurs/Johannes Fuchs 1

Klassenbeziehungen & Vererbung

Programmierung eines NewsTickers in Java

Programmierung Nibo 2 Teil 3 Display. * by nicaisystems

Dokumentation zum Projekt Mail-Adapter in SAP PI Sinkwitz, Sven Theel, Thomas

Programmierkurs Java

PHP Einsteiger Tutorial Kapitel 4: Ein Kontaktformular in PHP Version 1.0 letzte Änderung:

Microsoft PowerPoint 2013 Folienübergänge

Es ist für die Lösung der Programmieraufgabe nicht nötig, den mathematischen Hintergrund zu verstehen, es kann aber beim Verständnis helfen.

Microsoft Outlook Express 5.x (S/MIME-Standard)

Zahlendarstellung Logikfunktionen Register Eingänge Infrarot senden TSOP-Effekte Weiterführendes U Abend 3:

Einführung in Automation Studio

Inhaltsverzeichnis. Grundbegriffe der C-Programmierung Für den HI-TECH C-Compiler

C++-Zusammenfassung. H. Schaudt. August 18, 2005

tel 2.5 Benutzerhandbuch

C++ - Einführung in die Programmiersprache Polymorphismus und Vererbung. Eltern

Assembler und Hochsprachen

A n l e i t u n g. Beamer- Treiber- Download (FBI EB/ 19 )

CCS Compiler Tutorial mit Beispielen

Willkommen zur Vorlesung. Objektorientierte Programmierung Vertiefung - Java

Teile und Herrsche. Themen heute. Eigene Funktionen Parameter Fallunterscheidungen Fehlersuche. Programmieren für Ingenieure Sommer 2015

8.1 Grundsätzlicher Aufbau der Beispiele

Java Kurs für Anfänger Einheit 5 Methoden

VB.net Programmierung und Beispielprogramm für GSV

Numerische Datentypen. Simon Weidmann

Vererbung. Was versteht man unter dem Begriff Vererbung?

LCD-Verwaltungssoftware LCD-VSW

SCAN OPERATOR 12. Bedienungsanleitung. Ab Version Internet:

Wintersemester Maschinenbau und Kunststofftechnik. Informatik. Tobias Wolf Seite 1 von 22

BLUE LINE BLAU NEGATIV MIT WEISSER LED

Ausbildungsziel: Die Nutzung der Zwischenablage -Kopieren und Einfügen-

Zeiterfassungsanlage Handbuch

Software Engineering Klassendiagramme Einführung

3 Objektorientierte Konzepte in Java

Transkript:

Scope Die Erstellung einer eigenen LCD-Ansteuerung Version 1.0 Created 06.01.2012 Autor Erik Bartmann Internet http://www.erik-bartmann.de Email arduino@erik-bartmann.de Arduino LC-Display-Ansteuerung Seite 2

Das LCD vom Typ HD44780 Liebe Freunde, ich möchte in diesem Arduino-AddOn die Programmierung der Ansteuerung eines LC-Displays behandeln. Habt Ihr die Vorgehensweise verstanden, ist es mehr oder weniger einfach, jedes beliebige Display anderer Hersteller anzusteuern. Bevor wir uns an die Arbeit machen, ist es unabdingbar, dass jeweilige Datenblatt zu studieren. Andernfalls können wir die Sache vergessen, denn ohne detaillierte Informationen über das Display bzw. den Treiber, der das Display ansteuert, fehlen uns jegliche Grundlagen, wie der Hersteller die Ansteuerung realisiert hat. Mit Raten kommt man da nicht zum Ziel. Zum Glück haben wir das Internet, wo nahezu alle Informationen zu finden sind. Es kann zwar in manchen Fällen etwas Zeit in Anspruch nehmen und vielleicht ist es auch erforderlich, den jeweiligen Hersteller anzuschreiben mit der Hoffnung, er wird auch reagieren. Doch nun zum Objekt unserer Begierde. Für das LC-Display, welches ich in diesem AddOn verwende, existiert schon eine fertige Library, doch ich möchte euch zeigen, wie wir unabhängig davon ein Grundgerüst entwickeln, dass zwar nicht so ausgereift wie die mit der Arduino Entwicklungsumgebung gelieferte Library ist, doch einen guten Einstieg in die Analyse des Datenblattes bzw. der objektorientierten Programmierung bietet. Das Display ist vom Typ HD44780 des Herstellers Hitachi, das ich auch in einigen Buchkapiteln verwendet habe. Es wird weltweit sehr oft verwendet und hat sich deshalb zu einem Quasi-Standard gemausert. Auf dem folgenden Bild siehst Du ein angeschlossenes Display. Arduino LC-Display-Ansteuerung Seite 3

Das hier verwendete Modell hat 2 Zeilen mit je 16 Zeichen, die aus einer 5x7 Punktmatrix zusammengesetzt sind. Du erkennst zwar eine 5x8 Matrix, doch die untere Zeile wird nicht genutzt. Gleich zu Anfang möchte ich Dir schon einmal den Schaltplan präsentieren, damit Du einen Überblick über den sehr geringen Schaltungsaufwand bekommst und nicht in Panik ausbrichst. Außerdem können wir diesen Schaltplan als Ausgangspunkt nehmen, um bei meinen Erläuterungen immer einmal wieder darauf zurückzugreifen. Natürlich benötigt ein derartiges Bauteil eine Versorgungsspannung, die mit +5V bzw. GND (Masse) gekennzeichnet ist. Die beiden Pins mit den Bezeichnungen A (Anode) bzw. K (Kathode) stehen für die Hintergrundbeleuchtung. Kommen wir jetzt aber zu den richtig wichtigen Anschlüssen, die zur Ansteuerung des Displays benötigt werden. Arduino LC-Display-Ansteuerung Seite 4

Anschlussbelegung Hier siehst Du die einzelnen Anschlüsse mit ihren Bezeichnungen: Registerwahl (Register-Select) Read/Write Enabled Datenbus D0 bis D7 (8-Bit) Vielleicht ist Dir im Schaltplan aufgefallen, dass lediglich die Anschlüsse D4 bis D7 verwendet wurden. Da es sich um die Datenleitungen handelt und wir nur die Hälfte der zur Verfügung stehenden Pins nutzen, bedeutet das jedoch nicht, dass uns etwas von der Funktionalität verloren geht. Das Display kann sowohl im 8-Bit, als auch im 4-Bit Modus betrieben werden. Da in fast allen Schaltungen der 4-Bit-Modus verwendet wird, werden wir das auch hier tun. Um einen Bytewert auf eine 8-Bit Leitung zu schicken, ist eine einzige Operation von Nöten. Arduino LC-Display-Ansteuerung Seite 5

8-Bit-Modus 1 0 1 1 0 0 1 0 LSB MSB Um die gezeigte Bitkombination an das LC-Display zu schicken, ist eine einzige Operation notwendig. Arduino LC-Display-Ansteuerung Seite 6

1. Schritt 2. Schritt 4-Bit-Modus 1 0 1 1 0 0 1 0 LSB MSB 0 0 1 0 1 0 1 1 Im 1. Schritt werden die obersten 4 Bits, im 2. Schritt, die untersten 4 Bits übertragen. Das bedeutet zwar ein wenig Mehraufwand, was sich sicherlich auf die Ausführungsgeschwindigkeit auswirkt, doch immer noch so schnell passiert, dass wir den Unterschied zum 8-Bit Modus nicht wahrnehmen würden. Wie aber können wir jetzt etwas auf das LC-Display schicken, um etwas zu sehen? Es hängt sicherlich in erster Linie davon ab, was wir auf die Datenleitungen (D4 bis D7) schicken, doch auch die Steuerleitungen R/W (ist auf 0: Masse gelegt, weil wir nur auf das Display schreiben), R/S und Enabled spielen sicherlich ebenfalls eine entscheidende Rolle. Das Zusammenspiel aller Leitungen macht in der Summe das aus, wie sich das Display verhält. Wenn Du Deinen Mikrocontroller programmierst, dann bedienst Du Dich einem vordefinierten Befehlssatz, damit das ausgeführt wird, was Du beabsichtigt hast. Ähnlich verhält es sich mit dem LC-Display. Alleine das LC-Display, was ja genau genommen nur eine Flüssigkeitskristallanzeige ist, besitzt ja keine Logik. Zu Ansteuerung wird ein sogenannter Treiber benötigt. Dieser Baustein enthält die Logik bzw. einen Befehlssatz, um die Anzeige zu steuern. Arduino LC-Display-Ansteuerung Seite 7

Wir unterscheiden bei der Ansteuerung des LC-Displays zwei Kategorien. Zum einen muss das Display konfiguriert werden, damit bestimmte Grundvoraussetzungen (z.b. Ansteuerungsmodus, Zeilenanzahl, etc.) erfüllt werden. Das hat nichts mit den sichtbaren Zeichen in der Anzeige zu tun. Zum anderen möchten wir natürlich etwas Sichtbares in Richtung Display schicken, denn das ist ja eigentlich die Aufgabe dieses Bauteils. Es wird also unterschieden zwischen: Senden eines Kommandos (zur Konfiguration) Senden von Zeichen (zur Anzeige) Starten wir jetzt jedoch mit den Kommandos zur Konfiguration, denn andersherum würde es wenig Sinn machen, denn zur Anzeige muss das Display vorkonfiguriert sein. Den schon angesprochenen Befehlssatz schauen wir uns jetzt ein wenig genauer an. Befehlssatz Befehl RS RW D7 D6 D5 D4 D3 D2 D1 D0 Displayinhalt löschen 0 0 0 0 0 0 0 0 0 1 Cursor auf Startposition 0 0 0 0 0 0 0 0 1 X Modus festlegen 0 0 0 0 0 0 0 1 I/D S Display/Cursor 0 0 0 0 0 0 1 D C B Display/Cursor schieben 0 0 0 0 0 1 S/C R/L X X Funktionen 0 0 0 0 1 DL N F X X CGRAM Adresse setzen 0 0 0 1 CGRAM-Adresse DDRAM Adresse setzen 0 0 1 DDRAM-Adresse Adresse/Status lesen 0 1 BF CG-/DDRAM-Adresse Daten in DDRAM/CGRAM schreiben 1 0 Daten Daten aus DDRAM/CGRAM lesen 1 1 Daten Auf den ersten Blick ist diese Tabelle sicherlich verwirrend und es ist nicht eindeutig klar, wie sie zu lesen ist. Doch das ist eigentlich ganz einfach. Als Beispiel nehme ich einfach einmal die Zeile, in der eine Funktion aufgerufen wird, um das Display zu konfigurieren. Befehl RS RW D7 D6 D5 D4 D3 D2 D1 D0 Funktionen 0 0 0 0 1 DL N F X X Wir konzentrieren uns hierbei lediglich auf die Datenleitungen (D0 bis D7), dir in der Tabelle in umgekehrter Reihenfolge stehen. Die logische 1 an Datenleitung D5 ist eine feste Größe und teilt dem Treiber mit: Pass auf, jetzt komme eine Funktion mit bestimmten Argumenten!. Die Argumente werden durch die weiter rechts stehenden Steuerbits repräsentiert. Arduino LC-Display-Ansteuerung Seite 8

Da wären also: DL N F die natürlich eine bestimmte Aufgabe haben. Die X in den Spalten sagen uns, dass sie ignoriert werden, egal, was dort für ein Wert enthalten ist (Don t care bits). Steuerbit 0 1 DL 4-Bit Modus 8-Bit Modus N 1-zeiliges Display 2/4-zeiliges Display F 5x7 Font 5x10 Font Die komplette Tabelle kommt später noch. In der Programmierung werden die einzelnen Befehle ohne die Angabe der weiter rechts stehenden Bits erst einmal formuliert bzw. definiert. Das erfolgt entweder als Binär- oder als Hex-Wert. Die Definition der Funktion lautet z.b. wie folgt, wobei ich den Namen natürlich frei gewählt habe. #define LCD_FUNCTIONCALL 0b00100000 // 0x20 Diese Bitkombination (der Hex-Wert steht als Kommentar dahinter) entspricht genau der, aus der Tabelle. Jetzt werden die Steuerbits ebenfalls als Definitionen festgelegt: #define LCD_4BITMODE #define LCD_8BITMODE #define LCD_1LINE #define LCD_2LINE #define LCD_5x7FONT #define LCD_5x10FONT 0b00000000 // 0x00 0b00010000 // 0x10 0b00000000 // 0x00 0b00001000 // 0x08 0b00000000 // 0x00 0b00000100 // 0x04 Arduino LC-Display-Ansteuerung Seite 9

Ich kann also die Funktion mit dem genannten Namen aufrufen. Doch wie verknüpfe ich die Steuerbits mit der Funktion? Das ist mir schleierhaft. Die Informationen der Steuerbits müssen dem Funktionsaufruf hinzugefügt werden, um dann als Ganzes in Richtung Datenbus übertragen werden. Das Verknüpfen erfolgt über die bitweise ODER-Verknüpfung. Sehen wir uns das an einem Beispiel genauer an. Wir wollen folgende Grundeinstellungen des Displays vornehmen: 4-Bit Mode 2 Zeilen-Display 5x7 Font Folgende Befehlszeile würde die Konfiguration vornehmen, wobei cmd die Methode darstellt, die die Werte in Richtung Datenbus versendet. Darauf kommen wir natürlich später noch zu sprechen. Funktionsaufruf Argumente cmd(lcd_functioncall LCD_4BITMODE LCD_2LINE LCD_5x7FONT); Die bitweise ODER-Verknüpfung erfolgt über das Pipe-Zeichen. Im Endeffekt wird dann folgende Bitkombination an den Display-Treiber versendet: LCD_FUNCTIONCALL 00100000 LCD_4BITMODE 00000000 LCD_2LINE 00001000 LCD_5x7FONT 00000000 Ergebnis: 00101000 Der cmd-aufruf erfolgt demnach mit der Bitkombination 00101000 und konfiguriert das Display wie gewünscht. Arduino LC-Display-Ansteuerung Seite 10

Im Anschluss kommen wir zum Verhalten des Displays. Ich meine damit noch nicht die konkrete Darstellung von Zeichen, sondern folgende Punkte: Display an/aus Cursor an/aus Blinken an/aus Es handelt sich ebenfalls um eine Konfiguration, die jedoch von den Grundeinstellungen separat betrachtet wird. Dazu bedienen wir uns ebenfalls eines Kommandos. #define LCD_DISPLAYCONTROL 0b00001000 // 0x08 Diese Bitkombination (der Hex-Wert steht als Kommentar dahinter) entspricht genau der, aus der Tabelle. Jetzt werden die Steuerbits ebenfalls als Definitionen wie schon beim Funktionsaufruf - festgelegt: #define LCD_DISPON #define LCD_DISPOFF #define LCD_CURSORON #define LCD_CURSOROFF #define LCD_BLINKON #define LCD_BLINKOFF 0b00000100 // 0x04 0b00000000 // 0x00 0b00000010 // 0x02 0b00000000 // 0x00 0b00000001 // 0x01 0b00000000 // 0x00 Ein möglicher Aufruf könnte wie folgt aussehen: Funktionsaufruf Argumente cmd(lcd_displaycontrol LCD_DISPON LCD_BLINKON); Es wird das Display eingeschaltet (sonst sieht man nämlich bei der späteren Textausgabe nicht viel) und der blinkende Cursor angezeigt. Ich wollte Dir ja noch die komplette Tabelle mit den Bedeutungen der Steuerbits liefern. Hier ist sie: Arduino LC-Display-Ansteuerung Seite 11

Tabelle der Steuerbits Steuerbit 0 1 I/D Cursorposition dekrementieren Cursorposition inkrementieren S Displayinhalt fest Displayinhalt weiterschieben D Display aus Display an C Cursor aus Cursor an B Cursor fest Cursor blinkt S/C Cursor bewegen Displayinhalt verschieben R/L Nach links schieben Nach rechts schieben DL 4-Bit Modus 8-Bit Modus N 1-zeiliges Display 2/4-zeiliges Display F 5x7 Font 5x10 Font BF Annahme von Kommandos Beschäftigt Die letzte Zeile dient nur dem Lesen von Statusinformationen. Arduino LC-Display-Ansteuerung Seite 12

LCD-Timing Bevor wir jetzt in Kürze zur Darstellung von richtigen Textinhalten auf dem LC-Display kommen, müssen wir noch ein paar äußerst wichtige Dinge ansprechen. Ein Treiberbaustein empfängt Daten bzw. Steuersignale in zeitlicher Abfolge. Es existieren unterschiedliche zeitliche Aspekte, die ebenfalls im Datenblatt vermerkt sind und ohne die unbedingte Einhaltung läuft rein Garnichts! Initialisierung Die Initialisierung des Displays muss nach einem bestimmten Ritus erfolgen. Da wir unser Display nur im 4-Bit Modus betreiben, ist die Seite 46 / Figure 24 sicherlich einen Blick wert. Hier eine kurze Zusammenfassung: Power on Min. 40ms warten Warten, bis min. V CC = 4.5 V erreicht sind. Senden von 0x03 Min. 40ms warten 1. Durchlauf Senden von 0x03 Min. 150µs warten 2. Durchlauf Senden von 0x03 Min. 150µs warten Senden von 0x02 3. Durchlauf Von mir sicherheitshalber eingefügt Endgültiges Setzen auf 4-Bit Mode Die Abarbeitung eines einzelnen Befehls nimmt schon etwas Zeit in Anspruch und erfolgt nicht ohne Rechenzeit. Im Datenblatt auf Seite 24 / Tabelle 6 findest Du in der rechten Spalte Informationen über die Ausführungszeiten, die sich bis auf die ersten beiden so um ca. 37µs bewegen. Aus diesem Grund ist es notwendig, mindestens diese angegebene Zeit als Wartezeit Arduino LC-Display-Ansteuerung Seite 13

(Delay) im Sketch zu hinterlegen. Du musst dem Treiber die Möglichkeit geben, seinen Befehl auszuführen bzw. abzuarbeiten. Enable-Impuls Nach der Übertragung eines Befehls - sei es ein Kommando oder ein Zeichen - an den Treiber, muss ein sogenannter Enable-Impuls hinten angehängt werden. Er dient quasi als Abschlusskennung und muss in Form eines LOW-HIGH-LOW Impulses einer bestimmten Länge erfolgen. Details dazu stehen im Datenblatt auf Seite 49 / Figure 25. Dort wird eine Impulsdauer von mindesten 450ns vorgeschrieben. Den muss ich also hinten an die Datenübertragung anhängen, richtig!? Damit liegst Du richtig, doch das kann ja nicht auf dem Datenbus erfolgen, denn ein Impuls bezieht sich eigentlich immer nur auf eine einzelne Signalleitung. Zu diesem Zweck gibt es die Enable-Leitung, die mit E gekennzeichnet ist. Dort muss der besagte Impuls mit der angegebenen Dauer abgesetzt werden. min. 450ns Jetzt wird es langsam ernst, denn die Umsetzung des bisher angesprochenen steht ins Haus. Wir wollen eine Klasse programmieren, die es uns ermöglicht, alles das einzubauen, was wir gelernt haben. Arduino LC-Display-Ansteuerung Seite 14

Programmierung der LCD-Klasse Die Programmierung ist für denjenigen vielleicht schon etwas gewöhnungsbedürftig, der noch nie etwas mit objektorientierter Programmierung am Hut hatte. Doch ich werde wie immer Schritt für Schritt vorgehen, damit nach Möglichkeit niemand auf der Strecke bleibt. Die Grundlagen der objektorientierten Programmierung bzw. die Erstellung einer Klasse für eine Bibliothek (auch Library genannt), findest Du in meinem Buch erstmalig im Projekt 10 (Seite 315), wenn es um den elektronischen Würfel geht. Für dieses Tutorial fasse ich das jedoch noch einmal kurz zusammen. Um eine Klasse in C++ zu erstellen, werden in der Regel zwei programmtechnische Konstrukte benötigt: Header-Datei (Dateiendung.h) Klassen-Datei (Dateiendung.cpp) Die Header-Datei beinhaltet lediglich sogenannte Prototyp-Informationen und keinen ausformulierten Code. Salopp ausgedrückt, ist das quasi eine Vorankündigung an den Compiler, damit er weiß, was auf ihn zukommt. In die Klassen-Datei wird dann der komplette ausformulierte Code gepackt, der benötigt wird. Ziemlich weit hergeholt meinst Du!? Kann ich verstehen, denn das erste Mal ging es mir nicht anders! Aber keine Sorge, denn wir werden das schon schaffen hab ich ja auch Zuerst habe ich mir einmal Gedanken über den Namen der Klasse gemacht, der natürlich in irgendeiner Weise schon sprechend sein sollte, damit jeder sofort weiß, worum es denn geht. Die mit der Arduino-Entwicklungsumgebung mitgelieferte Library zur Ansteuerung des LCD nennt sich ja LiquidCrystal. Also habe ich mich für LCDisp entschieden. Du kannst natürlich jeden beliebigen Namen nehmen, solange er nicht mit schon vorhandenen kollidiert. Das dürfte aber nicht allzu schwierig sein. Meine beiden Dateien lauten demnach: LCDisp.h LCDisp.cpp Das wäre also schon mal geschafft. Um das Anschließen des LC-Displays ein wenig flexibel zu gestalten, verwenden wir innerhalb der Klasse Variablen, die in diesem Kontext Attribute bzw. Felder genannt werden, um die gewünschten Werte der Anschlusspins zu übergeben. Für dieses Tutorial beschreibe ich der Einfachheit halber ja den 4-Bit Modus und ein LC-Display mit 2 Zeilen. Das wird also intern Code mäßig fest verdrahtet. Hast Du das Prinzip dann verstanden und das ist meine Absicht kannst Du alles nach eigenen Wünschen anpassen bzw. erweitern. Die hier vorgestellte Programmierung legt den Grundstein zum Verständnis der LCD- Ansteuerung. Alles Weitere kommt dann von Dir. Arduino LC-Display-Ansteuerung Seite 15

Die Klasse, die wir gleich programmieren dient als Schablone zur Erstellung eines LCD-Objektes, was durch die Instanziierung erfolgt (Siehe Buch Seite 335, 2. Abschnitt). Durch die Instanziierung wird aus der Klasse ein Objekt, wobei implizit der sogenannte Konstruktor aufgerufen wird, um das Objekt erstmalig zu initialisieren (Siehe Buch Seite 325). Hier siehst Du den Konstruktor: Zu 1: Übergabe der Konstruktorparameter an die internen Felder. Zu 2: Die Pins rs und en als Ausgänge programmieren. Zu 3: Die Pins des Datenbusses D4 bis D7 werden ebenfalls als Ausgänge programmiert. Zu 4: Hier wird die LCDInit-Methode aufgerufen, um das Display zu initialisieren. Darauf kommen wir gleich noch zu sprechen. Arduino LC-Display-Ansteuerung Seite 16

Ich habe da schon noch so meine Zweifel!? Was bedeutet der Datentyp uint8_t und wo wurden die Feldvariablen deklariert? Ok, Ardus! Der Datentyp uint8_t hat in irgendeiner Weise mit dem Datentyp int zu tun, denn das int kommt ja irgendwie darin vor. Ich muss zugeben, dass die Namenskonvention schon kryptisch anmutet, doch nehmen wir diesen Datentyp einmal auseinander. Ich habe blaue Markierungen über bzw. unter der zu erläuternden Stelle im Namen gesetzt. u : unsigned 8 : Datenbreite = 8 Bits uint8_t int : Integer _t : Typ-Extension Der ANSI-Standard für die C-Programmierung hat einige neue Datentypen aufgenommen, damit die Portabilität zu anderen Plattformen erhöht wird. Dazu gehört auch der genannte Datentyp uint8_t. Nähere Informationen findest Du unter http://en.wikipedia.org/wiki/stdint.h#stdint.h Natürlich hätten wir auch den reinen Datentyp int verwenden können, doch dieser erstreckt sich ebenfalls in den negativen Bereich und hat zusätzlich einen viel größeren Wertebereich, der an dieser Stelle etwas oversized ist. Arduino LC-Display-Ansteuerung Seite 17

Kommen wir jetzt zur schon erwähnten Initialisierungsmethode LCDInit. Im Abschnitt über das LCD-Timing habe ich diese Prozedur schon angesprochen. Falls noch etwas unklar sein sollte, dann schaue dort noch einmal nach. Die beiden markierten Punkte 1 und 2 möchte ich dennoch kurz ansprechen, obwohl ich sie schon erwähnt hatte. Zu 1: An dieser Stelle wird die LCD-Funktion LCD_FUNCTIONCALL aufgerufen. Die einzelnen Argumente habe ich in einem separaten Feld functionmode ausgelagert, das dann in der darauffolgenden Zeile zusammen mit dem Funktionsaufruf der cmd-methode übergeben wird. Zu 2: Auch hier werden, wie unter zu 1, die Argumente für den LCD_DISPLAYCONTROL-Aufruf in dem Feld displaymode ausgelagert und in der darauffolgenden Zeile zusammengefügt. Arduino LC-Display-Ansteuerung Seite 18

Kommen wir jetzt zu zwei Methoden, die für das Versenden der Daten an das Display verantwortlich sind. cmd send2lcd Die cmd-methode sorgt dafür, dass die ankommenden 8-Bit Daten in 2x4-Bit Daten gesplittet werden. Wir haben uns ja wie schon mehrfach erwähnt für den 4-Bit Modus entschieden. Wie machen wir aber auf 8-Bit die erforderlichen 2x4-Bit Daten? Wir bedienen uns dazu der umfangreichen Möglichkeiten der Bitmanipulation. Schiebeoperator >> Bitweise UND-Verknüpfung Da zuerst die 4 höherwertigen Bits übertragen werden müssen, wenden wir die Schiebeoperation >> (Schieben nach rechts) an. Wir nehmen als Beispiel wieder die Bitkombination, die ich schon eingangs gezeigt habe. Arduino LC-Display-Ansteuerung Seite 19

Diese Operation wird durch den Befehl send2lcd(c >> 4, LOW); // Zuerst die obersten 4 Bits ermöglicht. Der in c enthaltene Wert wird um 4 Binärstellen nach rechts verschoben und dann der send2lcd-methode übergeben. Lasse Dich nicht durch den 2. Parameter verunsichern, der hier mit LOW angegeben ist. Es teilt der Methode lediglich mit, dass jetzt ein Kommando zu versenden ist und kein sichtbares Zeichen zur Anzeige kommen soll. Schaue Dir dazu noch einmal die Steuerleitung RS an. Sie benötigt einen LOW-Pegel, damit die Daten als Kommando interpretiert werden. Du siehst es gleich besser, wenn wir die send2lcd-methode genauer unter die Lupe nehmen. Jetzt sind also die untersten 4-Bits an der Reihe, um auf die Reise zu gehen. Dazu wird der bitweise UND-Operator verwendet. Diese Operation wird durch den Befehl send2lcd(c & 0x0f, LOW); // Danach die untersten 4 Bits ermöglicht. Arduino LC-Display-Ansteuerung Seite 20

Kommen wir jetzt zur send2lcd-methode. Dort erfolgt ja das eigentlich versenden an den LCD- Treiber. Hier werden die von der cmd-methode geschickten Werte an die digitalen Pins D4 bis D7 versendet. Zuvor muss jedoch der digitale Pin RS mit LOW-Pegel versehen werde. Das erfolgte ja durch die Übergabe des 2. Argumentes der cmd-methode. Nun muss jedes einzelne Bit separiert und dem entsprechenden Pin zugeführt werden. Das geschieht wieder mittels binärer Bitoperatoren. Diesmal arbeiten Schiebeoperator >> und binärer UND-Operator Hand in Hand. Sehen wir uns dazu einfach das Versenden der untersten 4-Bits an. Diese Bitkombination lautet ja: Wir müssen das an Position 0 stehende Bit an den digitalen Pin 4 versenden. Dazu wird eine Technik verwendet, bei der das an der LSB-Position stehende Bit ausgewertet wird. LSB bedeutet Least Significant Bit und steht für das niederwertigste Bit. Es werden nach der Reihe alle benötigten Bits über die Schiebeoperation an die LSB-Position verschoben und dort mit dem bitweisen UND-Operator 0x01 abgefragt, der als eine Art Maske arbeitet. Das erste Bit steht natürlich schon an der richtigen LSB-Position und braucht nicht erst dorthin verschoben werden. Deshalb steht auch die Ziffer 0 hinter dem Schiebeoperator. Arduino LC-Display-Ansteuerung Seite 21

Das Bit an Position 1 muss jetzt um eine Position nach rechts manövriert werden. Das erfolgt über die Befehlszeile So geht das Spiel weiter, bis alle 4 Bits versendet wurden. Abschließend erfolgt noch der notwendige Aufruf der Enable-Methode, über die wir auch schon ein paar Worte verloren haben: Eigene Methoden zur Steuerung erstellen LCD-Inhalt löschen Bevor Du etwas in Deinem LC-Display anzeigen möchtest, macht es manchmal Sinn, das vorherige zu löschen, um Platz für Neues zu schaffen. Wie aber löschen wir den Inhalt? Nun, es handelt sich sicherlich um ein Kommando und nicht um eine Textausgabe. Wenn Du einen Blick in die Befehlssatztabelle riskierst, dann findest Du direkt in der ersten Zeile die Lösung. Dort steht nämlich Displayinhalt löschen. Der dazu notwendige Code lautet 0x01. Damit dies aber alles ein wenig sprechender wird, legen wir uns wieder eine Definition an. #define LCD_CLEAR 0b00000001 // 0x01 Den Aufruf verpacken wir das recht komfortabel in eine eigens dafür erstellte Methode. Abschließend warten wir 2ms, da diese Operation lt. Datenblatt ziemlich lange dauert. Es werden mindestens 1.52ms dafür veranschlagt. Wir sind also mit dem verwendeten Wert auf der sicheren Seite. Arduino LC-Display-Ansteuerung Seite 22

Cursor in Home-Position Du kannst den Cursor ohne den Inhalt zu löschen in die HOME-Position bringen. Der Code dazu lautet: #define LCD_HOME 0b00000010 // 0x02 Die Methode dazu lautet: Auch hier muss nach dem Absetzen des Kommandos lt. Datenblatt die Zeit von mindestens 1.52ms verstrichen sein, bevor es weiter gehen kann. Auf diese Weise kannst Du Dir alle erdenklichen Funktionalitäten selbst zusammenstellen. Das war eigentlich schon fast alles. Stimmt, denn wir haben ja noch gar keinen Text an das LC-Display verschickt. Wie funktioniert das denn? Du musst in Deinem Haupt-Sketch lediglich die Klasse LCDisp bekannt machen, ein Display- Objekt erstellen und die print-methode zur Ausgabe aufrufen. Ich zeige Dir, was ich meine: Arduino LC-Display-Ansteuerung Seite 23

Hier ist doch etwas faul!? Soweit ich mich entsinne, haben wir die print-methode nicht in der LCDisp-Klasse implementiert! Wie können wir sie dann zur Ausgabe eines Textes nutzen??? Ok, Ardus! Das habe ich mir für den Schluss aufgehoben, denn jetzt wird s noch mal richtig gut. Dazu müssen wir ein wenig mehr über die objektorientierte Programmierung in Erfahrung bringen. Wir machen uns den Umstand zu Nutze, dass wir Funktionalitäten einer bestehenden Klasse in unsere Klasse einbinden können. Das Stichwort hierzu lautet Vererbung. Doch ich zeige Dir hier zuerst einmal die Header-Datei LCDisp.h, denn dann kann ich dort mit meinen Erläuterungen einhaken. Zuerst der Bereich, der die Definitionen beinhaltet: Arduino LC-Display-Ansteuerung Seite 24

Jetzt die eigentliche Code-Implementierung: Na, höre ich da schon Dein Stöhnen!? Da gibt es mindestens 2 Stellen, die Dir den Schlaf rauben könnten richtig? Ich habe sie sicherheitshalber schon einmal farblich hervorgehoben und nummeriert. Zu 1: Hier wenden wir die Technik bzw. das Paradigma mit der Bezeichnung Vererbung an. Unsere LCDisp-Klasse beerbt die Funktionalität der Print-Klasse. Oder anders herum vererbt die Print- Klasse ihre Funktionalität der LCDisp-Klasse. Print Basisklasse (Elternklasse) LCDisp abgeleitete Klasse (Kindklasse) Arduino LC-Display-Ansteuerung Seite 25

Kindklassen erben die Attribute (Felder) bzw. Methoden ihrer Elternklasse. Sie können weitere Attribute bzw. Methoden hinzufügen oder bestehende Methoden modifizieren. Aber warum machen wir das Ganze? Nun, die Print-Klasse enthält ein paar nützliche Methoden, derer wir uns bedienen können. Du hast gesehen, dass wir die print-methode aufgerufen haben, ohne, dass sie ein Mitglied unserer LCDisp-Klasse ist. Der Verdacht liegt nahe, dass sie ein Mitglied der Print-Klasse ist. Und so ist es auch. Die print-methode wird immer dazu verwendet, Daten auszugeben. Sie hat aber die Besonderheit, dass sie ihrerseits die write-methode aufruft, die für die eigentliche Datenausgabe verantwortlich ist. print-methode Aufruf write-methode Die write-methode wird zur einfachen Zeichenausgabe (8-Bit) verwendet. Du siehst hier den impliziten Aufruf der write-methode, wenn die print-methode von außen explizit aufgerufen wird. Print-Klasse print("hallo") print-methode write-methode...... Arduino LC-Display-Ansteuerung Seite 26

Jetzt erbt unsere LCDisp-Klasse jedoch von der Print-Klasse und übernimmt wie schon angesprochen alle Mitglieder (Attribute + Methoden) dieser Klasse. Dazu gehören natürlich auch u.a. die print- bzw. write-methode. Zu 2: Was würde aber passieren, wenn wir in unserer LCDisp-Klasse ebenfalls eine write-methode implementierten? Sie würde die eigentliche write-methode überschreiben und quasi ersetzen. Das machen wir mit der folgenden Zeile in der Header-Datei: Das Schlüsselwort virtual ist hier nicht unbedingt notwendig, macht die Sache aber ggf. etwas übersichtlicher. Ich zeige Dir gleich die eigentliche write-methode der Print-Klasse, die aber zwingend mit virtual deklariert sein muss. Auf diese Weise können wir jetzt unsere eigene write-methode schreiben, die durch die print- Methode aufgerufen wird. Klingt irgendwie noch ein bisschen verwirrend oder!? Schaue Dir dazu am besten die folgende Grafik an. abgeleitete Klasse (Kindklasse) LCDisp-Klasse Basisklasse (Elternklasse) Print-Klasse mylcd.print("hallo") print-methode write-methode write-methode............ Die print-methode bleibt unverändert und steht der LCDisp-Klasse durch Vererbung zur Verfügung. Durch das Überschreiben der write-methode (muss die gleiche Signatur vorweisen), wird diese jetzt durch die print-methode implizit aufgerufen. Arduino LC-Display-Ansteuerung Seite 27

Wenn wir uns die Header-Datei der Print-Klasse unter: arduino- 1.0\hardware\arduino\cores\arduino\Print.h einmal anschauen, dann sehen wir die Definition von drei write-methoden: In der korrespondierenden Print.cpp Datei finden wir jedoch nur eine einzige Kodierung der write-methode. Der entsprechende Kommentar gibt uns die Bestätigung, dass diese Methode überschrieben werden kann. Verantwortlich dafür ist das Schlüsselwort virtual, das Du in der Headerdatei findest. Wir verwenden übrigens bei der Vererbung das Schlüsselwort public, damit die erbende Klasse (LCDisp) die gleichen Rechte besitzt, wie die vererbende Klasse (Print). Abschließende Worte Ich habe absichtlich nicht den kompletten Funktionsumfang der bestehenden LiquidCrystal- Library umgesetzt. Versuche Dich selbst einmal daran, denn nur auf diese Weise kannst Du etwas lernen. Natürlich kannst Du Dich ggf. an der vorhandenen Library orientieren, aber nicht, um dort Code 1:1 zu übernehmen. Das würde zwar funktionieren, doch Du betrügst Dich und andere. Finde Deinen eigenen Weg. Viel Spaß dabei... Arduino LC-Display-Ansteuerung Seite 28

Kompletter Sketch-Code Abschließend möchte ich Dir noch den kompletten Sketch-Code präsentieren. Header-Datei #ifndef LCDisp_h #define LCDisp_h #include <Arduino.h> // LCD-Kommandos definieren #define LCD_CLEAR #define LCD_HOME #define LCD_FUNCTIONCALL 0b00000001 // 0x01 0b00000010 // 0x02 0b00100000 // 0x20 #define LCD_DISPLAYCONTROL 0b00001000 // 0x08 // LCD-Funktionen (Argumente für LCD_FUNCTIONCALL) #define LCD_4BITMODE #define LCD_8BITMODE #define LCD_1LINE #define LCD_2LINE #define LCD_5x7FONT #define LCD_5x10FONT 0b00000000 // 0x00 0b00010000 // 0x10 0b00000000 // 0x00 0b00001000 // 0x08 0b00000000 // 0x00 0b00000100 // 0x04 // LCD-Displaycontrol (Argumente für LCD_DISPLAYCONTROL) #define LCD_DISPON #define LCD_DISPOFF #define LCD_CURSORON #define LCD_CURSOROFF #define LCD_BLINKON #define LCD_BLINKOFF 0b00000100 // 0x04 0b00000000 // 0x00 0b00000010 // 0x02 0b00000000 // 0x00 0b00000001 // 0x01 0b00000000 // 0x00 class LCDisp : public Print{ public: // Konstructor für den 4-Bit Modus // Reihenfolge: R/S, E, DB4, DB5, DB6, DB7 LCDisp(uint8_t rs, uint8_t en, Arduino LC-Display-Ansteuerung Seite 29

uint8_t db4, uint8_t db5, uint8_t db6, uint8_t db7); void cls(); // LCD-Anzeige löschen void home(); // Cursor nach HOME virtual size_t write(uint8_t); // Wird von print der Print-Klasse aufgerufen private: uint8_t rspin; uint8_t enpin; // RS-Anschluss-Pin // Enable-Anschluss-Pn uint8_t datapin4; // Datenbus D4 uint8_t datapin5; // Datenbus D5 uint8_t datapin6; // Datenbus D6 uint8_t datapin7; // Datenbus D7 uint8_t displaymode; // Argumente für LCD_DISPLAYCONTROL uint8_t functionmode; // Argumante für LCD_FUNCTIONCALL void send2lcd(uint8_t, uint8_t); // Sendet daten zum Display void sendenable(); void LCDInit(); void cmd(uint8_t); // Sendet Enable-Signal // Initialisiert LC-Display // Kommando-Methode }; #endif Klassen-Datei #include "LCDisp.h" // Konstruktor LCDisp::LCDisp(uint8_t rs, uint8_t en, uint8_t db4, uint8_t db5, uint8_t db6, uint8_t db7){ rspin = rs; enpin = en; datapin4 = db4; datapin5 = db5; datapin6 = db6; datapin7 = db7; pinmode(rspin, OUTPUT); // Registerauswahl: 0 = Befehlsregister, 1 = Datenregister pinmode(enpin, OUTPUT); // Enable Arduino LC-Display-Ansteuerung Seite 30

pinmode(datapin4, OUTPUT); pinmode(datapin5, OUTPUT); pinmode(datapin6, OUTPUT); pinmode(datapin7, OUTPUT); LCDInit(); // LC-Display initialisieren } void LCDisp::cmd(uint8_t c){ send2lcd(c >> 4, LOW); // Zuerst die obersten 4 Bits send2lcd(c & 0x0f, LOW); // Danach die untersten 4 Bits delaymicroseconds(2000); } void LCDisp::send2LCD(uint8_t s, uint8_t mode){ digitalwrite(rspin, mode); // Bei einem Kommando muss R/S-Register auf LOW gesetzt werden digitalwrite(datapin4, (s >> 0) & 0x01); digitalwrite(datapin5, (s >> 1) & 0x01); digitalwrite(datapin6, (s >> 2) & 0x01); digitalwrite(datapin7, (s >> 3) & 0x01); sendenable(); } // Überschreibt die write-methode der Print-Klasse size_t LCDisp::write(uint8_t text){ send2lcd(text >> 4, HIGH); // Zuerst die obersten 4 Bits send2lcd(text & 0x0f, HIGH); // Danach die untersten 4 Bits delaymicroseconds(2000); } void LCDisp::sendEnable(){ // Generierung eines LOW-HIGH-LOW Impulses digitalwrite(enpin, LOW); delaymicroseconds(1); Arduino LC-Display-Ansteuerung Seite 31

digitalwrite(enpin, HIGH); delaymicroseconds(1); Seite 49) // Hier 1000ns: Der Enable-Impuls muss > 450ns betragen (Datenblatt digitalwrite(enpin, LOW); delaymicroseconds(100); (Datenblatt Seite 24) // Hier 100us: Ein Kommando benötigt 37us für die Abarbeitung } void LCDisp::LCDInit(){ digitalwrite(rspin, LOW); // Auf LOW setzen, damit Kommandos entegegen genommen werden können digitalwrite(enpin, LOW); // Auf LOW setzen, damit Kommandos entegegen genommen werden können delaymicroseconds(50000); // 50 Millisekunden warten, bevor Kommandos gesendet werden können // Siehe HD44780 Datenblatt Seite 46, Abbildung 24 // Mehrfacher Aufruf der Funktion ist notwendig (komisch, nicht!?) // 1. Versuch send2lcd(0x03, LOW); delaymicroseconds(4500); // Länger wie 4.1ms warten // 2. Versuch send2lcd(0x03, LOW); delaymicroseconds(150); // Länger wie 150us warten // 3. Versuch send2lcd(0x03, LOW); delaymicroseconds(150); // Sicherheitshalber kurz warten. Steht nicht im Datenblatt!!! // Endgültiges Setzen auf 4-Bit send2lcd(0x02, LOW); // Initialer Functionmode functionmode = LCD_4BITMODE LCD_2LINE LCD_5x7FONT; cmd(lcd_functioncall functionmode); // Initialer Displaymode displaymode = LCD_DISPON LCD_BLINKON; Arduino LC-Display-Ansteuerung Seite 32

cmd(lcd_displaycontrol displaymode ); } void LCDisp::cls(){ cmd(lcd_clear); delaymicroseconds(2000); } void LCDisp::home(){ } cmd(lcd_home); delaymicroseconds(2000); Sketch-Code #include "LCDisp.h" void setup(){ LCDisp mylcd(12, 11, 5, 4, 3, 2); // Initialisierung mylcd.cls(); mylcd.print("arduino..."); // LCD Inhalt löschen // Anzeige } void loop(){/* leer */ } Arduino LC-Display-Ansteuerung Seite 33