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
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
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
>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 ?
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...
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.
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.
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.
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
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) {} }
Einen Tip hätte ich noch. StartI2C(); while(SSPCON2bits.SEN); //warten bis Startcondition beendet ist StopI2C(); while(SSPCON2bits.PEN); //warten bis Stopcondition beendet ist
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
>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.
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.
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.