Bascom-AVR

Kleiner Bascom AVR Kurs -
LCD - Liquid Crystal Display - Textanzeige

Hallo!

In diesem Beitrag möchte ich darüber berichten wie man LCDs (Liquid Crystal Displays) mit Bascom ansteuert. Damit meine ich die ein- oder mehrzeiligen Textdisplays (alphanumerisch), nicht die Grafikdisplays. Die Grafikdisplays sind etwas schwieriger zu handhaben und sind vielleicht mal Thema eines anderen Beitrags.

Gleich vorab. Eigentlich ist es sehr einfach. Man sucht in der Bascom-Hilfe nach "LCD", liest sich alles durch, schließt das LCD an und fertig. Alles was ich noch bieten kann, ist ein kleiner Bericht der aufzeigt wie ich es gemacht habe und vielleicht noch eine kleine Auflistung der wichtigsten LCD-Befehle.

Viele Text-LCDs verwenden den LCD-Controller HD44780. Diese und alle kompatiblen Displays werden von Bascom voll unterstützt. Solche LCDs bekommt man ziemlich günstig bei Pollin. Wenn man dort im Shop nach "Industriestandard" sucht, dann findet man ein paar wirklich günstige LCDs, die mit Bascom funktionieren sollten.

Gängige LCD-Controller:

  • HD44780/HDD44780 (Industriestandard, kein Problem mit Bascom)
  • SED1278 (kompatibel zum HD44780, kein Problem mit Bascom)
  • KS0073 (teilweise kompatibel zum HD44780, kein Problem mit Bascom)
  • LC7985 (kompatibel zum HD44780)
  • M50530 (???)
  • SED1531 (???)

Es gibt zwei Möglichkeiten wie Bascom ein LCD ansteuert. Entweder über einen Datenbus (BUS-Modus) oder über auswählbare Pins eines Ports (PORT-Modus). Der BUS-Modus ist nur dann möglich, wenn man z.B. auch einen externen Speicher an den AVR-µC anhängen kann (Bus Interface). Dann teilen sich der externe Speicherbaustein und das LCD die Leitungen. Der ATmega8 hat keinen solchen Bus. Für uns ist nur der PORT-Modus interessant. Im PORT-Modus können wir selber bestimmen an welchen Pins das LCD hängt. Dafür braucht dieser Modus aber auch etwas mehr Programmspeicher im µC.

Die Daten können an das LCD über 8 oder 4 µC-Pins übermittelt werden (8-Bit Modus bzw. 4-Bit Modus). Der 8-Bit Modus ist ein wenig schneller. Dafür werden im 4-Bit Modus nicht so viele µC-Pins belegt.

Die LCDs mit HD44780-Controller stellen normalerweise diese Anschlüsse bereit:

01 -- GND (VSS)
02 -- 5 V (VCC oder VDD)
03 -- Kontrast (VO oder VEE)
04 -- RS (Register Select)
05 -- R/W (Read/Write)
06 -- E (Enable)
07 -- D0 (Datenbit 0, im 4-Bit Modus nach GND schalten)
08 -- D1 (Datenbit 1, im 4-Bit Modus nach GND schalten)
09 -- D2 (Datenbit 2, im 4-Bit Modus nach GND schalten)
10 -- D3 (Datenbit 3, im 4-Bit Modus nach GND schalten)
11 -- D4 (Datenbit 4)
12 -- D5 (Datenbit 5)
13 -- D6 (Datenbit 6)
14 -- D7 (Datenbit 7)
15 -- evt. Hintergrundbeleuchtung, siehe Datenblatt
16 -- evt. Hintergrundbeleuchtung, siehe Datenblatt

Anschluss an den ATmega8:

LCD-Pin 1  (VSS)      -->  GND
LCD-Pin 2  (VDD)      -->  5 V Versorgungsspannung
LCD-Pin 3  (Kontrast) -->  z.B. Poti/Trimmer für Kontrasteinstellung
LCD-Pin 4  (RS)       -->  an einen Pin des ATmega8 (z.B. PORTD.2)
LCD-Pin 5  (R/W)      -->  GND
LCD-Pin 6  (E)        -->  an einen Pin des ATmega8 (z.B. PORTD.3)
LCD-Pin 7  (D0)       -->  im 4-Bit Modus nach GND schalten
LCD-Pin 8  (D1)       -->  im 4-Bit Modus nach GND schalten
LCD-Pin 9  (D2)       -->  im 4-Bit Modus nach GND schalten
LCD-Pin 10 (D3)       -->  im 4-Bit Modus nach GND schalten
LCD-Pin 11 (D4)       -->  an einen Pin des ATmega8 (z.B. PORTD.4)
LCD-Pin 12 (D5)       -->  an einen Pin des ATmega8 (z.B. PORTD.5)
LCD-Pin 13 (D6)       -->  an einen Pin des ATmega8 (z.B. PORTD.6)
LCD-Pin 14 (D7)       -->  an einen Pin des ATmega8 (z.B. PORTD.7)
LCD-Pin 15 (HG-Bel.)  -->  siehe Datenblatt
LCD-Pin 16 (HG-Bel.)  -->  siehe Datenblatt

Leider gibt es große Unterschiede zwischen den Displays, was die Temperaturabhängigkeit betrifft. LCDs für Normaltemperaturen arbeiten meist mit einer positiven Spannung am VO-Pin (Kontrast). Und Displays mit erweitertem Temperaturbereich oder große Displays, brauchen meist eine negative Spannung am VO-Pin. Leider findet man gerade bei Billig-LCDs erst beim Anschließen heraus, mit welcher Spannung der VO-Pin versorgt werden muss.

Ziemlich gute Informationen bekommt man unter http://www.sprut.de/electronic/lcd/index.htm. Also wenn dein Display nicht so funktioniert wie es funktionieren sollte, dann lohnt es sich, dort mal vorbei zu schauen und sich geballtes Wissen über die LCDs rein zu ziehen. Und zum Erstellen der evt. benötigten negativen Spannung, hat sprut.de auch etwas zu sagen: http://www.sprut.de/electronic/switch/minus.html

Das Problem mit der negativen Spannung umgeht man am einfachsten, mit einem neuen LCD. ;-) Für meine ersten Tests verwende ich das bei Pollin gekaufte "Powertip PC 1602-F". Leider ist Pollin nicht gerade verlässlich, was die Verfügbarkeit der Produkte betrifft. Es kann also leicht sein, dass dieses LCD nicht erhältlich ist wenn du bei Pollin danach suchst.

lcd_16x2_mittel.jpg lcd_atmega8_v13.gif

Die normalen LCD-Routinen von Bascom nutzen den R/W-Pin nicht. Es wird einfach lange genug gewartet, so dass Bascom das LCD nicht auslesen muss. Die Mindestwartezeiten sind im HD44780-Datenblatt aufgeführt. Das funktioniert ziemlich gut.

Der R/W-Pin muss nur dann beschaltet werden, wenn man in Bascom die LCD-Routinen einer Zusatz-Library, wie z.B. die LCD4BUSY-Library, nutzt. Das bringt's aber nur, wenn das LCD sehr schnell reagieren soll. Z.B. wenn sich die Anzeige nicht nur alle Sekunden, sondern im Millisekundenbereich ändern soll. Dann könnte es auch sehr langsame LCDs geben, die sich nicht an das ausgemachte Timing halten. Dann kann man den R/W-Pin in Verbindung mit der LCD4BUSY-Library ebenfalls nutzen.

Aber im Normalbetrieb und so lange es keine Probleme damit gibt, ist es nicht notwendig den R/W-Pin an den µC anzuschließen. Zumindest nicht, wenn man Bascom nutzt.

Die Ansteuerung eines LCD läuft unter Bascom ähnlich einfach wie die Ausgabe von Text mit dem Befehl PRINT. Statt mit PRINT an die UART, schickt man den Text mit dem Befehl LCD an das Display. Zusätzlich gibt es noch ein paar Befehle um den Cursor auf dem Display zu positionieren und das Display zu löschen. Aber viel mehr ist nicht dahinter. Das Schwierigste an der Sache ist, das Display richtig anzuschließen und in Bascom richtig zu konfigurieren.

Konfiguration

Zum Konfigurieren des LCD stellt Bascom ein paar Befehle zur Verfügung. Da für uns nur der PORT-Modus interessant ist, gehe ich nicht näher auf die Befehle für den BUS-Modus ein. Wenn man nicht toll herumkonfiguriert, dann nimmt Bascom an, dass wir das LCD im 4-Bit PORT-Modus ansprechen möchten.

CONFIG LCDPIN

Mit diesem Befehl wird Bascom mitgeteilt, welche Pins zur Ansteuerung des LCDs verwendet werden. Das würde für den oben gezeigten Schaltplan so aussehen:

Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , _
   Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2

Die Hilfe zu diesem Befehl findet man hier: http://avrhelp.mcselec.com/index.html?config_lcdpin.htm

CONFIG LCD

Damit gibt man den Typ des Displays an. Gemeint ist die Anzahl an Zeilen und Spalten. Mögliche Einstellungen sind:

  • 16 * 1, 16 * 1a, 16 * 2 (Standard), 16 * 4
  • 20 * 2, 20 * 4, 20 * 4A
  • 40 * 4

Weiters kann man mit diesem Befehl auch die Verwendung eines anderen Chipsatzes einstellen. Neben dem Standard (HD44780) kann man noch zwischen "KS077" und "DOGM" wählen. Nähere Infos stehen in der Hilfe zu diesem Befehl.

Beispiel:

Config Lcd = 16 * 2

Die Hilfe zu diesem Befehl findet man hier: http://avrhelp.mcselec.com/index.html?config_lcd.htm

Befehle

Die Anzeige des LCD bestimmen hauptsächlich die vier Befehle CURSOR, CLS, LOCATE und LCD. Es gibt noch weitere LCD-Befehle wie z.B. HOME, SHIFTLCD, SHIFTCURSOR, DISPLAY und INITLCD. Nähere Infos darüber findest du in der Bascom-Hilfe. Weiters sollte man wissen, dass die Ausgabe auf ein LCD ziemlich langsam ist und deshalb der Befehl LCD nicht in einem Interrupt-Handler eingesetzt werden sollte.

CURSOR

Mit diesem Befehl stellt man das Verhalten des Cursors ein. Der Cursor ist bei LCDs meist ein Unterstrich. Diesen kann man ein-/ausschalten und blinken lassen.

Beispiel:

CURSOR OFF
CURSOR ON BLINK

Die Hilfe zu diesem Befehl findet man hier: http://avrhelp.mcselec.com/index.html?cursor.htm

CLS

CLS löscht das Display und setzt den Cursor in die linke, obere Ecke.

Die Hilfe zu diesem Befehl findet man hier: http://avrhelp.mcselec.com/index.html?cls.htm

LOCATE

LOCATE setzt den Cursor in die angegebene Zeile und Spalte.

Beispiel:

LOCATE 1, 1 ' Zeile 1 Spalte 1
LOCATE 2, 10 ' Zeile 2 Spalte 10

Statt LOCATE 1, 1 könnte man auch den Befehl HOME verwenden.

Die Hilfe zu diesem Befehl findet man hier: http://avrhelp.mcselec.com/index.html?locate.htm

INITLCD

Dieser Befehl initialisiert das Display. INITLCD braucht man im Normalfall nicht, da Bascom das Display automatisch beim Start initialisiert. Aber INITLCD bietet sich an, um zwischendurch das Display zurück zu setzen, falls etwas (z.B. ein Relais) die Displayausgabe gestört hat. Das Initialisieren dauert ein wenig und sieht manchmal auch nicht besonders gut aus. Deshalb sollte man es nicht übertreiben und das Display nur nur im Notfall alle paar Minuten und im Normalfall nur alle paar Stunden neu initialisieren. Wie oft du INITLCD wirklich einsetzt, musst du natürlich selber entscheiden. Wenn Störungen öfter auftreten, dann solltest du dir vielleicht lieber Gedanken über eine bessere Entstörung der Schaltung machen.

Die Hilfe zu diesem Befehl findet man hier: http://avrhelp.mcselec.com/index.html?initlcd.htm

LCD

Mit diesem Befehl schreibt man auf das Display. LCD verhält sich sehr ähnlich dem PRINT-Befehl und kann meist genau so eingesetzt werden. Statt mit PRINT auf die UART, schreibt man mit LCD auf das Display.

Beispiel:

CLS
LCD "Zeile 1"
LOCATE 2, 1
LCD "Zeile 2!

Die Hilfe zu diesem Befehl findet man hier: http://avrhelp.mcselec.com/index.html?lcd_2.htm

Beispiele

Einfaches "Hallo Welt"-Beispiel

$regfile = "m8def.dat"
$crystal = 8000000
$hwstack = 100
$swstack = 100
$framesize = 100


Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , _
   Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2
Config Lcd = 16 * 2


Cls
Locate 1 , 1
Lcd "Hallo Welt"


End
lcd_hallo_welt_1.jpg

"Hallo Welt"-Beispiel mit Zähler

Die Erklärungen stehen im Quellcode.

$regfile = "m8def.dat"
$crystal = 8000000
$hwstack = 100
$swstack = 100
$framesize = 100


Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , _
   Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2
Config Lcd = 16 * 2
Cursor Off

Dim Initcounter As Byte
Dim Bt As Byte
Dim S As String * 2


Do
   For Initcounter = 1 To 36
      'LCD löschen
      Cls

      'Haupttext der ersten Zeile anzeigen
      Locate 1 , 1
      Lcd "Hallo Welt...."

      'Haupttext der zweiten Zeile anzeigen
      Locate 2 , 1
      Lcd "Servus LCD...."

      'Jede Sekunde um 1 hochzählen und neuen Wert anzeigen
      For Bt = 1 To 99
         'Neuen Wert in einen Text umwandeln
         S = Str(bt)
         S = Format(s , "00")

         'Neuen Wert in der ersten Zeile ab Spalte 15 anzeigen
         Locate 1 , 15
         Lcd S

         'Neuen Wert in der zweiten Zeile ab Spalte 15 anzeigen
         Locate 2 , 15
         Lcd S

         'Eine Sekunde warten
         Wait 1
      Next Bt

      'Das LCD nach ca. einer Stunden neu initialisieren
      If Initcounter = 36 Then
         Initlcd
      End If
   Next Initcounter
Loop

End
lcd_hallo_welt_2.jpg

Der Haupttext wird jede Minute neu geschrieben. Die Zahl wird jede Sekunde neu geschrieben. Es wird also nicht jede Sekunde alles neu geschrieben, sondern nur der sich ändernde Bereich (die Zahl). Würde man jede Sekunde das ganze Display löschen und neu beschreiben, dann würde die Anzeige unangenehm flackern.