Hallo:) ich habe mir selber jetzt ein serielles LCD-Display zusammengebaut das über 3 Anschlüsse mit dem Microcontroller angeschlossen wird. Nur die CLK, Enable und der Datenbus sind mit dem Microcontroller verbunden. Zwischen dem Microcontroller habe ich ein Schieberegister angeschloessen dass die Daten an das LCD-Display leiten soll. Den Schaltplan habe ich im Anhang auch hinzugefügt. Hab auch mein programm auf dem Microcontroller draufgespielt und die einzelnen Pinnen mit dem Oszilloskop überprüft. Signale bekamme ich an den jeweiligen Pins wenn z.b clock auf high schaltete setze der datenbus auch auf high und das umgekehrt. Ich habe glaube ich bei der Initialisierung bestimmt ein Fehler gemacht nur ich weiss nicht wo genau:(. Bei einer bestimmten steigenden Clock-flanke schaltet sich die Hintergrundbeleuchtung meiens Displays aus:( Hoffe könnt mir was weiter helfen^^
dass macht er nur wenn ich mein programmm draufspiele, dann wird das display dunkel. Außerdem zeigt mir dann dieses display nichts an was ich programmiert habe :(
also ist der plan selber schonmal falsch oder wie darf ich das jetzt verstehen? hab diesen plan von ulrich radig gefunden. Dies wurde mir auch empfohlen.
Lass die 4 Datenleitungen offen. Das LCD kümmert sich selbst um die. Das hier
1 | void lcd_init (void) |
2 | {
|
3 | |
4 | //Set Port Direction Register
|
5 | //LCD_DDR = 0x07;
|
6 | DDR_LCD_DATA_ENABLE |= (1<<LCD_DATA_ENABLE); |
7 | DDR_LCD_CLOCK |= (1<<LCD_CLOCK); |
8 | DDR_LCD_DATA |= (1<<LCD_DATA); |
9 | PORT_LCD_DATA_ENABLE &= ~(1<<LCD_DATA_ENABLE); |
10 | |
11 | //Wait a short Time afer Power on
|
12 | |
13 | WAIT(10); |
14 | |
15 | |
16 | for (unsigned char a=0;a<3;a++) |
17 | {
|
18 | lcd_write (0x22,0); //Init in 4 Bit Mode |
19 | lcd_write (0x80,0); //Set DD-Ram Adresse = 0 |
20 | }
|
hat der Radig Ulli geschrieben? Das kann ich nicht glauben. Das ist ein kompletter Unsinn.
leider ja mir ist nicht im klaren wieso er eine for schleife für die initialisierung des 4 bit und der DD-Ram benutzt. Ich würde dies komplett weg lassen und nur die beiden Initialisierungen aufschreiben. Hab den code etwas geändert genau so: void lcd_init (void) { //Set Port Direction Register DDR_LCD_DATA_ENABLE |= (1<<LCD_DATA_ENABLE); DDR_LCD_CLOCK |= (1<<LCD_CLOCK); DDR_LCD_DATA |= (1<<LCD_DATA); PORT_LCD_DATA_ENABLE &= ~(1<<LCD_DATA_ENABLE); //Wait a short Time afer Power on WAIT(10); lcd_write (0x22,0); //Init in 4 Bit Mode lcd_write (0x80,0); //Set DD-Ram Adresse = 0 lcd_write (0x40,0); //1 Zeilen lcd_write (0xD0,0); //Display On } sofern dies richtig jetzt nun ist. Dies habe ich so aus dem Datenblatt entnommmen hoffe habe alles wichtige in meiner lcd_init enthalten.
Adrian schrieb: > leider ja mir ist nicht im klaren wieso er eine for schleife für die > initialisierung des 4 bit und der DD-Ram benutzt. Eben. Die korrekte Sequenz, die funktioniert lautet: Du präsentierst dem LCD an den Datenbits D4 bis D7 erst mal eine 3 (d.h D4 auf 1, D5 auf 1). Und das 3 mal hintereinander, wobei jedesmal RS auf 0 bleibt und natürlich so wie immer die Enable Leitung gepulst wird. Aber Achtung: du musst zwischen den Enable Pulsen Wartezeiten einhalten! Erst dann ist sicher gestellt, dass das LCD auf jeden Fall im 8-Bit Modus ist, egal was vorher passiert ist. Und erst dann präsentierst du ihm einmalig eine 2 an den Datenleitungen D4 bis D7 (also D5 auf 1). WIeder: Rs muss auf 0 bleiben und auf Enable wird ein Puls erzeugt. Und erst dann ist das LCD im 4-Bit Modus und du kannst erstmals die Funktion lcd_write benutzen. PS: Du kannst ein LCD beliebig langsam ansteuern. D.h. wenn du die Möglichkeit dazu hast, dann kannst du an die Ausgangsleitungen vom Schieberegister, bzw an die Enable Steuerleutung etwas zusätzlich anschliessen, womit du die Pegel erkennen kannst und somit siehst, ob da die Pegel rauskommen, so wie sie eigentlich sein sollten. Du darfst die Pulse, die zeitlichen Abstände etc. beliebig langsam machen, so dass du als Mensch da noch mitkommst. Nur zu schnell darf es nicht sein. Es gibt da minimal einzuhaltende Wartezeiten. Insbesondere die ersten Initialisierungsschritte sind da kritisch. AVR-Tutorial: LCD
snayer2311 schrieb: > ich weiss gerade nicht ob das so richtig ist wie dues mir gerade gesagt > hast So wie Karl Heinz es gesagt hat, ist es richtig. So wie du es machst, ist es falsch. Lies einfach mal das Datenblatt zum Display und überleg, ob die Zeiten und Abläufe, die darin auftauchen auch in deinem Programm auftauchen. Du musst gerade zu Beginn der Initialisierung (Datenbreite) das Timing unbedingt einhalten.
1 | lcd_write (0x22,0); //Init in 4 Bit Mode |
Dass du da über einen Trick schnell hintereinander eine 0x2 sendest hilft da nicht weiter und Kommentare kann das Display auch nicht lesen...
1 | goto ConversionLoop; |
> weiss gerade nicht ob das so richtig ist Ist das C? Dann ist es falsch: ein Anfänger braucht sicher kein GOTO in einem Stück C-Code... > Nibbel Noch so einer: ein halbes Byte ist ein Nibble, der mit einem Nippel nun so gar nichts zu tun hat...
:
Bearbeitet durch Moderator
Lothar Miller schrieb: >
1 | > lcd_write (0x22,0); //Init in 4 Bit Mode |
2 | >
|
> Dass du da über einen Trick schnell hintereinander eine 0x2 sendest Ja, das ist mir auch aufgefallen. Das könnte vielleicht sogar funktionieren. Glücklich bin ich damit trotzdem nicht. @snayer2311 Der springende Punkt ist, dass du zum Umschalten in den 4 Bit Modus die Funktion lcd_write noch nicht benutzen kannst! Genau das hab ich versucht dir klar zu machen. du kannst die shift_out benutzen, denn die gibt im Grunde ja ein Nibble kontrolliert an das Schieberegister aus. Allerdings ist das Interface für diese Funktion etwas 'unhandlich', weil der Aufrufer die Bits zurecht schieben muss und nicht die Funktion das selber macht. Eventuell würde ich mir da eine eigene Funktion shift_out_nibble machen, die den Zurechtschiebeteil an die Datenbits erledigt, damit ich in lcd_init den Teil nicht habe (den das ist beim Fehlersuchen in der lcd_init eher unpraktisch, wenn man an dieser Stelle laufend um die Ecke denken muss) Aber da musst du durch. Genau deswegen hab ich es angesprochen, dass du den ganzen Vorgang beliebig langsam machen darfst. Nutze das tatsächlich aus! Häng meinetwegen ein paar LED an die Leitungen, die zum LCD gehen und sieh dir an, welche Pegel wann da am LCD ankommen. Du MUSST die angegebene Sequenz dort aufleuchten sehen. 3 mal hintereinander das Bitmuster für 3 an den Datenleitungen und dann einmalig das Bitmuster für 2 an den Datenleitungen. Wenn du langsam machst, dann überfährst du auch ganz sicher nicht das LCD. Sorry. Aber solche 'Spezialsachen' kann man nun mal nicht machen, wenn man nicht gewillt ist, sich mit der Materie zu beschäftigen. Daher geb ich dir auch nur Tips und sag dir, was du letzten Endes an den Ausgängen vom Schieberegister sehen musst. Aber machen .. musst DU es.
:
Bearbeitet durch User
Habe ich soweit gemacht jetzt meckert, eine eigene Funktion geschreiben die den Zurechtschiebeteil macht ohne die lcd_write Funktion zuschreiben. Jetzt meckert er über einen Fehler den ich nicht verstehe. Irgendein zeichen fehlt aber entdecke den Fehler nicht Error 1 expected ';', ',' or ')' before '=' token F:\Hauptprojekt serielle Displaysteuerung\SeriellesDisplay\SeriellesDisplay\lcd.c 20 27 SeriellesDisplay er
Anscheinend soll das Programm so von Ulrich Radig funktionieren ohne dass man da was ändern sollte. Wieso solle ich da eine neue Funktion schreiben wenn lcd_write ja nur dass alles in dem Schieberegister schreibt und die Funktion shift_data out eigentlich das was in dem Schieberegister steht ins display aufnimmt. Am ende dieser Funktion ist ja dieses enable dass die alle daten des Displays im Schieberegister aufnimmt. Hab auf seiner Seite genau mir das gleiche serielle Display zusammengebaut. hmm dann hab ich i-wie ein anders Problem mache gerade eine Fehler analyse und möchte mal sowie es ulrich radig gemacht hatte meine pins am portC anschließen.
snayer2311 schrieb: > Wieso solle ich .... Weil Ulli 2007 mit der damailgen Compilergeneration wusste was er tat. Er hatte das Wissen und das Können, das durchzuziehen. Du hingegen sträubst dich seit Tagen, dir eine simple Hilfsfunktion zu schreiben, so dass du die Grund-Initialisierung ...
1 | void lcd_init() |
2 | {
|
3 | //Set Port Direction Register
|
4 | //LCD_DDR = 0x07;
|
5 | DDR_LCD_DATA_ENABLE |= (1<<LCD_DATA_ENABLE); |
6 | DDR_LCD_CLOCK |= (1<<LCD_CLOCK); |
7 | DDR_LCD_DATA |= (1<<LCD_DATA); |
8 | PORT_LCD_DATA_ENABLE &= ~(1<<LCD_DATA_ENABLE); |
9 | |
10 | _delay_ms( 50 ); // 16 sollten eigentlich reichen |
11 | |
12 | shift_out_nibble( 0x03 ); |
13 | _delay_ms( 10 ); // minimum 4.1 ms |
14 | shift_out_nibble( 0x03 ); |
15 | _delay_ms( 1 ); // minimum 0.1 ms |
16 | shift_out_nibble( 0x03 ); |
17 | _delay_ms( 1 ); |
18 | |
19 | shift_out_nibble( 0x02 ); |
20 | _delay_ms( 1 ); |
21 | |
22 | // ab jetzt sind wir im 4-Bit Modus und lcd_write kann benutzt werden
|
23 | |
24 | lcd_write (0x0C,0); //Display On |
25 | }
|
... schreiben kannst bzw. anstelle der NOP da einfach mal ein paar längere _delay_xx einzufügen und mit ein paar LED oder einem Voltmeter nachzusehen ob auch alles richtig angeschlossen ist. (und mit 'längere' meine ich nicht Millisekunden, sondern durchaus Zeiten im Sekundenbereich oder noch länger) Aber es ist ok. Die Funktion shift_out_nibble wäre zwar in 5 Minuten geschrieben (vor allen Dingen deshalb weil man sich an lcd_write orientieren kann, aber lediglich ein Nibble ausgibt und nicht ein ganzes Byte) und die Zeitsteuerung von NOP auf _delay_xx umgestellt, du rödelst dafür lieber tagelang rum und klebst an Code fest, den du nicht verstehts bzw. an einem Übertragungsmechanismus den du nicht verstehst, bzw. an Code dessen Details du nicht verstehst. Vereinfacht gesagt und auf einen Punkt gebracht.
:
Bearbeitet durch User
habs jetzt soweit alles geändert wies mir beschrieben wurde hoffe das stimmt zumindest. hab ein problem beim debuggen und zwar stoppt er bei schon beim ersten delay und bleibt dann bei running fest hängen. was kann ich da machen?
hab die zeiten was runtergeschraubt um zu testen ob der dann aus dem running schneller herausspringt aber ohne erfolg
Hallo:) Ich bin mir nicht gerade sicher ob diese Funktion die Daten auch richtig in das schieberegister reinstellt
1 | void shift_out_nibble (char data) |
2 | {
|
3 | unsigned h_nibble; |
4 | unsigned l_nibble; |
5 | |
6 | h_nibble = (data&0xF0)>>1; |
7 | |
8 | _delay_ms(450); |
9 | |
10 | l_nibble |= (data&0x0F)<<3; |
11 | |
12 | _delay_ms(450); |
13 | |
14 | //Schreiben der 1. 4Bit an das LCD Display
|
15 | shift_data_out(h_nibble); |
16 | |
17 | //Schreiben der 1. 4Bit an das LCD Display
|
18 | shift_data_out(l_nibble); |
19 | |
20 | }
|
21 | void shift_data_out (char byte) |
22 | {
|
23 | for (unsigned char a=4; a>0; a--) |
24 | {
|
25 | if ( (byte & (1<<(a-1))) != 0) |
26 | {
|
27 | PORT_LCD_DATA |= (1<<LCD_DATA); //Data PIN (High) |
28 | enable(); |
29 | }
|
30 | else
|
31 | {
|
32 | PORT_LCD_DATA &= ~(1<<LCD_DATA); //Data PIN (LOW) |
33 | enable(); |
34 | }
|
35 | Clock(); |
36 | }
|
37 | |
38 | enable(); |
39 | }
|
:
Bearbeitet durch User
snayer2311 schrieb: > Hallo:) Ich bin mir nicht gerade sicher ob diese Funktion die Daten auch > richtig in das schieberegister reinstellt Was heißt du bist dir nicht sicher? Schreib dir ein Testprogramm
1 | int main() |
2 | {
|
3 | ...
|
4 | |
5 | shift_data_out( 0x01 << 3); |
6 | |
7 | while( 1 ) |
8 | ;
|
9 | }
|
und sieh nach (Voltmeter oder LED), ob am Pin DB4 vom LCD eine 1 anliegt und alle anderen auf 0 sind. Dasselbe probierst du mit 0x02, 0x04 und 0x08 und den Pins DB5, DB6 und DB7 am LCD, die jeweils auf 1 liegen müssen und die jeweils anderen auf 0. Wenn du dann noch ein bischen spielen willst, dann probierst du das noch mit anderen Kombinationen der 'Zahlenwerten' bzw. der RS Leitung. Dann bist du sicher. Das ganze geht schneller, als hier eine Frage einzutippen und so ganz nebenbei erhöht das auch noch deine Programmierpraxis und deine Fähigkeiten dir selbst zu helfen, indem du dir überlegst, wie man etwas testen kann. Dein Problem: du sitzt da wie der Hase vor der Schlange, weil dein LCD nicht reagiert. Gut. Was du übersiehst: damit ein LCD funktioniert, muss eine komplexe Kette von Aktionen korrekt sein. Und die kann man alle einzeln testen und sicherstellen, dass sie funktionieren. Das beginnt mit der Verkabelung, führt über die korrekte Ansteuerung der dazwischen liegenden IC (in deinem Fall das Schieberegister) und endet erst zum Schluss in der korrekten Initialisierungssequenz. Aber jeder Schritt ist für sich einzeln testbar. Und dieses Prinzip der aufeinander aufbauenden Tests vom einfachen zum immer komplexeren ist ein allgemeines Prinzip. Daher ist es gut darin eine gewisse Praxis zu haben. Das wird dir auch in Zukunft noch so manches mal aus der Patsche helfen, wenn du dich überwindest und in diese Einzeltests ein wenig Zeit investierst.
:
Bearbeitet durch User
Soweit habe ich das verstanden nur mein problem ist gerade welche schleife ich für die funktion shift_data_out verwenden soll. hab gerade diese schleife genommmen for (unsigned char a=4; a>0; a--) { if ( (data & (1<<(a-1))) != 0) { PORT_LCD_DATA |= (1<<LCD_DATA); //Data PIN (High) } else { PORT_LCD_DATA &= ~(1<<LCD_DATA); //Data PIN (LOW) } Clock(); } enable(); } Beim Compilieren ist immer die lcd leitung null und ich messe an ausgängen nichts. Dann wie erreiche ich zum beispiel dass ich an db4 eine 1 bekomme wenn meine schleife 4 mal durchläuft?
hab es hinbekommen die Initialiserung funktioniert soweit :) hab jetzt auch den quelltext verstanden :)
Soweit funktioniert bei mir die Initialisierung. Ich sehe einen blinken Curser und kann ihn beliebig switchen wie ich es gerne möchte. Aber wenn ich ein Wort ausgeben möchte funktioniert das mit der funktion lcd_print(0,0,"Hallo"); irgendwie nicht. Ich bekomme dann links nur zwei große striche etwa so || und ein komisches Zeichen heraus und der kurser bleibt dann stehen. Was muss da umstellen in meiner Funktion?
Hier ist mein Projekt zu der Seriellen Display-Ansteuerung. Hat alles jetzt wunderbar funktioniert. Ich hab mein Fehler gefunden warum es nicht funktioniert hatte. Der Fehler lag an der Compilierung meines AVR-Dragons. Er hat meinen Programmtext anders Programmiert als der AVR-Burn Compiler. Ich nehme jetzt in Zukunft AVR-Burn um mein Programmtext zu compilieren.
Hi >Der Fehler lag an der Compilierung meines AVR-Dragons. Der Dragon compiliert überhaupt nichts. >Er hat meinen Programmtext anders Programmiert als der AVR-Burn Compiler. Der Dragon sieht gar nichts von deinem Programmtext. AVR-Burn (falls das so heißt) dürfte auch kein Compiler sein. MfG Spess
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.