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


von Jürgen (Gast)


Angehängte Dateien:

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

von max power (Gast)


Lesenswert?

> Anschlußplan siehe Anhang.
sehe ich nicht.

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

hilfe ich bin blind!

von Jürgen (Gast)


Angehängte Dateien:

Lesenswert?

Komisch, ich hatte doch alles zusammen gepackt.
Nächster versuch.

von Jürgen (Gast)


Angehängte Dateien:

Lesenswert?

hat wieder nicht funktioniert.
Probier ichs anderst.

von Jürgen (Gast)


Lesenswert?

Keiner eine Idee?

von max power (Gast)


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-Tutorial:_LCD#Initialisierung_des_Displays

von Jürgen (Gast)


Angehängte Dateien:

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:
1
warte(500);    //Warten bis Display hochgefahren ist  
2
RS_L;
3
RW_L;
4
EN_S;
5
DISPLAY_PORT = 0b00111000;  //Aus Datenblatt
6
  asm("nop");        //Ein Zyklus Pause. Bei  einem Takt von 4Mhz
7
  asm("nop");        //250ns. x2 500ns
8
EN_L;
9
RS_S;
10
RW_S;
11
  warte(1);
12
13
RS_L;
14
RW_L;
15
EN_S;
16
DISPLAY_PORT = 0b00001111; //Aus Datenblatt
17
  asm("nop");
18
  asm("nop");
19
EN_L;
20
RS_S;
21
RW_S;
22
  warte(1);
23
24
RS_L;
25
RW_L;
26
EN_S;
27
DISPLAY_PORT = 0b00000001; //Aus Datenblatt
28
  asm("nop");
29
  asm("nop");
30
EN_L;
31
RS_S;
32
RW_S;
33
  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?

von Rolf D. (rolfdegen)


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=23657#post23657
1
//----------------------------------------------------------------------
2
// Titel        : "2-Draht LC-Display" für den ATmega88/168
3
//----------------------------------------------------------------------
4
// Funktion     : Ansteuerung für 2-Draht-LC-Display
5
//              : (kompatiebel zum CC2-Interface)
6
// Schaltung    : "PC-Lüftersteuerung"
7
//----------------------------------------------------------------------
8
// Prozessor    : ATmega88/168
9
// Takt         : 16.0000 MHz
10
// Sprache      : C
11
// C-Compiler   : WinAVR - 20080610 (programmiert in AVR-Studio) 
12
//              : (http://sourceforge.net/projects/winavr/)
13
// Datum        : 10.10.2008
14
// Version      : 1.0   R.Degen
15
//----------------------------------------------------------------------
16
#define     DF_CPU 16000000   // Taktfrequenz ATmega
17
#include    <avr\io.h>        // AVR Register und Konstantendefinitionen
18
#include    <util\delay.h>    // Bibliothek mit Warteroutinen
19
//----------------------------------------------------------------------
20
21
// Pinbelegung für das LCD, an verwendete Pins anpassen
22
 
23
#define lcd_port      PORTC         // Port für LCD
24
#define lcd_ddr       DDRC          // Port-Richtung
25
#define lcd_clk       PC0           // Clk-Leitung an Schieberegister 74HCT164
26
#define lcd_data      PC1           // Data-Leitung an Schieberegister u. Enable-Signal LCD 
27
28
//-----------------------------------------------
29
//  Funktions-Routinen
30
//-----------------------------------------------
31
32
// Clk-Impuls für Schieberegister erzeugen
33
void lcd_clk_impuls()
34
    {
35
     _delay_us(5);                  // 5µsec warten
36
     lcd_port |= (1<<lcd_clk);      // Clk-Pin auf 1
37
     _delay_us(10);                 // 10µsec warten
38
     lcd_port &= ~(1<<lcd_clk);     // Clk-Pin auf 0
39
     _delay_us(5);                  // 5µsec warten
40
    }
41
42
// Ausgänge des Schieberegisters auf 0 setzen
43
void lcd_clr_schieberegister()
44
    {
45
     lcd_port &= ~(1<<lcd_data);    // Data-Leitung am Eingang des Schieberegisters auf 0
46
     uint8_t i;                     // Bit-Zähler (8Bit Integer ohne Vorzeichen)
47
     for (i=0;i<7;i++)              // Zählerschleife
48
      {
49
       lcd_clk_impuls();            // 7x Clk-Impulse am Schieberegister erzeugen
50
      }                             // Zählerschleife beenden?
51
    }
52
53
// Enabled-Impuls am LC-Display erzeugen und danach Schieberegister löschen
54
void lcd_enabled_impuls()
55
    {
56
      _delay_us(5);                 // 5µsec warten
57
      lcd_port |= (1<<lcd_data);    // Data-Leitung auf 1
58
      _delay_us(10);                // 10µsec warten
59
      lcd_clr_schieberegister();    // Schieberegister löschen
60
      _delay_us(5);
61
     }
62
     
63
// sende Hi-Nibble an LC-Display (LCD-init.Mode)
64
void lcd_send_hi_nibble(uint8_t nibble)
65
    { 
66
      lcd_port |= (1<<lcd_data);    // Lcd-Enabled-Bit auf 1
67
      lcd_clk_impuls();             // Bit ins Schieberegister übertragen
68
      lcd_port &=~ (1<<lcd_data);   // Lcd-RS-Bit auf 0
69
      lcd_clk_impuls();             // Bit ins Schieberegister übertragen
70
      uint8_t i;                    // Bit-Zähler (8Bit Integer ohne Vorzeichen)
71
      for (i=0;i<4;i++)             // Zählerschleife (4 mal)
72
       {
73
       if (nibble & 0x80)           // Bit7 in nibble prüfen (Bits in nibble mit 0b10000000 maskieren) 
74
        {
75
        lcd_port |= (1<<lcd_data);  // wenn Bit7=1 dann Data-Leitung auf 1
76
        }
77
        else
78
        {
79
         lcd_port &=~(1<<lcd_data); // wenn Bit7=0 dann Data-Leitung auf 0
80
        }
81
         lcd_clk_impuls();          // Bit ins Schieberegister übertragen
82
         nibble = nibble<<1;        // Bits in nibble 1x nach links routieren
83
       }                            // Zählerschleife beenden?
84
      lcd_port &= ~ (1<<lcd_data);  // erstes Bit im Schieberegister auf 0 setzen (unbenutzt)
85
      lcd_clk_impuls();             // Bit ins Schieberegister übertragen
86
      lcd_enabled_impuls();         // Lcd-Enabled Impuls erzeugen
87
    }
88
    
89
// sende ein Byte ans LC-Display
90
// wenn cmd=0 ein LCD-Kommandobyte senden / wenn cmd=1 ein LCD-Datenbyte senden)
91
// in data befindet das Kommando- oder Datenbyte
92
void lcd_send_data(uint8_t cmd, uint8_t data)
93
    {
94
      uint8_t i1;                   // Zähler (8Bit Integer ohne Vorzeichen)
95
      for (i1=0;i1<2;i1++)          // 1.Zählerschleife (2 mal) um high- und low-nibble zu senden
96
      {
97
      lcd_port |= (1<<lcd_data);    // Lcd-Enabled-Bit auf 1
98
      lcd_clk_impuls();             // Bit ins Schieberegister übertragen
99
      if (cmd==0)                   // LCD-Kommandobyte ?
100
        {
101
         lcd_port &=~(1<<lcd_data); // Lcd-RS-Bit auf 0
102
        }
103
      else
104
        {
105
         lcd_port |= (1<<lcd_data); // Lcd-RS-Bit auf 1
106
        }
107
      lcd_clk_impuls();             // Bit ins Schieberegister übertragen
108
      uint8_t i2;                   // Bit-Zähler (8Bit Integer ohne Vorzeichen)
109
      for (i2=0;i2<4;i2++)          // 2.Zählerschleife (4 mal) für ein nibble
110
       {
111
        if (data & 0x80)            // Bit7 in data prüfen (Bits in data mit 0b10000000 maskieren) 
112
         {
113
          lcd_port |= (1<<lcd_data);// wenn Bit7=1 dann Data-Leitung auf 1
114
         }
115
        else
116
         {
117
          lcd_port &=~(1<<lcd_data);// wenn Bit7=0 dann Data-Leitung auf 0
118
         }
119
        lcd_clk_impuls();           // Bit ins Schieberegister übertragen
120
        data = data<<1;             // Bits in Data 1x nach links routieren
121
       }                            // 2.Zählerschleife beenden?
122
      lcd_port &= ~ (1<<lcd_data);  // erstes Bit im Schieberegister auf 0 setzen (unbenutzt)
123
      lcd_clk_impuls();             // Bit ins Schieberegister übertragen
124
      lcd_enabled_impuls();         // Lcd-Enabled Impuls erzeugen
125
      }                             // 1.Zählerschleife beenden ?
126
      _delay_ms(5);                 // warte bis LCD bereit für nächsten Datenempfang
127
      }
128
          
129
// Init. LC-Display:4-Bit Interface,5x7 Dots,2 Rows,Cursor on,Line-Cursor on,Display on 
130
void lcd_init()
131
    {
132
     _delay_ms(100);                // 100ms warten bis LC-Display bereitnach Power on
133
     lcd_clr_schieberegister();     // Schieberegister löschen
134
     _delay_us(10);                 // 10us warten
135
// ab hier: LCD-Resetsequenz
136
     lcd_send_hi_nibble(0b00110000);// sende 1.Hi-Nibble an LC-Display
137
     _delay_ms(5);                  // 5ms warten bis LC-Display bereit
138
     lcd_send_hi_nibble(0b00110000);// sende 2.Hi-Nibble an LC-Display
139
     _delay_ms(5);                  // 5ms warten bis LC-Display bereit
140
     lcd_send_hi_nibble(0b00110000);// sende 3.Hi-Nibble an LC-Display
141
     _delay_ms(5);                  // 5ms warten bis LC-Display bereit
142
// LCD in 4Bit-Mode schalten
143
     lcd_send_hi_nibble(0b00100000);// sende Hi-Nibble an LC-Display
144
     _delay_ms(5);                  // 5ms warten bis LC-Display bereit
145
// ab hier ist LCD im 4-Bit Modus
146
// (Parameterliste: 1.Byte = cmd, 2.Byte = Data)
147
     lcd_send_data(0,0b00101000);   // LCD-Command 2 Zeilen, 5x8 Dots 
148
     lcd_send_data(0,0b00001000);   // LCD-Comand Display aus
149
     lcd_send_data(0,0b00000001);   // LCD-Comand Display löschen
150
     lcd_send_data(0,0b00000110);   // LCD-Comand Display Entrymode
151
     lcd_send_data(0,0b00001111);   // LCD-Comand Display ein
152
    }
153
154
//-----------------------------------------------------------------
155
// Hauptprogramm
156
//-----------------------------------------------------------------
157
158
int main (void)
159
     {
160
      lcd_ddr |= (1<<lcd_clk);      // Portleitung CLK (Clk-Schieberegister) auf Ausgang konfigurieren
161
      lcd_ddr |= (1<<lcd_data);     // Portleitung DATA (Data-Schieberegister) auf Ausgang konfigurieren
162
      lcd_port &=~(1<<lcd_clk);     // CLK auf 0 setzen
163
      lcd_port &=~(1<<lcd_data);    // DATA auf 0 setzen
164
      lcd_init();                   // init. LC-Display
165
      lcd_send_data(1,'H');         // Text senden
166
      lcd_send_data(1,'a');
167
      lcd_send_data(1,'l');
168
      lcd_send_data(1,'l');
169
      lcd_send_data(1,'o');
170
      lcd_send_data(1,' ');
171
      lcd_send_data(1,'C');
172
      lcd_send_data(1,'o');
173
      lcd_send_data(1,'m');
174
      lcd_send_data(1,'p');
175
      lcd_send_data(1,'u');
176
      lcd_send_data(1,'t');
177
      lcd_send_data(1,'e');
178
      lcd_send_data(1,'r');
179
      lcd_send_data(1,'C');
180
      lcd_send_data(1,'l');
181
      lcd_send_data(1,'u');
182
      lcd_send_data(1,'b');
183
      lcd_send_data(1,' ');
184
      lcd_send_data(1,'2');
185
     }

Gruß Rolf

von Hc Z. (mizch)


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?

von Rolf D. (rolfdegen)


Lesenswert?

Poti für den Kontrast mal verstellen.

von Jürgen (Gast)


Angehängte Dateien:

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.