Hallo
Sollte da nicht noch eine kleine Verzögerung dazwischen sein? Ich weiß nicht wie schnell so ein PIC ist, aber laut Datenblatt (Seite 31ff) sollte E min. 230ns (tw) high sein.Code:... LCD_E = 1; // Enable (LCD) LCD_E = 0; ...
Gruß
mic
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(0x2; // 2-zeilig, 5x8-Punkt-Matrix
LCD_WriteRegister(0x0; // 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');
}
Hallo
Sollte da nicht noch eine kleine Verzögerung dazwischen sein? Ich weiß nicht wie schnell so ein PIC ist, aber laut Datenblatt (Seite 31ff) sollte E min. 230ns (tw) high sein.Code:... LCD_E = 1; // Enable (LCD) LCD_E = 0; ...
Gruß
mic
Bild hier
Atmel’s products are not intended, authorized, or warranted for use
as components in applications intended to support or sustain life!
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
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
Bild hier
Atmel’s products are not intended, authorized, or warranted for use
as components in applications intended to support or sustain life!
hier der aktuelle code, leider immernoch ohne erfolg
aber danke schonmal für die hilfe.
habe die BUSY abfrage erstmal rausgenomen und 25ms eingesetzt.
Code:/******************************************************************************* 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'); }
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:
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:Code:... x = zeichen & 0xf0; // LCD_RW = 0; // LCD im Schreiben-Mode LCD_RS = 1; // LCD im Befehl-Mode PORTLCD = x; //höherwertiges nibbel ...
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
Bild hier
Atmel’s products are not intended, authorized, or warranted for use
as components in applications intended to support or sustain life!
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
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(); }
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?
GrußEntry ModeSet 0 0 0 0 0 0 0 1 I/D SH Assign cursor moving direction and enable the shift of entire display.
mic
Bild hier
Atmel’s products are not intended, authorized, or warranted for use
as components in applications intended to support or sustain life!
und noch ein fehler, es muss
void LCD_WriteRegister(unsigned char data) nur char ist zu klein
klappt aber immer noch nicht
mensch du bist klasseso 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.
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; 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'); }
Lesezeichen