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
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!?
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.
achso... ich hab jetzt ein 16 Mhz Quarz dran! muss ich des dann umschreiben? auf > #ifndef F_CPU > #define F_CPU 16000000 > #endif
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.
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?
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
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
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.
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.
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 !
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.