Hallo, habe folgenden Code um das Display (4x20) im 2Zeile 5x8 Modus zu initialisieren: void initLCD(void) { LCD_DDR = 0xEF; // alle Pins PortC auf Ausgang schalten wait10ms(10); int i; for (i= 0;i<3;i++) { LCD_PORT = 3; // 8Bit wait10ms(1); } LCD_PORT = 2; // 4Bit wait10ms(1); LCD_PORT = 10; // 2-Line Mode 5x8 wait10ms(1); LCD_Enable(); LCD_PORT = 15; // Cursor =1, Blink =1, Disp = 1 _delay_ms(1); LCD_Enable(); LCD_PORT = 1; // clear Disp LCD_Enable(); LCD_PORT = 6; //Kursor nach rechts wandernd, kein Display shift wait10ms(1); } Das Habe ich hier: http://www.sprut.de/electronic/lcd/index.htm#4x40 her und aus dem Datenblatt des Controllers. Aber es funktioniert leider nicht richtig. Die Zeichen sehen arg komisch aus, es hält sich auch nicht an das Layout (Zeilen) und löschen (D0 =1) geht auch nicht! Hat von euch vielleicht jemand eine Idee was ich falsch mache? Die HW habe ich bereits gründlich debugged, da liegt der Fehler nicht! // LCD Display #define LCD_DDR DDRC #define LCD_PORT PORTC #define LCD_PIN PINC #define LCD_D0 PINC0 #define LCD_D1 PINC1 #define LCD_D2 PINC2 #define LCD_D3 PINC3 #define LCD_RS PINC4 #define LCD_RW PINC5 #define LCD_ENB PINC6 Servus Sven!
noch zur Info: void LCD_Enable(void) { LCD_PORT |= (1<<LCD_ENB); _delay_us(50); LCD_PORT &= ~(1<<LCD_ENB); }
Ich würde die Warteschleifen kontrollieren und ggf. mal um 50%/100% hochsetzen. Und ich würde die elektrischen Verbindungen aller Leitungen checken, ob Unterbrechungen oder Vertauschungen vorhanden sind. Kannst du anhand des Controllerdatenblatts und der Charactertabelle dort drin eine Systematik ausmachen zwischen deinen Wunschzeichen und den angezeigte Zeichen?
Grüß euch! Mit den Wartezeiten hab ich schon gespielt, das hatte bislang keinen Erfolg. Die Leitungen hab ich alle kontrolliert, jede einzeln auf Hi geschaltet und mit dem Multimeter am LCD-Sockel nachgemessen. Komisch ist ja, dass nicht mal das löschen des LCD hinhaut, es liegt damit wohl an der Initialisierung. Hab dazu auch unterschiedliche Lösungen gefunden, und ausprobiert. Hat von euch auch Jemand auch so ein Display, und kann mal die Initialisierungen vergleichen? Servus Sven!
Hab das nochmal überarbeitet, anhand eines Datenblattes das ich bei Electronic Assembly gefunden habe! Dort wird folgende Initialisierung vorgeschlagen: void initLCD(void) // Initialisierung des Displays |||4x20 Display ist ein 2 Zeilen 5*8 Dislpay!||| { LCD_DDR = 0xFF; // alle Pins PortC auf Ausgang schalten wait10ms(10); LCD_setRS(0); LCD_setRW(0); LCD_setENB(0); LCD_PORT = 2; // 4Bit _delay_ms(5); LCD_PORT = 2; // 4Bit _delay_ms(3); LCD_PORT = 8; // 2-Line Mode 5x8 _delay_ms(5); LCD_PORT = 0; // 2-Line Mode 5x8 _delay_ms(3); //LCD_Enable(); LCD_PORT = 15; // Cursor =1, Blink =1, Disp = 1 _delay_ms(5); LCD_PORT = 0; // Cursor auf Anfang _delay_ms(3); LCD_PORT = 1; // Display löschen _delay_ms(5); //LCD_Enable(); LCD_PORT = 0; // clear Disp _delay_ms(3); LCD_PORT = 6; //Kursor nach rechts wandernd, kein Display shift wait10ms(1); } Hat aber auch nichts gebracht!
So ist das dann doch übersichtlicher: void LCD_Command(char byte_high) //Pin0-Pin3 sind die Datenleitungen { putch(byte_high); // Ausgeben auf Uart für Debug! char byte_low = byte_high; //Sichern für unteres Nibble // Oberes Nibble zuerst ausgeben byte_high &= ~0x0f; //unteres Nibbel 0 setzen byte_high = byte_high>>4; //Wert ins untere Nibble schieben. LCD_PORT = byte_high; //oberes Nibbel Ausgeben LCD_Enable(); //Enable Impuls putch(byte_high); // Ausgeben auf Uart für Debug! // Dann unteres Nibble byte_low &= ~0x0f; //oberes Nibble löschen LCD_PORT = byte_low; //unteres Nibbel Ausgeben LCD_Enable(); putch(byte_low); // Ausgeben auf Uart für Debug! //_delay_us(50); _delay_ms(5); } void initLCD(void) // Initialisierung des Displays |||4x20 Display ist ein 2 Zeilen 5*8 Dislpay!||| { LCD_DDR = 0xFF; // alle Pins PortC auf Ausgang schalten wait10ms(10); LCD_setRS(0); LCD_setRW(0); LCD_setENB(0); LCD_PORT = 2; // 4Bit _delay_ms(5); LCD_Command(40); // 4 Bit 5x8 LCD_Command(0x0F); // Cursor =1, Blink =1, Disp = 1 LCD_Command(0x01); // Display löschen LCD_Command(6); //Kursor nach rechts wandernd, kein Display shift wait10ms(1); }
war noch ein Bug drin muss so sein, sorry: byte_low &= 0x0f; //oberes Nibble löschen
Ich benutze folgenden CODE für eine 4x20 LCD von electronic assembly mit KS0073 und mega32. #include <avr/io.h> //LCD-Steuerleitungen #define LCD_CONTROL PORTA #define LCD_CONTROL_DIR DDRA #define LCD_RS 1 //PortD.4 #define LCD_RW 2 //PortD.6 #define LCD_EN 3 //PortD.5 //LCD-Datenport: Reihenfolge des High Nibbles (4-7) muss eingehalten werden, //Port kann getauscht werden: #define LCD_DATEN PORTA #define LCD_DATEN_DIR DDRA #define LCD_BF PINA #define LCD_D4 4 //Porta.4 #define LCD_D5 5 //Porta.5 #define LCD_D6 6 //Porta.6 #define LCD_D7 7 //Porta.7 //********************************************************************** *************** //Delay ca. 0.5*x ms bei 16 MHz //********************************************************************** *************** void delay (unsigned int x) { unsigned int a, y; for (a=0; a<x; a++) { for (y=0; y<1333; y++) { asm("nop"); } } } //********************************************************************** *************** //LCD code //********************************************************************** *************** void lcd_busy(void) { unsigned char test=0; LCD_CONTROL &= ~(1<<LCD_RS); LCD_CONTROL |= (1<<LCD_RW); LCD_DATEN_DIR &= ~((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); //Eingang für BUSY FLAG while (1) { LCD_CONTROL|=(1<<LCD_EN); asm("nop"); asm("nop"); if (!(LCD_BF & (1<<LCD_D7))) test = 1; LCD_CONTROL &= ~(1<<LCD_EN); LCD_CONTROL |=(1<<LCD_EN); asm("nop"); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); if (test) break; } LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); //Ausgänge } void lcd_befehl(unsigned char befehl) { LCD_CONTROL &= ~((1<<LCD_RS) | (1<<LCD_RW)); LCD_DATEN = ((0b11110000 & befehl)|(LCD_DATEN& 0b00001111)); //PORTA = HIGH Nibble LCD_CONTROL |= (1<<LCD_EN); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); //High Nibble mit fallender Flanke übernehmen LCD_DATEN = ((0b11110000 & (befehl<<4))|(LCD_DATEN& 0b00001111)); //Low Nibble LCD_CONTROL |= (1<<LCD_EN); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); lcd_busy(); } void lcd_char(unsigned char daten) { LCD_CONTROL |=(1<<LCD_RS); //Für Daten LCD_CONTROL &= ~(1<<LCD_RW); //LCD soll lesen LCD_DATEN = ((0b11110000 & daten)|(LCD_DATEN& 0b00001111)); LCD_CONTROL |= (1<<LCD_EN); //Daten übernehmen asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); LCD_DATEN = ((0b11110000 & (daten<<4))|(LCD_DATEN& 0b00001111)); LCD_CONTROL|= (1<<LCD_EN); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); lcd_busy(); } void lcd_string (unsigned char *string) { while (*string) lcd_char (*string++); } void lcd_init(void) { delay(20); LCD_CONTROL_DIR |=((1<<LCD_RW)|(1<<LCD_EN)|(1<<LCD_RS)); //Ausgänge LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); //Ausgänge LCD_CONTROL &= ~(1<<LCD_EN); lcd_befehl(0b00100100); //4Bit Modus mit extension Bit RE=1 lcd_befehl(0b00001001); //4 Zeilen lcd_befehl(0b00100000); //extension Bit RE = 0 lcd_befehl(0b00001110); //LCD an lcd_befehl(0b00000001); //LCD löschen+Home lcd_befehl(0b00000110); } int main(void) { lcd_init(); lcd_string("Hallo Welt!"); return 0; }
@Sven wie viel Zeit läßt du dem Display nach dem PowerUp? AFAIK sollte man dem schon ein bisschen Bedenkzeit lassen ehe man es mit Daten bombadiert...
Hallo, void initLCD(void) { LCD_DDR = 0xEF; // alle Pins PortC auf Ausgang schalten wait10ms(10); int i; for (i= 0;i<3;i++) { LCD_PORT = 3; // 8Bit wait10ms(1); } LCD_PORT = 2; // 4Bit wait10ms(1); LCD_PORT = 10; // 2-Line Mode 5x8 wait10ms(1); LCD_Enable(); LCD_PORT = 15; // Cursor =1, Blink =1, Disp = 1 _delay_ms(1); LCD_Enable(); LCD_PORT = 1; // clear Disp LCD_Enable(); LCD_PORT = 6; //Kursor nach rechts wandernd, kein Display shift wait10ms(1); } ich vermisse hier meherere LCD_Enable(); und das setzen von RS und RW. Im geänderten Code steht zwar dazu was drin aber die E-Pulse fehlen immernoch. Timingdiagramm des KS0073 genauer ansehen. ;) Das Display nimmt Deine anliegenden Daten erst mit dem H-Puls an Enable zur Kenntnis. In Deiner Gruß aus Berlin Michael
In der LCD_Command Funktion setze ich erst die Ausgänge dann das Enable Signal für 50 µs. Vor der Initialisierung warte ich 100ms.Den Code von oben werde ich mal mit meinem vergleichen. Danke Euch!
Ich habe auch mal die Busy Funktion übernommen. So sieht es jetzt aus: // -------- LCD Funktionen ---------------------------- void initLCD(void) // Initialisierung des Displays |||4x20 Display ist ein 2 Zeilen 5*8 Dislpay!||| { LCD_DDR = 0xFF; // alle Pins PortC auf Ausgang schalten wait10ms(100); LCD_setRS(0); LCD_setRW(0); LCD_setENB(0); LCD_PORT = 2; // 4Bit _delay_ms(5); LCD_Command(40); // 4 Bit LCD_Command(15); // Cursor =1, Blink =1, Disp = 1 LCD_Command(1); // Display löschen LCD_Command(6); //Kursor nach rechts wandernd, kein Display shift wait10ms(1); } void LCD_setRS(uint8_t Val) { if (Val == 0) LCD_PORT &= ~(1 << LCD_RS); if (Val == 1) LCD_PORT |= (1 << LCD_RS); } void LCD_setRW(uint8_t Val) { if (Val == 0) LCD_PORT &= ~(1 << LCD_RW); if (Val == 1) LCD_PORT |= (1 << LCD_RW); } void LCD_setENB(uint8_t Val) { if (Val == 0) LCD_PORT &= ~(1 << LCD_ENB); if (Val == 1) LCD_PORT |= (1 << LCD_ENB); } void LCD_Enable(void) { LCD_PORT |= (1<<LCD_ENB); //Enable auf High _delay_us(40); //40ms langer Impuls LCD_PORT &= ~(1<<LCD_ENB); //Enable auf Low } void LCD_Clear(void) { LCD_Command(0x01); _delay_ms(5); } void LCD_Out(char *text) { while (*text) { LCD_Data(*text++); //Zeichen ausgeben auf LCD } } void LCD_Data(char byte_high) { LCD_busy(); char text[] = "LCD_Data():"; UART_Text_out(text,0); putch(byte_high); // Ausgeben auf Uart für Debug! char byte_low = byte_high; //Sichern für unteres Nibble // Oberes Nibble zuerst ausgeben byte_high = byte_high>>4; //Wert ins untere Nibble schieben. byte_high |= (1<<LCD_RS); //RS setzen LCD_PORT = byte_high; //oberes Nibbel des Befehls Ausgeben LCD_Enable(); //Enable Impuls putch(byte_high); // Ausgeben auf Uart für Debug! // Dann unteres Nibble byte_low &= 0x0f; //oberes Nibble löschen byte_low |= (1<<LCD_RS); //RS setzen LCD_PORT = byte_low; //unteres Nibbel Ausgeben LCD_Enable(); putch(byte_low); // Ausgeben auf Uart für Debug! putch('\n'); //_delay_us(50); _delay_ms(5); LCD_busy(); } void LCD_Command(char byte_high) //Pin0-Pin3 sind die Datenleitungen { LCD_busy(); putch(byte_high); // Ausgeben auf UART für Debug! char byte_low = byte_high; //Sichern für unteres Nibble // Oberes Nibble zuerst ausgeben byte_high = byte_high>>4; //Wert ins untere Nibble schieben. LCD_PORT = byte_high; //oberes Nibbel des Befehls Ausgeben LCD_Enable(); //Enable Impuls putch(byte_high); // Ausgeben auf UART für Debug! // Dann unteres Nibble byte_low &= 0x0f; //oberes Nibble löschen LCD_PORT = byte_low; //unteres Nibbel Ausgeben LCD_Enable(); putch(byte_low); // Ausgeben auf Uart für Debug! //_delay_us(50); _delay_ms(5); LCD_busy(); } void LCD_busy(void) { unsigned char test=0; LCD_PORT &= ~(1<<LCD_RS); LCD_PORT |= (1<<LCD_RW); LCD_DDR &= ~((1<<LCD_D3)|(1<<LCD_D2)|(1<<LCD_D1)|(1<<LCD_D0)); //Eingang für BUSY FLAG while (1) { LCD_PORT|=(1<<LCD_ENB); asm("nop"); asm("nop"); if (!(LCD_BF & (1<<LCD_D3))) test = 1; LCD_PORT &= ~(1<<LCD_ENB); LCD_PORT |=(1<<LCD_ENB); asm("nop"); asm("nop"); LCD_PORT &= ~(1<<LCD_ENB); if (test) break; } LCD_DDR = 0xFF; //Ausgänge } Geht aber leider immer noch nicht. :(
Hast du mal meinen Code 1:1 übernommen und die entsprechende Pinbelegung des LCDs angepasst? Bei mir geht der CODE mit dem LCD von EA DIP204-4 von Electronic Assembly. Hast du auch den Kontrast richtig eingestellt? Welches LCD (Typ, Hersteller) hast du genau? Funktioniert die UART-Ausgabe, oder bleibt er irgendwo bei der busy-Abfrage hängen?
Hallo Peter, deinen Code werde ich jetzt mal probieren. Bisher habe ich nur meinen angepasst. Ich habe das Gleiche Display wie du. Die UART-Ausgabe geht, er bleibt nur hängen, wenn ich das Display abziehe! Habe eben nochmal die restlichen 4 Datenleitungen (0-3) über einen 1KO Widerstand auf Masse gelegt, nicht das da noch irgendwas rumspukt.Der Kontrast sollte OK sein, ich sehe ja manchmal Zeichen, wenn auch nicht die gewünschten. Wenn er falsch wäre, wäre doch entweder alles Schwarz, oder grün, oder nicht? Derzeit sehe ich allerdings garnichts mehr auf dem Display.. Sven
Hab es so angepasst: #include <avr/io.h> //LCD-Steuerleitungen #define LCD_CONTROL PORTC #define LCD_CONTROL_DIR DDRC #define LCD_RS 5 //PortD.4 #define LCD_RW 6 //PortD.6 #define LCD_EN 7 //PortD.5 #define LCD_DATEN PORTC #define LCD_DATEN_DIR DDRC #define LCD_BF PINC #define LCD_D4 1 //Porta.4 #define LCD_D5 2 //Porta.5 #define LCD_D6 3 //Porta.6 #define LCD_D7 4 //Porta.7 //********************************************************************** *************** //Delay ca. 0.5*x ms bei 16 MHz //********************************************************************** *************** void delay (unsigned int x) { unsigned int a, y; for (a=0; a<x; a++) { for (y=0; y<1333; y++) { asm("nop"); } } } //********************************************************************** *************** //LCD code //********************************************************************** *************** void lcd_busy(void) { unsigned char test=0; LCD_CONTROL &= ~(1<<LCD_RS); LCD_CONTROL |= (1<<LCD_RW); LCD_DATEN_DIR &= ~((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); //Eingang für BUSY FLAG while (1) { LCD_CONTROL|=(1<<LCD_EN); asm("nop"); asm("nop"); if (!(LCD_BF & (1<<LCD_D7))) test = 1; LCD_CONTROL &= ~(1<<LCD_EN); LCD_CONTROL |=(1<<LCD_EN); asm("nop"); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); if (test) break; } LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); //Ausgänge } void lcd_befehl(unsigned char befehl) { LCD_CONTROL &= ~((1<<LCD_RS) | (1<<LCD_RW)); LCD_DATEN = ((0xF0 & befehl)|(LCD_DATEN& 0x0F)); //PORTA = HIGH Nibble LCD_CONTROL |= (1<<LCD_EN); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); //High Nibble mit fallender Flanke übernehmen LCD_DATEN = ((0xF0 & (befehl<<4))|(LCD_DATEN& 0x0F)); //Low Nibble LCD_CONTROL |= (1<<LCD_EN); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); lcd_busy(); } void lcd_char(unsigned char daten) { LCD_CONTROL |=(1<<LCD_RS); //Für Daten LCD_CONTROL &= ~(1<<LCD_RW); //LCD soll lesen LCD_DATEN = ((0xF0 & daten)|(LCD_DATEN& 0x0F)); LCD_CONTROL |= (1<<LCD_EN); //Daten übernehmen asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); LCD_DATEN = ((0xF0 & (daten<<4))|(LCD_DATEN& 0x0F)); LCD_CONTROL|= (1<<LCD_EN); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); lcd_busy(); } void lcd_string (unsigned char *string) { while (*string) lcd_char (*string++); } void lcd_init(void) { delay(20); LCD_CONTROL_DIR |=((1<<LCD_RW)|(1<<LCD_EN)|(1<<LCD_RS)); //Ausgänge LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); //Ausgänge LCD_CONTROL &= ~(1<<LCD_EN); lcd_befehl(36); //4Bit Modus mit extension Bit RE=1 lcd_befehl(9); //4 Zeilen lcd_befehl(32); //extension Bit RE = 0 lcd_befehl(14); //LCD an lcd_befehl(1); //LCD löschen+Home lcd_befehl(6); } int main(void) { lcd_init(); lcd_string("Hallo Welt!"); return 0; } Aber Das Display bleibt leer! Schade. Was mach ich nur falsch?
Du musst die Reihenfolge einhalten: FALSCH: #define LCD_D4 1 //Porta.4 #define LCD_D5 2 //Porta.5 #define LCD_D6 3 //Porta.6 #define LCD_D7 4 //Porta.7 Richtig: #define LCD_D4 4 //Porta.4 #define LCD_D5 5 //Porta.5 #define LCD_D6 6 //Porta.6 #define LCD_D7 7 //Porta.7 sonst funktioniert die Aufteilung der Nibbels mit meinem Code nicht. Mit AVR-Studio kannst du auch leicht simulieren, ob die richtigen Signale am Port ausgegeben werden.
Ach stimmt natürlich. Aber dann müsste ich es ja umlöten. AVRStudio hab ich leider nicht. Denkst du denn ich habe einen Fehler in meinem Code (oben)?
so müsste es jetzt auch mit deiner Pinbelegung funktionieren #include <avr/io.h> //LCD-Steuerleitungen #define LCD_CONTROL PORTC #define LCD_CONTROL_DIR DDRC #define LCD_RS 5 //PortD.4 #define LCD_RW 6 //PortD.6 #define LCD_EN 7 //PortD.5 //LCD-Datenport: Reihenfolge des High Nibbles (4-7) muss eingehalten werden, //Port kann getauscht werden: #define LCD_DATEN PORTC #define LCD_DATEN_DIR DDRC #define LCD_BF PINC #define LCD_D4 1 //Porta.4 #define LCD_D5 2 //Porta.5 #define LCD_D6 3 //Porta.6 #define LCD_D7 4 //Porta.7 //********************************************************************** *************** //Delay ca. 0.5*x ms bei 16 MHz //********************************************************************** *************** void delay (unsigned int x) { unsigned int a, y; for (a=0; a<x; a++) { for (y=0; y<1333; y++) { asm("nop"); } } } //********************************************************************** *************** //LCD code //********************************************************************** *************** void lcd_busy(void) { unsigned char test=0; LCD_CONTROL &= ~(1<<LCD_RS); LCD_CONTROL |= (1<<LCD_RW); LCD_DATEN_DIR &= ~((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); //Eingang für BUSY FLAG while (1) { LCD_CONTROL|=(1<<LCD_EN); asm("nop"); asm("nop"); if (!(LCD_BF & (1<<LCD_D7))) test = 1; LCD_CONTROL &= ~(1<<LCD_EN); LCD_CONTROL |=(1<<LCD_EN); asm("nop"); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); if (test) break; } LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); //Ausgänge } void lcd_befehl(unsigned char befehl) { LCD_CONTROL &= ~((1<<LCD_RS) | (1<<LCD_RW)); LCD_DATEN = (0b11110000 & befehl)>>3|(LCD_DATEN& 0b11100001); LCD_CONTROL |= (1<<LCD_EN); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); //High Nibble mit fallender Flanke übernehmen LCD_DATEN = ((0b11110000 & (befehl<<4))>>3)|(LCD_DATEN& 0b11100001); //Low Nibble LCD_CONTROL |= (1<<LCD_EN); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); lcd_busy(); } void lcd_char(unsigned char daten) { LCD_CONTROL |=(1<<LCD_RS); //Für Daten LCD_CONTROL &= ~(1<<LCD_RW); //LCD soll lesen LCD_DATEN = (0b11110000 & daten)>>3|(LCD_DATEN& 0b11100001); LCD_CONTROL |= (1<<LCD_EN); //Daten übernehmen asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); LCD_DATEN = ((0b11110000 & (daten<<4))>>3)|(LCD_DATEN& 0b11100001); LCD_CONTROL|= (1<<LCD_EN); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); lcd_busy(); } void lcd_string (unsigned char *string) { while (*string) lcd_char (*string++); } void lcd_init(void) { LCD_CONTROL_DIR |=((1<<LCD_RW)|(1<<LCD_EN)|(1<<LCD_RS)); //Ausgänge LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); //Ausgänge LCD_CONTROL &= ~(1<<LCD_EN); delay(20); lcd_befehl(0b00100100); //4Bit Modus mit extension Bit RE=1 lcd_befehl(0b00001001); //4 Zeilen lcd_befehl(0b00100000); //extension Bit RE = 0 lcd_befehl(0b00001110); //LCD an lcd_befehl(0b00000001); //LCD löschen+Home lcd_befehl(0b00000110); } int main(void) { lcd_init(); lcd_string("Hallo Welt!"); return 0; }
Danke für die Hilfe! Leider bleibt das Display leer. Werde nochmal alles durchmessen, vielleicht ist was abgegangen. Servus Sven
Hallo, das muss so sein: #define LCD_RS 4 //PortD.4 #define LCD_RW 5 //PortD.6 #define LCD_EN 6 //PortD.5 aber ansonsten ist die HW OK! Aber das Display ist leider immer noch leer.
Nochmal zur HW,muss ich Reset noch irgendwie anschließen? Die Kontrastspannung kann ich (ohne LCD) zwischen 0 un d1,4V einstellen, wenn ich das LCD anschließe liegen an dem PIN -0.13V an.D4-D7 hab ich direkt an die PINS des µC angeschlossen, D0-D3 über 1KOhm auf GND. Passt das soweit?
Sag mir mal genau deine komplette Pinbelegung. Ich ändere dann das Programm ab. Das obige modifizierte Programm Funktioniert nur mit dieser Reihenfolge: #define LCD_DATEN PORTC #define LCD_DATEN_DIR DDRC #define LCD_BF PINC #define LCD_D4 1 //Porta.4 #define LCD_D5 2 //Porta.5 #define LCD_D6 3 //Porta.6 #define LCD_D7 4 //Porta.7 kein Wunder das es bei dir nicht geht. Sonst müsste alles OK sein!
So sieht meine Pinbelegung aus: #define LCD_DDR DDRC #define LCD_PORT PORTC #define LCD_PIN PINC #define LCD_D0 PINC0 #define LCD_D1 PINC1 #define LCD_D2 PINC2 #define LCD_D3 PINC3 #define LCD_RS PINC4 #define LCD_RW PINC5 #define LCD_ENB PINC6
Ich denke du hast anstatt D0-D3 D4-D7 gemeint. So sollt es jetzt eigentlich Funktionieren. Du kannst auch noch ein paar nops mehr einfügen. Ich hatte auch schon mal das Problem als ich das LCD an langen Leitungen hatte, waren die Pegelwechsel zu schnell. #include <avr/io.h> //LCD-Steuerleitungen #define LCD_CONTROL PORTC #define LCD_CONTROL_DIR DDRC #define LCD_RS 4 //PortD.4 #define LCD_RW 5 //PortD.6 #define LCD_EN 6 //PortD.5 //LCD-Datenport: Reihenfolge des High Nibbles (4-7) muss eingehalten werden, //Port kann getauscht werden: #define LCD_DATEN PORTC #define LCD_DATEN_DIR DDRC #define LCD_BF PINC #define LCD_D4 0 //Porta.4 #define LCD_D5 1 //Porta.5 #define LCD_D6 2 //Porta.6 #define LCD_D7 3 //Porta.7 //********************************************************************** *************** //Delay ca. 0.5*x ms bei 16 MHz //********************************************************************** *************** void delay (unsigned int x) { unsigned int a, y; for (a=0; a<x; a++) { for (y=0; y<1333; y++) { asm("nop"); } } } //********************************************************************** *************** //LCD code //********************************************************************** *************** void lcd_busy(void) { unsigned char test=0; LCD_CONTROL &= ~(1<<LCD_RS); LCD_CONTROL |= (1<<LCD_RW); LCD_DATEN_DIR &= ~((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); //Eingang für BUSY FLAG while (1) { LCD_CONTROL|=(1<<LCD_EN); asm("nop"); asm("nop"); if (!(LCD_BF & (1<<LCD_D7))) test = 1; LCD_CONTROL &= ~(1<<LCD_EN); LCD_CONTROL |=(1<<LCD_EN); asm("nop"); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); if (test) break; } LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); //Ausgänge } void lcd_befehl(unsigned char befehl) { LCD_CONTROL &= ~((1<<LCD_RS) | (1<<LCD_RW)); LCD_DATEN = (0b11110000 & befehl)>>4|(LCD_DATEN& 0b11110000); LCD_CONTROL |= (1<<LCD_EN); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); //High Nibble mit fallender Flanke übernehmen LCD_DATEN = ((0b11110000 & (befehl<<4))>>4)|(LCD_DATEN& 0b11110000); //Low Nibble LCD_CONTROL |= (1<<LCD_EN); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); lcd_busy(); } void lcd_char(unsigned char daten) { LCD_CONTROL |=(1<<LCD_RS); //Für Daten LCD_CONTROL &= ~(1<<LCD_RW); //LCD soll lesen LCD_DATEN = (0b11110000 & daten)>>4|(LCD_DATEN& 0b11110000); LCD_CONTROL |= (1<<LCD_EN); //Daten übernehmen asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); LCD_DATEN = ((0b11110000 & (daten<<4))>>4)|(LCD_DATEN& 0b11110000); LCD_CONTROL|= (1<<LCD_EN); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); lcd_busy(); } void lcd_string (unsigned char *string) { while (*string) lcd_char (*string++); } void lcd_init(void) { LCD_CONTROL_DIR |=((1<<LCD_RW)|(1<<LCD_EN)|(1<<LCD_RS)); //Ausgänge LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); //Ausgänge LCD_CONTROL &= ~(1<<LCD_EN); delay(20); lcd_befehl(0b00100100); //4Bit Modus mit extension Bit RE=1 lcd_befehl(0b00001001); //4 Zeilen lcd_befehl(0b00100000); //extension Bit RE = 0 lcd_befehl(0b00001110); //LCD an lcd_befehl(0b00000001); //LCD löschen+Home lcd_befehl(0b00000110); } int main(void) { lcd_init(); lcd_char(0b10100011); lcd_string("Hallo Welt!"); return 0; }
Ich musste es noch so abändern, weil mein Compiler keine Zahlen im Binärformat mag.. #include <avr/io.h> //LCD-Steuerleitungen #define LCD_CONTROL PORTC #define LCD_CONTROL_DIR DDRC #define LCD_RS 4 //PortD.4 #define LCD_RW 5 //PortD.6 #define LCD_EN 6 //PortD.5 //LCD-Datenport: Reihenfolge des High Nibbles (4-7) muss eingehalten //Port kann getauscht werden: #define LCD_DATEN PORTC #define LCD_DATEN_DIR DDRC #define LCD_BF PINC #define LCD_D4 0 //Porta.4 #define LCD_D5 1 //Porta.5 #define LCD_D6 2 //Porta.6 #define LCD_D7 3 //Porta.7 //********************************************************************** *************** //Delay ca. 0.5*x ms bei 16 MHz //********************************************************************** *************** void delay (unsigned int x) { unsigned int a, y; for (a=0; a<x; a++) { for (y=0; y<1333; y++) { asm("nop"); } } } //********************************************************************** *************** //LCD code //********************************************************************** *************** void lcd_busy(void) { unsigned char test=0; LCD_CONTROL &= ~(1<<LCD_RS); LCD_CONTROL |= (1<<LCD_RW); LCD_DATEN_DIR &= ~((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); //Eingang für BUSY FLAG while (1) { LCD_CONTROL|=(1<<LCD_EN); asm("nop"); asm("nop"); if (!(LCD_BF & (1<<LCD_D7))) test = 1; LCD_CONTROL &= ~(1<<LCD_EN); LCD_CONTROL |=(1<<LCD_EN); asm("nop"); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); if (test) break; } LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); //Ausgänge } void lcd_befehl(unsigned char befehl) { LCD_CONTROL &= ~((1<<LCD_RS) | (1<<LCD_RW)); LCD_DATEN = (0xF0 & befehl)>>4|(LCD_DATEN& 0xF0); LCD_CONTROL |= (1<<LCD_EN); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); //High Nibble mit fallender Flanke LCD_DATEN = ((0xF0 & (befehl<<4))>>4)|(LCD_DATEN& 0xF0); //Low Nibble LCD_CONTROL |= (1<<LCD_EN); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); lcd_busy(); } void lcd_char(unsigned char daten) { LCD_CONTROL |=(1<<LCD_RS); //Für Daten LCD_CONTROL &= ~(1<<LCD_RW); //LCD soll lesen LCD_DATEN = (0xF0 & daten)>>4|(LCD_DATEN& 0xF0); LCD_CONTROL |= (1<<LCD_EN); //Daten übernehmen asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); LCD_DATEN = ((0xF0 & (daten<<4))>>4)|(LCD_DATEN& 0xF0); LCD_CONTROL|= (1<<LCD_EN); asm("nop"); LCD_CONTROL &= ~(1<<LCD_EN); lcd_busy(); } void lcd_string (unsigned char *string) { while (*string) lcd_char (*string++); } void lcd_init(void) { LCD_CONTROL_DIR |=((1<<LCD_RW)|(1<<LCD_EN)|(1<<LCD_RS)); //Ausgänge LCD_DATEN_DIR |=((1<<LCD_D7)|(1<<LCD_D6)|(1<<LCD_D5)|(1<<LCD_D4)); //Ausgänge LCD_CONTROL &= ~(1<<LCD_EN); delay(20); /* lcd_befehl(0b00100100); //4Bit Modus mit extension Bit RE=1 lcd_befehl(0b00001001); //4 Zeilen lcd_befehl(0b00100000); //extension Bit RE = 0 lcd_befehl(0b00001110); //LCD an lcd_befehl(0b00000001); //LCD löschen+Home lcd_befehl(0b00000110);*/ lcd_befehl(36); //4Bit Modus mit extension Bit RE=1 lcd_befehl(9); //4 Zeilen lcd_befehl(32); //extension Bit RE = 0 lcd_befehl(14); //LCD an lcd_befehl(1); //LCD löschen+Home lcd_befehl(6); } int main(void) { lcd_init(); // lcd_char(0b10100011); lcd_char(0xA3); lcd_string("Hallo Welt!"); return 0; } Es geht! Der Text erscheint tatsächlich! Hab schon nicht mehr daran geglaubt.! Vielen Dank Peter, ohne deine Hilfe hätte ich das aufgegeben, so lang ich mich nun damit rumgeärgert habe. Mal sehen, wo der Fehler in meinem Code ist. Servus, Sven!
Das hier war der Fehler in meinem Programm: void LCD_Enable(void) { LCD_PORT |= (1<<LCD_ENB); //Enable auf High delay_us(60); //60ms langer Impuls LCD_PORT &= ~(1<<LCD_ENB); //Enable auf Low } Und so geht es: void LCD_Enable(void) { LCD_PORT |= (1<<LCD_ENB); //Enable auf High asm("nop"); LCD_PORT &= ~(1<<LCD_ENB); //Enable auf Low } So ganz verstanden hab ich es aber noch nicht.
Hallo, Ich habe eine ganz ähnliches Problem. Bei meinem Display werden nach dem initalisieren ein Text in alle 4 Zeilen geschrieben. Dieser erscheint auch. Aber nur Kurz und mit wenig Kontrast. ca. 2 Sec. später löscht er sich wieder und nur Zeile 1 und Zeile 3 bleiben sichtbar(mit vollem Kontrast). Dann bewegt sich der Cursor?? Im Anschluss wird der Text gelöscht und der Cursor erscheint blinkend. 1 sec später erscheint wieder Zeile 1 und 3. Mir kommt das ganze vor als ob ich in einer Schleife hängen würde. Aber weit und breit hab ich keine Schleife reinprogrammiert. Hat jemand von euch eine ähnliche Erfahrung? An was könnte das nich liegen?Zu wenig Strom am Display? Display Treiber Schrott? Es handelt sich um den KS0066 als Display Treiber Chip(Reichelt LCD 204B LED) (4bit Modus, Hintergrundbeleuchtung nicht angeschlossen) Gruß Uli
Hab auch so ein ähnliches problem... das display schaltet sich für ca. 2-3 sekunden an und geht dann wieder aus! Hab keine ahnung woran das liegen könnte.... das display ist ein lcd1602A und liegt an portc. quellcode befindet sich im anhang...
Meine Vermutung: Das LCD bekommt über die Drähtchen zu wenig Strom. Und dann macht der Treiberbaustein was er will Gruß Uli
@ Uli Eigene Diskussion aufmachen und Projektfiles mit Sourcecode, Makefile etc. bereitstellen. Link zum Datenblatt des LCD ist auch hilfreich. Schaltplan kann auch helfen. Dann hoffen, dass die Problembeschreibung so gut ist, dass jemand auf das Problem anspringt. @ Matze Meinst du dieses LC-Display LCD-1602A von Crystalfontz? http://www.datasheet4u.com/html/L/C/D/LCD-1602A_CA.pdf.html > PORTC = 0b00100000; //4 Bit Mode setzen Bist du sicher, dass da nicht 3x was zum LCD geschickt werden muss, bevor du so in den 4-Bit Modus wechseln kannst (vgl. Seite 17 im PDF oben)?
Ja es muß dreimal gesendet werden....hatte nur ein datenblatt das halb englisch halb chineschisch war. da infos rauszuziehen ist schlecht... vielen dank für die hilfe.... mfg matze
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.