Hey, Ich habe ein Problem. Probiere nun schon seit 2 Tagen mein 2x8 LCD zum laufen zu bringen, doch kriege es nicht her. Es leuchten nur die schwarzen Balken in der ersten Zeile. Datenblatt LCD: http://docs-europe.electrocomponents.com/webdocs/0f25/0900766b80f25db8.pdf Hier der Programmcode: /******************************** * Diplom_Prototyp.c * * Created: 21.12.2011 * * Author: Raphael Tschernitz * *******************************/ #define F_CPU 16000000UL #define En PINA6; #define Rs PINA4; #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> void delayms(int x) // Spart so speicherplatz.. { _delay_ms(x); } void delayus(int y) { _delay_us(y); } void init() { DDRA=0xFF; // DDRA als Ausgang DDRC=0xFF; PORTA=0x00; PORTC=0x00; } void send(int VeeEnRsRWData4321) { PORTA=1<<En; // Enable delayus(50); PORTA=VeeEnRsRWData4321; // Vee En Rs RW Data4-1 delayus(100); PORTA=0<<En; // Werte übernehmen delayus(100); // Bisele Warta } void WriteChar(int VeEnRsRWData4321) { PORTA=1<<Rs; delayus(50); PORTA=1<<En; // Enable delayus(50); PORTA=VeEnRsRWData4321; // Vee En Rs RW Data4-1 delayus(100); PORTA=0<<En; // Werte übernehmen delayus(50); PORTA=0<<Rs; delayus(100); // Bisele Warta } void lcd_init() { /* PA0 Data1 1 2 2 3 3 4 4 RS 5 RW 6 En 7 Vee */ /* Power on Wait > 40ms ((Vee En RW RS D4 D3 D2 D1)) 0 0 0 0 0 0 1 1 // Function set Wait > 37us 0 0 0 0 0 0 1 0 // Function set 0 0 0 0 N F X X // N = 0; 1-line display, F = 0; 5x8 dot character font (meins: 0 0 0 0 1 0 0 0) Wait > 37us 0 0 0 0 0 0 1 0 // Function set again :S 0 0 0 0 N F X X // N = 0; 1-line display, F = 0; 5x8 dot character font (meins: 0 0 0 0 1 0 0 0) Wait > 37us 0 0 0 0 0 0 0 0 // Display on/off control 0 0 0 0 1 D C B // D = 0; Display off, C = 0; Cursor off, B = 0; Blinking off (meins: 0 0 0 0 1 1 0 0) Wait > 37us 0 0 0 0 0 0 0 0 // Display clear 0 0 0 0 0 0 0 1 Wait > 1.52ms 0 0 0 0 0 0 0 0 // Entry mode set 0 0 0 0 0 1 ID S // I/D = 1; Increment by 1, S = 0; No shift (meins: 0 0 0 0 0 1 1 0) Wait ?? */ delayms(1000); // Function set send(0b01000011); // Function set send(0b01000010); send(0b01001000); // 1-Line Display, 5x8 dot character font // Function set again :S send(0b01000010); send(0b01001100); // 2-Line Display, 5x8 dot character font // Display on/off control send(0b01000000); send(0b01001100); // Display on, Cursor off, Blinking off // Display clear send(0b01000000); send(0b01000001); delayms(2); // Entry mode set send(0b01000000); send(0b01000100); // no increment by 1, no shift delayms(2); } int main(void) { init(); lcd_init(); int i=0; while(i<10) // nur zum Anzeigen, dass While-Schleife startet { PORTC=0x0F; delayms(100); PORTC=0xF0; delayms(100); i++; } PORTC=0x00; while(1) { // H WriteChar(01011000); WriteChar(01011000); delayms(500); } } Könnt Ihr einen Fehler finden, bin echt am verzweifeln. :S
Ersetze: Ralf schrieb: > // Spart so speicherplatz.. durch: // Verschwendet so enorm Speicherplatz. ;)
Da hilft nur eins: mit dem Oszi prüfen, ob alle Signale auch so anliegen, wie sie sollen. Joe
> init(); > lcd_init(); Dein init() fummelt bereits an den PORTA Leitungen zum LCD. Die 1000ms Wartezeit in lcd_init() bis das LCD aus dem Power-On-Reset kommt, verpufft. > void lcd_init() > { > delayms(1000); > send(0b01000011); // Function set Das ist sehr unterschiedlich zu den bewährten LCD Routinen aus dem Tutorial in der Artikelsammlung. Dort wird eine Initialierung verwendet um Kommandomodus zu kommen, die auch arbeitet, wenn das LCD im 8-Bit oder 4-Bit Modus ist. > /* PA0 Data1 > 1 2 > 2 3 > 3 4 Da kommst du nicht weiter. Du musst für das 4-Bit Interface am LCD auf DB4-DB7 ankommen, die unteren Datenleitungen DB0-DB3 am LCD sind wirkungslos! PA0: AVcc AGND und ARef sind korrekt beschaltet? > WriteChar(01011000); Die Zahl 01011000 ist nicht die Zahl, die du meinst, dass sie ist.
Zum Stil des Programmes. Das hier
1 | void send(int VeeEnRsRWData4321) |
2 | {
|
3 | PORTA=1<<En; // Enable |
4 | delayus(50); |
5 | PORTA=VeeEnRsRWData4321; // Vee En Rs RW Data4-1 |
6 | delayus(100); |
7 | PORTA=0<<En; // Werte übernehmen |
8 | delayus(100); // Bisele Warta |
9 | }
|
ist beispielsweise kompletter Unsinn. Du musst dir bewusst sein, dass eine Zuweisung an einen Port immer ALLE Portpins ändert. Ein PORTA=1<<En; // Enable ändert nicht nur die Enable Leitung, sondern auch die Datenleitungen, die am selben Port liegen. Ein PORTA=VeeEnRsRWData4321; // Vee En Rs RW Data4-1 ändert ebenfalls alle Portbits. Du verlangst hier nicht mehr oder weniger vom Aufrufer, als das er dir ein Datenbyte übergibt, in dem die entsprechenden Bits für Enbale und Rs bereits richtig gesetzt sind. Wozu? Um dieses Detail kann sich die Funktion problemlos selber kümmern und du hast beim Aufruf der Funktion ein Detailproblem weniger, um dass du dich beim Aufruf kümmern musst. Das hier PORTA=0<<En; // Werte übernehmen .... no comment. Auch hier ändern sich wieder ALLE Portpins. Sie werden alle zu 0. Was das LCD sieht (sehen würde, wenn du die korrekten Datenpins am LCD benutzt), wenn du genau im Umschalten des Enable Pins auch die Datenleitungen auf 0 fallen lässt, das wissen nur die Götter.
> _delay_ms(x); > _delay_us(y); Sabotiert die Funktionen; die arbeiten mit variablem Argument anders als gedacht. > PORTA=VeeEnRsRWData4321; // Vee En Rs RW Data4-1 Ignoriert IMHO die Timing Vorgaben aus dem Datenblatt. Die RS und RW müssen vor und nach dem Toggle von EN gesetzt sein. > PORTA=0<<En; // Werte übernehmen Im Moment des Pegelwechsels werden so LOW-Pegel vom LCD übernommen. Die Zeit tH (Data Hold Time, min. 10 ns) wird nicht eingehalten. Möglicherweise gibt es weitere Timingprobleme; habe ich nicht weiter kontrolliert.
Vielen Dank für die schnellen Antworten. Das mit dem init() werde ich gleich mal ausprobieren. Die Datenleitungen sind schon korekt, hab sie hier nur mit dem falschen Namen kommentiert. (Data1 entspricht Data4 usw.) Sorry das ich das nicht erwähnt hab. Ich wollte mal das Programm selberschreiben, damit ich es auch komplett verstehe und weiß was ich gemacht habe. Wenn es einmal Funktioniert werde ich mich wahrscheinlich immer mehr der bewährten Art annähern bis das Programm perfekt ist. @ ernst: Ne ich habs ausprobiert, auf diese Art braucht das Programm nur einen drittel vom Speicherplatz dens zuvor gebraucht hat ;) @ Joe: Ich hab schon überprüft ob die Signale richtig ankommen und dort konnte ich keine Probleme feststellen. :)
Ups, das stimmt. Hab das PORTA=1<<EN; jetzt auf PORTA|=1<<EN geändert, jetzt ändert sich nur noch das Enable. Die Funktion werde ich später noch verbessern, dass es jetzt etwas undhandlich ist, ist noch egal. Also zuerst RW und RS auf 0 setzen, dann EN auf 1, kurz darauf die Daten setzten, während Daten gesetzt sind EN wieder auf 0 und Daten werden übernohmen? Pseudocode: PORTA|=0<<RW,0<<RS delay (tas=0-10ns) PORTA|=1<<EN PORTA|=Daten delay (tpw=460ns) PORTA|=0<<EN delay (th=10ns) Wie kann ich 4 bits gleichzeitig setzten? Wenn Daten zB: Daten=0b0101 und ich möchte diese Daten auf PINA0-3 setzen: PORTA|=Daten; ... setzt das dann die Daten auf die niedrigsten Bits also 0bxxxx0101 ?
> PORTA|=0<<RW,0<<RS Du schreibst jetzt hundert mal * Mit einer Oder-Operation kann man keine Bits auf 0 setzen. Mit einem Oder kann man Bits auf 1 ziehen, aber nicht umgekehrt. Dazu braucht man ein Und. * Eine 0 kann man nach links schieben so oft man will, sie bleibt immer 0. (Oder was gleichwertig ist, da ein Linksschieben einer Multiplikation mit 2 entspricht: 0 kann man mit jeder beliebigen Zahl multiplizieren, das Ergebnis wird wieder 0 sein) Bitmanipulation Aber eigentlich sind das alles Dinge, die man mit seinen ersten Programmen, bei denen es um Led-ein/Led-aus, Lauflicht, Blinklicht etc. geht, alle aussortiert und bis zum Erbrechen übt. Danach ist das Thema 'Wie werden einzelne Pins bzw. Pingruppen an einem Port korrekt und nebenwirkungsfrei angesprochen' durch und man wendet sich schwereren Dingen zu. Das korrekte und sichere Hantieren mit bitweisem Und/Oder/Nicht und den entsprechenden Maskenbytes (und wie man sie konstruiert) ist sozusagen das Kleine-Einmaleins der µC Programmierung.
Hi Ralf, hast du mal das LCD Beispiel aus dem Tutorial hier ausprobiert? So könntest du wenigstens prüfen/eingrenzen, ob es am Display liegt oder nicht. Bei mir funktioniert der Code aus dem Tutorial einwandfrei. Gruß
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.