Hallo zusammen, da ich keinen richtigen Beispielcode für das Ansteuern eines LCD Displays über einen ATmega16 gefunden habe, habe ich diesen Beitrag erstellt. Ich habe einen LCD Displaytech 204B an den PORTA meines ATmega16 angeschlossen, so wie es im Datenblatt des LCD Displaytech 204B stand. Dort steht auch welche Ports ich schalten muss um ein bestimmtes Symbol auf den LCD zu bekommen. Da ich jedoch noch keine Erfahrungen mit LCD Displays habe, wollte ich euch um einen Beispielcode bitten, der irgend ein Zeichen auf den Bildschirm zaubert. Datenblatt habe ich angehangen. Danke schonmal im voraus, Tobias
Tobias Neumann schrieb: > Hallo zusammen, > da ich keinen richtigen Beispielcode für das Ansteuern eines LCD > Displays über einen ATmega16 gefunden habe, habe ich diesen Beitrag > erstellt. Für dein spezifisches LCD wirdsich wahrscheinlich nicht allzuviel finden. Aber für Standard-LCD findet sich jede Menge. Dein Controller auf dem LCD ist ein KS0063B und so wie ich das auf die Schnelle sehe, funktioniert der sehr ähnlich einem HD7445. > Ich habe einen LCD Displaytech 204B an den PORTA meines > ATmega16 angeschlossen, so wie es im Datenblatt des LCD Displaytech 204B > stand. Was genau hast du wo angehängt. Ich glaube kaum, dass im Datenblatt exakt steht, welchen LCD Anschluss du an welchen Pin von deinem Port A angeschlossen hast. > Symbol auf den LCD zu bekommen. Da ich jedoch noch keine Erfahrungen mit > LCD Displays habe, wollte ich euch um einen Beispielcode bitten, der > irgend ein Zeichen auf den Bildschirm zaubert. Studiere die LCD Abschnitte in den Tutorials http://www.mikrocontroller.net/articles/AVR-Tutorial:_LCD http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung Auch wenn dein LCD nicht 100% identisch ist zu den dort gezeigten, ist es doch ähnlich genug, dass dieselben Prinzipien gehen.
Hallo, ich schreibe kurz nieder was ich wo angeschlossen habe: VSS -> GND VDD -> 5V VO -> nicht angeschlossen RS -> PD5 R/W -> PD6 E -> PD7 DB0-DB7 -> PA0-PA7 A -> nicht angeschlossen K -> nicht angeschlossen Ich lese mir mal die Tutorials durch und hoffe daraus schlauer zu werden.. danke schonmal :)
Das Problem ist das ich den Controller in C programmiere und mit den Codebeispielen nicht anfangen kann.. =/
Tobias Neumann schrieb: > Das Problem ist das ich den Controller in C programmiere und mit den > Codebeispielen nicht anfangen kann.. =/ 1) Im AVR-GCC-Tutorial sind die Codebeispiele in C 2) Wenn du nichts weiter tun willst als Codebeispiele abtippen ohne verstehen zu wollen was da passiert, ok, dann versteh ich, dass dich der Link ins Assemblerbeispiel nicht weiterbringt. Andere lesen sich den trotzdem durch und holen sich aus dem Text Informationen raus, die so nicht oder in anderer Formulierung im C-Tutorial stehen. Auf die Art ergänzen sich manchmal mehrere Tutorien: Was im einen nicht steht, steht im anderen. Was im einen unklar bleibt, wird im anderen erklärt.
VO -> nicht angeschlossen Ohne Kontrastspannung ist die Programmiersprache auch egal. Zeigt sowieso nix an;)
Oh, ich habe den zweiten Link total vergessen gehabt. Dort ist das Tutorial mit C-Code Beispielen.. sorry.. Ich arbeite mich mal durch.
Das Vee aus dem Tutorial, Ja. Damit kannst dann den Kontrast einstellen.
So, also ich habe jetzt alles wie im Tutorial angeschlossen, die lcd routinen .h und .c erstellt und es wie folgt in mein Makefile eingetragen: CC= avr-gcc CFLAGS= -Wall -mmcu=atmega16 -Os LDFLAGS=-mmcu=atmega16 all: $(f) $(f): $(f).o lcd-routines.o $(f).hex: $(f) avr-objcopy -j .text -j .data -O ihex $^ $@ brennen: $(f).hex avrdude -u -e -c avrispmkII -P usb -p m16 -U flash:w:$^ clean: $(RM) *.o $(f) *.hex //////////////////////////////////7 Er kompiliert zwar ohne Probleme, jedoch wird nichts auf dem Bildschirm angezeigt. Habe das LCD Beispiel 1 gebrannt. Ich glaube das ich es irgendwie im Makefile falsch eingetragen habe, das er als SRC die lcd-routine.c verwenden soll. Oder?
Tobias Neumann schrieb: > Er kompiliert zwar ohne Probleme, jedoch wird nichts auf dem Bildschirm > angezeigt. Habe das LCD Beispiel 1 gebrannt. Das war auch nicht unbedingt zu Erwarten. Dein LCD-Controller ist ein anderer als der im Tutorial verwendete. Ähnlich aber doch anders. Da wird dir nichts anderes übrig bleiben als die Datenblätter zu vergleichen und in der Initialisierung Anpassungen an deinen Controller vorzunehmen.
also habe ich es im Makefile richtig eingetragen? Mein Display verwendet ja auch den HD44780. Du meinst also das ich die Initialisierung in der lcd-routine.h anpassen soll?
Tobias Neumann schrieb: > Mein Display verwendet ja auch den HD44780. Du meinst also das ich die > Initialisierung in der lcd-routine.h anpassen soll? Datenblatt!!! Datenblatt!!! Datenblatt!!! Datenblatt!!! Nochmal: Schau bitte ins Datenblatt und vergleiche selber, ob die initialisierung im Code dazu passt.
Sorry wenn ich mich dumm anstelle.. bin nunmal ein totaler Newbie in Sachen LCD. Ich habe ja das Datenblatt angehange.. kann mir einer sagen wo diese Initialisierungsdaten stehen?.. Ich nehme an auf Seite 6 aber ich werde daraus nicht so wirklich schlau :(
wenn ich das richtig lese, dann musst Du eigentlich gar nichts initialisieren, das macht Dein Display nach dem Einschalten von alleine. Allerdings muss man mit dem Senden von Daten warten bis das Busy flag nicht mehr gesetzt ist. Meine Vermutung, Du schickst zu schnell nach Power-On die ersten Daten. Warte da einfach mal ne Sekunde und schau was passiert. Gruß Tom
Leider fehlt der Anhang, bzw. das Datenblatt noch immer. Aus leidvoller (Zeitverschwendung) Erfahrung weiß ich, daß es sehr sinnvoll ist sich an die Init-Routine des Datenblatt zu halten, und nicht blind der vom Displayhersteller zu vertrauen. Glücklicherweise sind die Namen der Steuerleitungen bei (fast) allen die gleichen. Achte auf die Position der Steuerbits im Datenbyte!! Hier fand ich schon Unterschiede, aus der Erklärung der Steuerbits habe ich dann Unterschiede (fast 100% kompatibel) gefunden. Mach die Wartezeiten ruhig etwas größer, so 50% stören für den Beginn keinen, ich nehme nach der Init immer den Busy- Flag-Test, ist zuverlässiger, und schneller.
James schrieb: > Leider fehlt der Anhang, bzw. das Datenblatt noch immer. Möge er im ersten Post schauen.
Hallo Leute, ich hab es leider immer noch nicht zum Laufen gebracht.. langsam verzweifele ich. Ich weiß nicht wo ich aus dem Datenblatt sehe welche Daten is wo in der lcd-routine.h reinschreiben muss. Ich denke mal das ihr meint das ich folgnde Initialisierungsgeschichten anpassen muss wie z.B: // Clear Display -------------- 0b00000001 #define LCD_CLEAR_DISPLAY 0x02 // Cursor Home ---------------- 0b0000001x #define LCD_CURSOR_HOME 0x02 // Set Entry Mode ------------- 0b000001xx #define LCD_SET_ENTRY 0x04 #define LCD_ENTRY_DECREASE 0x00 #define LCD_ENTRY_INCREASE 0x02 #define LCD_ENTRY_NOSHIFT 0x00 #define LCD_ENTRY_SHIFT 0x01 Jedoch weiß ich nicht woher ich die richtigen Daten aus dem Datenblatt entnehmen soll..
Guck mal auf Seite 5. Etwas ungewöhlich, aber die haben die Binärwerte statt mit 0 1 als l h geschrieben. Gruß Tom
Tobias Neumann schrieb: > Hallo Leute, > ich hab es leider immer noch nicht zum Laufen gebracht.. langsam > verzweifele ich. Ich weiß nicht wo ich aus dem Datenblatt sehe welche > Daten is wo in der lcd-routine.h reinschreiben muss. Nimm die LCD-Routinen als ANHALTSPUNKT Du hast einen K_irgendwas Controller auf dem LCD und keinen Standard HD44780. Im Datenblatt auf Seite 6 ist die Initialisierungssequenz ausführlich angegeben. > Ich denke mal das > ihr meint das ich folgnde Initialisierungsgeschichten anpassen muss wie Nein. Was wir denken ist: * du sollst dir am Tutorialcode grundsätzlich ansehen, wie LCD Routinen aussehen können und dann sollst du hergehen und deine eigenen schreiben. * du solltest C lernen * du solltest mit etwas einfacherem anfangen als mit einem LCD * du solltest dein LCD auf 8 Datenbits umverkabeln, dann dann (laut Datenblatt Seite 6) brauchst du das LCD gar nicht explizit initialisieren, weil der Controller auf dem LCD schon eine brauchbare Basisinitialisierung macht * du sollst die relevanten Teile im Datenblatt aufmerksam lesen, verstehen, ausprobieren und umsetzen und dich nicht darauf verlassen, dass dich hier im Forum irgendjemand da durchsprechen wird. Letzteres wird höchst wahrscheinlich schief gehen, weil hier niemand deine Hardware vor sich liegen hat und wir daher 'blind' arbeiten müssen. * du sollst dein Programm so umbauen, dass du die LCD Initialisierung zb mit einem Tasterdruck um jeweils einen Schritt weiter laufen lassen kannst. Dies deshalb, weil du dann mit einem Voltmeter die Pegel an den einzelnen Pins ansehen und mit der Vorgabe im Datenblatt vergleichen kannst. Edit: Beim Hochscrollen gesehen - du hast ja alle 8 Datenpins angeschlossen. Also vergiss die Sache mit dem Umverkabeln. AVcc vom Prozessor hast du beschaltet?
Ja ich habe schon viele Sachen mit meinem Mikrocontroller gemacht. Es ist nicht so das ich gerade mit Mikrokontrollern angefangen habe.. und mit C arbeite ich auch schon seit 2 Jahren. Ich habe jetzt wieder alle 8 Datenpins angeschlossen und versuche jetzt mit hilfe von Tutorial und Datenblatt mein eigenes kleines Beispielprogramm zu schreiben wo einfach nur einen Char auf dem Bildschirm ausgibt und es danach wieder cleared. Mal schauen ob ich das hin kriegen ;)
Also ich habe nun ein Beispielprogramm geschrieben was leider nicth funktioniert. Ich habe auch eine lcd-routine.h geschrieben. Ich habe dabei alles berücksichtigt was auch in der lcd-routine.h vom Tutorial steht, außer diesen Teil: #define LCD_SOFT_RESET 0x30 //Set CG RAM Address --------- 0b01xxxxxx (Character Generator RAM) #define LCD_SET_CGADR 0x40 #define LCD_GC_CHAR0 0 #define LCD_GC_CHAR1 1 #define LCD_GC_CHAR2 2 #define LCD_GC_CHAR3 3 #define LCD_GC_CHAR4 4 #define LCD_GC_CHAR5 5 #define LCD_GC_CHAR6 6 #define LCD_GC_CHAR7 7 // Set DD RAM Address --------- 0b1xxxxxxx (Display Data RAM) #define LCD_SET_DDADR 0x80 Diesen Teil kann ich aus meinem Datenblatt nicht wirklich entnehmen.. hat einer ne Idee was ich da laut Datenblatt angeben muss? Mein Programm sollte den String "Hello World!" über die funktion lcd_string() ausgeben. Aber er er leuchtet nur jede einzelne Zelle des Displays mit verschiedenen grau stufen auf.. also es sind keine Zeichen auf dem Display zu sehen aber irgendwas passiert schonmal.. wenigstens was!
Hm, ich versteh nicht ganz wie mir das bei meinem Problem helfen soll.. :)
Tobias Neumann schrieb: > Hm, ich versteh nicht ganz wie mir das bei meinem Problem helfen soll.. > :) Weil das ein ziemlich narrensicherer Code ist. Er macht nicht ähnliche Sachen an 6 verschiedenen Stellen, sondern ist streng modular. Außerdem erlaubt er beliebige Pinzuordnung. Je nach LCD können kleinere Änderungen im Init oder in der Positionierung nötig sein, aber mehr nicht. Peter
Ich wollte mal meine Eigene lcd init posten und euch fragen ob ich das denn so richtig mache, weil mein Programm funktioniert immer noch nicht und ich hab immernoch nur die zwei Balken auf dem Display: Also laut Datenblatt soll meine Initialisierung so aussehen: ---------------------------------------------------------------- - POWER On - Wait for more then 15ms - RS=0, R/W=0, DB7=0, DB6=0, DB5=1, DB4=1 - Wait for more then 4,1ms - RS=0, R/W=0, DB7=0, DB6=0, DB5=1, DB4=1 - Wait for more then 100us - RS=0, R/W=0, DB7=0, DB6=0, DB5=1, DB4=1 - RS=0, R/W=0, DB7=0, DB6=0, DB5=1, DB4=1, DB3=N, DB2=F - RS=0, R/W=0, DB7=0, DB6=0, DB5=0, DB4=0, DB3=1, DB2=0 (Display off) - RS=0, R/W=0, DB7=0, DB6=0, DB5=0, DB4=0, DB3=0, DB2=0,DB1=0, DB0=1 (Clear) -RS=0, R/W=0, DB7=0, DB6=0, DB5=0, DB4=0, DB3=0, DB2=1, DB1=I/D, DB0=Sh (Entry mode set) - Initialisation Ends. ------------------------------------------------------------------ Programmtechnisch habe ich das so geloest: ------------------------------------------------------------------ void lcd_init( void ) { DATA_DDR = 0xFF; SET_DDR = 0xE0; //-----Enable Display-------// _delay_ms(5000); lcd_enable(); _delay_ms(200); //--------1--Fset------------------// DATA_PORT |= (1<<PA4); DATA_PORT |= (1<<PA5); _delay_ms(500); DATA_PORT &= ~(1<<PA4); DATA_PORT &= ~(1<<PA5); _delay_ms(500); //---------2-----Fset-----------------// DATA_PORT |= (1<<PA4); DATA_PORT |= (1<<PA5); _delay_ms(500); DATA_PORT &= ~(1<<PA4); DATA_PORT &= ~(1<<PA5); _delay_ms(500); //---------3-----Fset-----------------// DATA_PORT |= (1<<PA4); DATA_PORT |= (1<<PA5); _delay_ms(500); DATA_PORT &= ~(1<<PA4); DATA_PORT &= ~(1<<PA5); _delay_ms(500); //------------SET Funktion-------------// DATA_PORT |= (1<<PA3); DATA_PORT |= (1<<PA4); DATA_PORT |= (1<<PA5); _delay_ms(500); DATA_PORT &= ~(1<<PA3); DATA_PORT &= ~(1<<PA4); DATA_PORT &= ~(1<<PA5); _delay_ms(500); //---------------Display Off-------------------------// DATA_PORT |= (1<<PA3); _delay_ms(15); DATA_PORT &= ~(1<<PA3); _delay_ms(15); //--------Display on------// DATA_PORT |= (1<<PA0); DATA_PORT |= (1<<PA1); DATA_PORT |= (1<<PA2); DATA_PORT |= (1<<PA3); _delay_ms(15); DATA_PORT &= ~(1<<PA0); DATA_PORT &= ~(1<<PA1); DATA_PORT &= ~(1<<PA2); DATA_PORT &= ~(1<<PA3); _delay_ms(15); //-----------Display clear------------// DATA_PORT |= (1<<PA0); _delay_ms(15); DATA_PORT &= ~(1<<PA0); _delay_ms(15); //----------Entrymode set-------// DATA_PORT |= (1<<PA2); DATA_PORT |= (1<<PA1); DATA_PORT &= ~(1<<PA0); _delay_ms(15); DATA_PORT &= ~(1<<PA2); DATA_PORT &= ~(1<<PA1); DATA_PORT |= (1<<PA0); _delay_ms(15); //--------Display on------// DATA_PORT |= (1<<PA0); DATA_PORT |= (1<<PA1); DATA_PORT |= (1<<PA2); DATA_PORT |= (1<<PA3); _delay_ms(15); DATA_PORT &= ~(1<<PA0); DATA_PORT &= ~(1<<PA1); DATA_PORT &= ~(1<<PA2); DATA_PORT &= ~(1<<PA3); _delay_ms(15); } ---------------------------------------------------------------- In meinem Programm gebe ich einfach den String "Hello World!" an die Funktion lcd_string. Die Syntax der Funktionen: ----------------------------------------------------------------- //////////////////////////////////////////////////////////////////////// //////// // Sendet eine 4-bit Ausgabeoperation an das LCD static void lcd_out( uint8_t data ) { data &= 0xFF; // Bits maskieren DATA_PORT |= data; lcd_enable(); } //////////////////////////////////////////////////////////////////////// //////// // Sendet ein Datenbyte an das LCD void lcd_data( uint8_t data ) { SET_PORT |= (1<<LCD_RS); // RS auf 1 setzen lcd_out( data ); // zuerst die oberen, lcd_out( data<<4 ); // dann die unteren 4 Bit senden _delay_us( LCD_WRITEDATA_US ); } void lcd_string( const char *data ) { while( *data != '\0' ) lcd_data( *data++ ); } //////////////////////////////////////////////////////////////////////// //////// // Erzeugt einen Enable-Puls static void lcd_enable( void ) { SET_PORT |= (1<<LCD_EN); // Enable auf 1 setzen _delay_us( LCD_ENABLE_US ); // kurze Pause SET_PORT &= ~(1<<LCD_EN); // Enable auf 0 setzen } ----------------------------------------------------------------- Ich glaube das das Problem entweder an der Initialisierung liegt, oder daran das ich vielleicht mit 8 Datenpins arbeite und die Funktions lcd_data() angepasst werden muss. Ich hoffe ihr könnt mir dabei helfen. Danke schonma und entschuldigt den extrem langen Post!
Tobias Neumann schrieb: > Ich wollte mal meine Eigene lcd init posten und euch fragen ob ich das > denn so richtig mache, weil mein Programm funktioniert immer noch nicht > und ich hab immernoch nur die zwei Balken auf dem Display: Was soviel heißt wie: Deine Initialisierung stimmt nicht. > Programmtechnisch habe ich das so geloest: > > ------------------------------------------------------------------ > > void lcd_init( void ) > { > DATA_DDR = 0xFF; > SET_DDR = 0xE0; > > //-----Enable Display-------// > _delay_ms(5000); > lcd_enable(); > _delay_ms(200); > Der Enable Pin heißt nicht 'Enable', weil er das LCD einschaltet. Er ist das Signal an das LCD, dass die restlichen Leitungen jetzt einen stabilen Zustand angenommen haben und daher vom LCD als gültig anzusehen sind. Wenn man will, kann man das so sagen: 'Jetzt gilts. Das was jetzt an den Leitungen anliegt, sind gültige Werte' > //--------1--Fset------------------// > DATA_PORT |= (1<<PA4); > DATA_PORT |= (1<<PA5); > _delay_ms(500); > > DATA_PORT &= ~(1<<PA4); > DATA_PORT &= ~(1<<PA5); > _delay_ms(500); Warum denkst du, verweisen wir dich immer auf anderen Code? Damit du den ignorierst? Woher soll denn dein LCD wissen, dass genau jetzt die an PA4 und PA5 anliegende 1 schon der endgültige Zustand ist? Weil dein Programm eine halbe Sekunde wartet? Du musst schon mit den Steuer-Pins wackeln (konkret dem Enable) um dem LCD mitzuteilen: Jetzt gilts! > oder > daran das ich vielleicht mit 8 Datenpins arbeite und die > Funktions lcd_data() angepasst werden muss. Ich hoffe ihr könnt mir > dabei helfen. Deine Funktion lcd_data + lcd_out ist ein einziger Schmarrn. Ein Mischmasch aus 4Bit und 8 Bit Anteuerung, wobei weder das eine noch das andere sauber durchgezogen ist. Tu dir selbst einen Gefallen und studiere erst mal anderen Code! Aber wirklich studieren und nicht einfach nur drüberschauen! Anweisung für Anweisung durchgehen. Abklären welchen Einfluss das auf die Pins hat, mit dem Datenblatt abklären was da passiert und warum ausgerechnet jetzt dieser Pin auf den Zustand gebracht wird, der im Programm steht. > Ja ich habe schon viele Sachen mit meinem Mikrocontroller gemacht. > Es ist nicht so das ich gerade mit Mikrokontrollern angefangen habe.. > und mit C arbeite ich auch schon seit 2 Jahren. Wenn ich deinen Code so ansehe: Ich mag es kaum glauben.
> VO -> nicht angeschlossen
Da bist du recht lapidar drüber hinweggegangen.
So lange VO (VEE) nicht richtig bedient wird,
normalerweise also per Poti die passende Spannung zwischen 0V und 5V
gefunden wird,
bei manchen Displays sogar eine negative Spannung (bei deinem nicht)
kannst du initialisieren wie du willst und nichts ist zu sehen.
Ganz abgesehen von den Problemen die die Anderen im Programm gefunden
haben.
Karl heinz Buchegger schrieb: > Warum denkst du, verweisen wir dich immer auf anderen Code? Damit du den > ignorierst? Woher soll denn dein LCD wissen, dass genau jetzt die an PA4 > und PA5 anliegende 1 schon der endgültige Zustand ist? Weil dein > Programm eine halbe Sekunde wartet? > > Du musst schon mit den Steuer-Pins wackeln (konkret dem Enable) um dem > LCD mitzuteilen: Jetzt gilts! Es könnte sein, dass ich mich da in deinem Code verlesen habe. Dein Mischmasch aus PA4 PA5 DATA_PORT SET_PORT und LCD_EN sucht aber auch seinesgleichen und ist hauptsächlich Eines: maximale Verwirrung! Wobei aus dem Code immer noch nicht hervor geht: Ist PA4 PA5 jetzt eine Steuerleitung oder sind das Datenleitungen? In deinem lcd_out kann man das auch nicht ablesen. Die gibt zwar laut Kommentar nur einen Nibble aus, verändert allerdings alle 8 Leitungen (und das auch nur in Richtung 0->1).
Hallo, habe die Initialisierung von diesem Beitrag hier und an meine Pinbelegung angepasst: Beitrag "Hilfe bei KS0076B" MaWin schrieb: >> VO -> nicht angeschlossen > > > Da bist du recht lapidar drüber hinweggegangen. > > So lange VO (VEE) nicht richtig bedient wird, > > normalerweise also per Poti die passende Spannung zwischen 0V und 5V > gefunden wird, > bei manchen Displays sogar eine negative Spannung (bei deinem nicht) > kannst du initialisieren wie du willst und nichts ist zu sehen. > > Ganz abgesehen von den Problemen die die Anderen im Programm gefunden > haben. V0 hab ich über einen Poti an 5V angeschlossen. Ich sehe zwei Balken, also müsste der Kontrast soin ordnung sein. Karl heinz Buchegger schrieb: > Der Enable Pin heißt nicht 'Enable', weil er das LCD einschaltet. > Er ist das Signal an das LCD, dass die restlichen Leitungen jetzt einen > stabilen Zustand angenommen haben und daher vom LCD als gültig anzusehen > sind. Wenn man will, kann man das so sagen: 'Jetzt gilts. Das was jetzt > an den Leitungen anliegt, sind gültige Werte' Das mit lcd_enable habe ich jetzt verstanden, habe es jetzt aus der initialisierung genommen. Karl heinz Buchegger schrieb: > Warum denkst du, verweisen wir dich immer auf anderen Code? Damit du den > ignorierst? Woher soll denn dein LCD wissen, dass genau jetzt die an PA4 > und PA5 anliegende 1 schon der endgültige Zustand ist? Weil dein > Programm eine halbe Sekunde wartet? > > Du musst schon mit den Steuer-Pins wackeln (konkret dem Enable) um dem > LCD mitzuteilen: Jetzt gilts! Ich versteh nicht ganz was du damit meinst.. soll ich jetzt nach jeder Fset anweisung noch ein lcd_enable machen?? Karl heinz Buchegger schrieb: > Deine Funktion lcd_data + lcd_out ist ein einziger Schmarrn. Ein > Mischmasch aus 4Bit und 8 Bit Anteuerung, wobei weder das eine noch das > andere sauber durchgezogen ist. Ja, ich bin in diesen Bitverknüpfungsgeschichten noch sehr unsicher.. könntest du mir denn eine funktionierende lcd_data+lcd_out für eine 8 Bit Datenübertragung schreiben? Karl heinz Buchegger schrieb: >> Ja ich habe schon viele Sachen mit meinem Mikrocontroller gemacht. >> Es ist nicht so das ich gerade mit Mikrokontrollern angefangen habe.. >> und mit C arbeite ich auch schon seit 2 Jahren. > > Wenn ich deinen Code so ansehe: Ich mag es kaum glauben. Ja ich habe davor mit den ganzen Interrupts gearbeitet und LEDs geschaltet, ein Zaehlrohr angeschlossen und solche Dinge. Ich arbeite jetzt vielleicht seit ung. 8 Wochen mit dem ATmega8. Mit C arbeite ich seit knapp 2 Jahren. Wobei ich erst vor kurzem mit diesen Bitoperationen angefangen habe... entschuldige bitte.
Karl heinz Buchegger schrieb: > Ist PA4 PA5 jetzt eine Steuerleitung oder sind das Datenleitungen? PA0 - PA 7 sind meine Datenleitungen. Diese habe ich in meinem init direkt reingeschrieben. RS = PD5 R/W = PD6 E = PD7 // LCD RS <--> PORTD Bit PD5 (RS: 0=Data, 1=Command) #define LCD_RS PD5 // LCD EN <--> PORTD Bit PD7 (EN: 1-Impuls für Daten) #define LCD_EN PD7 Sorry für meine Verwirrende schreibweise
Also Leute, ich habe mein Programm jetzt nochmal komplett überarbeitet und den Quelltext nun leserlich gestalltet (hoffentlich :)). Ich habe im Anhang mein .c file angehängt. Ich habe immernoch ein Initialisierungsproblem, da die schwarzen Balken auf meinem Display nicht verschwinen. Irgendwas mach ich noch falsch. Wäre nett wenn einer mal meine Initialisiesung mit dem Datenblatt welches ich auch nochmal angehangen habe durchgeht und mir sagt was ich falsch mache. Danke, Tobias.
1 | //Wait untill VDD rises to 4,5V
|
2 | _delay_ms(15); |
3 | //Function Set 1
|
4 | PORTA |= (1<<PA4); |
5 | PORTA |= (1<<PA5); |
6 | _delay_ms(5); |
7 | |
8 | PORTA &= ~(1<<PA4); |
9 | PORTA &= ~(1<<PA5); |
10 | _delay_ms(5); |
11 | //Function Set 2
|
12 | PORTA |= (1<<PA4); |
13 | PORTA |= (1<<PA5); |
14 | _delay_ms(1); |
Ich seh immer noch keine Enable Pulse, die dem LCD mitteilen: Jetzt gilts. OK. Analogie Du und dein Kumpel Herbert habt eine ganz besondere Form der Kommunikation: Vor jedem ist ein Schaltbrett mit Leuchten und darunter jeweils Schalter die entweder ein oder aus sein können. Die Schalter sind jeweils mit den Leuchten der Gegenstelle verbunden, so dass wenn du bei dir den Schalter 0 auf 'ein' stellst, beim Herbert die Lampe 0 aufleichtet. Und natürlich umgekehrt, betätigt Herbert seinen Schalter, so leuchtet bei dir eine Lampe auf. Ihr macht euch beide einen Code aus. Wenn die und die Lampenkombination aufleuchtet, dann bedeutet das irgendwas. Mit anderen Kombinationen natürlich auch, die eben dann was anderes bedeuten. Also legt ihr los. Du starrst auf deine Lampen. Die leuchten nacheinander auf, gehen wieder aus, leuchten wieder etc. Du weisst nie, ob eine bestimmte Leuchtkombination jetzt gültig ist oder nicht, denn natürlich vertut sich Herbert auch mal ab und zu. Er schaltet eine Lampe ein, die eigentlich aus sein sollte und umgekehrt. Herbert bemerkt das auch und schaltet schnell die Lampe wieder aus. mit seinen Wurstfingern kann er nicht alle Lampenschalter gleichzeitig betätigen, ab und zu muss er ins Codebuch schauen um die angestrebte Lampenstellung abzulesen. Kurz und gut: Woher sollst du denn als Beobachter der Lampen wissen, wann Herbert jetzt seine Schalter endgültig in der richtigen Stellung hat und das was bei dir aufleuchtet jetzt tatsächlich eine Nachricht von ihm ist? Eben. Du kannst es nicht wissen. Und daher macht ihr beide einen Zusatz: Ihr verlegt noch einen zusätzlichen Schalter auf jeder Seite, der in einer elektrischen Glocke auf der Gegenseite mündet. Jedesmal, wenn einer seine Schalter so hat, wie er das haben möchte, betätigt er zusätzlich den Schalter der beim anderen die Glocke läuten lässt. Und plötzlich geht alles wie geschmiert. Du siehst wie auf deinem Brett Lampen an und ausgehen und ... 'Bimmel' Die jetzt anliegende Lampenstellung ist die Nachricht Weiter: die Lampen machen wieder einen Tanz, gehen an und aus, einmal kannst du sogar erkennen, wie sich Herbert vertan hat und eine Lampe zuerst ein und dann wieder ausgeschaltet hat. Aber das macht nichts. Solange Herbert nicht bimmelt, kann er mit den Lampen machen was immer er will. 'Bimmel' - Herbert hat seine Schalter kontrollier, hat sie für richtig befunden und hat gebimmelt. Damit gilt die zum Zeitpunkt des Bimmelns anliegende Lampenkonfiguration für dich. Alles dazwischenliegende ist egal. Nur die Lampen die zum Zeitpunkt des Bimmelns leuchten (oder nicht leuchten) gelten. Mit der Betonung auf 'zum Zeitpunkt des Bimmelns'. Das ist die grundlegende Idee, die hinter dem Enable Pin des LCD steckt. Du kannst an den Datenpins umstellen soviel du willst, du kannst am R/W am Command/Data Pin rumstellen soviel du willst. Ist alles egal. Erst wenn der Puls am Enable kommt, dann gilt die zu diesem Zeitpunkt anstehende Einstellung und das LCD übernimmt die dann anliegende Pinkonfiguration und bearbeitet sie. Ist doch nicht so schwer zu verstehen.
der TE sollte sich langsam darüber gedanken machen ob er programmieren WILL das ist jetzt quasi eine grundsatzfrage ... ohne weitere C kenntnisse und wie so ein µC sowie solche signale funktionieren kommt man hier nicht weiter bzw ist es ein absoluter frust sich unwissend durch Code zu wühlen ohne nur ansatzweise zu verstehen wie es funzt wenn er will .. dann muss er lernen ... wenn er nicht will ... kann er sich maximal projekte nachbauen die seinem anspruch genügen alles andere führt nur dazu das hier elend lange threads entstehen wo zu 90% geflamed wird ..
Ich bewundere ja Kar Heinz für seine Geduld mit dem TE, aber ich stimme dem roflkartoffel zu, wir können nicht jemandem, dem so elemtare Grundkenntnisse fehlen komplett Schritt für Schritt vorkauen wie er sein Programm zu schreiben hat. Meine Meinung, Tom
roflkartoffel schrieb: > ohne weitere C kenntnisse und wie so ein µC sowie solche signale > funktionieren kommt man hier nicht weiter > bzw ist es ein absoluter frust sich unwissend durch Code zu wühlen > ohne nur ansatzweise zu verstehen wie es funzt Wobei man auch sagen muss, das 90% dieser Techniken in Wirklichkeit wahnsinnig simpel sind. Ich kann aber nicht ewig Beispiele konstruieren, die eine bestimmte Thematik losgelöst von Elektronik, Computern und Programmen beleuchten, um zu zeigen warum etwas so gemacht wird, so wie hier mit dem Enable Signal. Ob das jetzt Enable, Strobe (beim Centronics Druckerinterface), SCLK bei der Ansteuerung von Schieberegistern ... oder eben Herberts Bimmeln ist, es ist immer dieselbe Grundidee. Und es sind diese Grundideen, die man (neben natürlich technischem Handwerk, sprich Programmieren) verstehen muss, welches Problem sonst entsteht und wie die Idee genau dieses Problem eliminiert. Irgendwann muss er soweit sein, solche Ideen aus dem Datenblatt herauszulesen, bzw. wenn schon fremder Code vorhanden ist, diese Idee im Code sehen. In allen Codevorlagen ist die Reihenfolge: Bits an den Datenbports, Bits an den Steuerleitungen und dann "Enable auf 1; Enable auf 0". Da muss ich mich doch irgendwann, wenn ich das im Code lese, fragen: Warum ist denn das so? Was steckt da dahinter? > wenn er will .. dann muss er lernen ... > wenn er nicht will ... kann er sich maximal projekte nachbauen die > seinem anspruch genügen Jup. Der Unterschied zwischen 'Malen nach Zahlen' und 'Rausgehen in die Natur und das malen was man sieht'. Edit: Timer sind auch so ein Kapitel. Wahnsinnig simpel und trotzdem für Neueinsteiger so schwer zu verstehen. Ich weiß nicht warum, aber im relen Leben lösen Menschen genau dieselben Probleme ohne groß darüber nachzudenken. Nur wenn es um Computer und Programme geht, ist genau derselbe Sachverhalt plötzlich unendlich schwierig zu lösen.
Völlig richtig! Daher kommt es auch überhaupt nicht darauf an, ob man eine bestimmte Programmiersprache kann oder nicht, die Grundprinzipien sind davon unabhängig. Wenn er sich durch Beispielcode wühlt und dabei an einer Stelle nicht versteht warum dort etwas bestimmtes gemacht wird, dann kann er ja genau danach Fragen, aber dann hat er zumindest den Rest schon mal verstanden. Tom
Ganz ruhig bleiben.. Diejenigen die meinen mich hier beleidigen zu müssen sollen lieber mal garnichts schreiben. Ich versuche mein bestes und habe nunmal gerade erst mit LCD Displays angefangen und habe mich in der hinsicht vielleicht etwas schwer getan. An diejenigen die mich unterstützen, wie z.B Karl Heinz: Ich habe nun die Initialisierung ENDLICH hinbekommen.. nachdem du mir so anschaulich beschrieben hast wozu das ENABLE wirklich dient :). Danke schonmal dafür! Meine Initialisierung sieht nun wie folgt aus: void out_stat_reg (unsigned char command) { PORTA=0; PORTD &= ~(1<<PD6); _delay_ms(5); PORTD |= (1<<PD7); // Enable auf 1 setzen PORTA=command; PORTD &= ~(1<<PD7); // Enable auf 0 setzen _delay_ms(70); } // Initialisierung: void lcd_init( void ) { //Pins auf schreiben schalten (PA0-PA7) (PD5-PD7) DDRA = 0xFF; DDRD = 0xE0; //Pins alle low setzen PORTA = 0; PORTD = 0; //Wait untill VDD rises to 4,5V _delay_ms(2000); //Function Set 1 PORTD |= (1<<PD7); // Enable auf 1 setzen PORTA = 0x30; //Set PA4 und PA5 high PORTD &= ~(1<<PD7); // Enable auf 0 setzen _delay_ms(2000); //Function Set 2 PORTD |= (1<<PD7); // Enable auf 1 setzen PORTA = 0x30; //Set PA4 und PA5 high PORTD &= ~(1<<PD7); // Enable auf 0 setzen _delay_ms(2000); //Function Set 3 PORTD |= (1<<PD7); // Enable auf 1 setzen PORTA = 0x30; //Set PA4 und PA5 high PORTD &= ~(1<<PD7); // Enable auf 0 setzen _delay_ms(2000); out_stat_reg(0x3c); //set Display lines out_stat_reg(0x08); //Display off out_stat_reg(0x01); //Display clear out_stat_reg(0x06); //cursor increase out_stat_reg(0x0c); //Display on } Ich hoffe das ist nun verständlicher und sieht mal n bisschen besser aus als das was ich vorher fabriziert habe ;) Also es erscheinen nun die Zeichen "Lo<-" anstatt "Hello World!" auf dem Display. Aber wenigstens hat die Initialisierung schonmal funktioniert. Jetzt muss ich nurnoch rausfinden warum er nicht meinen gewünschten String ausgibt. Ich probier mal ein paar Dinge aus, wenn jemand n Vorschlag hat woran es liegen könnte kann er es ruhig hier posten. Danke erstmal an die jenigen die so Geduldig mit mir waren.
Hallo, also ich kann jetzt einen beliebigen char an das Display übergeben.. weiß aber nicht wie ich den Curser bewege. Wie kann ich dem Display denn sagen, das er, nachdem er einen char geschickt bekommen hat eine curserposition nach rechts rücken soll? Gruß, Tobias.
Schaust du in dein Datenblatt, auf Seite 5 sind alle Konfigurationskommandos zusammengestellt. Das LCD verändert die Cursor Position sowieso von sich aus nach jedem Zeichen. Mit der Konfiguration 'ENTRY MODE SET' kannst du dann noch festlegen, ob der Cursor nach Ausgabe eines Zeichens nach rechts oder nach links wandern soll.
Bsp Aus dem Datenblatt RS R/W 7 6 5 4 3 2 1 0 ENTRY MODE SET L L L L L L L H I/D SH I/D H = increase L = decrease SH H = Display is shifted L = Display is not shifted Du willst: Cursor soll automatisch nach rechts ( = increase) Displayanzeige wird nicht verschoben also I/D muss H (also 1) sein und sH muss L (also 0) sein. Dein Commandobyte ist also LLLLLHHL oder in gebräuchlicher 0/1 Schreibweise 0b00000110 in Hex soviel wie 0x06 Dieses Kommando schickst du zum LCD und dann macht es das Gewünschte. Edit: Seh gerade, dass das in deiner Init Sequenz sowieso enthalten ist. Zeig mal dein Programm. Wahrscheinlich wimmelt es da wieder mal von Cursor Home bzw. LCD Clear Aufrufen.
Ok. Ich habe nur ein ganz einfaches Programm erstellt wo direkt in der main den char sendet. Wenn ich genau weiß wie das richtig funktioniert will ich dann meine eigene putchar funktion erstellen. Meine init() kennst du ja. Meine main: int main(void) { lcd_init(); PORTD |= (1<<PD5); //RS auf 1 PORTA = 0x54; //send char 'T' lcd_enable(); //Jetzt gilts while(1) { } return 0; }
Naja, ich frage mich halt grade wie das genau Funktioniert. Ich habe jetzt versucht so zwei char nebeneinander zu senden: int main(void) { lcd_init(); PORTD |= (1<<PD5); PORTA = 0x54; lcd_enable(); PORTD |= (1<<PD5); PORTA = 0x4F; lcd_enable(); while(1) { } return 0; }
Ohjemine
1 | void putchar( char c ) |
2 | {
|
3 | PORTD |= (1<<PD5); |
4 | PORTA = c; |
5 | lcd_enable(); |
6 | }
|
7 | |
8 | int main(void) |
9 | {
|
10 | lcd_init(); |
11 | |
12 | putchar( 'H' ); |
13 | putchar( 'a' ); |
14 | putchar( 'l' ); |
15 | putchar( 'l' ); |
16 | putchar( 'o' ); |
17 | |
18 | while(1) |
19 | {
|
20 | }
|
21 | |
22 | return 0; |
23 | }
|
UNd führ dir endlich für PORTA und PDirgendwas und was du sonst noch so an Konstnaten hast, vernünfitge #define ein!
1 | #define LCD_DATA_PORT PORTA
|
2 | #define LCD_CTRL_PORT PORTD
|
3 | |
4 | #define LCD_RW_PIN PD6
|
5 | #define LCD_RS_PIN PD5
|
6 | #define LCD_E_PIN PD7
|
7 | |
8 | void putchar( char c ) |
9 | {
|
10 | LCD_CTRL_PORT |= (1<<LCD_RS_PIN); |
11 | LCD_CTRL_PORT &= ~(1<<LCD_RW_PIN); |
12 | |
13 | LCD_DATA_PORT = c; |
14 | |
15 | LCD_CTRL_PORT |= (1<<LCD_E_PIN); |
16 | _delay_ms( 1 ); |
17 | LCD_CTRL_PORT &= ~(1<<LCD_E_PIN); |
18 | }
|
19 | |
20 | void out_stat_reg (unsigned char command) |
21 | {
|
22 | LCD_DATA_PORT = 0; |
23 | LCD_CTRL_PORT &= ~(1<<LCD_RW_PIN); |
24 | |
25 | _delay_ms(5); |
26 | LCD_CTRL_PORT |= (1<<LCD_E_PIN); |
27 | LCD_DATA_PORT = command; |
28 | LCD_CTRL_PORT &= ~(1<<LCD_E_PIN); |
29 | _delay_ms(70); |
30 | }
|
31 | |
32 | |
33 | etc..... |
erstens wird der Code dadurch sehr viel besser verständlich, als wie wenn man ständig im Hinterkopf behalten muss, welcher Pin am Port D dann jetzt welche Leitung ist und zweites hast du dann die Pinbelegung an einer Stelle beisammen, was bei Änderungen ja höchst vorteilhaft sein soll.
Tobias Neumann schrieb: > Naja, ich frage mich halt grade wie das genau Funktioniert. Du gibst das Byte einfach auf dem Port aus. Allerdings muss die RS Leitung dazu High sein. (Und natürlich, wie immer, hinten nach ein Enable Puls) Siehe Datenblatt, Seite 5, in der Tabelle fast ganz unten, das 'Kommando' Write Data
Tobias Neumann schrieb: > Er zeigt mir aber nur ein 'H' an, wenn ich es so mache :/ Wie sieht deine lcd_enable aus? Hast du dir inzwischen ein paar #define gemacht, damit man nicht ständig mit PD5, PD6 und Konsorten durcheinanderkommt? Hast du nach dem Enable Puls ein bischen gewartet? Laut Tabelle benötigt die Ausgabe auch Zeit (42µs) ....
Ich habe grad irgend n kleinen bug drinnen, Nachdem ich die ganzen defines gemacht habe. Brauche noch kurz um den zu fixen.
JAAAAAAAAAAAAAAAAAAAAA! Ich habs endlich geschafft!!!! DANKE Karl Heinz ich LIEBE DICH :D Das Problem war das ich mal wieder zu "copy&paste" geil war und ich deine defines rauskopiert habe, wobei du RS = PD6 und RW = PD5 definiert hattest. Diese sind aber genau umgedreht.. das hat mich grad zur verzweiflung gebrahct.. aber jetzt gehts! DANKE DANKE DANKE Ich hab mein Programm mal in den Anhang gemacht, falls du es dir nochmal anschauen willst. Gruß, Tobias.
Tobias Neumann schrieb: > Ich hab mein Programm mal in den Anhang gemacht, falls du es dir nochmal > anschauen willst. Ich halt mich da jetzt raus. Nur eines noch: Du solltest anfangen auf Nomenklatur zu achten. Die eine Funktion heisst lcd_init, die andere out_stat_reg, dann wieder eine lcd_enable und die letzte putchar Was haben all diese Funktionsnamen gemeinsam? Richtig. Bis auf lcd_init und lcd_enable, die die gemeinsame 'Vorsilbe' lcd benutzen: Gar nichts Alle diese Funktionen gehören aber zum selben Code-'Modul'. Nämlich der Ansteuerung des LCD! Das sollte sich dann schon im Funktionsnamen niederschlagen. Den irgenwann hast du dann 25 vrschiedene Zeichen-Sende Routinen und weißt nicht mehr welche jetzt für UART, welche für SPI, TWI, LCD etc. zuständig ist. Und den Wildwuchs mit ENABLE solltest du auch beseitigen. Entweder von überall her wird lcd_enable aufgerufen, wenn man einen Enable Puls braucht, oder die Funktion fällt komplett weg. Aber nicht so wie jetzt.
Ok. Ich werde in Zukunft darauf achten. Danke nochmal für alles.
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.