Forum: Mikrocontroller und Digitale Elektronik LCD ansteuerung ueber pic18f4550


von Harald U. (lehon)


Lesenswert?

servus,
ich hab momentan ein kleines problem. ich möchte ein kleines LCD 
ansteuern( EA T123A-I2C ) mit Hilfe des Pic18f4550. das ganze soll ueber 
I²C laufen. durchgelesen habe ich beireits alle pdfs die ich gefunden 
habe. wie ein I2C funktioniert sollte ich verstanden haben, nur hab ich 
noch schwierigkeiten mit der übertragung bzw initialisierung, ob diese 
ueberhaupt stimmt.
meine überlegungen waren die folgenden:
SCL und SDA müssen als ausgang, da ja der controller der master is, 
daher
  TRISBbits.TRISB0 = 1;
  TRISBbits.TRISB1 = 1;

anschliessend    SSPCON1=0x28;
da ich somit das startbit setze und den takt angebe.
wenn ich jetzt daten an das lcd schicken möchte,muss ich das ganze in 
die while schleifen reinpacken oder lieber nicht?weil eigentlich müsste 
sie doch nicht rein, da der speicher nicht geloescht werden soll und 
somit die zeichen einfach stehenbleiben.
danach habe ich einfach das beispiel vom lcd herangezogen, indem man 
PHILIPS scrhreibt. 
http://www.lcd.elementy.pl/lcd/pdf/matrycowe/s_7123.pdf (bis auf die 
letzten 2 seiten identisch mit meinem handbuch)

da ich eine WriteI2C() funktion besitze, die mir die angegebene addresse 
in SSPBUF schreibt habe ich diese genommen. eine anschliessende abfrage 
auf busy flag ist auch dabei.
ich bin mir aber nicht sicher ob ich einfach,so wies dasteht, alle 
binaerzahlen in hex umwandeln kann und mit writei2c versenden. ich hab 
zwar gelesen, dass es zwischen addressen und datenbytes keinen 
unterschied gibt, aber irgendwie verwirrt mich das. vorallem die 
tatsache, das das bit fuer R/W an unterschiedlichen stellen vorkommt, 
macht mich sehr stutzig.

in zeile 7 des beispiels, steht als beschreibung, dass das RS bit 
gesetzt werden muss. muss ich das dann manuell machen oder geschieht das 
von selbst nach dem erneuten StartI2C befehl (welcher das enable bit 
setzt)?
so sieht der ganze code bei mir aus:

#include <i2c.h>
#include <p18cxxx.h>
void main(void)
{
  OSCCON |=0x70; // 8 MHz
  TRISBbits.TRISB0 = 1;     //   DA und SCL als output
  TRISBbits.TRISB1 = 1;
  SSPCON1=0x28;
         while(DataRdyI2C());
  SSPADD = 9;   //400kHz Baud clock(9) @16MHz  //100kHz Baud clock(39) 
@16MHz
while(DataRdyI2C());
StartI2C();
WriteI2C(0x74);
WriteI2C(0x00);    //  control byte sets RS and R/W for following data 
bytes
WriteI2C(0x2C);    //  4line display
WriteI2C(0x0E);    //  turns on display and cursor
WriteI2C(0x06);    //  increment address by 1 and shift cursor right. 
display is not shifted
StartI2C();      //  for writing data to ddram, RS must be set to 1. 
control byte needed
WriteI2C(0x40);
WriteI2C(0x74);    //  slave address for write
WriteI2C(0x40);    //  sends control byte
WriteI2C(0x50);    //  Write P to DDRAm
WriteI2C(0x48);    //  Write H
StopI2C();
StartI2C();
WriteI2C(0x74);
WriteI2C(0x80);    //  control byte
WriteI2C(0x02);    //  Return Home
StopI2C();
while(1) {}
}

wäre schön wenn mir jemand sagen koennte wo mein fehler sein kann. ich 
verstehs einfach nich. ich weiss das es fuer viele vielleicht als billig 
erscheint, aber ich bin trotzdem fast am verzweifeln -.-

MfG Harald

von Severino R. (severino)


Lesenswert?

Harald Unbekannt wrote:

> SCL und SDA müssen als ausgang, da ja der controller der master is,
> daher
>   TRISBbits.TRISB0 = 1;
>   TRISBbits.TRISB1 = 1;
>
> da ich somit das startbit setze und den takt angebe.

Mit 1 setzt Du die Pins aber als Eingang!

Es kann aber auch sein, dass die I2C-Funktionen die Pins ohnehin richtig 
setzen (->Doku!).

> wenn ich jetzt daten an das lcd schicken möchte,muss ich das ganze in
> die while schleifen reinpacken oder lieber nicht?weil eigentlich müsste
> sie doch nicht rein, da der speicher nicht geloescht werden soll und
> somit die zeichen einfach stehenbleiben.

Du hast drei while-Schleifen, die alle leer sind. Die ersten beiden 
warten einfach, bis DataRdyI2C() false ist. Was das bedeutet, musst Du 
in der Doku zur i2c-Library nachlesen.
Welchen Compiler benutzt Du überhaupt?
Die dritte while-Schleife sorgt dafür, dass das Programm dort 
stehenbleibt (eigentlich ewig loopt). Andernfalls würde das Programm 
u.U. immer wieder neu starten, und Dein LCD womöglich flackern.

Severino

von Harald U. (lehon)


Lesenswert?

das mit dem PortB is mir selbst grad aufgefallen, wollte ich grad 
aendern. aber aendert leider auch wenig an meinem problem.
ich benutze den MPLAB mit mcc18.
DataRdyI2C() is eigentlich nur das BusyFlag. also wenn er noch nich 
fertig is, soll er mit der schleife solange warten.

was mich noch etwas wundert, is die tatsache das der clock nicht 
einheitlich ist. ich weiss zwar das er nicht staendig hin und 
herschaltet,wenn keine daten gesendet werden, aber sollte er dann nicht 
einen gewissen pegel halten? bei mir is SDA und SCL wie staendige 
kondensatorendladekurven ohne ladezeit. wobei SDA ne hoehere amplitude 
hat, was ja eigentlich egal ist.
die andren 4 pins haben allerdings normale werte, so wie man es 
erwartet.

mfg Harald

von holger (Gast)


Lesenswert?

>WriteI2C(0x06);    //  increment address by 1 and shift cursor right.
display is not shifted
>StartI2C();      //  for writing data to ddram, RS must be set to 1.

Für meinen Geschmack fehlt da ein StopI2C();
Hast du auch Pullups an SDA und SCL ?

von Harald U. (lehon)


Lesenswert?

wegen dem stopi2c() hab ich mich auch schon gewundert, werd ich mal 
morgen testen.

wegen den pullups: PORTB is a bidirectional I/O port. PORTB can be 
software
programmed for internal weak pull-ups on all inputs.

da ich des oefteren les das man fuer i2c die beiden pins auf input 
stellen muss, werd ich irgendwie nochmehr verwirrt. da mein controller 
ja der master is und mein lcd ja sozusagen slave, is doch eigentlich SCL 
und SDA output oder nicht? also das ich nicht wie oben falsch 
geschrieben, die beiden pins auf high setze, sondern auf low fuer 
output?!
in dem text steht ja das ich es auf software ebene programmieren muss 
das die pullups aktiv sind, aber ich hab bisher NIE was dazu gefunden, 
oder versteh ich das falsch und die sind automatisch da, sobald ich die 
pins auf input setze?
aber laut dem text wegen den pullups muss es ja wieder so sein wie oben 
beschrieben. ich bin verwirrt...

von holger (Gast)


Lesenswert?

I2C ist ein Open Drain Bus. Wer da Master oder Slave ist,
ist dabei völlig belanglos.

Setz jeweils einen Pullup mit 2k2 bis 10k auf SDA und SCL.
Die internen Pullups sind zu schlapp oder möglicherweise
sogar gar nicht aktiv.

von Harald U. (lehon)


Lesenswert?

hab etz mal 2 2k2 reingeloetet. geholfen hat es nicht sehr viel.
wenn ich beide pins auf input setze,dann bekomme ich wenigstens ein 
gleichmaessiges 5V signal auf beiden pins. nur veraendert sich eben 
nichts durchs senden, da sie ja inputs sind.
als output hatte ich vorher nichts, jetzt ist es mit nadelimpulsen 
versehen, die dauerhaft vorkommen. sieht eher aus als haette ich dadurch 
die stoerungen verstaerkt.

von holger (Gast)


Lesenswert?

Hier mal ne I2CInit() die bei mir funktioniert:

//############################################################
void I2CInit(void)
//############################################################
{
 unsigned char by;

 SSPCON1=0x08;     //I2C-Master
 SSPCON2=0x00;
 SSPSTATbits.SMP=1;  //SlewRate Control Disabled

// SSPADD=0xD0;    //ca. 50kHz
// SSPADD=0x80;    //etwas kleiner als 100kHz laut OsCI
// SSPADD=0x70;    //kleinen Tick größer als 100kHz laut OsCI

 SSPADD=i2cspeed;


 SSPCON1bits.SSPEN=1;  //Enable I2C-Bus
 by=SSPBUF;             //dummy read clears BF
}


Wie du siehst habe ich an PORTB noch nicht mal die
Datenrichtung angegeben. Nach Reset bedeutet das also
Input. Funktioniert wunderbar bei mir bis 400kHz.

Die Pullups brauchst du aber auf jeden Fall.

von Harald U. (lehon)


Lesenswert?

danke fuer deine hilfe.
die werte die du setzt habe ich teilweise auch schon ausprobiert gehabt. 
hab jetzt trotzdem nochmal alle portb initalisierungen rausgeschmissen 
und hauptsaechlich nur deine befehle drinnenstehen, auch wenn vieles 
aehnlich ist. nur jetzt habe ich wieder den alten zustand, wo SCL und 
SDA undefiniert sind und machen was sie wollen. daher geht auch das lcd 
nicht.

als SSPADD hab ich 0x80 und 0x70 probiert, da ja mein lcd mit 100kHz 
arbeitet, der rest kann ja so wies is "theoretisch" uebernommen werden.

irgendwie ham se mich beschissen, die meinten alle das man des mit 
vorgefertigten befehlen nur initialisieren muss und dann geht alles Oo

von Harald U. (lehon)


Lesenswert?

also, wenn ich INTCON2bits.RBPU auf 0 setze, was bedeutet das alle PortB 
Pullups aktiviert sind, und ich zugleich die beiden wichtigen pins, SCL 
und SDA, auf input stelle, dann bekomme ich das erhoffte dauer high 
signal. dauerhaftes high signal hat man, wenn eben keine daten gesendet 
werden.
wenn ich aber (SSPCON1bits.SSPEN=1;  //Enable I2C-Bus)   setze, dann 
wird mein signal wieder komplett verhunzt.
das ganze sieht momentan so aus:

#include <i2c.h>
#include <p18cxxx.h>
unsigned char by;
void main(void)
{
  OSCCON |=0xC0; // 1 MHz
  TRISBbits.TRISB0 = 1;  //  SDA input=1 output=0
  TRISBbits.TRISB1 = 1;  //  SCL input=1 output=0
  INTCON2bits.RBPU = 0;  //  enable Pullups for PortB-Pins

SSPCON1=0x08;             //I2C-Master
SSPCON2=0x00;
SSPSTATbits.SMP=1;      //SlewRate Control Disabled 100kHz und 1MHz
SSPADD=0x80;         // 0x80 < 100kHz;  0x70 > 100kHz
SSPCON1bits.SSPEN=1;    //Enable I2C-Bus
by=SSPBUF;              //dummy read clears BF

StartI2C();
WriteI2C(0x74);    //  slave address for write
WriteI2C(0x00);    //  control byte sets RS and R/W for following data 
bytes
WriteI2C(0x2C);    //  4line display
WriteI2C(0x0E);    //  turns on display and cursor
WriteI2C(0x06);    //  increment address by 1 and shift cursor right.
                                display is not shifted
StopI2C();
StartI2C();    //  for writing data to ddram, RS must be set to 1.
                                control byte needed
WriteI2C(0x74);    //  slave address for write
WriteI2C(0x40);    //  sends control byte
WriteI2C(0x50);    //  Write P to DDRAm
WriteI2C(0x48);    //  Write H
StopI2C();
while(1)     {}
}

von holger (Gast)


Lesenswert?

Einen Tip hätte ich noch.

 StartI2C();
 while(SSPCON2bits.SEN);  //warten bis Startcondition beendet ist

 StopI2C();
 while(SSPCON2bits.PEN);  //warten bis Stopcondition beendet ist


von Harald U. (lehon)


Lesenswert?

ich dank dir fuer deine bemuehungen, aber das wars leider auch nicht. 
hab schon des oefteren mit solchen bedingungen rumprobiert und das ganze 
programm von oben bis unten damit zugestopft. was mir einfach nicht in 
den kopf geht, is die tatsache, dass mir SSPCON1bits.SSPEN=1; 
//Enable I2C-Bus       das signal total versaut. mit dem setzen der 
beiden pins auf input sieht das signal vorerst sehr gut aus. aber egal 
was ich danach mache kommt nichts sinnvolles bei raus bzw aendert sich 
garnichts, je nachdem.
meine einzigste idee waere noch, dass ich vielleicht ausversehen was an 
den verschiedenen takten verwurschtelt hab.
OSCCON |=0xC0; // 1 MHz
hab C0 und nicht 40 genommen, da idle leichter aufzuheben ist als 
sleepmode. aber eigentlich egal. die 0x40 sagt aufjedenfall aus das der 
takt auf 1MHz laeuft.
wie du ebenfalls empfohlen hast, hab ich Slew_off, damit das lcd auf 
100kHz laeuft, was ja auch standard betrieb ist.
wo ich mir am unsichersten bin is das SSPADD-Register bzw BRG(Baud Rate 
Generator). du hattest diese moeglichkeiten angegeben:
// SSPADD=0xD0;    //ca. 50kHz
// SSPADD=0x80;    //etwas kleiner als 100kHz laut OsCI
// SSPADD=0x70;    //kleinen Tick größer als 100kHz laut OsCI

ich selber hatte mir 28h(100kHz bei 4MHz) bzw A0h(100kHz bei 1MHz) 
errechnet. was mich jetzt sehr stutzig gemacht hat is die tatsache, dass 
ich fuer euch helfenden nen link zum datasheet posten wollte und das ist 
2 jahre aelter als meins. ich ging davon aus das es eigentlich kein 
problem sein sollte, aber genau der teil mit SSPADD is dort 
unterschiedlich. 
http://ww1.microchip.com/downloads/en/devicedoc/39632c.pdf  29h bzw 90h.
bis auf die 2 neuen werte konnte ich schon alle durchprobieren und bin 
mit meinem inzwischen planlosem rumprobieren auch schon ziemlich durch. 
hab auch das gefuehl das die 2 neuen werte auch wenig zum problem 
beitragen.
aber liege ich da richtig das ich zB. A0h(100kHz bei 1MHz) bzw 90h 
verwenden muss bei 1MHz?

mfg Harald

von holger (Gast)


Lesenswert?

>aber liege ich da richtig das ich zB. A0h(100kHz bei 1MHz) bzw 90h
>verwenden muss bei 1MHz?

Kann ich dir im Moment nicht sagen, aber wie du siehst
habe ich da rumprobiert und zum Schluss lieber
nachgemessen. Irgendwie kam ich mit dem Datenblatt wohl
auch nicht so ganz klar.

Einen letzten Tip hätte ich noch. Aus irgend einem
Grund habe ich folgende I2C_Write() geschrieben:

void I2C_Write(unsigned char by)
{
 PIR1bits.SSPIF=0;    //Lösche Flag SSPIF
 SSPBUF=by;      //Datenübertragung starten
 while(PIR1bits.SSPIF==0);  //Sicherheitshalber auch auf SSPIF warten
 PIR1bits.SSPIF=0;    //Lösche Flag SSPIF

//Der Wert von ACK steht jetzt in SSPCON2bits.ACKSTAT
}


Normalerweise hätte ich SSPSTATbits.BF genommen,
hat aber wohl nicht funktioniert. Deshalb der
Umweg über SSPIF.

von Harald U. (lehon)


Lesenswert?

der tipp klingt doch ganz gut. kanns leider erst am dienstag 
ausprobieren. da leider die fh bis dienstag zu is ^^
aber vielen dank, koennte mich vielleicht nen schritt weiter bringen.

von Harald U. (lehon)


Lesenswert?

hab jetzt ueberall delays eingebaut,damit dort keine 
ueberschneidungsprobleme auftauchen koennen.
das einzigste problem das ich jetzt noch habe ist, dass er 
while(PIR1bits.SSPIF==0);        garnicht mag. ich warte jetzt einfach 
ne zeit und setze es dann auf 0. aber eine loesung des problems war das 
trotzdem noch nicht. hab mir erneut alle relevanten sachen durchgelesen 
und so eingestellt wie angegeben, aber leider tut sich auch da nichts.
hab langsam das gefuehl das lcd is kaputt, was aber eigentlich nicht 
sein duerfte, da es neu ist.

mfg Harald

von Sekoya A. (sekoya)


Lesenswert?

hi Lehon,
kannst du komplet dein Projekt posten. verwende C8051...µC. Ich werde 
auch ein Programm an
gleiches LCD versenden, ich weiss aber nicht,wie das geht,
wie man versendet und welche befehlen man nutzt soll. Oder wenn du deine
e-mail adresse geben kannst,bitte, kann ich dir mein projekt senden und
kannst du durchschauen?
habe schon mal hier beschriebt aber keine konnte helfen,
die moderatoren haben leider auch darum nicht gekümmert.

grüß,

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.