LC-Display Ansteuerung

Dieses Projekt beschäftigt sich mit der Ansteuerung eines herkömmlichen LC-Display mittels eines PIC-Microcontrollers. Der verwendete Microcontroller ist ein PIC16F877.
In diesem Projekt wird eine LCD Anzeige mit einem HD44780 Controller verwendet. Dieser Typ von Controller hat sich auf dem Markt durchgesetzt und wird in den meissten LCD Anzeigen eingebaut. Ein weiterer häufig verwendeter Controller ist der KS0066. Dieser ist aber etwas schwieriger zu initialisieren. Ungeachtet der Controller der LCD Anzeigen, haben alle Module die gleiche Pinbelegung:


Dabei ist allein die Hintergrundbeleuchtung optional. Es gibt auch LCD's mit Hintergrundbeleuchtung, die aber nur 14 Pins haben. Dann ist die Hintergrundbeleuchtung schon auf dem Modul zur Versorgungsspannung kontaktiert. Mit dem Signal RS wird dem Modul mitgeteilt, ob Instruktionen (RS=0) oder Daten (RS=1) übertragen werden.

Die Anzeigen können je nach Typ bis zu 4 Zeilen haben, welche jeweils 8,12,16,20 oder 40 Zeichen beinhalten können. Die Zeichen werden auf Punktmatrizen von 5x8 Pixeln dargestellt. Mein LCD-Modul besitzt 2 Zeilen mit jeweils 16 Zeichen. Da unterschiedliche Anzeigegrössen existieren, gibt es bei einigen Displays eine andere Zeilenadressierung:


Das Distplay lässt sich auf 2 Arten anzeuern. Mit einem 8-Bist oder einem 4-Bit Datenbus (Der Modus wird bei der Initialisierung des Displays festgelegt). Bei der 4-Bit Variante werden die Leitungn DB4 bis DB7 benutzt und die restlichen Datenleitungen mit GND verbunden. So werden insgesamt nur 7 Leitungen benötigt um das Display anzusteuern.
Bei der 4-Bit Datenübertragung werden die Daten bei der fallenden Flanke des Enable-Pins in 2 Takten übertragen. Mit dem ersten Takt des Enable-Pins werden die ersten 4 Bits (7-4) übertragen, danach die Bits 3-0. Die 8-Bit-Variante braucht nur einen Takt. Alle Komandos für das Display bleiben bei beiden Varianten gleich.


Der Befehlssatz des HD44780-Controllers:





Benutzerdefinierte Zeichen

Es können bis zu acht benutzerdefinierte Zeichen erstellt werden, die die Zeichencodes 0...7 erhalten. DIe zugehörigen Bitmuster werden ins CG-RAM geschrieben. Zeichen 0 steht an Adresse 0...7, Zeichen 1 an 8...15, etc. Jedes Zeichen besteht aus acht Bytes entsprechend den acht Pixelzeilen eines Zeichens. Die unterste Zeile ist für den Cursor reserviert, kann aber auch verwendet werden. Die oberste Piselzeile wird durch das erste Byte definiert, die zweitoberste durch das zweite Byte, usw. Die fünf nierwertigstern Bits jedes Bytes entsprechen den fürnf horizontalen Pixeln jedr Zeile.


Zeichensatz des HD44780 Controllers



Initialisiertung des Displays

Bei der Initialisiertung des LCD werden die Datenbusbreite, der Zeichensatz und die Anzahl der Zeilen definiert. Diese Eigenschaften des Displays können nur in der Initialisierungsphase gesetzt werden. Die Initialisierung muss immer als erstes ausgeführt werden. Die Initialisierung darf aber erst 15ms nach dem Anlegen der Betriebsspannung beginnen, da der Controller solange für den internen Reset-Vorgang benötigt.

Folgende Funktionen müssen in dieser Reihenfolge ausgeführt werden:

  1. Display löschen
  2. Funktion
    DL=0: 4-Bit Datenbusbreite
    N=1: 2-Zeilen Display
    F=0: 5x7 Zeichenformat
  3. Display On/Off
    D=0: Display aus
    C=0: Cursor aus
    B=0: Blinkfunktion aus
  4. Entry Mode Set
    I/D=1: Inkrementiert DD-RAM nach dem Lese-/Schreibvorgang
    S=0: Kein Schieben des Displayinhalts
  5. Schreiben des DD-RAM
Wurde das Display erfolgreich initialisiet, können Daten in das DD-RAM geschrieben werden.


Der Schaltplan



Das LCD-Modul

Das hier verwendete LC-Display ist ein LM086ALN von Hitachi. Der eingebaute Controller ist ein HD44780 und das Display hat zwei Linien mit jeweils 16 Zeichen. Diese Version ist mit Backlight ausgestattet. Die Spannungsversorgung für das Backlight wird nicht über Pin 15 und 16 angeschlossen, wie sonst üblich, sondern ist direkt auf den Modul mit Vss und Vdd verbunden. Ansonsten ist die Pinbelegung genau wie oben beschrieben.





Folgendes Bild zeigt mein kleines LCD-Experimentierboard. Das LCD-Modul wird auf eine Steckleiste gesteckt und ist somit austauschbar. Mit dem Poti lässt sich der Kontrast am LC-Display einstellen und eine Status-LED zeigt die Betriebsspannung an. Die drei Taster sind für den Betrieb des Displays natürlich nicht notwendig.




Der Programmcode

Im folgenden Programmcode sind verschiedenste Funktionen des LC-Display implementiert, die für den Betrieb notwendig sind. Das File wird als "includefile" im Hauptprogramm eingebunden. Somit können diese Funktionen überall verwendet werden, ohne den Programmcode jedesmal hinzuschreiben.


//  lcd.c
//
//  lcd_init()   LCD initialization. Must be called before any other function.
//  lcd_putc(c)  Will display a character on LCD
//  \f  clear display
//  \n  second line
//  \b  move back one position
//  lcd_gotoxy(x,y) Set position on LCD (upper left is 1,1)

//  Defined PIN connection:
//
//     D0  RS
//     D1  R/W
//     D2  E
//     D4  D4
//     D5  D5
//     D6  D6
//     D7  D7

struct lcd_pin_map
{
        boolean rs;
        boolean rw;
        boolean enable;
        boolean unused;
        int data : 4;
} lcd;

#byte lcd = 0xF83
#byte lcd = 8                 //Port D: Address 8)
#define lcd_type 2           // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40    // RAM address second line

//LCD start up
BYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};

struct lcd_pin_map const lcd_write = {0,0,0,0,0}; // write mode
struct lcd_pin_map const lcd_read = {0,0,0,0,15}; // read mode

BYTE lcd_read_byte()
{
      byte low, high;

      set_tris_d(lcd_read);
      lcd.rw = 1;
      delay_cycles(1);
      lcd.enable = 1;
      delay_cycles(1);
      high = lcd.data;
      lcd.enable = 0;
      delay_cycles(1);
      lcd.enable = 1;
      delay_us(1);
      low = lcd.data;
      lcd.enable = 0;
      set_tris_d(lcd_write);
      return( (high<<4) | low);
}

void lcd_send_nibble(byte n)
{
      lcd.data = n;
      delay_cycles(1);
      lcd.enable = 1;
      delay_us(2);
      lcd.enable = 0;
}

void lcd_send_byte(byte address, byte n)
{
      lcd.rs = 0;

      while ( bit_test(lcd_read_byte(),7) ) ;

      lcd.rs = address;
      delay_cycles(1);
      lcd.rw = 0;
      delay_cycles(1);
      lcd.enable = 0;
      lcd_send_nibble(n >> 4);
      lcd_send_nibble(n & 0xF);
}

void lcd_init()
{
    byte i;

    set_tris_d(lcd_write);
    lcd.rs = 0;
    lcd.rw = 0;
    lcd.enable = 0;
    delay_ms(15);

    for(i=1;i<=3;++i)
    {
       lcd_send_nibble(3);
       delay_ms(5);
    }
    lcd_send_nibble(2);

    for(i=0;i<=3;++i)
    {
       lcd_send_byte(0,LCD_INIT_STRING[i]);
    }
}

void lcd_gotoxy(byte x, byte y)
{
    byte address;

    if(y!=1)
    {
        address=lcd_line_two;
    }
    else
    {
        address=0;
    }
    address=adress+x-1;
    lcd_send_byte(0,0x80|address);
}

void lcd_putc(char c)
{
    switch (c)
    {
        case '\f':  lcd_send_byte(0,1);
                    delay_ms(2);            break;
        case '\n':  lcd_gotoxy(1,2);        break;
        case '\b':  lcd_send_byte(0,0x10);  break;
        default:    lcd_send_byte(1,c);     break;
    }


LCD Testprogramm

//LCD, Testprogramm
//Oliver Knecht

#include <16F877.H>
#use delay(clock = 4000000)
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP

#include "lcd.c"

void main()
{
   int p=0;

   delay_ms(500);
   lcd_init();
   delay_ms(500);

   while(1)
   {
      lcd_putc("\fHello World\n");
      lcd_putc("1.Test");

      for(p;p<10;p++)
      {
        lcd_putc(".")
      }

      delay_ms(3000);
      lcd_putc("\fLC-Display\n");
      lcd_putc("LM086ALN");
      delay_ms(3000);
      lcd_putc("\fHD44780A\n");
      lcd_putc("Controller");
      delay_ms(3000);
      lcd_putc("\fPIC 16F877-20/P\n");
      lcd_putc("4 MHz");
      delay_ms(3000);
      lcd_putc("\f");
      delay_ms(3000);
   }
}




Folgendes kleine Video zeigt das Ergebnis des Programms:



Impressum PHP Counter Sie sind Besucher: 517134