Prinzipiell sollte ein HD44780 kompatibles Display (oder auch KS0070)
verwendet werden. Als Quelle können beispielsweise die alphanumerischen Displays
von Conrad Electronic bzw. Reichelt dienen. Ich habe beispielsweise ein 2x16
Display verwendet. Dieses erscheint mir für den Anfang vollkommen ausreichend.
Auf die Verwendung von Grafik-LCDs werde ich nicht eingehen, da mir deren
Verwendung im Rahmen meiner Projekte als nicht sinnvoll erscheint. Außerdem ist
deren Ansteuerung wesentlich komplexer.
Die Pinbelegung des LC-Displays lässt sich aus dem Datenblatt wie folgt
entnehmen:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
VSS | VDD | VO | RS | R/W | E | DB1 | DB2 | DB3 | DB4 | DB5 | DB6 | DB7 | DB8 | BLA | BLK |
Hierbei ist VSS Masse, VDD die Betriebsspannung von +5V und VO die
Kontrastspannung. Pin 4 bis 6 dienen der Steuerung des Displays. Auf Pin 7 bis
14 erfolgt die Übertragung der Datenbits, 15 und 16 dienen dem Anschluss einer
Hintergrundbeleuchtung, falls das Display über eine verfügt.
Eine Anschlussvariante eines solchen Displays stellt die folgende Grafik dar:
Prinzipiell kann man ein solches Display entweder im 8-Bit-Modus oder
im 4-Bit-Modus ansteuern. Da der ATmega8 nicht gerade über sehr viele IO-Pins
verfügt, habe ich mich für den 4-Bit-Modus entschieden. So spart man 4 Pins am
Controller ein, welche man anderweitig verwenden kann.
Der einzige Nachteil ist, dass man nun zum Übertragen eines einzigen Bytes zwei
Schreibzugriffe durchführen muss in nicht wie im 8-Bit-Modus nur einen. Es wird
zuerst das höhere Nibble (Bit 7...4) und danach das niedere Nibble (Bit 3...0)
übertragen.
Nach dem Aufbau der obigen Schaltung sollte beim Zuschalten der Betriebsspannung
mindestens ein schwarzer Balken zu sehen sein. Das Display kann natürlich auch
an einen anderen Port des MC angeschlossen werden, hierbei müssten aber in der
Bibliothek die entsprechenden Pins abgeändert werden.
Möchte man das Display vom MC aus ansteuern, so muss dieses zuerst
ordnungsgemäß initialisiert werden. Wie das funktioniert, kann man im Normalfall
dem Datenblatt entnehmen.
Zuerst muss man den entsprechenden Port, im Beispiel PORTD als Ausgang
definieren. Dies könnte zum Beispiel so aussehen:
DDRD = 0xFF;
Da nach dem Einschalten des Displays mindestens 15ms gewartet werden soll,
wird nun ein entsprechendes Delay eingefügt.
delay(20000);
Im nächsten Schritt sollen DB4 und DB5 am Display auf High-Pegel gesetzt werden.
PORTD = 0x30>>4;
//entspricht 0b00110000
Um dem LCD mitzuteilen, dass es diesen Wert übernehmen kann, muss kurz dessen
E-Port (Nr. 6) auf high und danach gleich wieder auf low gesetzt werden. Dies
erfolgt durch folgende Kommandos:
PORTD |= (1<<PD6);
__asm__ __volatile__( "rjmp 1f\n 1:" );
//warte 500ns
PORTD &= ~(1<<PD6);
Am praktischsten ist es, diese Befehle in eine eigenständige Funktion zu
schreiben, da man sie häufiger benötigt (Bsp. toggle_e ( )).
Nun muss laut Datenblatt länger als 4,1ms gewartet werden, bis der
Displaycontroller die Daten übernommen hat. Danach muss noch einmal das selbe
Bitmuster an den PORTD ausgegeben werden. Nun muss erneut mindestens 100μs
gewartet werden.
Da es soviel Spaß gemacht hat, muss sich dieser ganze Zyklus nun auch noch ein
drittes Mal wiederholen.
Nun ist das Display soweit, dass man ihm sagen kann, in welchem Funktionsmodus
man es betreiben möchten. In diesem Fall ist es der 4-Bit-Modus, das Display hat
zwei Zeilen und ein einzelner Charakter hat 5*7 Pixel.
Begonnen wird mit der Initialisierung des 4-Bit-Modus.
PORTD = 0x20>>4;
//entspricht 0b00100000
toggle_e();
delay(100);
Hiermit wird eine logische '1' an DB5 gelegt, wie es laut Datenblatt auch
erforderlich ist, um die Funktionsweise zu definieren. Da DB4 auf '0' liegt,
erkennt der Displaycontroller, dass der 4-Bit-Modus verwendet werden soll.
Als nächstes soll dem Display begreiflich gemacht werden, das beide Zeilen
genutzt werden. Hierzu muss laut Datenblatt eine 0x28 an den Datenpins des
Displays anliegen, da aber nur vier der Pins genutzt werden, kann die
Einstellung des Modus nicht einfach durch PORTD=0x28 erfolgen (DB3 und DB5
müssen auf H-Pegel gesetzt werden).
Hierzu wird zuerst durch das Lesen des Busy-Flags geprüft, ob das Display bereit
ist. Ist es gelöscht, so können die Daten geschrieben werden. Ist es bereit, so
muss ihm klar gemacht werden, dass die folgenden Daten als Befehl zu deuten
sind. Dies erfolgt durch RS=0 (PD4 am AVR) und RW=0 (liegt soundso auf Masse).
Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere
zuerst.
PORTD = (data>>4)&0x0F;
toggle_e();
PORTD = data&0x0F;
toggle_e();
In diesem Fall ist data = 0x28, wie es bereits oben erwähnt wurde.
Dann werden alle Datenpins wieder auf logisch '0' gesetzt.
PORTD = 0x0F;
Laut Datenblatt muss man, um das Busy-Flag zu lesen RW auf High-Pegel und RS auf
Low-Pegel setzen, d.h. für die Pins am AVR, dass PD5 auf '1' und PD4 auf '0'
gesetzt werden müssen.
Zur Überprüfung des Busy-Flags muss zunächst der entsprechende Pin am Controller
(PD7) als Eingang konfiguriert werden. Dann kann man Prüfen, ob eine logische
'1' anliegt oder ob der Pin auf logisch '0' liegt.
PORTD |= (1<<PD5);
//RW=1 Lese-Modus
DDRD = 0xF0;
//als Eingang definieren
Liegt DB7 am Controller auf '1', so bedeutet das, dass er gerade beschäftigt
ist, andernfalls ist er bereit.
Vor dem Lesen muss an Pin 6 am Controller (E - - > chip enable) eine '1' liegen,
nach dem Lesezugriff kann dieses Bit wieder gelöscht werden.
PORTD |= _BV(PD6);
__asm__ __volatile__( "rjmp 1f\n 1:" );
//delay (500ns)
dataH = PIND; //zuerst hohes Nibble lesen
PORTD &= ~(1<<PD6);
__asm__ __volatile__( "rjmp 1f\n 1:" );
//delay
PORTD |= (1<<PD6);
__asm__ __volatile__( "rjmp 1f\n 1:" );
//delay
dataL = PIND; //lese niederes Nibble
PORTD &= ~(1<<PD6);
Dieser Code liest neben dem Busy-Flag gleich noch den Adresszähler aus. Die
Überprüfung, ob Bit 7 auf logisch '1' ist (entspricht DB7)sollte nun auch keine
Hürde mehr sein.
Nun funktioniert das Display also im 2-Zeilen-Betrieb.
Als nächstes soll das Display ausgeschaltet werden. Dies erfolgt durch das
Senden von 0x08 (vgl. Datenblatt). Das Senden erfolgt analog zu der obigen
Erklärung (dort war es 0x28 für den 4-Bit-Modus).
Danach muss das Display gelöscht werden. Hierzu muss 0x01 gesendet werden (vgl.
Datenblatt).
Zu guter letzt muss noch der Start-Modus (entry mode) definiert werden. Hier
soll das Display einfach aktiviert und der Cursor deaktiviert werden. Dies
erfolgt durch Senden von 0x0C.
Hiermit ist die Initialisierung des Displays abgeschlossen!
Prinzipiell empfehle ich den Download der LCD-Library von Peter Pfleurys Homepage (siehe Rubrik Links), da sie universell einsetzbar für alle HD44780 kompatiblen alphanumerischen Displays ist. Sie ist über ein Header-File leicht modifizierbar.
Das Schreiben von Daten auf dem Display funktioniert mit den bereits oben angeführten Befehlen. RS muss auf H-Pegel sein, R/W auf Low. Nun können die Daten wie oben beschrieben Nibble für Nibble an das Display übertragen werden. Für die genaue Funktionsweise und Reihenfolge der Prozeduren sei auf die in der Bibliothek enthaltenen Funktionen verwiesen. Diese sollten mit obigen Erklärung relativ leicht zu verstehen sein.