PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : LCD (KS0066) 4Bit-Mode init brauche hilfe, PIC 18f4550



andi.studi
20.07.2008, 01:32
Hallo PIC freunde ich hoffe ihr seid dieses Thema noch nicht leid, und könnt mir weiterhelfen, ich versuch es schon seit einer Woche ohne erfolg.

Ich möchte ein 4x20 LCD im 4-Bit mode ansteuern LCD Treiber ist ein KS0066.

Ich bekomme einfach kein Zeichen auf das LCD und manchmal sieht es nach einem reset so aus als wenn er im 1-Zeilenmodus wäre.

Bitte helft mir ich komme nicht weiter ;(

/************************************************** ************
C18-compiler

PortPin: Display
RB0 = E
RB2 = RS
RB3 = R/W
RB4..RB7 = D4..D7
************************************************** ***************************/


/** I N C L U D E S ************************************************** ********/

#include <p18f4550.h>
#include <delays.h>


/** D E F I N I T I O N S ************************************************** **/

#define PORTLCD LATB
#define TRIS_LCD TRISB
#define LCD_E PORTBbits.RB0
#define LCD_RS PORTBbits.RB2
#define LCD_RW PORTBbits.RB3

//************************************************** **************************

#pragma code


void delay100us(unsigned char multiplikator)
// for PicLSBK (16MHz Taktzyklus = 4 MHz Befehlszyklus)
{
Delay10TCYx(40*multiplikator); //40*10*0,25µs = 100 µs
}


void LCD_BUSY(void)
{
unsigned char temp1;
// unsigned char temp2;
do
{
TRIS_LCD = 0xF0; // LCD-PORT = high nibbles:eingang; low nibbles:ausgang
//Display abfrage
LCD_RS = 0; // LCD im Befehls-Mode
LCD_RW = 1; // LCD im Lesen-Mode
LCD_E = 1; // Enable (LCD)
temp1 = PORTLCD;
temp1 = temp1 & 0xF0; // Niederw.Nibble (steuerbits) ausmaskieren
LCD_E = 0; // toggeln

LCD_E = 1; // Enable (LCD)
// temp2 = PORTLCD;
// temp2 = (temp2>>4)&0x0f;
// temp2 = temp1 | temp2; // Nibbles verbinden
LCD_E = 0; // toggeln
} while (temp1>=0x80);

delay100us(1);
LCD_RW = 0; // Busy = low: LCD im Schreiben-Mode
TRIS_LCD = 0x00; // LCD-PORT = Ausgänge
PORTLCD = 0x00; // Daten und Steuerleitungen LOW
}


void LCD_WriteZeichen(unsigned char zeichen)
{
unsigned char x;

LCD_BUSY(); // Warten bis LCD bereit ist

// LCD_RW = 0; // LCD im Schreiben-Mode
LCD_RS = 1; // LCD im Befehl-Mode

x = zeichen & 0xf0;
PORTLCD = x; //höherwertiges nibbel

LCD_E = 1; // Enable (LCD)
LCD_E = 0;


x = zeichen;
x = (x << 4)& 0xf0; //niederwertiges nibbel
PORTLCD = x;

LCD_E = 1; // Enable (LCD)
LCD_E = 0;

LCD_RS = 0;
}


void LCD_WriteString(char *String)
{
char zeichen;

zeichen = *String;
while(zeichen !='\0')
{
LCD_WriteZeichen(zeichen); // zeichen am LC-Display ausgeben
String++;
zeichen = *String;
}
}

void LCD_WriteRegister(char data)
{
unsigned char x;

LCD_BUSY(); // Warten bis LCD bereit ist

// LCD_RW = 0; // LCD im Schreiben-Mode
// LCD_RS = 0; // LCD im Befehl-Mode

x = data & 0xf0;
PORTLCD = x; //höherwertiges nibbel

LCD_E = 1; // Enable (LCD)
LCD_E = 0;


x = data;
x = (x << 4)& 0xf0; //niederwertiges nibbel
PORTLCD = x;

LCD_E = 1; // Enable (LCD)
LCD_E = 0;
}



void LCD_Init(void)
{
// LCD initialisieren

TRIS_LCD = 0x00; // LCD-PORT = Ausgänge
PORTLCD = 0x00; // Daten und Steuerleitungen LOW


delay100us (150);
delay100us (150); // warte über 30ms
delay100us (2);

PORTLCD = 0x30; // Interface auf 8-Bit setzen
LCD_E = 1; // Enable (LCD)
LCD_E = 0;
delay100us(45);
// Interface auf 8-Bit setzen
LCD_E = 1; // Enable (LCD)
LCD_E = 0;
delay100us(45);
// Interface auf 8-Bit setzen
LCD_E = 1; // Enable (LCD)
LCD_E = 0;
delay100us(45);

PORTLCD = 0x20; // Interface auf 4-Bit setzen
LCD_E = 1; // Enable (LCD)
LCD_E = 0;

LCD_WriteRegister(0x28); // 2-zeilig, 5x8-Punkt-Matrix
LCD_WriteRegister(0x08); // Display aus
LCD_WriteRegister(0x01); // Display löschen
LCD_WriteRegister(0x02); // Kursor nach rechts wandernd, kein Display-Shift
LCD_WriteRegister(0x0C); // Display ein [ 0x0C = ein, 0x08 = aus ]
}


void main (void)
{
LCD_Init();
LCD_WriteZeichen('t');
LCD_WriteZeichen('e');
LCD_WriteZeichen('s');
LCD_WriteZeichen('t');
}

radbruch
20.07.2008, 13:30
Hallo


...
LCD_E = 1; // Enable (LCD)
LCD_E = 0;
...
Sollte da nicht noch eine kleine Verzögerung dazwischen sein? Ich weiß nicht wie schnell so ein PIC ist, aber laut Datenblatt (http://www.datasheetcatalog.org/datasheets2/55/553815_1.pdf) (Seite 31ff) sollte E min. 230ns (tw) high sein.

Gruß

mic

andi.studi
20.07.2008, 13:41
habe schon einen nop zwischen gelegt entspricht 0,25 µs. klappt leider auch nicht.

und ich habe noch nen fehler in der LCD_WriteZeichen gefunden
jetzt wird LCD_RS auch auf 1 gesetzt,
früher wurde es mit 0 überschrieben.

leider immernoch ohne erfolg

radbruch
20.07.2008, 14:28
Hallo

Das nop würde ich auf jeden Fall mal drinlassen, eventuell (zum Testen) sogar ein zweites. Poste doch nochmal den aktuellen Code (in code-Tags), speziell wegen dem RS- und dem RW-Bit. Ich würde RS generell auf High setzen und nur während des Inits (und bei Steuerbefehlen wie clear) auf Low schalten.

Display off/on kannst du testweise auch weglassen. Ob deine Busy-Abfrage funktionert weis ich nicht, sicherheitshalber könntest du Zwangsverzögerungen nach den Befehlen ( bei display_clear z.B. 1,5ms!) einbauen.

Gruß

mic

andi.studi
20.07.2008, 14:46
hier der aktuelle code, leider immernoch ohne erfolg
aber danke schonmal für die hilfe.

habe die BUSY abfrage erstmal rausgenomen und 25ms eingesetzt.




/************************************************** *****************************
PortPin: Display
RB0 = E
RB2 = RS
RB3 = R/W
RB4..RB7 = D4..D7
************************************************** ***************************/


/** I N C L U D E S ************************************************** ********/

#include <p18f4550.h>
#include <delays.h>


/** D E F I N I T I O N S ************************************************** **/

#define PORTLCD LATB
#define TRIS_LCD TRISB
#define LCD_E PORTBbits.RB0
#define LCD_RS PORTBbits.RB2
#define LCD_RW PORTBbits.RB3
#define nop _asm nop _endasm

//************************************************** **************************

#pragma code


void delay100us(unsigned char multiplikator)
// for PicLSBK (16MHz Taktzyklus = 4 MHz Befehlszyklus)
{
Delay10TCYx(40*multiplikator); //40*10*0,25µs = 100 µs
}


void LCD_BUSY(void)
{
unsigned char temp1;
// unsigned char temp2;
do
{
TRIS_LCD = 0xF0; // LCD-PORT = high nibbles:eingang; low nibbles:ausgang
//Display abfrage
LCD_RS = 0; // LCD im Befehls-Mode
LCD_RW = 1; // LCD im Lesen-Mode
LCD_E = 1; // Enable (LCD)
temp1 = PORTLCD;
temp1 = temp1 & 0xF0; // Niederw.Nibble (steuerbits) ausmaskieren
LCD_E = 0; // toggeln

LCD_E = 1; // Enable (LCD)
// temp2 = PORTLCD;
// temp2 = (temp2>>4)&0x0f;
// temp2 = temp1 | temp2; // Nibbles verbinden
LCD_E = 0; // toggeln
} while (temp1>=0x80);

delay100us(1);
LCD_RW = 0; // Busy = low: LCD im Schreiben-Mode
TRIS_LCD = 0x00; // LCD-PORT = Ausgänge
PORTLCD = 0x00; // Daten und Steuerleitungen LOW
}


void LCD_WriteZeichen(unsigned char zeichen)
{
unsigned char x;
delay100us(250);
// LCD_BUSY(); // Warten bis LCD bereit ist


x = zeichen & 0xf0;
// LCD_RW = 0; // LCD im Schreiben-Mode
LCD_RS = 1; // LCD im Befehl-Mode
PORTLCD = x; //höherwertiges nibbel

nop;
LCD_E = 1; // Enable (LCD)
nop;
LCD_E = 0;

delay100us(50);
x = zeichen;
x = (x << 4)& 0xf0; //niederwertiges nibbel
LCD_RS = 1; // LCD im Befehl-Mode
PORTLCD = x;

LCD_E = 1; // Enable (LCD)
nop;
LCD_E = 0;
nop;
LCD_RS = 0;
}


void LCD_WriteString(char *String)
{
char zeichen;

zeichen = *String;
while(zeichen !='\0')
{
LCD_WriteZeichen(zeichen); // zeichen am LC-Display ausgeben
String++;
zeichen = *String;
}
}

void LCD_WriteRegister(char data)
{
unsigned char x;
delay100us(250);
// LCD_BUSY(); // Warten bis LCD bereit ist

// LCD_RW = 0; // LCD im Schreiben-Mode
// LCD_RS = 0; // LCD im Befehl-Mode

x = data & 0xf0;
PORTLCD = x; //höherwertiges nibbel

LCD_E = 1; // Enable (LCD)
nop;
LCD_E = 0;

delay100us(50);
x = data;
x = (x << 4)& 0xf0; //niederwertiges nibbel
PORTLCD = x;

LCD_E = 1; // Enable (LCD)
nop;
LCD_E = 0;
}



void LCD_Init(void)
{
// LCD initialisieren

TRIS_LCD = 0x00; // LCD-PORT = Ausgänge
PORTLCD = 0x00; // Daten und Steuerleitungen LOW


delay100us (150);
delay100us (150); // warte über 30ms
delay100us (100);

PORTLCD = 0x30; // Interface auf 8-Bit setzen
LCD_E = 1; // Enable (LCD)
nop;
LCD_E = 0;
delay100us(50);
// Interface auf 8-Bit setzen
LCD_E = 1; // Enable (LCD)
nop;
LCD_E = 0;
delay100us(2);
// Interface auf 8-Bit setzen
LCD_E = 1; // Enable (LCD)
nop;
LCD_E = 0;
delay100us(2);

PORTLCD = 0x20; // Interface auf 4-Bit setzen
LCD_E = 1; // Enable (LCD)
nop;
LCD_E = 0;

LCD_WriteRegister(0x28); // 2-zeilig, 5x8-Punkt-Matrix
LCD_WriteRegister(0x08); // Display aus
LCD_WriteRegister(0x01); // Display löschen
LCD_WriteRegister(0x02); // Kursor nach rechts wandernd, kein Display-Shift
LCD_WriteRegister(0x0c); // Display ein [ 0x0C = ein, 0x08 = aus ]

}


void main (void)
{
LCD_Init();
LCD_WriteZeichen('t');
LCD_WriteZeichen('e');
LCD_WriteZeichen('s');
LCD_WriteZeichen('t');
}

radbruch
20.07.2008, 15:16
Hallo

In LCD_WriteRegister() sollte die Verzögerung nach dem Schreiben des zweiten Nipples sein (delay100us(50);), sonst scheint mir das richtig zu sein.

Kannst du nun mehr als eine Zeile erkennen (mit max. Kontrast)?

In LCD_WriteZeichen() scheint mir noch ein Fehler zu sein:

...
x = zeichen & 0xf0;
// LCD_RW = 0; // LCD im Schreiben-Mode
LCD_RS = 1; // LCD im Befehl-Mode
PORTLCD = x; //höherwertiges nibbel
...
Nach &0xf0 sind die Bits 0-3 in x gelöscht, RS ist aber bit2 und wird mit PORTLCD = x; wieder gelöscht. Richtig wäre wohl entweder eine andere Reihenfolge:

PORTLCD = x; //höherwertiges nibbel
LCD_RS = 1; // LCD im Befehl-Mode

oder eine andere Formulierung:

PORTLCD = x | 4; //höherwertiges nibbel und Datenmode setzen

Ich bin aber leider auch kein LCD-Profi, wir tasten uns ran ;)

Gruß

mic

andi.studi
20.07.2008, 15:47
;) LCD_WriteZeichen() hab ich kurz nach absenden des codes auch gefunden.

habe jetzt eine verzögerung von 5 ms nach dem ersten und 2. nibble in den funktionen LCD_WriteZeichen und LCD_WriteRegister eingefügt.

aber leider immer noch ohne licht am ender des tunels:(

ja ich sehe alle 4 zeilen, wobei sie aber ganz komisch flackern auch wenn ich nur init aufrufe.

hier der neue code



/** I N C L U D E S ************************************************** ********/

#include <p18f4550.h>
#include <delays.h>


/** D E F I N I T I O N S ************************************************** **/

#define PORTLCD LATB
#define TRIS_LCD TRISB
#define LCD_E PORTBbits.RB0
#define LCD_RS PORTBbits.RB2
#define LCD_RW PORTBbits.RB3
#define nop _asm nop _endasm

//************************************************** **************************

#pragma code


void delay100us(unsigned char multiplikator)
// for PicLSBK (16MHz Taktzyklus = 4 MHz Befehlszyklus)
{
Delay10TCYx(40*multiplikator); //40*10*0,25µs = 100 µs
}


void LCD_BUSY(void)
{
unsigned char temp1;
// unsigned char temp2;
do
{
TRIS_LCD = 0xF0; // LCD-PORT = high nibbles:eingang; low nibbles:ausgang
//Display abfrage
LCD_RS = 0; // LCD im Befehls-Mode
LCD_RW = 1; // LCD im Lesen-Mode
LCD_E = 1; // Enable (LCD)
temp1 = PORTLCD;
temp1 = temp1 & 0xF0; // Niederw.Nibble (steuerbits) ausmaskieren
LCD_E = 0; // toggeln

LCD_E = 1; // Enable (LCD)
nop;
LCD_E = 0; // toggeln
} while (temp1>=0x80);

delay100us(1);
LCD_RW = 0; // Busy = low: LCD im Schreiben-Mode
TRIS_LCD = 0x00; // LCD-PORT = Ausgänge
PORTLCD = 0x00; // Daten und Steuerleitungen LOW
}


void LCD_WriteZeichen(unsigned char zeichen)
{
unsigned char x;
delay100us(200);
delay100us(200);
// LCD_BUSY(); // Warten bis LCD bereit ist

LCD_RW = 0; // LCD im Schreiben-Mode
LCD_RS = 1; // LCD im Befehl-Mode

x = zeichen & 0xf0;
x = x | LCD_RS;
PORTLCD = x; //höherwertiges nibbel

nop;
LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;

delay100us(50); //5ms warten nach den 1.nibble

x = zeichen;
x = (x << 4)& 0xf0; //niederwertiges nibbel
x = x | LCD_RS;
PORTLCD = x;

delay100us(50); //5ms warten nach den 2.nibble
LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;
nop;
LCD_RS = 0;
}


void LCD_WriteString(char *String)
{
char zeichen;

zeichen = *String;
while(zeichen !='\0')
{
LCD_WriteZeichen(zeichen); // zeichen am LC-Display ausgeben
String++;
zeichen = *String;
}
}

void LCD_WriteRegister(char data)
{
unsigned char x;
delay100us(200);
delay100us(200);
// LCD_BUSY(); // Warten bis LCD bereit ist

// LCD_RW = 0; // LCD im Schreiben-Mode
// LCD_RS = 0; // LCD im Befehl-Mode

x = data & 0xf0;
PORTLCD = x; //höherwertiges nibbel


LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;

delay100us(50); //5ms warten nach den 1.nibble
x = data;
x = (x << 4)& 0xf0; //niederwertiges nibbel
PORTLCD = x;

delay100us(50); //5ms warten nach dem 2.nibble
LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;
}



void LCD_Init(void)
{
// LCD initialisieren

TRIS_LCD = 0x00; // LCD-PORT = Ausgänge
PORTLCD = 0x00; // Daten und Steuerleitungen LOW


delay100us (150);
delay100us (150); // warte über 30ms
delay100us (100);

PORTLCD = 0x30; // Interface auf 8-Bit setzen
LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;

delay100us(50); //warte 5ms

LCD_E = 1; // Interface auf 8-Bit setzen
nop;nop; // Enable (LCD)
LCD_E = 0;

delay100us(2); //warte 200µs

LCD_E = 1; // Interface auf 8-Bit setzen
nop;nop; // Enable (LCD)
LCD_E = 0;

delay100us(2); //warte 200µs

PORTLCD = 0x20; // Interface auf 4-Bit setzen
LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;

LCD_WriteRegister(0x28); // 2-zeilig, 5x8-Punkt-Matrix
LCD_WriteRegister(0x08); // Display aus
LCD_WriteRegister(0x01); // Display löschen
LCD_WriteRegister(0x02); // Kursor nach rechts wandernd, kein Display-Shift
LCD_WriteRegister(0x0c); // Display ein [ 0x0C = ein, 0x08 = aus ]

}


void main (void)
{
LCD_Init();

}

radbruch
20.07.2008, 16:09
Hallo

Die Wartezeit nach dem zweiten Nipple muss nach der Übergabe der Daten mit E erfolgen. Datentyp für Parameter bei write_register wäre unsigned char schöner, aber sollte auch mit char funktionieren. Ich würde immer noch die Display off/on-Befehle zum Testen weglassen. Bei

LCD_WriteRegister(0x02); // Cursor nach rechts wandernd, kein Display-Shift

müßte der Wert doch 0x06 sein, oder?

Entry ModeSet 0 0 0 0 0 0 0 1 I/D SH Assign cursor moving direction and enable the shift of entire display.
Gruß

mic

andi.studi
20.07.2008, 16:09
und noch ein fehler, es muss

void LCD_WriteRegister(unsigned char data) nur char ist zu klein
klappt aber immer noch nicht

andi.studi
20.07.2008, 16:24
mensch du bist klasse;) so langsam sollten die fehler aber angst bekommen und verschwinden wenn wir so weitermachen ;)

die wartezeit nach dem 2. nibble ist jetzt auch nach dem 2. nibble (also nach enable).

hast recht es muss 0x06 heißen da hat sich bei sprut wohl ein fehler eingeschlichen und ich hab es bein abtippen nicht gemerkt.

Display off ist auch raus. // on muss doch drin bleiben, oder nicht, ist ja nach der internen init aus.




/** I N C L U D E S ************************************************** ********/

#include <p18f4550.h>
#include <delays.h>


/** D E F I N I T I O N S ************************************************** **/

#define PORTLCD LATB
#define TRIS_LCD TRISB
#define LCD_E PORTBbits.RB0
#define LCD_RS PORTBbits.RB2
#define LCD_RW PORTBbits.RB3
#define nop _asm nop _endasm

//************************************************** **************************

#pragma code


void delay100us(unsigned char multiplikator)
// for PicLSBK (16MHz Taktzyklus = 4 MHz Befehlszyklus)
{
Delay10TCYx(40*multiplikator); //40*10*0,25µs = 100 µs
}


void LCD_BUSY(void)
{
unsigned char temp1;
// unsigned char temp2;
do
{
TRIS_LCD = 0xF0; // LCD-PORT = high nibbles:eingang; low nibbles:ausgang
//Display abfrage
LCD_RS = 0; // LCD im Befehls-Mode
LCD_RW = 1; // LCD im Lesen-Mode
LCD_E = 1; // Enable (LCD)
temp1 = PORTLCD;
temp1 = temp1 & 0xF0; // Niederw.Nibble (steuerbits) ausmaskieren
LCD_E = 0; // toggeln

LCD_E = 1; // Enable (LCD)
nop;
LCD_E = 0; // toggeln
} while (temp1>=0x80);

delay100us(1);
LCD_RW = 0; // Busy = low: LCD im Schreiben-Mode
TRIS_LCD = 0x00; // LCD-PORT = Ausgänge
PORTLCD = 0x00; // Daten und Steuerleitungen LOW
}


void LCD_WriteZeichen(unsigned char zeichen)
{
unsigned char x;
delay100us(200);
delay100us(200);
// LCD_BUSY(); // Warten bis LCD bereit ist

LCD_RW = 0; // LCD im Schreiben-Mode
LCD_RS = 1; // LCD im Befehl-Mode

x = zeichen & 0xf0;
x = x | LCD_RS;
PORTLCD = x; //höherwertiges nibbel

nop;
LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;

delay100us(50); //5ms warten nach den 1.nibble

x = zeichen;
x = (x << 4)& 0xf0; //niederwertiges nibbel
x = x | LCD_RS;
PORTLCD = x;

LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;
delay100us(50); //5ms warten nach den 2.nibble
LCD_RS = 0;
}


void LCD_WriteString(unsigned char *String)
{
unsigned char zeichen;

zeichen = *String;
while(zeichen !='\0')
{
LCD_WriteZeichen(zeichen); // zeichen am LC-Display ausgeben
String++;
zeichen = *String;
}
}

void LCD_WriteRegister(unsigned char data)
{
unsigned char x;
delay100us(200);
delay100us(200);
// LCD_BUSY(); // Warten bis LCD bereit ist

// LCD_RW = 0; // LCD im Schreiben-Mode
// LCD_RS = 0; // LCD im Befehl-Mode

x = data & 0xf0;
PORTLCD = x; //höherwertiges nibbel


LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;

delay100us(50); //5ms warten nach den 1.nibble
x = data;
x = (x << 4)& 0xf0; //niederwertiges nibbel
PORTLCD = x;

LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;
delay100us(50); //5ms warten nach dem 2.nibble
}



void LCD_Init(void)
{
// LCD initialisieren

TRIS_LCD = 0x00; // LCD-PORT = Ausgänge
PORTLCD = 0x00; // Daten und Steuerleitungen LOW


delay100us (150);
delay100us (150); // warte über 30ms
delay100us (100);

PORTLCD = 0x30; // Interface auf 8-Bit setzen
LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;

delay100us(50); //warte 5ms

LCD_E = 1; // Interface auf 8-Bit setzen
nop;nop; // Enable (LCD)
LCD_E = 0;

delay100us(2); //warte 200µs

LCD_E = 1; // Interface auf 8-Bit setzen
nop;nop; // Enable (LCD)
LCD_E = 0;

delay100us(2); //warte 200µs

PORTLCD = 0x20; // Interface auf 4-Bit setzen
LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;

LCD_WriteRegister(0x28); // 2-zeilig, 5x8-Punkt-Matrix
// LCD_WriteRegister(0x08); // Display aus
LCD_WriteRegister(0x01); // Display löschen
LCD_WriteRegister(0x06); // Kursor nach rechts wandernd, kein Display-Shift
LCD_WriteRegister(0x0c); // Display ein [ 0x0C = ein, 0x08 = aus ]

}


void main (void)
{
LCD_Init();
LCD_WriteZeichen('t');
}

radbruch
20.07.2008, 17:03
Hallo

Tja, so langsam gehen mir die Ideen aus. Du könntest bei Display on (sollte doch besser drin bleiben) ein 0x0f übergeben, dann müßte der Cursor irgendwo sichtbar sein und blinken.

Was ich noch nicht nachvollziehen kann ist das Timeing mit den Verzögerungen. Vielleicht nochmal prüfen ob wirklich die erwartete Zeit gewartet wird. Wird bei Delay10TCYx() wirklich ein 16-bit-Wert erwartet (z.B. 40*200)? Im Zweifel eine kleine Blinksteuerung im Sekundentakt programmieren und mit Stoppuhr überprüfen:


void blink(void)
{
unsigned char temp;
while(1)
{
led_an;
for(temp=0; temp<50; temp++) delay100us(200); // 50*20ms=1sek
led_aus;
for(temp=0; temp<50; temp++) delay100us(200); // 50*20ms=1sek
}
}

(ungetestet)

Gruß

mic

andi.studi
20.07.2008, 17:51
hi

hast mal wieder recht
an Delay10TCYx() darf nur 0..255 sprich 8 bit

hab die funktion abgeändert leider viel mir auf dieschnelle nix beseres ein als eine long veriable zu verwende.






void delay100us(unsigned long multiplikator)
// for PicLSBK (16MHz Taktzyklus = 4 MHz Befehlszyklus)
{
unsigned long i;

for (i=0;i<(multiplikator*400);i++) // 400*nop=100µs
{nop;}
}


lcd flackert nicht mehr, aber zeichen sind auch nicht drauf zu erkennen ](*,)

HILFE ](*,)

radbruch
20.07.2008, 18:15
Hallo

Der multiplikator kann ja weiterhin 8 Bit haben, muß also nicht long sein.

Vielleicht wird die Schleife von Kompiler wegrationalisiert. Ich verzögere mit Dummy-Befehlen in der Zählschleife:

void delay(uint8_t d)
{
uint16_t d1, dummy;
for (d1=d*255; d1>0; d1--) dummy^=d1;
}


Eleganter wäre allerdings dies:

void delay100us(unsigned char multiplikator)
// for PicLSBK (16MHz Taktzyklus = 4 MHz Befehlszyklus)
{
while(multiplikator--) Delay10TCYx(40); //40*10*0,25µs = 100 µs
}

Wenn die Wartezeit zu kurz ist scheint mir der Clearbefehl kritisch, weil der recht lange zur Ausführung benötigt. Dann würden die nachfolgenden Einstellungen ins Nirwana gehen. Vielleicht mal testweise ohne clear initialisieren. Hast du das mit dem "Display on-Cursor on-Cursor blink" mal getestet?

Gruß

mic

andi.studi
20.07.2008, 18:18
erstes erfolgs erlebnis init scheint zu funktionieren, auch wenn nur seeeehr langsam.

hab zum test das display auf einzeilig umgestellt

LCD_WriteRegister(0x20); funktioniert

zudem bei LCD an courser an
LCD_WriteRegister(0x0f); fungtioniert auch

das komische
erst nach sa 5 sec ist 1 zeilen mode aktiv
nach weiteren 20 sec blinkt der courser an positon 1
nach 6 sec geht er wieder für 20 sec aus und kommt für 6 sec wieder.

von einem zeichen keine spur

andi.studi
20.07.2008, 18:32
deine while schleife gefällt mir sehr gut, ich war so frei sie gleich einzubauen.

courser blinkt nun an erster position aber im wechsel mit einem rechteck 5x8 dot's

radbruch
20.07.2008, 18:41
Hallo


...ich war so frei sie gleich einzubauen.
So war's auch gedacht :)

Schön, immerhin ein Fortschritt. Zeig doch nochmal deinen aktuellen (geputzten?) Code. Ich würde das Übernehmen der Daten in eine Funktion schreiben und nochmals die high-Zeit verlängern:


void strobe(void)
{
LCD_E = 1; // Daten übernehmen
delay100us(3);
LCD_E = 0;
}

Hast du ein Datenblatt für dein Display (oder eine genaue Typangabe)? Ich verwende das oben erwähnte KS0066U-Datenblatt (http://www.datasheetcatalog.org/datasheets2/55/553815_1.pdf) (war eine der ersten Fundstellen der Suchmaschine), vielleicht gibt's da Unterschiede.

Blockcursor 5x8 ist schon richtig. Ist das Init() und das Blinken immer noch so langsam?

Gruß

mic

andi.studi
20.07.2008, 19:01
link zum datenblatt meines LCD
http://www.zyscom.pl/katalog/ym2004a.pdf

verwende das gleiche controler datenblat wie du : http://www.datasheetcatalog.org/datasheets2/55/553815_1.pdf

init ist nun sehr schnell fertig :) und keine pausen danach, courser blinkt fröhlich an zeilen anfang ununterbrochen.



/** I N C L U D E S ************************************************** ********/

#include <p18f4550.h>
#include <delays.h>


/** D E F I N I T I O N S ************************************************** **/

#define PORTLCD LATB
#define TRIS_LCD TRISB
#define LCD_E PORTBbits.RB0
#define LCD_RS PORTBbits.RB2
#define LCD_RW PORTBbits.RB3
#define nop _asm nop _endasm // verzögerung 0,25µs

//************************************************** **************************

#pragma code


void delay100us(unsigned char multiplikator)
// for PicLSBK (16MHz Taktzyklus = 4 MHz Befehlszyklus)
{
while(multiplikator--) Delay10TCYx(40); //40*10*0,25µs = 100 µs
}


void LCD_BUSY(void)
{
unsigned char temp1;
// unsigned char temp2;
do
{
TRIS_LCD = 0xF0; // LCD-PORT = high nibbles:eingang; low nibbles:ausgang
//Display abfrage
LCD_RS = 0; // LCD im Befehls-Mode
LCD_RW = 1; // LCD im Lesen-Mode
LCD_E = 1; // Enable (LCD)
temp1 = PORTLCD;
temp1 = temp1 & 0xF0; // Niederw.Nibble (steuerbits) ausmaskieren
LCD_E = 0; // toggeln

LCD_E = 1; // Enable (LCD)
nop;
LCD_E = 0; // toggeln
} while (temp1>=0x80);

delay100us(1);
LCD_RW = 0; // Busy = low: LCD im Schreiben-Mode
TRIS_LCD = 0x00; // LCD-PORT = Ausgänge
PORTLCD = 0x00; // Daten und Steuerleitungen LOW
}


void LCD_WriteZeichen(unsigned char zeichen)
{
unsigned char x;
delay100us(200);
// LCD_BUSY(); // Warten bis LCD bereit ist

LCD_RW = 0; // LCD im Schreiben-Mode
LCD_RS = 1; // LCD im Befehl-Mode

x = zeichen & 0xf0;
x = x | LCD_RS;
PORTLCD = x; //höherwertiges nibbel

nop;
LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;

delay100us(50); //5ms warten nach den 1.nibble

x = zeichen;
x = (x << 4)& 0xf0; //niederwertiges nibbel
x = x | LCD_RS;
PORTLCD = x;

LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;
delay100us(50); //5ms warten nach den 2.nibble
LCD_RS = 0;
}


void LCD_WriteString(unsigned char *String)
{
unsigned char zeichen;

zeichen = *String;
while(zeichen !='\0')
{
LCD_WriteZeichen(zeichen); // zeichen am LC-Display ausgeben
String++;
zeichen = *String;
}
}

void LCD_WriteRegister(unsigned char data)
{
unsigned char x;
delay100us(200);
// LCD_BUSY(); // Warten bis LCD bereit ist

// LCD_RW = 0; // LCD im Schreiben-Mode
// LCD_RS = 0; // LCD im Befehl-Mode

x = data & 0xf0;
PORTLCD = x; //höherwertiges nibbel


LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;

delay100us(50); //5ms warten nach den 1.nibble
x = data;
x = (x << 4)& 0xf0; //niederwertiges nibbel
PORTLCD = x;

LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;
delay100us(50); //5ms warten nach dem 2.nibble
}



void LCD_Init(void)
{
// LCD initialisieren

TRIS_LCD = 0x00; // LCD-PORT = Ausgänge
PORTLCD = 0x00; // Daten und Steuerleitungen LOW


delay100us (150);
delay100us (150); // warte über 30ms
delay100us (100);

PORTLCD = 0x30; // Interface auf 8-Bit setzen
LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;

delay100us(50); //warte 5ms

LCD_E = 1; // Interface auf 8-Bit setzen
nop;nop; // Enable (LCD)
LCD_E = 0;

delay100us(2); //warte 200µs

LCD_E = 1; // Interface auf 8-Bit setzen
nop;nop; // Enable (LCD)
LCD_E = 0;

delay100us(2); //warte 200µs

PORTLCD = 0x20; // Interface auf 4-Bit setzen
LCD_E = 1; // Enable (LCD)
nop;nop;
LCD_E = 0;

LCD_WriteRegister(0x28); // 2-zeilig, 5x8-Punkt-Matrix
LCD_WriteRegister(0x08); // Display aus
LCD_WriteRegister(0x01); // Display löschen
LCD_WriteRegister(0x06); // Kursor nach rechts wandernd, kein Display-Shift
LCD_WriteRegister(0x0f); // Display ein [ 0x0C = ein, 0x08 = aus ]

}


void main (void)
{
LCD_Init();

LCD_WriteZeichen('t');
LCD_WriteZeichen('x');
}

andi.studi
20.07.2008, 19:13
noch mal mit funktion void enable (void)



/** D E F I N I T I O N S ************************************************** **/

#define PORTLCD LATB
#define TRIS_LCD TRISB
#define LCD_E PORTBbits.RB0
#define LCD_RS PORTBbits.RB2
#define LCD_RW PORTBbits.RB3
#define nop _asm nop _endasm // verzögerung 0,25µs

//************************************************** **************************

#pragma code

void delay100us(unsigned char multiplikator)
// for PicLSBK (16MHz Taktzyklus = 4 MHz Befehlszyklus)
{
while(multiplikator--) Delay10TCYx(40); //40*10*0,25µs = 100 µs
}

void enable(void)
{
LCD_E = 1; // Daten übernehmen
delay100us(3);
LCD_E = 0;
}

void LCD_BUSY(void)
{
unsigned char temp1;
// unsigned char temp2;
do
{
TRIS_LCD = 0xF0; // LCD-PORT = high nibbles:eingang; low nibbles:ausgang
//Display abfrage
LCD_RS = 0; // LCD im Befehls-Mode
LCD_RW = 1; // LCD im Lesen-Mode
LCD_E = 1; // Enable (LCD)
temp1 = PORTLCD;
temp1 = temp1 & 0xF0; // Niederw.Nibble (steuerbits) ausmaskieren
LCD_E = 0; // toggeln

enable();
} while (temp1>=0x80);

delay100us(1);
LCD_RW = 0; // Busy = low: LCD im Schreiben-Mode
TRIS_LCD = 0x00; // LCD-PORT = Ausgänge
PORTLCD = 0x00; // Daten und Steuerleitungen LOW
}


void LCD_WriteZeichen(unsigned char zeichen)
{
unsigned char x;
delay100us(200);
// LCD_BUSY(); // Warten bis LCD bereit ist

LCD_RW = 0; // LCD im Schreiben-Mode
LCD_RS = 1; // LCD im Befehl-Mode

x = zeichen & 0xf0;
x = x | LCD_RS;
PORTLCD = x; //höherwertiges nibbel

nop;
enable();
delay100us(50); //5ms warten nach den 1.nibble

x = zeichen;
x = (x << 4)& 0xf0; //niederwertiges nibbel
x = x | LCD_RS;
PORTLCD = x;

enable();
delay100us(50); //5ms warten nach den 2.nibble
LCD_RS = 0;
}


void LCD_WriteString(unsigned char *String)
{
unsigned char zeichen;

zeichen = *String;
while(zeichen !='\0')
{
LCD_WriteZeichen(zeichen); // zeichen am LC-Display ausgeben
String++;
zeichen = *String;
}
}

void LCD_WriteRegister(unsigned char data)
{
unsigned char x;
delay100us(200);
// LCD_BUSY(); // Warten bis LCD bereit ist

// LCD_RW = 0; // LCD im Schreiben-Mode
// LCD_RS = 0; // LCD im Befehl-Mode

x = data & 0xf0;
PORTLCD = x; //höherwertiges nibbel


enable();

delay100us(50); //5ms warten nach den 1.nibble
x = data;
x = (x << 4)& 0xf0; //niederwertiges nibbel
PORTLCD = x;

enable();
delay100us(50); //5ms warten nach dem 2.nibble
}



void LCD_Init(void)
{
// LCD initialisieren

TRIS_LCD = 0x00; // LCD-PORT = Ausgänge
PORTLCD = 0x00; // Daten und Steuerleitungen LOW


delay100us (150);
delay100us (150); // warte über 30ms
delay100us (100);

PORTLCD = 0x30; // Interface auf 8-Bit setzen
enable();

delay100us(50); //warte 5ms

// Interface auf 8-Bit setzen
enable(); // Enable (LCD)

delay100us(2); //warte 200µs

enable(); // Interface auf 8-Bit setzen
// Enable (LCD)

delay100us(2); //warte 200µs

PORTLCD = 0x20; // Interface auf 4-Bit setzen
enable(); // Enable (LCD)

LCD_WriteRegister(0x28); // 2-zeilig, 5x8-Punkt-Matrix
LCD_WriteRegister(0x08); // Display aus
LCD_WriteRegister(0x01); // Display löschen
LCD_WriteRegister(0x06); // Kursor nach rechts wandernd, kein Display-Shift
LCD_WriteRegister(0x0f); // Display ein [ 0x0C = ein, 0x08 = aus ]
}


void main (void)
{
LCD_Init();

LCD_WriteZeichen('t');
LCD_WriteZeichen('x');
}

andi.studi
20.07.2008, 19:55
wenn ich nach

ein 'E' ausgeben will. bekomme ich aufeinmal 2 blinkende courser einen in der ersten zeile an 1. stelle (wie gehabt) und einen 2 . in der 2. zeile an 5. stelle???



void main (void)
{
LCD_Init();
LCD_WriteZeichen('E');
}

radbruch
20.07.2008, 21:49
Hallo

Ein Verdacht:
'E' hat den Hexwert 0x45, das ist Binär 0b01000101. Wenn nun beim Schreiben der Daten das RS nicht gesetzt wäre, würde dies den Start des Usergraphik-Bereich definieren:

Set CGRAM Address 0 0 0 1 AC5 AC4 AC3 AC2 AC1 AC0 Set CGRAM address in address counter.
Alle weiteren Daten würden dann in den Grafikspeicher geschrieben werden, der Cursor würde aber vermutlich trotzdem im sichtbaren Bereich bewegt werden. Das ist allerdings reine Spekulation. Was ich in diesem Zusammenhang nicht weiß:

x = x | LCD_RS;

Funktioniert dies wie erwartet? Der Wert für LCD_RS ist doch 1, wir benötigen aber 4 (RS ist PortBit2) zum verodern, oder? Vielleicht mal sicherheitshalber doch diese Formulierung verwenden:

x = zeichen & 0xf0;
PORTLCD = x; //höherwertiges nibbel
LCD_RS = 1; // LCD Daten-Mode setzen

Gruß

mic

andi.studi
20.07.2008, 22:14
Der Wert für LCD_RS ist doch 1, wir benötigen aber 4 (RS ist PortBit2)



#define LCD_RS PORTBbits.RB2


sobald LCD_RS auf 1 gesetzt wird sollte auch RB2 high ein (wertigkeit 4)
werde es aber an einem einfacheren prog testen.



x = zeichen & 0xf0;
PORTLCD = x; //höherwertiges nibbel
LCD_RS = 1; // LCD Daten-Mode setzen


wersuch ich gleich mal...


void LCD_WriteZeichen(unsigned char zeichen)
{
unsigned char x;
delay100us(250);
// LCD_BUSY(); // Warten bis LCD bereit ist

LCD_RW = 0; // LCD im Schreiben-Mode
LCD_RS = 1; // LCD im Befehl-Mode

delay100us(1);
x = zeichen & 0xf0;
PORTLCD = x; //höherwertiges nibbel
LCD_RS=1;
delay100us(1);
enable();
delay100us(50); //5ms warten nach den 1.nibble

x = zeichen;
x = (x << 4)& 0xf0; //niederwertiges nibbel
PORTLCD = x;
LCD_RS=1;
delay100us(1);

enable();
delay100us(50); //5ms warten nach den 2.nibble
LCD_RS = 0;
}

=D> =D> =D> ich hab ein zeichen :)

leider sieht es so aus als wenn es ständig neu geschrieben würde es flackert etwas.

andi.studi
20.07.2008, 22:20
while (1);
nach LCD_WriteZeichen('X');
und das flackern ist weg

radbruch
20.07.2008, 22:32
Das bedeutet, es funktioniert? Juhu!

while(1); am Ende von main() ist ja klar, im Eifer des Gefechts glatt übersehen...

Viel Spass mit dem Display.

mic

andi.studi
20.07.2008, 22:56
hm schade das ich hier kein bild posten kann

sonst würdest du jetzt ein foto des LCD sehen, au dem steht

HaLLo Mic vielen dan
tuetzung !!!
k fuer Deine Unters

danke noch mal,
jetzt kann ich beruhigt ins bett, sitze schon seit einer woche daran.
jetzt fehlen noch die feinheiten, aber der anfang ist ja schonmal da;)
dank nochmal ohne dich hätte ich bestimmt noch ne weitere woche gebraucht um das zu erziehlen.

andi.studi
23.07.2008, 16:34
hallo mic,
und alle anderen microcontroller freunde.

weiß einer von euch wieso ich zwar folgendermassen einen string ans lcd senden kann:



.
.
.
.
void LCD_WriteString(unsigned char *string)
{
while(*string)
{
LCD_WriteZeichen(*string++); // zeichen am LC-Display ausgeben
}

void main (void)
{
unsigned char buffer[]="hallo";

LCD_Init();

LCD_WriteString(buffer);

while(1);
}


aber in der folgenden form:


void main (void)
{

LCD_Init();

LCD_WriteString("hallo..");

while(1);
}

diese compiler fehlermeldungen bekomme?
196:Warning [2054] suspicious pointer conversion

sie bezieht sich auf "LCD_WriteString("hallo..");"



LCD_WriteZeichen('H'); klappt doch auch.
ich ich müsste einem pointer wie *string ja auch in folgender vorm was zuweisen können:

string="hallo"; oder liege ich da falsch und er schickt <hallo> ins nirvana???


hoffe jemand kann mir helfen

Matzenerich
15.08.2008, 17:37
Hallo Andreas,
kann ich Dir so auch noch nicht sagen, aber hier tummelst Du Dich also rum!

Gruß
Matthias \:D/

andi.studi
15.08.2008, 17:51
hi Matthias,

bist du etwa auch fleißig?

dieses Thema kann aber geschlossen werden ;)

sehe https://www.roboternetz.de/phpBB2/viewtopic.php?t=41967

string an lcd senden, string in pointer speichern


const rom ist die lösung


void LCD_WriteString(const rom int8 *string)
{
while(*string)
{
LCD_WriteZeichen(*string++); // zeichen am LC-Display ausgeben
}
}