Hi Leute, ja ich weiß schon wieder ein LCD Thema.. ^^ Ich beschäftige mich gerade mit der Textausgabe auf einem LCD mit einem Atmega8L programmiert mit Avr Studio. Das LCD Display sollte im 4 Bit Mode am PortB betrieben werden. Die oberen 4 Bits am Port B PB4 - PB7 sind PD4 - PD7. PB0 entspricht RS, PB1 RW und PB2 Enable. Das verhalten: Starte ich das LCD ohne Microcontroller erscheint in der Reihe 2 ein schwarzer "Balken". Wird dann der Microcontroller gestartet verschwindet durch das Init der schwarze Balken. Sollte denke ich so sein. Jedoch wird nach dem LCD Init kein Character ausgegeben. Bei der Umsetzung habe ich mich stark an das Beispiel aus dem AVR-GCC-Tutorial gehalten. Klar könnte ich einfach das Sample nehmen und glücklich sein. Aber ich will verstehen wie das LCD angesteuert werden muss. Anbei noch der Sourcecode der bei mir aktuell am Atmega läuft. //********************************************************************** ******* //* Programm: LCD_Test.c //* //* Funktion: ... //* //* Author: Luki //* //* Datum: 25.11.2010 //* //* Hardware (AVRboard01/ATmega8): //* - Taster: T1, T2, T3 --> PD4(T0), PD3(INT1), PD2(INT0) //* - LEDs: LD0...LD7 --> PB0...PB7 (Jumper schliessen!) //* - RGB-LED: BLUE(PC2), BLUE(PC3), GREEN(PC4), RED(PC5) //* - Summer: PD5 //********************************************************************** ******* #define F_CPU 1000000UL /* 1Mhz */ #include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <avr/io.h> #include <util/delay.h> #include <util/twi.h> #define PCF_SLA 0x20 #define LCD_RS 0 #define LCD_RW 1 #define LCD_EN 2 #define LCD_DB4 4 #define LCD_DB5 5 #define LCD_DB6 6 #define LCD_RB7 7 #define LCD_FUNCT_SET 0x20 #define LCD_SET_4_BIT 0x00 #define LCD_CLEAR_DISP 0x01 #define LCD_RET_HOME 0x02 #define LCD_NUM_LINES 0x08 #define LCD_5X8_DOTS 0x00 #define LCD_DISPLAY_OFF 0x08 #define LCD_SOFT_RESET 0x30 #define LCD_ENTRY_MODE_SET 0x04 #define LCD_ENTRY_INCREASE 0x02 #define LCD_ENTRY_NOSHIFT 0x00 #define LCD_SET_DISPLAY 0x08 #define LCD_DISPLAY_ON 0x04 #define LCD_CURSOR_OFF 0x00 #define LCD_BLINKING_OFF 0x00 void LCD_Enable(void) { PORTB |= (1<<LCD_EN); _delay_us(20); PORTB &= ~(1<<LCD_EN); } void I2C_LCD_OUT (unsigned short int LCDData) { LCDData &= 0xF0; PORTB &= ~(0xF0); PORTB |= LCDData; LCD_Enable(); } void I2C_LCD_CMD (unsigned short int CMD_Data) { PORTB &= ~(1<<LCD_RS); I2C_LCD_OUT(CMD_Data); I2C_LCD_OUT((CMD_Data<<4)); _delay_us(50); } void I2C_LCD_DATA(unsigned short int Data) { PORTB |= (1<<LCD_RS); I2C_LCD_OUT(Data); I2C_LCD_OUT((Data<<4)); _delay_us(50); } int main(void) { DDRB = 0xFF; _delay_ms(500); // LCD Init I2C_LCD_OUT(LCD_SOFT_RESET); LCD_Enable(); _delay_ms(5); // Step 2 LCD_Enable(); _delay_ms(5); // Step 3 LCD_Enable(); _delay_ms(5); // Set LCD to 4 Bit Mode I2C_LCD_OUT(LCD_FUNCT_SET | LCD_SET_4_BIT); _delay_ms(5); I2C_LCD_CMD(LCD_FUNCT_SET | LCD_NUM_LINES | LCD_5X8_DOTS); I2C_LCD_CMD(LCD_SET_DISPLAY | LCD_DISPLAY_ON | LCD_CURSOR_OFF | LCD_BLINKING_OFF); I2C_LCD_CMD(LCD_ENTRY_MODE_SET | LCD_ENTRY_INCREASE | LCD_ENTRY_NOSHIFT); // Clear Display I2C_LCD_CMD(LCD_CLEAR_DISP); I2C_LCD_DATA( 'T' ); while(1) { } return 0; } Ich wäre sehr dankbar wenn mir jemand weiterhelfen kann !! Danke, Luki
:
Bearbeitet durch User
Hi, wenn Du hier alles Verstanden hast, dann findest Du auch alle Fehler. http://www.sprut.de/electronic/lcd/ Wichtig, lies Dir bitte das DB des HD44780 durch. https://www.sparkfun.com/datasheets/LCD/HD44780.pdf Das ist die Grundlage für alle LCD. Andere Chip bedeutet manchmal ein anderes Timing. Stelle bitte einen realen Schaltplan und gute, scharfe Bilder ein.
Hi Muß nicht das Display zuerst auf 8bit und dann 3x auf 4bit eingestellt werden? MfG
Hi ... fast ... 3x auf 8bit, dann erst, wenn das Display ganz sicher 8-bittig läuft, auf 4bit wechseln. Bin selber aber nur etwas in ASM beheimatet
Ich habe mir das Datenblatt und auch die Sprut Seite durchgelesen und versehe auch wie das LCD angesteuert werden muss. Glaub ich halt. Entweder ich übersehe etwas oder ich bin einfach zu blöde :D Anbei noch ein Schaltplan (Ist handgezeichnet ich hoffe man kann alles lesen) und ein Foto von meinem Aufbau. Zur Info. Das I2C Port Expander Board welches auf das LCD zugeschnitten ist wird nicht aktiv verwendet. Ich nehme davon nur die Versorgung für das LCD, die Hintergrundbeleuchtung und die Kontrast Einstellung. Im nächsten Schritt soll es natürlich über I2C angesteuert werden.
Lukas A. schrieb: > LCD_Enable(); > _delay_ms(5); //hier 16 > > // Step 2 > LCD_Enable(); > _delay_ms(5); //OK > > // Step 3 > LCD_Enable(); > _delay_ms(5); //OK Siehe aber dazu nochmals das Datenblatt. Sonst lerne zu debuggen. Dazu kannst du diesen Simulator nehmen: http://www.dinceraydin.com/djlcdsim/djlcdsim.html Oftmals ist aber der Kontrast falsch eingestellt und man erkennt nichts, obwohl was da ist.
Ich hab das jetzt im Debugger durchgesteppt und die einzelnen Bits welche an den Port B geschrieben werden auch im LCD Simulator eingetragen. Zum Schluss ist dann im LCD Simulator der Buchstabe T gestanden. Auf meinem Display aber nicht. Es sieht wirklich danach aus als ob es sich um ein Timing Problem beim Init handelt. Ich muss nochmals genau die Zeiten aus dem Datenblatt ansehen und mit meinen vergleichen. Ich habe den Code nochmals etwas geändert. Quasi eine Dummy Version. :)
1 | void LCD_Enable(void) |
2 | {
|
3 | |
4 | PORTB |= (1<<LCD_EN); |
5 | |
6 | _delay_us(40); |
7 | |
8 | PORTB &= ~(1<<LCD_EN); |
9 | |
10 | |
11 | }
|
12 | |
13 | |
14 | void I2C_LCD_OUT (unsigned short int LCDData) |
15 | {
|
16 | |
17 | LCDData &= 0xF0; // Oberen 4 Bits maskieren |
18 | |
19 | PORTB &= ~(0xF0); // Obere 4 Bit maske löschen |
20 | |
21 | |
22 | PORTB |= LCDData; |
23 | |
24 | LCD_Enable(); |
25 | |
26 | }
|
27 | |
28 | |
29 | void I2C_LCD_CMD (unsigned short int CMD_Data) |
30 | {
|
31 | |
32 | |
33 | PORTB &= ~(1<<LCD_RS); |
34 | |
35 | I2C_LCD_OUT(CMD_Data); |
36 | I2C_LCD_OUT((CMD_Data<<4)); |
37 | |
38 | _delay_us(50); |
39 | |
40 | }
|
41 | |
42 | void I2C_LCD_DATA(unsigned short int Data) |
43 | {
|
44 | |
45 | PORTB |= (1<<LCD_RS); |
46 | |
47 | I2C_LCD_OUT(Data); |
48 | I2C_LCD_OUT((Data<<4)); |
49 | |
50 | _delay_us(50); |
51 | }
|
52 | |
53 | |
54 | |
55 | int main(void) |
56 | {
|
57 | |
58 | |
59 | |
60 | DDRB = 0xFF; |
61 | PORTB = 0x00; |
62 | _delay_ms(500); |
63 | |
64 | |
65 | |
66 | // LCD Init
|
67 | PORTB |= (0b00110000); |
68 | LCD_Enable(); |
69 | _delay_ms(16); |
70 | |
71 | |
72 | // Step 2
|
73 | LCD_Enable(); |
74 | _delay_ms(5); |
75 | |
76 | |
77 | // Step 3
|
78 | LCD_Enable(); |
79 | _delay_ms(5); |
80 | |
81 | |
82 | |
83 | // Set LCD to 4 Bit Mode
|
84 | I2C_LCD_OUT(0b00100000); |
85 | _delay_ms(5); |
86 | |
87 | // 2-Lines, 5x8-Matrix
|
88 | I2C_LCD_CMD(0b00101000); |
89 | |
90 | // Display off
|
91 | I2C_LCD_CMD(0b00001000); |
92 | |
93 | // Clear display
|
94 | I2C_LCD_CMD(0b00000001); |
95 | |
96 | |
97 | I2C_LCD_CMD(0b00000110); |
98 | |
99 | // Display ON
|
100 | I2C_LCD_CMD(0b00001100); |
101 | |
102 | |
103 | I2C_LCD_DATA('T'); |
104 | |
105 | |
106 | while(1) |
107 | {
|
108 | }
|
109 | |
110 | return 0; |
111 | |
112 | |
113 | }
|
Hat sonst noch wer Ideen oder ähnliches ? Grüße Luki
Lukas A. schrieb: > Hat sonst noch wer Ideen oder ähnliches ? Kontrastspannung stimmt? Gibt auch LCDs mit negativer Kontrastspannung. Sonst teste doch einfach mal ein simples "hello world" was man quasi ueberall, auch als hex, runter laden kann. Die Fuses stimmen? Also nix clk/8 oder sowas? Sonst programmier doch erst mal einen "LED-Blinker" und guck ob es der AVR ueberhaupt tut.
Lukas A. schrieb: > Hat sonst noch wer Ideen oder ähnliches ? Lukas A. schrieb: > #define LCD_RET_HOME 0x02 Auf jeden Fall einmal Cursor Home kommandieren und vor dem Schreiben eines Strings oder Characters einmal die Cursor-Adresse setzen.
Lukas A. schrieb: > void I2C_LCD_CMD (unsigned short int CMD_Data) //hier typ unsigned short > { > > > PORTB &= ~(1<<LCD_RS); > > I2C_LCD_OUT(CMD_Data); > I2C_LCD_OUT((CMD_Data<<4)); > > _delay_us(50); > > } Hier setzt du och den RS Pin high. > void I2C_LCD_OUT (unsigned short int LCDData) > { > > LCDData &= 0xF0; // Oberen 4 Bits maskieren > > PORTB &= ~(0xF0); // Obere 4 Bit maske löschen > > PORTB |= LCDData; > > LCD_Enable(); > > } Hier setzt du wiederum den RS Pin auf low.
Peter W. schrieb: > Kontrastspannung stimmt? Gibt auch LCDs mit negativer Kontrastspannung. > Sonst teste doch einfach mal ein simples "hello world" was man quasi > ueberall, auch als hex, runter laden kann. > Die Fuses stimmen? Also nix clk/8 oder sowas? > Sonst programmier doch erst mal einen "LED-Blinker" und guck ob es der > AVR ueberhaupt tut. Kontrastspannung stimmt. Hab den ganzen Kontrastbereich durch und es wurde nichts sichtbar. Was meinst du mit Fuses beim lcd ? Ja AVR funktioniert sicher. Am PortB alle LEDs blinken lassen, Lauflicht mit C und ASM, Pwm also der AVR sollte funktionieren. Codeleser schrieb: > Auf jeden Fall einmal Cursor Home kommandieren und vor > dem Schreiben eines Strings oder Characters einmal die > Cursor-Adresse setzen. Ja du hast recht das muss ich noch versuchen. aSma>> schrieb: > Hier setzt du och den RS Pin high. Nein hier setze ich den RS auf Low. aSma>> schrieb: > Hier setzt du wiederum den RS Pin auf low. aSma>> schrieb: >> LCDData &= 0xF0; // Oberen 4 Bits maskieren Im ersten Schritt werden die oberen 4 Bits von LCDData maskiert. Die unteren 4 Bits gelöscht. aSma>> schrieb: > PORTB &= ~(0xF0); // Obere 4 Bit maske löschen Hier invertiere ich 0xF0 --> 0b11110000 zu 0b00001111 und verunde dass dann mit dem Port B somit bleiben die Unteren 4 Bits stehen und die Oberen 4 Bits werden gelöscht. Bitte korrigiert mich wenn ich jetzt einen Blödsinn geschrieben habe.
Lukas A. schrieb: > Ja AVR funktioniert sicher. Hast du keinen Konflikt mit dem SPI Programmer (ISP Port)? Oder verwendest du einen Bootloader ....
Servus, ich habe mich gestern bei einer fkt. bei dir vertan. Die Funktion: >void I2C_LCD_OUT (unsigned short int CMD_Data) ist und bleibt eine Fehlerquelle. Wenn du Daten sendest muss RS Pin auf level high bleiben. Durch deine Maskierung setzt du portB 0,1,2,3 auf low. > PORTB &= ~(0xF0); // Obere 4 Bit maske löschen Einfach diese Zeile entfernen und dann müsste es gehen. Außerdem nochmals dein PORTB ist nur 8bit groß, deshalb reicht ein "unsigned short" aus. Ich frage mich überhaupt, ob es überhaubt einen unsigned short int als Datentyp gibt?!
aSma>> schrieb: > Einfach diese Zeile entfernen und dann müsste es gehen. Du scheinst die Bedeutung eines "~" (noch) nicht zu kennen.
Sorry für die späte Rückmeldung. Ich war beruflich unterwegs. Ich sitzt nun wieder vorm Atmega :D Als erstes das Cursor home hat nichts gebracht. Codeleser schrieb: > Hast du keinen Konflikt mit dem SPI Programmer (ISP Port)? > Oder verwendest du einen Bootloader .... Nein ich verwende keinen Bootloader ich programmiere den Atmega über den ISP port mit einem ISP Progger. Denkst du dass der ISP Port mir da dazwischen funkt ? Ich werde einfach mal den Port D versuchen. Grüße Luki
Sooo Leute. Sorry für den Doppelpost. Ich habe nun nochmals mit neuer frische das Datenblatt durchgelesen. Und siehe da wenn man die Ausführzeiten der Kommandos wie im Datenblatt einhält wird auch ein Charakter bzw. ein String am LCD ausgegeben. Vielen dank nochmals für die Unterstützung. Ich werde wahrscheinlich noch weiter berichten wenn das LCD am I2C hängt. Grüße Luki
Hallo Leute :) Ich habe leider wieder Probleme mit meinem LCD Display. Dieses mal habe ich das LCD über I2C angeschlossen und natürlich dazwischen den Portexpander und die nötige Elektronik dazu. Das LCD Init funktioniert einwandfrei, ich kann auch Strings am LCD ausgeben usw.. ABER ich kann meinen Cursor nicht nach belieben am LCD positionieren. Durch schreiben der Cursorposition in den DDRAM sollte der Cursor je nach Position ja am LCD springen. Sehe ich das richtig ? Hier in kurzer Ausschnitt wie meine Funktion zum Cursor setzten aussieht. Oben auch noch die defines damit man weiß was welchen Wert hat.
1 | #define LCD_RS 0x00
|
2 | #define LCD_RW 0x01
|
3 | #define LCD_EN 0x02
|
4 | #define LCD_SOFT_RESET 0x30
|
5 | #define LCD_SET_4BIT 0x20
|
6 | #define LCD_FUNCTION_SET 0x20
|
7 | #define LCD_NUM_LINES 0x08
|
8 | #define LCD_5X8_DOTS 0x00
|
9 | #define LCD_SET_DISPLAY 0x08
|
10 | #define LCD_DISPLAY_ON 0x04
|
11 | #define LCD_CURSOR_OFF 0x00
|
12 | #define LCD_CURSOR_ON 0x02
|
13 | #define LCD_BLINKING_OFF 0x00
|
14 | #define LCD_BLINKING_ON 0x01
|
15 | #define LCD_ENTRY_MODE_SET 0x04
|
16 | #define LCD_ENTRY_INCREASE 0x02
|
17 | #define LCD_ENTRY_NOSHIFT 0x00
|
18 | #define LCD_CLEAR_DISP 0x01
|
19 | #define LCD_CURSOR_HOME 0x02
|
20 | #define LCD_SET_DDADR 0x80
|
21 | #define LCD_ADR_LINE1 0x00
|
22 | #define LCD_ADR_LINE2 0x40
|
23 | #define LCD_SET_CGADR 0x40
|
24 | |
25 | |
26 | void LCD_Enable(void) |
27 | {
|
28 | // Set enable Bit
|
29 | TWDR |= (1<<LCD_EN); |
30 | TWI_Send(); |
31 | // Wait until enable is set on Lcd
|
32 | _delay_us(20); |
33 | // Reset Enable bit
|
34 | TWDR &= ~(1<<LCD_EN); |
35 | TWI_Send(); |
36 | _delay_us(20); |
37 | }
|
38 | |
39 | void LCD_Out(unsigned short Lcd_Data) |
40 | {
|
41 | Lcd_Data &= 0xF0; |
42 | TWDR &= ~(0xF0); |
43 | |
44 | TWDR |= Lcd_Data; |
45 | |
46 | LCD_Enable(); |
47 | }
|
48 | |
49 | void LCD_CMD(unsigned short Data) |
50 | {
|
51 | TWDR &= ~(1<<LCD_RS); |
52 | TWI_Send(); |
53 | |
54 | LCD_Out(Data); |
55 | LCD_Out(Data<<4); |
56 | |
57 | _delay_us(42); |
58 | |
59 | }
|
60 | |
61 | |
62 | void LCD_Data(unsigned short Data) |
63 | {
|
64 | TWDR |= (1<<LCD_RS); |
65 | TWI_Send(); |
66 | |
67 | LCD_Out(Data); |
68 | LCD_Out(Data<<4); |
69 | |
70 | _delay_us(46); |
71 | |
72 | }
|
73 | |
74 | void LCD_Clear(void) |
75 | {
|
76 | LCD_CMD(LCD_CLEAR_DISP); |
77 | _delay_ms(2); |
78 | }
|
79 | |
80 | void LCD_Home(void) |
81 | {
|
82 | LCD_CMD(LCD_CURSOR_HOME); |
83 | _delay_ms(2); |
84 | }
|
85 | |
86 | |
87 | void LCD_Init(void) |
88 | {
|
89 | // Wait for lcd bootup
|
90 | _delay_ms(15); |
91 | |
92 | // three times lcd soft reset
|
93 | LCD_Out(LCD_SOFT_RESET); |
94 | _delay_ms(5); |
95 | |
96 | LCD_Out(LCD_SOFT_RESET); |
97 | _delay_ms(1); |
98 | |
99 | LCD_Out(LCD_SOFT_RESET); |
100 | _delay_ms(1); |
101 | |
102 | // set lcd to 4 Bit mode
|
103 | LCD_Out(LCD_FUNCTION_SET | LCD_SET_4BIT); |
104 | _delay_ms(5); |
105 | |
106 | // Set lcd to 5x8 Dots and 2 lines
|
107 | LCD_CMD(LCD_FUNCTION_SET | LCD_NUM_LINES | LCD_5X8_DOTS); |
108 | |
109 | // LCD Display on, no cursor, cursor blinking off
|
110 | LCD_CMD(LCD_SET_DISPLAY | LCD_DISPLAY_ON | LCD_CURSOR_ON | LCD_BLINKING_ON); |
111 | _delay_ms(2); |
112 | |
113 | // TODO
|
114 | LCD_CMD(LCD_ENTRY_MODE_SET | LCD_ENTRY_INCREASE |LCD_ENTRY_NOSHIFT); |
115 | _delay_ms(2); |
116 | |
117 | // Clear display
|
118 | LCD_Clear(); |
119 | |
120 | // Cursor move home
|
121 | LCD_Home(); |
122 | |
123 | |
124 | }
|
125 | |
126 | |
127 | |
128 | void LCD_SetCursor(unsigned int x, unsigned int y) |
129 | {
|
130 | |
131 | uint8_t data; |
132 | |
133 | switch(y) |
134 | {
|
135 | // Line 1
|
136 | case 1: |
137 | |
138 | data = LCD_SET_DDADR + LCD_ADR_LINE1 + x; |
139 | |
140 | break; |
141 | |
142 | // Line 2
|
143 | case 2: |
144 | |
145 | data = LCD_SET_DDADR + LCD_ADR_LINE2 + x; |
146 | |
147 | // default value if there was set a wrong line number
|
148 | default:
|
149 | return; |
150 | |
151 | LCD_CMD(data); |
152 | |
153 | }
|
154 | }
|
155 | |
156 | void LCD_WriteString(char *String) |
157 | {
|
158 | while (*String != '\0') |
159 | {
|
160 | LCD_Data(*String++); |
161 | }
|
162 | |
163 | }
|
164 | |
165 | void LCD_WriteString_XY(unsigned short x, unsigned short y, char *String) |
166 | {
|
167 | |
168 | LCD_SetCursor(x,y); |
169 | LCD_WriteString(String); |
170 | |
171 | }
|
172 | |
173 | |
174 | |
175 | int main(void) |
176 | {
|
177 | // Var declaration
|
178 | unsigned int receiveBuffer[27]; |
179 | unsigned short recvData; |
180 | struct WBO2 Wbo2_Data; |
181 | |
182 | // Init of TWI, UART and LCD
|
183 | TWI_Init(); |
184 | //USART_Init(MYUBBR);
|
185 | LCD_Init(); |
186 | LCD_SetCursor(10,2); |
187 | |
188 | |
189 | |
190 | while (1) |
191 | {}
|
192 | |
193 | |
194 | |
195 | }
|
Nach dem im Main die Funktion LCD_SetCursor aufgerufen wird ist jedoch der Cursor immer noch an seiner Homeposition. Vielleicht sieht jemand den Fehler und kann mir evtl. weiterhelfen. Vielen Dank im voraus !! :) Grüße Luki
Hi Wenn ich Das richtig verstehe, liegt der Befehl, die Position zu Ändern, im DEFAULT-Zweig. Also noch innerhalb der Switch-Abfrage. Lukas .. schrieb: > void LCD_SetCursor(unsigned int x, unsigned int y) > { > > uint8_t data; > > switch(y) > { > // Line 1 > case 1: > > data = LCD_SET_DDADR + LCD_ADR_LINE1 + x; > > break; > > // Line 2 > case 2: > > data = LCD_SET_DDADR + LCD_ADR_LINE2 + x; > > // default value if there was set a wrong line number > default: > return; > > LCD_CMD(data); > > } > } Setze des 'LCD_CMD(data) 2 Zeilen runter, also zwischen die beiden schließenden Klammern - dann bist Du in der X/Y-Routiene, aber außerhalb der Switch-Abarbeitung. MfG Edit: nich->noch, bisz->bist ... wurde sogar Beides angemeckert ... man muß halt nur drauf achten :/
:
Bearbeitet durch User
Vielen Dank für deine Hilfe !! Du hattest recht ! Außerdem habe ich noch einen Fehler in der SetCursor Funktion gefunden. Im Case2: Habe ich auch das break; vergessen. Vielen Dank nochmal!! Und sorry für die Schreibfehler ! :/ Grüße Luki
Hi Toll, daß Es funktioniert :) ... ich 'kann' C :) ... (ok, ein blindes Huhn mag auch nen Korn - aber Den -> C:) mag ich irgendwie, sieht aus, wie ein Pilz-Kopf) MfG
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.