Forum: Compiler & IDEs LCD-Tutorial.:)


von Warhammer (Gast)


Lesenswert?

hi, ich bin gerade dabei das LCD-Tutorial zu testen.

ich bekomme das Display im 4Bit Modus ans laufen, heisst der Cursor 
blinkt an der ersten stelle, aber mehr auch nicht.
1
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
2
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
3
//
4
// Die Pinbelegung ist über defines in lcd-routines.h einstellbar
5
 
6
#include <avr/io.h>
7
#include "lcd-routines.h"
8
#include <util/delay.h>
9
 
10
// sendet ein Datenbyte an das LCD
11
 
12
void lcd_data(unsigned char temp1)
13
{
14
   unsigned char temp2 = temp1;
15
 
16
   LCD_PORT |= (1<<LCD_RS);        // RS auf 1 setzen
17
 
18
   temp1 = temp1 >> 4;
19
   temp1 = temp1 & 0x0F;
20
   LCD_PORT &= 0xF0;
21
   LCD_PORT |= temp1;               // setzen
22
   lcd_enable();
23
 
24
   temp2 = temp2 & 0x0F;
25
   LCD_PORT &= 0xF0;
26
   LCD_PORT |= temp2;               // setzen
27
   lcd_enable();
28
   
29
   _delay_us(42);
30
}
31
 
32
// sendet einen Befehl an das LCD
33
 
34
void lcd_command(unsigned char temp1)
35
{
36
   unsigned char temp2 = temp1;
37
 
38
   LCD_PORT &= ~(1<<LCD_RS);        // RS auf 0 setzen
39
 
40
   temp1 = temp1 >> 4;              // oberes Nibble holen
41
   temp1 = temp1 & 0x0F;            // maskieren
42
   LCD_PORT &= 0xF0;
43
   LCD_PORT |= temp1;               // setzen
44
   lcd_enable();
45
 
46
   temp2 = temp2 & 0x0F;            // unteres Nibble holen und maskieren
47
   LCD_PORT &= 0xF0;
48
   LCD_PORT |= temp2;               // setzen
49
   lcd_enable();
50
   
51
   _delay_us(42);
52
}
53
 
54
// erzeugt den Enable-Puls
55
void lcd_enable(void)
56
{
57
   // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers einfügen
58
   // http://www.mikrocontroller.net/topic/81974#685882
59
   LCD_PORT |= 1<<LCD_EN;
60
    _delay_us(1);                   // kurze Pause
61
   // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern
62
   // http://www.mikrocontroller.net/topic/80900
63
   LCD_PORT &= ~1<<LCD_EN;
64
}
65
 
66
// Initialisierung: 
67
// Muss ganz am Anfang des Programms aufgerufen werden.
68
 
69
void lcd_init(void)
70
{
71
   LCD_DDR = LCD_DDR | 0x0F | (1<<LCD_RS) | 1<<LCD_EN ;   // Port auf Ausgang schalten
72
 
73
   // muss 3mal hintereinander gesendet werden zur Initialisierung
74
 
75
   _delay_ms(15);
76
   LCD_PORT &= 0xF0;
77
   LCD_PORT |= 0x03;            
78
   LCD_PORT &= ~(1<<LCD_RS);      // RS auf 0
79
   lcd_enable();
80
 
81
   _delay_ms(5);
82
   lcd_enable();
83
 
84
   _delay_ms(1);
85
   lcd_enable();
86
   _delay_ms(1);
87
 
88
   // 4 Bit Modus aktivieren 
89
   LCD_PORT &= 0xF0;
90
   LCD_PORT |= 0x02;
91
   lcd_enable();
92
   _delay_ms(1);
93
 
94
   // 4Bit / 2 Zeilen / 5x7
95
   lcd_command(0x28);
96
    
97
   // Display ein / Cursor aus / kein Blinken
98
   lcd_command(0x0C); 
99
 
100
   // inkrement / kein Scrollen
101
   lcd_command(0x06);
102
 
103
   lcd_clear();
104
}
105
 
106
// Sendet den Befehl zur Löschung des Displays
107
 
108
void lcd_clear(void)
109
{
110
   lcd_command(CLEAR_DISPLAY);
111
   _delay_ms(5);
112
}
113
 
114
// Sendet den Befehl: Cursor Home
115
 
116
void lcd_home(void)
117
{
118
   lcd_command(CURSOR_HOME);
119
   _delay_ms(5);
120
}
121
 
122
// setzt den Cursor in Zeile y (1..4) Spalte x (0..15)
123
 
124
void set_cursor(uint8_t x, uint8_t y)
125
{
126
  uint8_t tmp;
127
 
128
  switch (y) {
129
    case 1: tmp=0x80+0x00+x; break;    // 1. Zeile
130
    case 2: tmp=0x80+0x40+x; break;    // 2. Zeile
131
    case 3: tmp=0x80+0x10+x; break;    // 3. Zeile
132
    case 4: tmp=0x80+0x50+x; break;    // 4. Zeile
133
  }
134
  lcd_command(tmp);
135
}
136
 
137
// Schreibt einen String auf das LCD
138
 
139
void lcd_string(char *data)
140
{
141
    while(*data) {
142
        lcd_data(*data);
143
        data++;
144
    }
145
}
146
147
148
 
149
int main(void)
150
{
151
    lcd_init();
152
 
153
    lcd_data('T');
154
    lcd_data('e');
155
    lcd_data('s');
156
    lcd_data('t');
157
 
158
    set_cursor(0,2);
159
 
160
    lcd_string("Hello World!");
161
 
162
    while(1)
163
    {
164
    }
165
 
166
    return 0;
167
}

beim Compilen bekomme ich folgende Fehlermeldung:

"../lcd-routines.c:126: warning: 'tmp' may be used uninitialized in this 
function"

versteh ich nicht so ganz...

von Falk B. (falk)


Lesenswert?

@  Warhammer (Gast)

>ich bekomme das Display im 4Bit Modus ans laufen, heisst der Cursor
>blinkt an der ersten stelle, aber mehr auch nicht.

Was? Ausgabe von Zeichen nicht möglich?

Und du musst den Code des tutorials nicht in voller Länge hier posten, 
das ist sinnlos.

>beim Compilen bekomme ich folgende Fehlermeldung:

>"../lcd-routines.c:126: warning: 'tmp' may be used uninitialized in this
>function"

Kann man hier ignorien. Oder schreib einfach

uint8_t tmp=0;

Dann ist die Warnung weg.

MFG
Falk

von Warhammer (Gast)


Lesenswert?

joa oaky...

aber wie bekomme ich jetzt zeichen auf das dingen?

von Falk B. (falk)


Lesenswert?

@ Warhammer (Gast)

>aber wie bekomme ich jetzt zeichen auf das dingen?

Das steht ja wohl idiotensicher im Tutorial. Hast du die Taktfrequenz 
richtig angegeben?

MfG
Falk

von Warhammer (Gast)


Lesenswert?

joa hab ich...erst hatte ich da die flasche drinne, aber nun die 
richtige...
der cursor binkt an der ersten stelle...

von Falk B. (falk)


Lesenswert?

Und die Zeichen? Hello World!

von Warhammer (Gast)


Lesenswert?

nein nix...nur der cursor am blinken

von Frank B. (frank_b) Benutzerseite


Lesenswert?

Der Cursor darf eigentlich auch nicht blinken; das Blinken wird im Code 
doch zusammen mit dem Cursor abgeschaltet.

Bist du wirklich 100% sicher, dass Du es richtig verdrahtet hast ?

Poste doch mal das Makefile.

von Warhammer (Gast)


Lesenswert?

öööhm makefile?

ich hab im avr studio als device den atmega88 ausgewählt.(GCC)

dann habe ich ein lcd-routines.c datei erstellt, und den inhalt aus dem 
tutorial kopiert, und das main file unten dran gehängt.

dann habe ich im gleichen ordner noch ein lcd-routines.h erstellt und 
die frequenz auf 4Mhz gestellt, und die Ports auf PORTB.

...
#define F_CPU 4000000

#define CLEAR_DISPLAY 0x01
#define CURSOR_HOME   0x02

#define LCD_PORT      PORTB
#define LCD_DDR       DDRB
#define LCD_RS        PB4
#define LCD_EN        PB5;

dann alles Compeliert und an das STK 500 übertragen. Verbindungen hab 
ich schon 2mal durchgemessen.

achja fuse bits.

da ist nur SPIEN an
BODLEVEL steht auf protection disable
und SUT_CKSEL steht auf Ext. Crystal 3-8mhz,....+65ms

mehr hab ich nicht gemacht...

von Andreas K. (a-k)


Lesenswert?

Tatsächlich genau so?
1
#define LCD_EN        PB5;
Ok bei dem Code geht das zufällig gut. Ist aber trotzdem falsch.

von Falk B. (falk)


Lesenswert?

@ Andreas Kaiser (a-k)

>#define LCD_EN        PB5;

>Ok bei dem Code geht das zufällig gut. Ist aber trotzdem falsch.

Wie meinen das der Herr?

MfG
Falk

von Falk B. (falk)


Lesenswert?

Ahhh, das Semikolon.

von Warhammer (Gast)


Lesenswert?

joa okay...

aber ; draussen...aber trotzdem kein text-.-

von Warhammer (Gast)


Lesenswert?

keiner noch ne idee?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich an deiner Stelle würde das Datenblatt vom Display und vom darin 
genannten LCD-Controller peinlich genau lesen und 
Initialisierungssequenz und -timing checken. Hast du den Namen des 
Displays und Link zu den Datenblättern schon gepostet?

Das derzeitige Hochfahren kann das normale Hardware-Hochfahren vom 
Display nach Power-Up sein und deine ganzen Kommandos seitens des µC 
versickern im Silizium. Hast du Messmöglichkeiten, um Reaktionen des 
Displays zu checken (Busyflag) und das Power-up von µC und LCD zu 
überwachen/steuern?

von Peter D. (peda)


Lesenswert?

Warhammer wrote:
> keiner noch ne idee?

Ich habs mir angewöhnt, IO-Pins als Bitvariablen zu definieren.

Das mit dem |=,&= verleitet doch zu gerne zu Fehlern.

x = 0; x = 1; ist gut lesbar und eindeutig.

Hier mal ein (bulletproof) Beispiel:

http://www.mikrocontroller.net/attachment/30300/lcd_drv.zip


Peter

von Warhammer (Gast)


Lesenswert?

hrm,

also es handelt sich um dieses

Disply:
http://www.powertip.com.tw/products_2.php?product_id=1171043123&area_idbk=1170985616

ich hab da keine "zeiten" gefunden

ich bin echt verzweifelt...

von Gerd G. (elektrikser)


Lesenswert?

Der LCD-Controller sollte ein KS0066U (http://www.eio.com/ks0066u.pdf) 
sein. Ist eigentlich kompatibel zum HD44780.

von Michael H* (Gast)


Lesenswert?

lad dir doch mal die demo von proteus runter. da gibts libs für display 
und µc und auch ein virtuelles oszi.
http://www.labcenter.co.uk/download/prodemo_download.cfm
und wenn das da alles wunderbar funktioniert, hast du wohl irgendwo 
einen hardwarefehler.

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

In den Datenblättern sind schon etwas unterschiedliche Init-Sequenzen 
drin.

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

Man erkennt, dass beim KS0066U der grünmarkierte Teil nicht vorhanden 
ist und dass zwischen den anderen Befehlen bestimmte Wartezeiten 
einzuhalten sind. Ähnliche Wartezeiten sind auch beim HD44780 vorhanden, 
allerdings sind diese in einer anderen Tabelle (table 6) aufgeführt.

Die nächste Aufgabe ist ein Vergleich mit dem Tutorial-Code.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Dies ist die originale lcd_init aus dem Tutorial
1
void lcd_init(void)
2
{
3
   LCD_DDR = LCD_DDR | 0x0F | (1<<LCD_RS) | 1<<LCD_EN ;   // Port auf Ausgang schalten
4
 
5
   // muss 3mal hintereinander gesendet werden zur Initialisierung
6
 
7
   _delay_ms(15);
8
   LCD_PORT &= 0xF0;
9
   LCD_PORT |= 0x03;            
10
   LCD_PORT &= ~(1<<LCD_RS);      // RS auf 0
11
   lcd_enable();
12
 
13
   _delay_ms(5);
14
   lcd_enable();
15
 
16
   _delay_ms(1);
17
   lcd_enable();
18
   _delay_ms(1);
19
 
20
   // 4 Bit Modus aktivieren 
21
   LCD_PORT &= 0xF0;
22
   LCD_PORT |= 0x02;
23
   lcd_enable();
24
   _delay_ms(1);
25
 
26
   // 4Bit / 2 Zeilen / 5x7
27
   lcd_command(0x28);
28
    
29
   // Display ein / Cursor aus / kein Blinken
30
   lcd_command(0x0C); 
31
 
32
   // inkrement / kein Scrollen
33
   lcd_command(0x06);
34
 
35
   lcd_clear();
36
}

Für das KS0066U würde man es z.B. so anpassen. Ich habe allerdings kein 
LCD mit KS0066U zur Hand, um das zu testen.

Beim Ändern der Wartezeiten unbedingt die Dokumentation zu _delay_ms 
beachten. Je nach Prozessortakt gibt es Grenzen für den erlaubten Wert 
und längere Wartezeiten müssen in mehrere kleinere Wartezeiten 
aufgeteilt werden. 30ms im Einzelaufruf funktioniert nur unterhalb von 
8,734 MHz!

Statt 30ms auch mal mit 100ms experimentieren.
1
#define KS0066U 
2
3
void lcd_init(void)
4
{
5
   LCD_DDR = LCD_DDR | 0x0F | (1<<LCD_RS) | 1<<LCD_EN ;   // Port auf Ausgang schalten
6
7
#ifdef KS0066U 
8
   // 30ms (Einzelaufruf nur unterhalb F_CPU 8,734 MHz möglich)
9
   _delay_ms(10);  // lt. Datenblatt längere Wartezeit nach Power-On 
10
   _delay_ms(10);
11
   _delay_ms(10);
12
#else
13
   _delay_ms(15);
14
15
   // muss 3mal hintereinander gesendet werden zur Initialisierung
16
   LCD_PORT &= 0xF0;
17
   LCD_PORT |= 0x03;            
18
   LCD_PORT &= ~(1<<LCD_RS);      // RS auf 0
19
   lcd_enable();
20
 
21
   _delay_ms(5);
22
   lcd_enable();
23
 
24
   _delay_ms(1);
25
   lcd_enable();
26
   _delay_ms(1);
27
#endif 
28
 
29
   // 4 Bit Modus aktivieren 
30
   LCD_PORT &= 0xF0;
31
   LCD_PORT |= 0x02;
32
   lcd_enable();
33
   _delay_ms(1);
34
35
   // 4Bit / 2 Zeilen / 5x7
36
   lcd_command(0x28);
37
    
38
   // Display ein / Cursor aus / kein Blinken
39
   lcd_command(0x0C); 
40
41
#ifdef KS0066U 
42
   _delay_ms(2);
43
#endif 
44
 
45
   // inkrement / kein Scrollen
46
   lcd_command(0x06);
47
 
48
   lcd_clear();
49
}

von Warhammer (Gast)


Lesenswert?

joa erstmal vielen dank, das du dir soviel mühe gemacht hast.

funktioniert leider immernoch nicht.

was mit bis jetzt aufgefallen ist.

wenn ich die spannung zuschalte ist es totaler zufall was auf dem 
display erscheint...habs jetzt so 10mal gemacht und 3-4mal hatte ich 
wieder den cursor am blinken 2mal hatte ich an der sten stelle einen 
buchstaben, ein "F" und noch einen, und im restlichen gar nix.

ich habe gerade nochmal testweise ein programm für die datenübertragung 
mit rs232 übertragen und ausprobiert(wollte den takt von 4MHz testen) 
das funktioniert einwandfrei.

noch ne idee?

und noch ne frage, wo hast du die schönen blockdiagramme und das wissen 
über die verwendetetn controller her? ich hab in den datenblättern 
keinen hinweis gefunden(allerdings steht da auch nur die PIN belegung 
und die Abmessungen)

achja
_delay_ms(10);
hab ich am anfang 10x hinternanter eingetragen...
auch keine änderung

von Michael H* (Gast)


Lesenswert?

...simulieren! die tuts sind an sich idiotensicher.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Die Datenblätter findet man, wenn man in dem Datenblatt des Displays den 
Namen des LCD-Controllers herausfischt und dann mit diesem Namen eine 
Datenblattsuche macht (einfach über Google mit Namen und filetype:pdf) 
oder auf den verlinkten Seiten beim Wikiartikel LCD

Das Buntmalen habe ich mit einem Grafikprogramm gemacht, hatte heute 
mittag Langeweile ;-)

Im Moment habe ich auch keine bessere Idee (Verlängerung der Wartezeit 
vor dem ersten Kommando hast du ja schon gemacht).

In meiner Praxis habe ich festgestellt, dass eine ungültige 
Initialisierung den LCD-Controller blockieren kann. Also vor einem neuen 
Versuch mit neuem Programm das Targetboard und das LCD-Display stromlos 
machen.

von Warhammer (Gast)


Lesenswert?

hrm okay, ich habe das display dierekt 2mal bestellt,

werde morgen den ganzen kram mal mit dem atmega 16 ausprobieren.

von Warhammer (Gast)


Lesenswert?

und dem anderen display

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.