Forum: Mikrocontroller und Digitale Elektronik PIC und LCD QC1602A V2.0 bringen mich zum Wahnsinn


von Gerhard H. (oderlachs)


Lesenswert?

Hallo Freunde !

Seit einiger Zeit befasse ich mich aktiv mit der PIC Programmierung, per 
MPLAB.X  und XC8 C Compiler.
Ich wollte ein Programm zur LCD Anzeige schreiben , doch gelang es mir 
nicht, dem LCD was zu entlocken.
Da ich nun einiger der LCD QC1602A V2.0 habe, dachte ich, dass diese 
doch nicht alle defekt sein könnten. Also habe ich ein Arduinoprojekt 
gestartet für die Anzeige per LCD....und siehe da alle LCD sind OK.
Nun habe ich fast einen ganzen Tag gesessen , Programm neu geschrieben 
und wieder versucht. Dann habe ich ein Anderes LCD EW162B0YLY per 
Adapter angeschlossen und siehe da es geht tadellos. was mache ich nun 
falsch ???

Hier der Code:
1
 /*
2
 * File:   meinLCD_1.c
3
 * Author: gerhard hinze 
4
 *
5
 * Created on 02. April 2017, 16:03
6
 */
7
// CONFIG
8
#pragma config FOSC = XT        // Oscillator Selection bits (XT oscillator)
9
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
10
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
11
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
12
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
13
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
14
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
15
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)
16
17
// #pragma config statements should precede project file includes.
18
// Use project enums instead of #define for ON and OFF.
19
#define _XTAL_FREQ 4000000  //EasyPIC-40 FQ= 4.0MHz  
20
//#define _XTAL_FREQ 3686400  //EasyPIC-40 FQ= 3.6864MHz
21
#include <xc.h>
22
/* ========================================================================== */
23
/*                                                                            */
24
/*                 MCU = PIC16F877A   XTAL = 4.000 MHz                        */
25
/*                                                                            */
26
/* ========================================================================== */
27
/*                                                                            */
28
/*                  Definitionen LCD 16x2 Anschlüsse                          */
29
/*                                                                            */
30
/* ========================================================================== */
31
32
#define RS  RA1
33
#define RW  RA2
34
#define EN  RA3
35
36
#define D0  RD0
37
#define D1  RD1
38
#define D2  RD2
39
#define D3  RD3
40
#define D4  RD4
41
#define D5  RD5
42
#define D6  RD6
43
#define D7  RD7
44
45
#define SET_CMD_PORT    TRISA
46
#define SET_DAT_PORT    TRISD
47
#define DATA_PORT       PORTD
48
#define CMD_PORT        PORTA
49
50
#define DELAY_INIT  __delay_ms(200)
51
#define DELAY_CMD   __delay_ms(50)
52
#define DELAY_DAT   __delay_ms(10)
53
/* ========================================================================== */
54
/*                                                                            */
55
/*                                                                            */
56
/*                                                                            */
57
/* ========================================================================== */
58
void LCD_Init();
59
void CMD_Init();
60
void CHR_Init();
61
void CMD_Write(unsigned char cmd);
62
void CHR_Write(unsigned char chr);
63
void TXT_Write(char *txt, unsigned char x, unsigned char y);
64
void SET_Pos(unsigned char x, unsigned char y);
65
/* ========================================================================== */
66
/*                                                                            */
67
/*                  LCD Initialisieren                                        */
68
/*                                                                            */
69
/* ========================================================================== */
70
void LCD_Init()
71
{
72
  SET_CMD_PORT  = 0x00;            //  PORTA alles OUTPUT
73
  SET_DAT_PORT  = 0x00;            //  PORTD alles OUTPUT
74
  CMD_PORT      = 0x00;            //  PORTA alles LOW - Pegel
75
  DATA_PORT     = 0x00;            //  PORTD alles LOW - Pegel
76
          
77
        DELAY_INIT;                //  Warten bis Ub(LCD) sich stabilisiert hat
78
        CMD_Write(0x01);           //  Display clear, Cursor auf Pos. 1.1
79
        CMD_Init();
80
       
81
        CMD_Write(0x38);           //  8-BIT 5*7Pkt
82
        CMD_Init();
83
        
84
        CMD_Write(0x0C);           //  Display ein und Cursor OFF, blinkt nicht
85
        CMD_Init();
86
        
87
        CMD_Write(0x06);           //  Cursor autoincrement
88
        CMD_Init();
89
        
90
        CMD_Write(0x80);           //  Setze Cursor Zeile 1, Spalte 0
91
        CMD_Init();
92
        
93
}
94
/* ========================================================================== */
95
/*                                                                            */
96
/*               Kommando Init zur Kommandouebernahme vom PORTD               */
97
/*                                                                            */
98
/* ========================================================================== */
99
void CMD_Init()
100
{
101
   RS = 0;  // Kommando
102
   RW = 0;
103
   EN = 0;
104
   DELAY_CMD;
105
   EN = 1;
106
   DELAY_CMD;
107
}
108
109
/* ========================================================================== */
110
/*                                                                            */
111
/*                Kommando Init zur Datenuebernahme vom PORTD                 */
112
/*                                                                            */
113
/* ========================================================================== */
114
void CHR_Init()
115
{
116
   RS = 1;  //Daten
117
   RW = 0;
118
   EN = 0;
119
   DELAY_DAT;
120
   EN = 1;
121
  DELAY_DAT;
122
 }
123
/* ========================================================================== */
124
/*                                                                            */
125
/*                  Kommando Schreiben                                        */
126
/*                                                                            */
127
/* ========================================================================== */
128
void CMD_Write(unsigned char cmd)
129
{
130
   DATA_PORT = cmd;  //PORTD = cmd(Befehlswert)
131
   CMD_Init();
132
}
133
/* ========================================================================== */
134
/*                                                                            */
135
/*                  1 Zeichen schreiben                                       */
136
/*                                                                            */
137
/* ========================================================================== */
138
void CHR_Write(unsigned char chr)
139
{
140
    DATA_PORT = chr;  //PORTD = chr (Zeichen/Byte)
141
    CHR_Init();
142
  
143
}
144
145
/* ========================================================================== */
146
/*                                                                            */
147
/*              Cursor Position schreiben                                     */
148
/*                                                                            */
149
/* ========================================================================== */
150
void SET_Pos(unsigned char x, unsigned char y)
151
{
152
    if(y == 1)               // Zeile 1
153
    CMD_Write(0x80 + x);   // Setze RAM-Adresse + X-position
154
  else if(y == 2)          // Zeile 2
155
    CMD_Write(0xC0 + x); // Setze RAM-Adresse + X-position
156
}
157
158
/* ========================================================================== */
159
/*                                                                            */
160
/*                   Text schreiben                                           */
161
/*                                                                            */
162
/* ========================================================================== */
163
void TXT_Write(char *txt, unsigned char x, unsigned char y)
164
{   SET_Pos(x,y);
165
    int i;
166
  for(i=0;i<=16;i++)
167
    {// Durchlauf Textstring bis Stringende: "0"
168
        if (txt[i]== 0)
169
            return;
170
        else
171
      CHR_Write(txt[i]);  
172
    }// Char ("Zeichen") schreiben
173
}
174
175
/* ========================================================================== */
176
/*                                                                            */
177
/*                                                                            */
178
/*                                                                            */
179
/*                                                                            */
180
/* ========================================================================== */
181
182
183
void init()
184
 {
185
    ADCON1 = 0x07;               // PORTA als digitaler I/O
186
 
187
 }
188
189
/* ========================================================================== */
190
/*                                                                            */
191
/*                    Mainroutine/Hauptprogramm                               */
192
/*                                                                            */
193
/* ========================================================================== */
194
195
196
void main(void) {
197
    init();
198
    LCD_Init();
199
    __delay_ms(200);
200
    TXT_Write("Hallo",6,1);  // Schreibe in Zeile 1 ab Spalte 5
201
    TXT_Write("PIC16F877A",3,2);  // Schreibe in Zeile 2 ab Spalte 3
202
203
    while(1);
204
}

Vielleicht hat ja wer einen guten Hinweis für mich, ich hoffe das ich 
das C-Listing gut genug kommentiert habe.

Mit vielen Dank im Voraus

Gerhard

: Bearbeitet durch User
Beitrag #4961041 wurde vom Autor gelöscht.
von Volker S. (vloki)


Lesenswert?

Gerhard H. schrieb:
> Ich wollte ein Programm zur LCD Anzeige schreiben , doch gelang es mir
> nicht, dem LCD was zu entlocken.

Wie sieht das LCD aus nachdem du versucht hast zu initialisieren und zu 
schreiben?
Alles schwarz, obere Zeile schwarz oder gar nichts schwarz?

<edit> Poste doch mal einen Link auf das Datasheet, dem du die Sequenz 
zur Initialisierung entnommen hast...

: Bearbeitet durch User
von Gerhard H. (oderlachs)


Lesenswert?

Hallo,
die obere Zeile ist "schwarz", das heißt alle 16 Zeichen sind mit allen 
Pixel aktiv, sprich 16 Rechtecke, a 5x8 Pixel, werden angezeigt...
das ist wenn ich nur das LCD initialisiere..
Schreibe ich den Text, siehe Listing, habe ich in der 2. Zeile habe ich 
an 4.Stelle(mit 1 beginnend) ein wirres Zeichen...das aber nur wenn ich 
die Bordspannung nach dem Flashen kurz unterbreche  sonst nur schwarzer 
Balken.
Schreibe ich nur in die erste Zeile und unterbreche die Spannung kurz 
ist gar nix zu sehen. Ohne Spannungsunterbrechung , so wie bei der nur 
Initialisierung

Gerhard

: Bearbeitet durch User
von Volker S. (vloki)


Lesenswert?

Gerhard H. schrieb:
> Hallo,
> die obere Zeile ist "schwarz", das heißt alle 16 Zeichen sind mit allen
> Pixel aktiv, sprich 16 Rechtecke, a 5x8 Pixel, werden angezeigt...
> das ist wenn ich nur das LCD initialisiere..

Ist vorher auch schon so oder?
Die Initialisierung kommt mir seltsam vor.
Meine sieht ungefähr so aus:
1
void LCD_Init (void)
2
{
3
    LCD_RW = 0; LCD_RW_DIR = 0;
4
    LCD_RS = 0; LCD_RS_DIR = 0;
5
    LCD_E  = 0; LCD_E_DIR  = 0;
6
7
    LCD_PINS_DIGITAL();
8
9
    LCD_DIR_OUT();
10
11
    LCD_busy_cnt = 1;    // busy_flag time out counter
12
13
    LCD_DELAY_5MS();LCD_DELAY_5MS();LCD_DELAY_5MS();    // wait for 15ms
14
// display reset procedure
15
    LCD_Write_Nibble(LCD_RESET);    LCD_DELAY_5MS();
16
    LCD_Write_Nibble(LCD_RESET);    LCD_DELAY_5MS();
17
    LCD_Write_Nibble(LCD_RESET);    LCD_DELAY_5MS();
18
19
#ifdef LCD_USE_8BIT_DATA
20
    LCD_Write_Nibble(EIGHT_BIT); while(LCD_Busy()){;} // wait
21
    LCD_Command(EIGHT_BIT_TWO_LINE);
22
#else
23
    LCD_Write_Nibble(FOUR_BIT); while(LCD_Busy()){;} // wait
24
    LCD_Command(FOUR_BIT_TWO_LINE);
25
#endif
26
    LCD_Command(DISPLAY_CTRL + DISPLAY_ON);// + BLINK_ON);
27
    LCD_Command(ENTRY_MODE + CURSOR_INC + DSHIFT_OFF);
28
    LCD_Clear();
29
    LCD_Home();
30
}

Volker S. schrieb:
> Poste doch mal einen Link auf das Datasheet, dem du die Sequenz
> zur Initialisierung entnommen hast...

: Bearbeitet durch User
von Jens P. (picler)


Lesenswert?

Gerhard H. schrieb:
> void init()
>  {
>     ADCON1 = 0x07;               // PORTA als digitaler I/O
>
>  }

Wenn ich das richtig sehe, hast du zwar die analogen Eingänge 
deaktiviert, aber die digitalen Ports nicht definiert.
So in der Art:

TRISD=0x00;
TRISA=0b11110001;

Versuche es mal damit.

: Bearbeitet durch User
von Gerhard H. (oderlachs)


Lesenswert?

Doch, doch Jens, siehe bitte hier:

Die Definitionen:

#define SET_CMD_PORT    TRISA
#define SET_DAT_PORT    TRISD
#define DATA_PORT       PORTD
#define CMD_PORT        PORTA


Gleich zu Anfang der Routine : "void LCD_Init()" setzen der Werte

  SET_CMD_PORT  = 0x00;            //  PORTA alles OUTPUT
  SET_DAT_PORT  = 0x00;            //  PORTD alles OUTPUT
  CMD_PORT      = 0x00;            //  PORTA alles LOW - Pegel
  DATA_PORT     = 0x00;            //  PORTD alles LOW - Pegel

@Volker:
Es ist nicht mein erstes LCD Programm.  mit einem PIC schon, aber ich 
kann mir beim besten Willen nicht vorstellen, das sich die Init-Routine 
eines LCD's im Ablauf zwischen AVR oder PIC Anwendung unterscheidet.
Gut ich bin PIC Anfänger und lasse mich gern belehren.

Hier das Datenblatt vom LCD:
https://www.openhacks.com/uploadsproductos/eone-1602a1.pdf

Leider ist für die Version 2.0 nirgends etwas aufzutreiben...Aus der 
Tabelle , Seite 5, habe ich die Hexa-Kommandowerte genommen/berechnet.

Gerhard

: Bearbeitet durch User
von Witkatz :. (wit)


Lesenswert?

Gerhard H. schrieb:
> EN = 0;
>    DELAY_CMD;
>    EN = 1;
>    DELAY_CMD;
> }

Du hälst EN ständig High und erzeugst zum Datenübernehmen einen kurzen 
neg. Impuls oder? In der Spec. ist das Timing des EN genau andersherum. 
Ich würde mal versuchen die Polarität des EN-Impuls zu drehen und 
wirklich nur einen kurzen Puls auszugeben also
1
  EN = 1;
2
  __delay_us(5); kurzer pos. Strobe
3
  EN = 0;
4
  DELAY_CMD;

: Bearbeitet durch User
von Volker S. (vloki)


Angehängte Dateien:

Lesenswert?

<edit2>OK, ich sehe der ST7066 scheint standardmäßig im 8-Bit zu sein 
und ich mach das dann wohl fast immer unnötiger Weise ;-)


Gerhard H. schrieb:
> @Volker:
> Es ist nicht mein erstes LCD Programm.  mit einem PIC schon, aber ich
> kann mir beim besten Willen nicht vorstellen, das sich die Init-Routine
> eines LCD's im Ablauf zwischen AVR oder PIC Anwendung unterscheidet.
> Gut ich bin PIC Anfänger und lasse mich gern belehren.

Na warum nimmst du dann nicht die Lib die du für den AVR geschrieben 
hast?

Im Ernst:
Wenn ich das richtig sehe, dann willst du den 8-bit Modus benutzen.
Den muss man bei allen dieser LCDs die ich kenne erst mal über den 4-bit 
Modus einstellen. Das steht nicht immer im Datasheet zum LCD, sondern 
oft nur im Datasheet des darin verwendeten Controllers. Das scheint bei 
dir der ST7066 zu sein. Da sind dann so Diagramme...

Bei meiner Init ist das LCD_RESET als 0x30 definiert.
LCD_Write_Nibble(LCD_RESET);    LCD_DELAY_5MS();

<edit>Da liegt ein Demo Projekt. 
http://picforum.ric323.com/viewtopic.php?f=40&t=210
Sollte auch leicht für PIC16 anpassbar sein. Benützt allerdings das 
BusyFlag...

: Bearbeitet durch User
von Gerhard H. (oderlachs)


Lesenswert?

@Volker :

Der 8-Bit Modus ist vom Board hardwaremäßig vorgegeben.

Eine Lib habe ich auch für AVR nicht extra geschrieben, weil das für 
eine einfache Anzeigen Programmierung gar nicht verlohnt.
Bei "Geany" als Programmierumgebung(LINUX) , ist es mit dem einbinden 
der LIB's auch so eine Sache...Unter Windows mit AVR -Studio wäre es was 
anderes..

Na ich werde mich mit diesen LCD's nicht lange mehr herum ärgern, habe 
schon 4 St. mit HD44780 geordert. Da die LCD's aber unter Arduino prima 
funktionieren muss ich sie entweder preiswert alle veräußern oder selber 
für eventuelle Arduino-Anwendungen benützen..

Nun, vielleicht finden sich ein paar Regentage noch, wo einem solches 
Probieren am PC eine willkommene Beschäftigung ist...

@Witkatz:

So sieht man sich wieder... ;)
das mit EN usw... habe ich ja schon lange in allen Varianten durch... 
das Dumme ist das ein mit HT44780 bestücktes LCD ohne Makel arbeitet...

Egal , wie schon oben geschrieben werde ich mich damit nicht mehr lange 
rum ärgern, obwohl hätte den Fehler doch gern gewusst. ;=)

Werde wenn Zeit das AVR-STK500 auf den Tisch bringen , nochmals damit 
versuchen, es würde mich umhauen ;) , wenn's damit ginge..
oder mit dem Atmel AT89S52 Entwicklerboard...**gg

Gerhard

von Volker S. (vloki)


Lesenswert?

Gerhard H. schrieb:
> Der 8-Bit Modus ist vom Board hardwaremäßig vorgegeben.

Ja, habe ich auch schon gemerkt ;-)
Ich vermute mal, dass ich das mit der manuelle Initialisierung vor 
langer Zeit aus der XLCD Bibliothek von Microchip übernommen habe...

Wenn die interne Initialisierung funktioniert, dann müsste man 
eigentlich nur auf die entsprechende Zeilenzahl einstellen. Was mich 
wundert ist, wieso nur die oberste Zeile schwarz ist.

von Gerhard H. (oderlachs)


Lesenswert?

So vielen Herzlichen Dank an Witkatz !!!!!

Hier musste ich wirklich EN, nach Deiner Info; im Pegel umändern  und es 
geht !!
Hurra !!
Hallo Witkatz, sei doch bitte so nett und schreibe mir mal genauer wo Du 
dafür die Quelle gefunden hast.

Damit wäre, das schon oft angesprochene Problem mit dem LCD QC1602A V2.0 
gelöst. :=)

Besten Grüsse und vielen Dank
vom einem, sich ein Loch in den ??? freuenden,

Gerhard

Nachtrag :

Ich hatte mir als PIC Neuling ein Beispiel genommen, vielleicht bin ich 
dadurch in den Irrgarten gekommen:
1
 //--------------------------------------
2
//write a byte to lcd.
3
void write(char x)
4
 {
5
  PORTD=x;                   //data send to PORTD
6
  rs=1;                      //is data not command.
7
  rw=0;                      //is write not read.
8
  e=0;                       //pull low enable signal.
9
  delay();                 //for a while.
10
  e=1;                       //pull high to build the rising edge.
11
 }
12
13
//--------------------------------------
14
//lcd display setting 
15
void lcd_enable()
16
 {
17
   rs=0;                     //is command not data
18
   rw=0;                     //is write not read. 
19
   e=0;                      //pull low enable signal.           
20
   delay();                  //for a while.  
21
   
22
   e=1;                      //pull high to build the rising edge
23
 }

: Bearbeitet durch User
von Volker S. (vloki)


Lesenswert?

Gerhard H. schrieb:
> Hallo Witkatz, sei doch bitte so nett und schreibe mir mal genauer wo Du
> dafür die Quelle gefunden hast.

Vermutlich aus den Diagrammen auf Seite 5 des dir verlinkten 
Datenblattes oder dem vom Controller aus dem diese Diagramme kopiert 
wurden.


Volker S. schrieb:
> Ich vermute mal, dass ich das mit der manuelle Initialisierung vor
> langer Zeit aus der XLCD Bibliothek von Microchip übernommen habe...
War Quatsch - Ich muss das machen, weil ich praktisch immer 4bit Mode 
verwende :-(

: Bearbeitet durch User
von Witkatz :. (wit)


Lesenswert?

Gerhard H. schrieb:
> Hallo Witkatz, sei doch bitte so nett und schreibe mir mal genauer wo Du
> dafür die Quelle gefunden hast.

Die Quelle hast du selbst verlinkt. Es ist das Timingdiagramm auf Seite 
5 des Datenblatts (1602A-1  LCD Module Specification), das du weiter 
oben anführst.

Ausserdem habe ich in die XLCD reingeschaut. Die kommt mit der PLIB von 
Microchip (PIC18F Legacy Peripheral Libraries v2.0). Ich benutze sie 
manchmal als Vorlage eigener Peripheriefunktionen.

Warum dein Display nicht funktioniert hat, weiss ich nicht. In dem 
Datenblatt finde ich keine maximale Zeit für EN = 1, bzw. das Display 
übernimmt die Daten bei der negativen Flanke nicht, wenn EN zu lange 1 
war. Irgendwo hier ist die Ursache zu suchen.

Gruß
witkatz

von Klaus (Gast)


Lesenswert?

Witkatz :. schrieb:
> Warum dein Display nicht funktioniert hat, weiss ich nicht. In dem
> Datenblatt finde ich keine maximale Zeit für EN = 1, bzw. das Display
> übernimmt die Daten bei der negativen Flanke nicht, wenn EN zu lange 1
> war. Irgendwo hier ist die Ursache zu suchen.

Das ist das klassische Motorola 6800 Interface. Die brauchen einen 
High-Puls am EN(able) wo Intel aktive low WR und RD haben. Der 
Ruhezustand von EN ist low, solange es high ist, sollten alle anderen 
Signale stabil sein.
1
void write(char x)
2
 {
3
  PORTD=x;                   //data send to PORTD
4
  rs=1;                      //is data not command.
5
  rw=0;                      //is write not read.
6
  e=1;
7
  e=0;                       //allways leave with EN low
8
 }
Der PIC mit 4 MHz ist so langsam, da braucht man kein delay für 140ns, 
höchstens ein NOP().

MfG Klaus

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.