Hallo liebe uC - Gemeinde. Seit ein paar Tagen bin ich bei einem Problem. Ich komme einfach nicht mehr weiter. Das Umfeld: - LCD 2*16 - PIC 18F4520 - MPLABX mit XC8 Codec (neuste Version) - Pickit3 Alles ist programmiert und sollte auch funktionieren, aber das tut's nicht :) Ich arbeite mit den __delay_us() und __delay_ms() für die Pausen. Aber genau da vermute ich das Problem. Wenn ich alle Delays auskommentiere und mit dem Debugger die Schritte selber weiter schalte, dann wird der LCD initialisiert und funktioniert. Von da an kann ich Code ändern und laden. Sobald ich aber den Controller vom Netz trenne und wieder starte geht nichts mehr, bis ich wieder das obige anwende. Was kann das sein, ich bin am Ende meines Lateins :) :(
Hallo Hans! Hältst Du denn die Timings deines Displays ein (die stehen im Datenblatt)? Wenn Du deinen Quellcode posten kannst, können wir dir besser helfen! Die genaue Bezeichnung des Displays ist auch wichtig!
Die Pausen sind sogar etwas grösser als im Datenblatt, die Init - Sequenz hat auf dem alten MPLAB funktioniert. Aber da gab es das #use delay, was meiner Meinung besser ist, da man dort auch Sekunden eingeben konnte und keine Grenze hatte ( mit __delay_ms kann ich nicht mal 100ms eingeben, schon motzt er. Hier der Code:
1 | #include <xc.h> |
2 | #include <stdio.h> |
3 | |
4 | #pragma config OSC = INTIO67 // Oscillator Selection bits (Internal oscillator block, port function on RA6 and RA7)
|
5 | #pragma config PWRT = ON // Power-up Timer Enable bit (PWRT enabled)
|
6 | #pragma config BOREN = OFF // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
|
7 | #pragma config WDT = OFF // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
|
8 | #pragma config MCLRE = OFF // MCLR Pin Enable bit (RE3 input pin enabled; MCLR disabled)
|
9 | |
10 | |
11 | #define LCD_RS LATBbits.LATB5
|
12 | #define LCD_RW LATBbits.LATB6
|
13 | #define LCD_E LATBbits.LATB7
|
14 | #define LCD_DATA LATD
|
15 | #define _XTAL_FREQ 8000000 // Clock frequency in Hz
|
16 | //#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/8000000.0)))
|
17 | //#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/8000.0)))
|
18 | |
19 | void initLCD(); |
20 | void writeLCD(char byte); |
21 | void enableLCD(); |
22 | void enableLCD1(); |
23 | void clock_set(); |
24 | |
25 | |
26 | void main (){ |
27 | |
28 | TRISA = 0x00; |
29 | TRISB = 0x00; |
30 | TRISC = 0x00; |
31 | TRISD = 0x00; |
32 | TRISE = 0x00; |
33 | OSCCON = 0xFF; |
34 | LATA = 0x00; |
35 | LATB = 0x00; |
36 | LATC = 0x00; |
37 | LATD = 0x00; |
38 | LATE = 0x00; |
39 | |
40 | initLCD(); |
41 | |
42 | while(1) |
43 | {
|
44 | LATC = 0x80; //LED EIN |
45 | writeLCD('A'); // ein Zeichen auf LCD schreiben |
46 | }
|
47 | }
|
48 | void initLCD() |
49 | {
|
50 | LCD_RS = 0; |
51 | LCD_RW = 0; |
52 | LCD_E = 0; |
53 | __delay_ms(50); |
54 | LCD_DATA = 0b00111000; //Function set |
55 | enableLCD(); |
56 | LCD_DATA = 0b00111000; //Function set |
57 | enableLCD(); |
58 | LCD_DATA = 0b00001100; //Display ON/OFF Control |
59 | enableLCD(); |
60 | LCD_DATA = 0b00000001; //clear |
61 | enableLCD(); |
62 | LCD_DATA = 0b00000111; //Entry Mode set |
63 | enableLCD(); |
64 | __delay_ms(20); |
65 | LCD_DATA = 0x01; // Clear LCD |
66 | enableLCD(); |
67 | }
|
68 | /*
|
69 | * Kommunikation mit dem LCD
|
70 | */
|
71 | void writeLCD(char byte) |
72 | {
|
73 | LCD_RW=0; |
74 | LCD_RS=0; |
75 | LCD_DATA= byte; |
76 | LCD_E = 1; |
77 | LCD_RS=1; |
78 | __delay_ms(1); |
79 | LCD_E = 0; |
80 | __delay_us(40); |
81 | }
|
82 | /*
|
83 | * Erzeugen eines Enable Strobbes, der Dauer 20µs
|
84 | */
|
85 | void enableLCD() |
86 | {
|
87 | LCD_E=1; |
88 | __delay_us(40); |
89 | LCD_E=0; |
90 | __delay_us(40); |
91 | }
|
92 | // langer Strobe für die 2ms Pause in der INIT
|
93 | void enableLCD1() |
94 | {
|
95 | LCD_E=1; |
96 | __delay_ms(2); |
97 | LCD_E=0; |
98 | __delay_us(40); |
99 | }
|
Mach mal das
1 | #define _XTAL_FREQ 8000000
|
vor
1 | #include <xc.h> |
Der braucht das ja schon da drin.
und vielleicht solltest du die Funktion "enableLCD1" in der INIT benutzen wie in dein Komentar beschrieben :-)
Hans Wiederkehr schrieb: > // langer Strobe für die 2ms Pause in der INIT > void enableLCD1() > { > LCD_E=1; > __delay_ms(2); > LCD_E=0; > __delay_us(40); > } Seit wann muß das E-Signal 2 ms lang high sein? Das ist doch irgendwie quatsch. Wahrscheinlich fängt die Zeit für das Display erst an zu zählen, wenn E auf low geht. Die lange Pause gehört ans Ende, und die Länge des Enable Pulses ist so rund eine µs, höchstens zwei MfG Klaus
Hans Wiederkehr schrieb: > // langer Strobe für die 2ms Pause in der INIT > void enableLCD1() > { > LCD_E=1; > __delay_ms(2); > LCD_E=0; > __delay_us(40); > } Das ist falsch. Die Wartezeit bis zum nächsten Befehl beginnt nach dem Enable-Puls. Für den Enable-Puls selber sind 1µs dicke ausreichend:
1 | void enableLCD1() |
2 | {
|
3 | LCD_E=1; |
4 | __delay_us(1); |
5 | LCD_E=0; |
6 | __delay_ms(2); |
7 | }
|
_XTAL_FREQ/8000000.0 sollte sein: _XTAL_FREQ/4000000.0 dasselbe bei _ms delay.
So, ich hab jetzt alle Ratschläge befolgt und geändert: - XTAL_FREQ kommt als aller erstes - Die Enable Funktion hat jetzt : E = 1, 1uS delay, E=0, 40 us delay. Klappt immer nich nicht. Wieder das selbe wie bisher :( Mir fallen gleich die Haare aus :) :) Hat noch wer ne Idee? Hier der neue code:
1 | #define _XTAL_FREQ 8000000
|
2 | |
3 | #include <xc.h> |
4 | #include <stdio.h> |
5 | #include <stdlib.h> |
6 | |
7 | #pragma config OSC = INTIO67 // Oscillator Selection bits (Internal oscillator block, port function on RA6 and RA7)
|
8 | #pragma config PWRT = ON // Power-up Timer Enable bit (PWRT enabled)
|
9 | #pragma config BOREN = OFF // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
|
10 | #pragma config WDT = OFF // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
|
11 | #pragma config MCLRE = OFF // MCLR Pin Enable bit (RE3 input pin enabled; MCLR disabled)
|
12 | |
13 | |
14 | #define LCD_RS LATBbits.LATB5
|
15 | #define LCD_RW LATBbits.LATB6
|
16 | #define LCD_E LATBbits.LATB7
|
17 | #define LCD_DATA LATD
|
18 | |
19 | void initLCD(); |
20 | void writeLCD(char byte); |
21 | void enableLCD(); |
22 | |
23 | int i = 0; |
24 | |
25 | void main (){ |
26 | |
27 | TRISA = 0x00; |
28 | TRISB = 0x00; |
29 | TRISC = 0x00; |
30 | TRISD = 0x00; |
31 | TRISE = 0x00; |
32 | OSCCON = 0xFF; |
33 | LATA = 0x00; |
34 | LATB = 0x00; |
35 | LATC = 0x00; |
36 | LATD = 0x00; |
37 | LATE = 0x00; |
38 | |
39 | initLCD(); |
40 | |
41 | while(1) |
42 | {
|
43 | LATC = 0x00; |
44 | if (i == 0); |
45 | {
|
46 | LATC = 0x80; //LED EIN |
47 | writeLCD('G'); // ein Zeichen auf LCD schreiben |
48 | i = 1; |
49 | }
|
50 | }
|
51 | }
|
52 | |
53 | void initLCD() |
54 | {
|
55 | |
56 | |
57 | LCD_RS = 0; |
58 | LCD_RW = 0; |
59 | LCD_E = 0; |
60 | __delay_ms(50); |
61 | LCD_DATA = 0b00111000; //Function set |
62 | enableLCD(); |
63 | LCD_DATA = 0b00111000; //Function set |
64 | enableLCD(); |
65 | LCD_DATA = 0b00111000; //Function set |
66 | enableLCD(); |
67 | LCD_DATA = 0b00001100; //Display ON/OFF Control |
68 | enableLCD(); |
69 | LCD_DATA = 0b00000001; //clear |
70 | enableLCD(); |
71 | __delay_ms(2); |
72 | LCD_DATA = 0b00000111; //Entry Mode set |
73 | enableLCD(); |
74 | LCD_DATA = 0x01; // clear |
75 | enableLCD(); |
76 | __delay_ms(2); |
77 | }
|
78 | /*
|
79 | * Kommunikation mit dem LCD
|
80 | */
|
81 | void writeLCD(char byte) |
82 | {
|
83 | LCD_RW=0; |
84 | LCD_RS=0; |
85 | __delay_us(1); |
86 | LCD_DATA= byte; |
87 | LCD_RS = 1; |
88 | enableLCD(); |
89 | }
|
90 | /*
|
91 | * Erzeugen eines Enable Strobbes, der Dauer 20µs
|
92 | */
|
93 | void enableLCD() |
94 | {
|
95 | LCD_E=1; |
96 | __delay_us(2); |
97 | LCD_E=0; |
98 | __delay_us(50); |
99 | }
|
Hö, hö, ho Hier
1 | LCD_DATA = 0b00111000; //Function set |
2 | enableLCD(); |
3 | LCD_DATA = 0b00111000; //Function set |
4 | enableLCD(); |
5 | LCD_DATA = 0b00111000; //Function set |
6 | enableLCD(); |
sind jeweils Wartezeiten einzuhalten! Bitte lass diesen Quatsch
1 | while(1) |
2 | {
|
3 | LATC = 0x00; |
4 | if (i == 0); |
5 | {
|
6 | LATC = 0x80; //LED EIN |
7 | writeLCD('G'); // ein Zeichen auf LCD schreiben |
8 | i = 1; |
9 | }
|
10 | }
|
wenn du etwas beim hochfahren des Programms nur einmalig ausführen willst, dann zieh es vor die while Schleife. Aber mach da keine Kunstprojekte draus. Das ist alles Code, den man erneut überprüfen muss, ob du dir da nicht wieder irgendwo einen Fehler eingebaut hast. Sinnlos überprüfen muss
1 | ....
|
2 | LATC = 0x80; //LED EIN |
3 | writeLCD('G'); // ein Zeichen auf LCD schreiben |
4 | |
5 | while(1) |
6 | {
|
7 | }
|
8 | }
|
feddich. Das ist simpel, überschaubar und mann muss nicht überlegen ob das so stimmt. Dein Problem ist jetzt das Timing für das LCD richtig hinzukriegen. Beschäftige dich damit und nicht mit irgendwelchen anderen zusätzlichen Komplikationen. Die lösen dein Problem ganz sicher nicht. Wenn das LCD erst mal läuft, dann kannst du dich nach Herzenslust austoben. Aber bitte nicht vorher. Das sind alles Dinge, die selbst wieder potentielle Fehler enthalten können. Und genau das kannst du jetzt überhaupt nicht brauchen.
Du sagst, du kannst das Programm durchsteppen und wenn du das tust, dann initialisiert es richtig. Kannst du auch Breakpoints setzen? Wenn ja, dann setz halt erst mal einen Breakpoint hier hin
1 | void initLCD() |
2 | {
|
3 | |
4 | |
5 | LCD_RS = 0; |
6 | LCD_RW = 0; |
7 | LCD_E = 0; |
8 | __delay_ms(50); |
9 | LCD_DATA = 0b00111000; //Function set |
10 | enableLCD(); |
11 | |
12 | <------------- Breakpoint |
13 | |
14 | LCD_DATA = 0b00111000; //Function set |
15 | enableLCD(); |
16 | LCD_DATA = 0b00111000; //Function set |
17 | enableLCD(); |
wenn du dann weiterlaufen lässt, initialisiert das LCD wenn du weitersteppst? Wenn du den Breakpoint tiefer setzt
1 | void initLCD() |
2 | {
|
3 | |
4 | |
5 | LCD_RS = 0; |
6 | LCD_RW = 0; |
7 | LCD_E = 0; |
8 | __delay_ms(50); |
9 | LCD_DATA = 0b00111000; //Function set |
10 | enableLCD(); |
11 | LCD_DATA = 0b00111000; //Function set |
12 | enableLCD(); |
13 | |
14 | <--------
|
15 | |
16 | LCD_DATA = 0b00111000; //Function set |
17 | enableLCD(); |
initialisiert es dann, wenn du weitersteppst? Sinn der Sache ist es, rauszufinden, wo die du dem LCD eine zu kurze Pause gibst. Indem du einen Breakpoint setzt, läuft das Programm bis dort hin mit voller Geschwindigkeit und danach langsamer. D.h. durch das versetzen des Breakpoints unterteilst du die Initialisierung in einen Teil, der volle Kanne abläuft und einen der langsamer abläuft. AN der Stelle, an der sich das Verhalten ändert (von funktioniert auf funktioniert nicht), würde ich mal ansetzem, dass du da dem LCD etwas zu wenig Zeit lässt.
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.