www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Display LCD W164B-NLW an Atmega 8515


Autor: Jürgen (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Ich weis, das Thema wurde schon x mal besprochen.
Hab auch gestern und heut den ganzen Tag gesucht und probiert. Aber es 
funktioniert einfach nicht

Hab mir im Betreff stehendes Display bei Reichelt gekauft und möchte es 
mit einem Atmega 8515 betreiben. Anschlußplan siehe Anhang.

Mein Problem ist:
Ich bekomme keinen Buchstaben angezeigt.

Ich denke Initsalliesiert ist es richtig. Die zwei Balken sind immer hin 
weg.

Was mach ich falsch?

Danke für die Hilfe.

Jürgen

Autor: max power (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Anschlußplan siehe Anhang.
sehe ich nicht.

>Ich denke Initsalliesiert ist es richtig.
sehe ich auch nicht.

hilfe ich bin blind!

Autor: Jürgen (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Komisch, ich hatte doch alles zusammen gepackt.
Nächster versuch.

Autor: Jürgen (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
hat wieder nicht funktioniert.
Probier ichs anderst.

Autor: Jürgen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Keiner eine Idee?

Autor: max power (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>//Display initsialieseiern

>DISPLAY_COMANDO(0b00111000); //Aus Datenblatt
>DISPLAY_COMANDO(0b00001111);
>DISPLAY_COMANDO(0b00000001);
>DISPLAY_COMANDO(0b00000110);

erst nach der initalisierung kann man das busy flag abfragen.
während der initalisierung es muss anderweitig gewartet werden.

auch muss vorher erst mal 20 ms gewartet werden bevor initalisiert wird.

http://www.mikrocontroller.net/articles/AVR-Tutori...

Autor: Jürgen (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Einen schönnen guten Abend.

Ich komme nicht weiter. :-(

Habe mir das Datenblatt genauer angeschaut 
(http://www.lcd-module.de/pdf/doma/blueline-w.pdf) Und das Zeitdiagram 
analysiert(schreibt man glaub ich anderst. Aber egal:-) ). Jetzt habe 
ich folgenden Code geschrieben um das Display zu initialisieren:
warte(500);    //Warten bis Display hochgefahren ist  
RS_L;
RW_L;
EN_S;
DISPLAY_PORT = 0b00111000;  //Aus Datenblatt
  asm("nop");        //Ein Zyklus Pause. Bei  einem Takt von 4Mhz
  asm("nop");        //250ns. x2 500ns
EN_L;
RS_S;
RW_S;
  warte(1);

RS_L;
RW_L;
EN_S;
DISPLAY_PORT = 0b00001111; //Aus Datenblatt
  asm("nop");
  asm("nop");
EN_L;
RS_S;
RW_S;
  warte(1);

RS_L;
RW_L;
EN_S;
DISPLAY_PORT = 0b00000001; //Aus Datenblatt
  asm("nop");
  asm("nop");
EN_L;
RS_S;
RW_S;
  warte(1);

Wenn ich es richtig verstanden habe müsste jetzt der Cursor blinken und 
der rest ist leer.?

Die Balken gehen zwar weg, aber der Cursor blinkt nicht.
Was mach ich falsch?

Autor: Rolf Degen (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallöchen..

Kleine Anregung zur LC-Display Ansteuerung in 4Bit-Mode ohne 
Busy-Abfrage.
Schau dir mal die Funktion lcd_init() genauer an.
Das Komplette Projekt mit Schaltplan kann man sich hier anschaun: 
http://www.cczwei-forum.de/cc2/thread.php?postid=2...
//----------------------------------------------------------------------
// Titel        : "2-Draht LC-Display" für den ATmega88/168
//----------------------------------------------------------------------
// Funktion     : Ansteuerung für 2-Draht-LC-Display
//              : (kompatiebel zum CC2-Interface)
// Schaltung    : "PC-Lüftersteuerung"
//----------------------------------------------------------------------
// Prozessor    : ATmega88/168
// Takt         : 16.0000 MHz
// Sprache      : C
// C-Compiler   : WinAVR - 20080610 (programmiert in AVR-Studio) 
//              : (http://sourceforge.net/projects/winavr/)
// Datum        : 10.10.2008
// Version      : 1.0   R.Degen
//----------------------------------------------------------------------
#define     DF_CPU 16000000   // Taktfrequenz ATmega
#include    <avr\io.h>        // AVR Register und Konstantendefinitionen
#include    <util\delay.h>    // Bibliothek mit Warteroutinen
//----------------------------------------------------------------------

// Pinbelegung für das LCD, an verwendete Pins anpassen
 
#define lcd_port      PORTC         // Port für LCD
#define lcd_ddr       DDRC          // Port-Richtung
#define lcd_clk       PC0           // Clk-Leitung an Schieberegister 74HCT164
#define lcd_data      PC1           // Data-Leitung an Schieberegister u. Enable-Signal LCD 

//-----------------------------------------------
//  Funktions-Routinen
//-----------------------------------------------

// Clk-Impuls für Schieberegister erzeugen
void lcd_clk_impuls()
    {
     _delay_us(5);                  // 5µsec warten
     lcd_port |= (1<<lcd_clk);      // Clk-Pin auf 1
     _delay_us(10);                 // 10µsec warten
     lcd_port &= ~(1<<lcd_clk);     // Clk-Pin auf 0
     _delay_us(5);                  // 5µsec warten
    }

// Ausgänge des Schieberegisters auf 0 setzen
void lcd_clr_schieberegister()
    {
     lcd_port &= ~(1<<lcd_data);    // Data-Leitung am Eingang des Schieberegisters auf 0
     uint8_t i;                     // Bit-Zähler (8Bit Integer ohne Vorzeichen)
     for (i=0;i<7;i++)              // Zählerschleife
      {
       lcd_clk_impuls();            // 7x Clk-Impulse am Schieberegister erzeugen
      }                             // Zählerschleife beenden?
    }

// Enabled-Impuls am LC-Display erzeugen und danach Schieberegister löschen
void lcd_enabled_impuls()
    {
      _delay_us(5);                 // 5µsec warten
      lcd_port |= (1<<lcd_data);    // Data-Leitung auf 1
      _delay_us(10);                // 10µsec warten
      lcd_clr_schieberegister();    // Schieberegister löschen
      _delay_us(5);
     }
     
// sende Hi-Nibble an LC-Display (LCD-init.Mode)
void lcd_send_hi_nibble(uint8_t nibble)
    { 
      lcd_port |= (1<<lcd_data);    // Lcd-Enabled-Bit auf 1
      lcd_clk_impuls();             // Bit ins Schieberegister übertragen
      lcd_port &=~ (1<<lcd_data);   // Lcd-RS-Bit auf 0
      lcd_clk_impuls();             // Bit ins Schieberegister übertragen
      uint8_t i;                    // Bit-Zähler (8Bit Integer ohne Vorzeichen)
      for (i=0;i<4;i++)             // Zählerschleife (4 mal)
       {
       if (nibble & 0x80)           // Bit7 in nibble prüfen (Bits in nibble mit 0b10000000 maskieren) 
        {
        lcd_port |= (1<<lcd_data);  // wenn Bit7=1 dann Data-Leitung auf 1
        }
        else
        {
         lcd_port &=~(1<<lcd_data); // wenn Bit7=0 dann Data-Leitung auf 0
        }
         lcd_clk_impuls();          // Bit ins Schieberegister übertragen
         nibble = nibble<<1;        // Bits in nibble 1x nach links routieren
       }                            // Zählerschleife beenden?
      lcd_port &= ~ (1<<lcd_data);  // erstes Bit im Schieberegister auf 0 setzen (unbenutzt)
      lcd_clk_impuls();             // Bit ins Schieberegister übertragen
      lcd_enabled_impuls();         // Lcd-Enabled Impuls erzeugen
    }
    
// sende ein Byte ans LC-Display
// wenn cmd=0 ein LCD-Kommandobyte senden / wenn cmd=1 ein LCD-Datenbyte senden)
// in data befindet das Kommando- oder Datenbyte
void lcd_send_data(uint8_t cmd, uint8_t data)
    {
      uint8_t i1;                   // Zähler (8Bit Integer ohne Vorzeichen)
      for (i1=0;i1<2;i1++)          // 1.Zählerschleife (2 mal) um high- und low-nibble zu senden
      {
      lcd_port |= (1<<lcd_data);    // Lcd-Enabled-Bit auf 1
      lcd_clk_impuls();             // Bit ins Schieberegister übertragen
      if (cmd==0)                   // LCD-Kommandobyte ?
        {
         lcd_port &=~(1<<lcd_data); // Lcd-RS-Bit auf 0
        }
      else
        {
         lcd_port |= (1<<lcd_data); // Lcd-RS-Bit auf 1
        }
      lcd_clk_impuls();             // Bit ins Schieberegister übertragen
      uint8_t i2;                   // Bit-Zähler (8Bit Integer ohne Vorzeichen)
      for (i2=0;i2<4;i2++)          // 2.Zählerschleife (4 mal) für ein nibble
       {
        if (data & 0x80)            // Bit7 in data prüfen (Bits in data mit 0b10000000 maskieren) 
         {
          lcd_port |= (1<<lcd_data);// wenn Bit7=1 dann Data-Leitung auf 1
         }
        else
         {
          lcd_port &=~(1<<lcd_data);// wenn Bit7=0 dann Data-Leitung auf 0
         }
        lcd_clk_impuls();           // Bit ins Schieberegister übertragen
        data = data<<1;             // Bits in Data 1x nach links routieren
       }                            // 2.Zählerschleife beenden?
      lcd_port &= ~ (1<<lcd_data);  // erstes Bit im Schieberegister auf 0 setzen (unbenutzt)
      lcd_clk_impuls();             // Bit ins Schieberegister übertragen
      lcd_enabled_impuls();         // Lcd-Enabled Impuls erzeugen
      }                             // 1.Zählerschleife beenden ?
      _delay_ms(5);                 // warte bis LCD bereit für nächsten Datenempfang
      }
          
// Init. LC-Display:4-Bit Interface,5x7 Dots,2 Rows,Cursor on,Line-Cursor on,Display on 
void lcd_init()
    {
     _delay_ms(100);                // 100ms warten bis LC-Display bereitnach Power on
     lcd_clr_schieberegister();     // Schieberegister löschen
     _delay_us(10);                 // 10us warten
// ab hier: LCD-Resetsequenz
     lcd_send_hi_nibble(0b00110000);// sende 1.Hi-Nibble an LC-Display
     _delay_ms(5);                  // 5ms warten bis LC-Display bereit
     lcd_send_hi_nibble(0b00110000);// sende 2.Hi-Nibble an LC-Display
     _delay_ms(5);                  // 5ms warten bis LC-Display bereit
     lcd_send_hi_nibble(0b00110000);// sende 3.Hi-Nibble an LC-Display
     _delay_ms(5);                  // 5ms warten bis LC-Display bereit
// LCD in 4Bit-Mode schalten
     lcd_send_hi_nibble(0b00100000);// sende Hi-Nibble an LC-Display
     _delay_ms(5);                  // 5ms warten bis LC-Display bereit
// ab hier ist LCD im 4-Bit Modus
// (Parameterliste: 1.Byte = cmd, 2.Byte = Data)
     lcd_send_data(0,0b00101000);   // LCD-Command 2 Zeilen, 5x8 Dots 
     lcd_send_data(0,0b00001000);   // LCD-Comand Display aus
     lcd_send_data(0,0b00000001);   // LCD-Comand Display löschen
     lcd_send_data(0,0b00000110);   // LCD-Comand Display Entrymode
     lcd_send_data(0,0b00001111);   // LCD-Comand Display ein
    }

//-----------------------------------------------------------------
// Hauptprogramm
//-----------------------------------------------------------------

int main (void)
     {
      lcd_ddr |= (1<<lcd_clk);      // Portleitung CLK (Clk-Schieberegister) auf Ausgang konfigurieren
      lcd_ddr |= (1<<lcd_data);     // Portleitung DATA (Data-Schieberegister) auf Ausgang konfigurieren
      lcd_port &=~(1<<lcd_clk);     // CLK auf 0 setzen
      lcd_port &=~(1<<lcd_data);    // DATA auf 0 setzen
      lcd_init();                   // init. LC-Display
      lcd_send_data(1,'H');         // Text senden
      lcd_send_data(1,'a');
      lcd_send_data(1,'l');
      lcd_send_data(1,'l');
      lcd_send_data(1,'o');
      lcd_send_data(1,' ');
      lcd_send_data(1,'C');
      lcd_send_data(1,'o');
      lcd_send_data(1,'m');
      lcd_send_data(1,'p');
      lcd_send_data(1,'u');
      lcd_send_data(1,'t');
      lcd_send_data(1,'e');
      lcd_send_data(1,'r');
      lcd_send_data(1,'C');
      lcd_send_data(1,'l');
      lcd_send_data(1,'u');
      lcd_send_data(1,'b');
      lcd_send_data(1,' ');
      lcd_send_data(1,'2');
     }

Gruß Rolf

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dein „warte(1)“ kehrt sofort zurück.  Warum?  Schau' Dir einfach den 
Code mal an.  Der kleinste Wert, bei dem gewartet wird, ist 2.  Und da 
bekommst Du nicht 2ms, sondern irgendetwas Zufälliges zwischen 0 und 2 
ms.  Die Idee, Zeitschleifen über einen Timer zu machen, ist 
grundsätzlich gut, aber dann sollte die Timerauflösung deutlich über der 
benötigten Zeit liegen und nicht darunter.

Function warte() hat eine weitere Macke: das Beschreiben der Variable 
„timer“ (eine 2-Byte-Variable) ist nicht dagegen gesichert, dass nach 
dem Schreiben des ersten Bytes ein Interrupt kommt.

Auch ist es überflüssig, R/W und RS auf einen Ruhezustand jedesmal 
zurückzusetzen.  Das fordert keiner, tut allerdings auch niemand weh.

Weiter habe ich nicht geschaut.  Warum nimmst Du zum Start nicht eine 
der vielen Implementationen, die es im Netz gibt?

Autor: Rolf Degen (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Poti für den Kontrast mal verstellen.

Autor: Jürgen (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Guten Morgen und ein herzliches Dankeschön
für die ausführlichen Antworten.

Hc Zimmerer schrieb:
> Dein „warte(1)“ kehrt sofort zurück.  Warum?  Schau' Dir einfach den
> Code mal an.  Der kleinste Wert, bei dem gewartet wird, ist 2.  Und da
> bekommst Du nicht 2ms, sondern irgendetwas Zufälliges zwischen 0 und 2
> ms.

Du hast recht, ich kann ja nicht 1 durch 2 teilen. (Ich schon, aber µC 
nicht ;-))

Werde ich noch mal überarbeiten müßen.

Hc Zimmerer schrieb:
> aber dann sollte die Timerauflösung deutlich über der
> benötigten Zeit liegen und nicht darunter.

Denn Satzteil verstehe ich nicht. Wenn ich die Auflösung kleiner mach 
kann ich doch eine Variable hochzählen lassen bis zu der Zeit wo ichs 
brauch.
Wenn ich die Auflösung größßer mach muss ich ja wieder was abziehen. Wie 
geht das?

Hc Zimmerer schrieb:
> Function warte() hat eine weitere Macke: das Beschreiben der Variable
> „timer“ (eine 2-Byte-Variable) ist nicht dagegen gesichert, dass nach
> dem Schreiben des ersten Bytes ein Interrupt kommt.

Hab ich verstanden. Werd ich in der nächsten Version ändern.

Hc Zimmerer schrieb:
> Auch ist es überflüssig, R/W und RS auf einen Ruhezustand jedesmal
> zurückzusetzen.  Das fordert keiner, tut allerdings auch niemand weh.

Schau dir bitte den Anhang noch mal an. Habe dort die Stellen markirt 
warum ich es gemacht habe. So hab ichs halt verstanden.

Hc Zimmerer schrieb:
> Warum nimmst Du zum Start nicht eine
> der vielen Implementationen, die es im Netz gibt?

Aus einem einfachen Grund:
Kopieren kann jeder. Ich möchte aber einen Lerneffekt erreichen und 
versuche das zu verstehen was ich schreib. Wir haben in der Schule eine 
lcd.c und eine lcd.h bekommen und die einzelnen Befehle dazu. Punkt das 
wars. Es hat funktioniert aber keiner hat verstanden wie. Der Lehrer war 
ein Profie was C angeht und hat auch demmensprechend seine Programme 
geschrieben. Jetzt will ichs aber verstehen und schreibe somit selber.

Rolf Degen schrieb:
> Poti für den Kontrast mal verstellen.

Das verstehle ich bei jedem neuen versuch.

Noch malls Danke. Ihr habt mir viel weitergeholfen.
Werde weiter probieren.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.