Forum: Mikrocontroller und Digitale Elektronik Problem LCD -- PIC


von Hans W. (coglione)


Lesenswert?

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 :) :(

von Nico (nico123)


Lesenswert?

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!

von Hans W. (coglione)


Lesenswert?

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
}

von test (Gast)


Lesenswert?

Mach mal das
1
#define _XTAL_FREQ 8000000
vor
1
#include <xc.h>

Der braucht das ja schon da drin.

von Castlerock (Gast)


Lesenswert?

und vielleicht solltest du die Funktion "enableLCD1" in der INIT 
benutzen wie in dein Komentar beschrieben :-)

von Klaus (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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
}

von Chris (Gast)


Lesenswert?

_XTAL_FREQ/8000000.0
sollte sein:
_XTAL_FREQ/4000000.0
dasselbe bei _ms delay.

von Hans W. (coglione)


Lesenswert?

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
}

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
Noch kein Account? Hier anmelden.