Forum: Mikrocontroller und Digitale Elektronik LCD an atmega 8


von atmega8 (Gast)


Lesenswert?

Hey!
Ich habe jetzt ein LCD Modul mir einem kompatiblen chip an meinen 
Atmega8 angeschlossen... Zum drittenmal habe ich kontrolliert ob die 
Pins am display auch wirklich mit den richtigen Pins am Atmega8 
verbunden sind! Den Code hab ich jetzt zum testen aus dem Tutorial 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung 
kopiert! Ich hab meinermeinung nach alles so wie im tutorial gemacht! 
Aber iwie funktionierts nicht! Gibts da vll noch iwelche Dinge die ich 
einstellen muss bevor ich das display verwenden kann? Oder kennt ihr 
noch Fehler die noch leicht unterlaufen können?

Danke

von moep (Gast)


Lesenswert?

Code? Schaltplan? Welches Display? Was genau passiert denn?

von atmega8 (Gast)


Lesenswert?

lcd_routines.h
1
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
2
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
3
//
4
 
5
#ifndef LCD_ROUTINES_H
6
#define LCD_ROUTINES_H
7
 
8
////////////////////////////////////////////////////////////////////////////////
9
// Hier die verwendete Taktfrequenz in Hz eintragen, wichtig!
10
 
11
#ifndef F_CPU
12
#define F_CPU 3686400
13
#endif
14
 
15
////////////////////////////////////////////////////////////////////////////////
16
// Pinbelegung für das LCD, an verwendete Pins anpassen
17
// Alle LCD Pins müssen an einem Port angeschlossen sein und die 4
18
// Datenleitungen müssen auf aufeinanderfolgenden Pins liegen
19
 
20
//  LCD DB4-DB7 <-->  PORTD Bit PD0-PD3
21
#define LCD_PORT      PORTD
22
#define LCD_DDR       DDRD
23
#define LCD_DB        PD0
24
 
25
//  LCD RS      <-->  PORTD Bit PD4     (RS: 0=Data, 1=Command)
26
#define LCD_RS        PD4
27
 
28
//  LCD EN      <-->  PORTD Bit PD5     (EN: 1-Impuls für Daten)
29
#define LCD_EN        PD5
30
 
31
////////////////////////////////////////////////////////////////////////////////
32
// LCD Ausführungszeiten (MS=Millisekunden, US=Mikrosekunden)
33
 
34
#define LCD_BOOTUP_MS           15
35
#define LCD_ENABLE_US           1
36
#define LCD_WRITEDATA_US        46
37
#define LCD_COMMAND_US          42
38
 
39
#define LCD_SOFT_RESET_MS1      5
40
#define LCD_SOFT_RESET_MS2      1
41
#define LCD_SOFT_RESET_MS3      1
42
#define LCD_SET_4BITMODE_MS     5
43
 
44
#define LCD_CLEAR_DISPLAY_MS    2
45
#define LCD_CURSOR_HOME_MS      2
46
 
47
////////////////////////////////////////////////////////////////////////////////
48
// Zeilendefinitionen des verwendeten LCD
49
// Die Einträge hier sollten für ein LCD mit einer Zeilenlänge von 16 Zeichen passen
50
// Bei anderen Zeilenlängen müssen diese Einträge angepasst werden
51
 
52
#define LCD_DDADR_LINE1         0x00
53
#define LCD_DDADR_LINE2         0x40
54
#define LCD_DDADR_LINE3         0x10
55
#define LCD_DDADR_LINE4         0x50
56
 
57
////////////////////////////////////////////////////////////////////////////////
58
// Initialisierung: muss ganz am Anfang des Programms aufgerufen werden.
59
void lcd_init( void );
60
 
61
////////////////////////////////////////////////////////////////////////////////
62
// LCD löschen
63
void lcd_clear( void );
64
 
65
////////////////////////////////////////////////////////////////////////////////
66
// Cursor in die 1. Zeile, 0-te Spalte
67
void lcd_home( void );
68
 
69
////////////////////////////////////////////////////////////////////////////////
70
// Cursor an eine beliebige Position 
71
void lcd_setcursor( uint8_t spalte, uint8_t zeile );
72
 
73
////////////////////////////////////////////////////////////////////////////////
74
// Ausgabe eines einzelnen Zeichens an der aktuellen Cursorposition 
75
void lcd_data( uint8_t data );
76
 
77
////////////////////////////////////////////////////////////////////////////////
78
// Ausgabe eines Strings an der aktuellen Cursorposition 
79
void lcd_string( const char *data );
80
 
81
////////////////////////////////////////////////////////////////////////////////
82
// Definition eines benutzerdefinierten Sonderzeichens.
83
// data muss auf ein Array[5] mit den Spaltencodes des zu definierenden Zeichens
84
// zeigen
85
void lcd_generatechar( uint8_t code, const uint8_t *data );
86
 
87
////////////////////////////////////////////////////////////////////////////////
88
// Ausgabe eines Kommandos an das LCD.
89
void lcd_command( uint8_t data );
90
 
91
 
92
////////////////////////////////////////////////////////////////////////////////
93
// LCD Befehle und Argumente.
94
// Zur Verwendung in lcd_command
95
 
96
// Clear Display -------------- 0b00000001
97
#define LCD_CLEAR_DISPLAY       0x01
98
 
99
// Cursor Home ---------------- 0b0000001x
100
#define LCD_CURSOR_HOME         0x02
101
 
102
// Set Entry Mode ------------- 0b000001xx
103
#define LCD_SET_ENTRY           0x04
104
 
105
#define LCD_ENTRY_DECREASE      0x00
106
#define LCD_ENTRY_INCREASE      0x02
107
#define LCD_ENTRY_NOSHIFT       0x00
108
#define LCD_ENTRY_SHIFT         0x01
109
 
110
// Set Display ---------------- 0b00001xxx
111
#define LCD_SET_DISPLAY         0x08
112
 
113
#define LCD_DISPLAY_OFF         0x00
114
#define LCD_DISPLAY_ON          0x04
115
#define LCD_CURSOR_OFF          0x00
116
#define LCD_CURSOR_ON           0x02
117
#define LCD_BLINKING_OFF        0x00
118
#define LCD_BLINKING_ON         0x01
119
 
120
// Set Shift ------------------ 0b0001xxxx
121
#define LCD_SET_SHIFT           0x10
122
 
123
#define LCD_CURSOR_MOVE         0x00
124
#define LCD_DISPLAY_SHIFT       0x08
125
#define LCD_SHIFT_LEFT          0x00
126
#define LCD_SHIFT_RIGHT         0x04
127
 
128
// Set Function --------------- 0b001xxxxx
129
#define LCD_SET_FUNCTION        0x20
130
 
131
#define LCD_FUNCTION_4BIT       0x00
132
#define LCD_FUNCTION_8BIT       0x10
133
#define LCD_FUNCTION_1LINE      0x00
134
#define LCD_FUNCTION_2LINE      0x08
135
#define LCD_FUNCTION_5X7        0x00
136
#define LCD_FUNCTION_5X10       0x04
137
 
138
#define LCD_SOFT_RESET          0x30
139
 
140
// Set CG RAM Address --------- 0b01xxxxxx  (Character Generator RAM)
141
#define LCD_SET_CGADR           0x40
142
 
143
#define LCD_GC_CHAR0            0
144
#define LCD_GC_CHAR1            1
145
#define LCD_GC_CHAR2            2
146
#define LCD_GC_CHAR3            3
147
#define LCD_GC_CHAR4            4
148
#define LCD_GC_CHAR5            5
149
#define LCD_GC_CHAR6            6
150
#define LCD_GC_CHAR7            7
151
 
152
// Set DD RAM Address --------- 0b1xxxxxxx  (Display Data RAM)
153
#define LCD_SET_DDADR           0x80
154
 
155
#endif
lcd_routines.c
1
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
2
// http://www.mikrocontroller.net/articles/HD44780
3
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
4
//
5
// Die Pinbelegung ist über defines in lcd-routines.h einstellbar
6
 
7
#include <avr/io.h>
8
#include "lcd-routines.h"
9
#include <util/delay.h>
10
 
11
////////////////////////////////////////////////////////////////////////////////
12
// Erzeugt einen Enable-Puls
13
static void lcd_enable( void )
14
{
15
    LCD_PORT |= (1<<LCD_EN);     // Enable auf 1 setzen
16
    _delay_us( LCD_ENABLE_US );  // kurze Pause
17
    LCD_PORT &= ~(1<<LCD_EN);    // Enable auf 0 setzen
18
}
19
 
20
////////////////////////////////////////////////////////////////////////////////
21
// Sendet eine 4-bit Ausgabeoperation an das LCD
22
static void lcd_out( uint8_t data )
23
{
24
    data &= 0xF0;                       // obere 4 Bit maskieren
25
 
26
    LCD_PORT &= ~(0xF0>>(4-LCD_DB));    // Maske löschen
27
    LCD_PORT |= (data>>(4-LCD_DB));     // Bits setzen
28
    lcd_enable();
29
}
30
 
31
////////////////////////////////////////////////////////////////////////////////
32
// Initialisierung: muss ganz am Anfang des Programms aufgerufen werden.
33
void lcd_init( void )
34
{
35
    // verwendete Pins auf Ausgang schalten
36
    uint8_t pins = (0x0F << LCD_DB) |           // 4 Datenleitungen
37
                   (1<<LCD_RS) |                // R/S Leitung
38
                   (1<<LCD_EN);                 // Enable Leitung
39
    LCD_DDR |= pins;
40
 
41
    // initial alle Ausgänge auf Null
42
    LCD_PORT &= ~pins;
43
 
44
    // warten auf die Bereitschaft des LCD
45
    _delay_ms( LCD_BOOTUP_MS );
46
    
47
    // Soft-Reset muss 3mal hintereinander gesendet werden zur Initialisierung
48
    lcd_out( LCD_SOFT_RESET );
49
    _delay_ms( LCD_SOFT_RESET_MS1 );
50
 
51
    lcd_enable();
52
    _delay_ms( LCD_SOFT_RESET_MS2 );
53
 
54
    lcd_enable();
55
    _delay_ms( LCD_SOFT_RESET_MS3 );
56
 
57
    // 4-bit Modus aktivieren 
58
    lcd_out( LCD_SET_FUNCTION |
59
             LCD_FUNCTION_4BIT );
60
    _delay_ms( LCD_SET_4BITMODE_MS );
61
 
62
    // 4-bit Modus / 2 Zeilen / 5x7
63
    lcd_command( LCD_SET_FUNCTION |
64
                 LCD_FUNCTION_4BIT |
65
                 LCD_FUNCTION_2LINE |
66
                 LCD_FUNCTION_5X7 );
67
 
68
    // Display ein / Cursor aus / Blinken aus
69
    lcd_command( LCD_SET_DISPLAY |
70
                 LCD_DISPLAY_ON |
71
                 LCD_CURSOR_OFF |
72
                 LCD_BLINKING_OFF); 
73
 
74
    // Cursor inkrement / kein Scrollen
75
    lcd_command( LCD_SET_ENTRY |
76
                 LCD_ENTRY_INCREASE |
77
                 LCD_ENTRY_NOSHIFT );
78
 
79
    lcd_clear();
80
}
81
  
82
////////////////////////////////////////////////////////////////////////////////
83
// Sendet ein Datenbyte an das LCD
84
void lcd_data( uint8_t data )
85
{
86
    LCD_PORT |= (1<<LCD_RS);    // RS auf 1 setzen
87
 
88
    lcd_out( data );            // zuerst die oberen, 
89
    lcd_out( data<<4 );         // dann die unteren 4 Bit senden
90
 
91
    _delay_us( LCD_WRITEDATA_US );
92
}
93
 
94
////////////////////////////////////////////////////////////////////////////////
95
// Sendet einen Befehl an das LCD
96
void lcd_command( uint8_t data )
97
{
98
    LCD_PORT &= ~(1<<LCD_RS);    // RS auf 0 setzen
99
 
100
    lcd_out( data );             // zuerst die oberen, 
101
    lcd_out( data<<4 );           // dann die unteren 4 Bit senden
102
 
103
    _delay_us( LCD_COMMAND_US );
104
}
105
 
106
////////////////////////////////////////////////////////////////////////////////
107
// Sendet den Befehl zur Löschung des Displays
108
void lcd_clear( void )
109
{
110
    lcd_command( LCD_CLEAR_DISPLAY );
111
    _delay_ms( LCD_CLEAR_DISPLAY_MS );
112
}
113
 
114
////////////////////////////////////////////////////////////////////////////////
115
// Sendet den Befehl: Cursor Home
116
void lcd_home( void )
117
{
118
    lcd_command( LCD_CURSOR_HOME );
119
    _delay_ms( LCD_CURSOR_HOME_MS );
120
}
121
 
122
////////////////////////////////////////////////////////////////////////////////
123
// Setzt den Cursor in Spalte x (0..15) Zeile y (1..4) 
124
 
125
void lcd_setcursor( uint8_t x, uint8_t y )
126
{
127
    uint8_t data;
128
 
129
    switch (y)
130
    {
131
        case 1:    // 1. Zeile
132
            data = LCD_SET_DDADR + LCD_DDADR_LINE1 + x;
133
            break;
134
 
135
        case 2:    // 2. Zeile
136
            data = LCD_SET_DDADR + LCD_DDADR_LINE2 + x;
137
            break;
138
 
139
        case 3:    // 3. Zeile
140
            data = LCD_SET_DDADR + LCD_DDADR_LINE3 + x;
141
            break;
142
 
143
        case 4:    // 4. Zeile
144
            data = LCD_SET_DDADR + LCD_DDADR_LINE4 + x;
145
            break;
146
 
147
        default:
148
            return;                                   // für den Fall einer falschen Zeile
149
    }
150
 
151
    lcd_command( data );
152
}
153
 
154
////////////////////////////////////////////////////////////////////////////////
155
// Schreibt einen String auf das LCD
156
 
157
void lcd_string( const char *data )
158
{
159
    while( *data != '\0' )
160
        lcd_data( *data++ );
161
}
162
 
163
////////////////////////////////////////////////////////////////////////////////
164
// Schreibt ein Zeichen in den Character Generator RAM
165
 
166
void lcd_generatechar( uint8_t code, const uint8_t *data )
167
{
168
    // Startposition des Zeichens einstellen
169
    lcd_command( LCD_SET_CGADR | (code<<3) );
170
 
171
    // Bitmuster übertragen
172
    for ( uint8_t i=0; i<8; i++ )
173
    {
174
        lcd_data( data[i] );
175
    }
176
}
eigentliches Program:
1
// 
2
// Anpassungen im makefile:
3
//    ATMega8 => MCU=atmega8 im makefile einstellen
4
//    lcd-routines.c in SRC = ... Zeile anhängen
5
// 
6
#include <avr/io.h>
7
#include "lcd-routines.h"
8
 
9
int main(void)
10
{
11
  // Initialisierung des LCD
12
  // Nach der Initialisierung müssen auf dem LCD vorhandene schwarze Balken
13
  // verschwunden sein
14
  lcd_init();
15
 
16
  // Text in einzelnen Zeichen ausgeben
17
  lcd_data( 'T' );
18
  lcd_data( 'e' );
19
  lcd_data( 's' );
20
  lcd_data( 't' );
21
 
22
  // Die Ausgabemarke in die 2te Zeile setzen
23
  lcd_setcursor( 0, 2 );
24
 
25
  // erneut Text ausgeben, aber diesmal komfortabler als String
26
  lcd_string("Hello World!");
27
 
28
  while(1)
29
  {
30
  }
31
 
32
  return 0;
33
}
Display: 
http://www.pollin.de/shop/dt/NDU0OTc4OTk-/Bauelemente_Bauteile/Aktive_Bauelemente/Displays/LCD_Modul_HMC16223SG.html
2-zeiliges LC-Display mit industriestandard-kompatiblem Controller 
(HDD44780 kompatibel)
Ich habs schon mal vor längerer Zeit mit Assembler angesprochen und da 
hats funktioniert!
Hab leider den assembler code nicht mehr...
Es wird nur ein schwarzer Balken angezeigt! Eigentlich müssten ja 2 
Balken angezeigt werden oder nicht! also nur nach der initialisierung!?

von Matthias (Gast)


Lesenswert?

atmega8 schrieb:
> #ifndef F_CPU
> #define F_CPU 3686400
> #endif

Diese Anweisungen sind etwas tückisch, weil sie dem Compiler u.U. ohne 
Warnung eine falsche Quarzfrequenz mitteilen, wenn du nichts explizit 
angibst.

von atmega8 (Gast)


Lesenswert?

achso... ich hab jetzt ein 16 Mhz Quarz dran! muss ich des dann 
umschreiben? auf
> #ifndef F_CPU
> #define F_CPU 16000000
> #endif

von Karl H. (kbuchegg)


Lesenswert?

atmega8 schrieb:
> achso... ich hab jetzt ein 16 Mhz Quarz dran! muss ich des dann
> umschreiben? auf
>> #ifndef F_CPU
>> #define F_CPU 16000000
>> #endif


Wenn du die Taktfrequenz in den Projekteinstellungen eingetragen hast, 
dann ist das nicht wichtig.

Sicherheitshalber kannst du ja mal den 3-Zeiler auf

#define F_CPU 16000000

reduzieren, dann gibts möglicherweise eine Warnung vom Compiler, die du 
aber ignorieren kannst. Aber abgesehen davon, wäre es wichtig, dass 
F_CPU den richtigen wert hat (egal ob über die Projekteinstellungen oder 
direkt im Header File), wie ja auch schon der Kommentar unmittelbar 
davon ...
1
////////////////////////////////////////////////////////////////////////////////
2
// Hier die verwendete Taktfrequenz in Hz eintragen, wichtig!

... aussagt. Der steht da nicht nur zum Spass.

von atmega8 (Gast)


Lesenswert?

Funktioniert immer noch nicht... ist es möglich, dass das lcd bereits 
defekt ist? eigentlich müssten ja auch 2 Balken angezeigt werden oder 
nicht?

von Anja (Gast)


Lesenswert?

atmega8 schrieb:
> Funktioniert immer noch nicht... ist es möglich, dass das lcd bereits
> defekt ist? eigentlich müssten ja auch 2 Balken angezeigt werden oder
> nicht?

Nein es ist nur nicht initialisiert. Vermutlich gibt es bei 16 MHz einen 
Überlauf in der Berechnung von delay_ms oder so.

Gruß Anja

von Anja (Gast)


Lesenswert?

Noch was was gerne übersehen wird:

die 15ms Delay dürfen erst dann beginnen zu laufen wenn das Display den 
internen Reset abgearbeitet hat. (VDD > Spannung im Datenblatt). Und 
nicht schon wenn der ATMEGA aus dem brown out Reset läuft.

Gruß Anja

von mr. mo (Gast)


Lesenswert?

atmega8 schrieb:
> Funktioniert immer noch nicht... ist es möglich, dass das lcd bereits
> defekt ist? eigentlich müssten ja auch 2 Balken angezeigt werden oder
> nicht?

hatte mal genau das gleiche problem, die initialisierung des display 
funtionierte einfach nicht. aus keiner library oder sonst woher. lösung 
war einfach die pausen zeiten in der initialisierung etwas höher zu 
stellen.

von HAZ (Gast)


Lesenswert?

Hi,

hast du mal am Kontrast gedreht, vielleicht siehst du deswegen nichts.

MfG

von Uwe (Gast)


Lesenswert?

Standartmäßig ist das Display nur für eine Zeile konfiguriert und erst 
nach der Initialisierung wird die 2. Zeile aktiviert. Das Heißt es geht 
auf jedenfall was bei der Initialisierung schief. Mach doch alle Takte 
mal ein bischen länger und warte als allerersten Befehl ein paar 
sekunden bis sich die Spannung stabilisiert hat. Danach verringerst du 
nach und nach die Wartezeit und machst nach und nach die Takte wieder 
kürzer bis es nicht mehr geht. Dann solltest du die Stelle gefunden 
haben.

von Uwe (Gast)


Lesenswert?

Ach so nicht vergessen beim start ist das Display auch auf 8_bit modus 
eingestellt. Das heißt du mußt ihm im 8-bit modus sagen das er im 4-bit 
modus arbeiten soll. Das ist auch ohne weiteres möglich es wird aber nur 
einmal enabled und nicht 2 mal , da volle 8-bit übertragen werden !

von Uwe (Gast)


Lesenswert?

Wegen des anfänglichen 8-Bit Modus können folglich auch die Unteren Bits 
N und F , im Function set befehl, nicht angesprochen werden weil diese 
auf D2 und D3 liegen (die aber nicht angeschlossen sind) .Daher muss 
dieser Befehl im 4-Bit modus wiederholt werden und das Display auf 2 
Zeilen konfiguriert werden.

von atmega8 (Gast)


Lesenswert?

Ok danke für euere Hilfe! Iwie kann ich meinen atmega8 jetzt überhaupt 
nicht mehr programmieren... hab in der zwischenzeit mal versucht auf die 
internen 4 Mhz umzustellen was mir aber anscheinend nicht gelungen 
ist... naja ich werds mal mit einem atmega16 versuchen und meld mich 
dann einfach wieder!

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.