Hallo, vielleicht könnt ihr mir helfen. So langsam bin ich mit meinem Latein am Ende. Beim lesen der einzelen Bit eines CMPS03 Kompass Sensors bekomme ich immer high, ergo 0xFF als Wert. Die Routine ist aus dem Keil Buch von Baldischweiler. Prozessor ist ein. 8051, Compiler ist Keil C51. Im Protokollanalyzer (Intronix Logicport)stimmt alles, es kommen auch Werte vom Sensor auf dem Bus. (siehe Anhang) Also Adressierung stimmt. Anderer Sensor und anderer Prozessor bringen das gleiche. Ich hab echt keine Ideen mehr. Wäre nett wenn euch was einfällt. DANKE Code der Leseroutine: /* *************************************************** * * I2C Library * * For Keil C, with features of bus fault * detection, no acknowledgement feature, * and I2C busy feature. **************************************************** */ uchar Si2c_in( bit btACK ) { I2CWAIT2; SSDA = 1; // Freigabe vom BUS SSCL = 1; I2CWAIT3; sbtD7 = SSDA; // Lesen des Bit 7 (MSB) SSCL = 0; I2CWAIT4; SSCL = 1; I2CWAIT3; sbtD6 = SSDA; // Lesen des Bit 6 SSCL = 0; I2CWAIT4; SSCL = 1; I2CWAIT3; sbtD5 = SSDA; // Lesen des Bit 5 SSCL = 0; I2CWAIT4; SSCL = 1; I2CWAIT3; sbtD4 = SSDA; // Lesen des Bit 4 SSCL = 0; I2CWAIT4; SSCL = 1; I2CWAIT3; sbtD3 = SSDA; // Lesen des Bit 3 SSCL = 0; I2CWAIT4; SSCL = 1; I2CWAIT3; sbtD2 = SSDA; // Lesen des Bit 2 SSCL = 0; I2CWAIT4; SSCL = 1; I2CWAIT3; sbtD1 = SSDA; // Lesen des Bit 1 SSCL = 0; I2CWAIT4; SSCL = 1; I2CWAIT3; sbtD0 = SSDA; // Lesen des Bit 0 (LSB) SSCL = 0; I2CWAIT4; SSDA = btACK; // ACK/NACK vom Master SSCL = 1; I2CWAIT3; // ACK-Takt SSCL = 0; I2CWAIT4; return(ucI2CVal); }
Du sammelst sbtD7..0 ein und gibst ucI2CVal zurück. Hängen die irgendwie zusammen ? Das ist mit dem Code leider nicht zu sehen.
ja, das sieht so aus: unsigned char bdata ucI2CVal; sbit sbtD0 = ucI2CVal ^0; sbit sbtD1 = ucI2CVal ^1; sbit sbtD2 = ucI2CVal ^2; sbit sbtD3 = ucI2CVal ^3; sbit sbtD4 = ucI2CVal ^4; sbit sbtD5 = ucI2CVal ^5; sbit sbtD6 = ucI2CVal ^6; sbit sbtD7 = ucI2CVal ^7; sbit SSCL = P0 ^1; sbit SSDA = P1 ^6;
Musst uns mehr Input geben. Welcher 8051 genauer? Taktfrequenz? I2C- Taktfrequenz? Möglichst das komplette Programm als Anhang.
hm Hier ist timing extrem wichtig im Zweifel länger warten(langsamer takten). Am besten Signalsequenzen kontrollieren. Das du zuvor die richtige Adresse senden und vielleicht noch ein register setzen musst ist dir bekannt? Hast du die Initsequenz des Kompasschips durchgezogen?
Du mußt schon die komplette I2C-Sequenz posten, nicht nur einen Brocken einfach so hinwerfen. Hier mal ein Beispielcode: http://home.tiscali.de/peterd/appl/soft/c51/eeprom/index.htm Peter P.S.: Man darf unter C auch Schleifen verwenden. Copy&Paste-Code hat die Eigenschaft, sehr fehleranfällig zu sein. Und speicherfressend ist er sowieso.
Hallo Matthias, deine Vermutung geht Richtung Timing, aber Timing ist okay, siehe Protokoll Analyzer. Ich kann ja den Sensor ansprechen, er leifert auch korrekte Daten auf dem Bus, uzu sehen am Analyzer Protokoll. Mehr Input: -Taktfrequenz I2C 100 Khz, siehe Diagramm. -M8051EW, 16 MHz Aus irgendeinem Grund ist der eine PIN immer high. Der bekommt einfach LOW nicht mit, im Gegensatz zum Analyzer. Entweder stimmt für ihn der Pegel nicht oder der läuft nur als output und lässt sich nicht abfragen. Die Pullups sind extern mit 4,7K beschaltet, Prozessor läuft mit 3,3 Volt. Code Complete /* *************************************************** * * I2C Library * * For Keil C, with features of bus fault * detection, no acknowledgement feature, * and I2C busy feature. **************************************************** */ uchar Si2c_in( bit btACK ) { I2CWAIT2; SSDA = 1; // Freigabe vom BUS SSCL = 1; I2CWAIT3; sbtD7 = SSDA; // Lesen des Bit 7 (MSB) SSCL = 0; I2CWAIT4; SSCL = 1; I2CWAIT3; sbtD6 = SSDA; // Lesen des Bit 6 SSCL = 0; I2CWAIT4; SSCL = 1; I2CWAIT3; sbtD5 = SSDA; // Lesen des Bit 5 SSCL = 0; I2CWAIT4; SSCL = 1; I2CWAIT3; sbtD4 = SSDA; // Lesen des Bit 4 SSCL = 0; I2CWAIT4; SSCL = 1; I2CWAIT3; sbtD3 = SSDA; // Lesen des Bit 3 SSCL = 0; I2CWAIT4; SSCL = 1; I2CWAIT3; sbtD2 = SSDA; // Lesen des Bit 2 SSCL = 0; I2CWAIT4; SSCL = 1; I2CWAIT3; sbtD1 = SSDA; // Lesen des Bit 1 SSCL = 0; I2CWAIT4; SSCL = 1; I2CWAIT3; sbtD0 = SSDA; // Lesen des Bit 0 (LSB) SSCL = 0; I2CWAIT4; SSDA = btACK; // ACK/NACK vom Master SSCL = 1; I2CWAIT3; // ACK-Takt SSCL = 0; I2CWAIT4; return(ucI2CVal); } bit Si2c_out( unsigned char ucValue ) { unsigned char ucErr = I2C_OK; ucI2CVal = ucValue; SSDA = sbtD7; // Senden des MSB SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2; SSDA = sbtD6; // Senden des Bit 6 SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2; SSDA = sbtD5; // Senden des Bit 5 SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2; SSDA = sbtD4; // Senden des Bit 4 SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2; SSDA = sbtD3; // Senden des Bit 3 SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2; SSDA = sbtD2; // Senden des Bit 2 SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2; SSDA = sbtD1; // Senden des Bit 1 SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2; SSDA = sbtD0; // Senden des Bit 0 SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2; SSDA = 1; // Datenfreigabe fuer ACK-Signal SSCL = 1; I2CWAIT1; // ACK-Takt if (SSDA) ucErr = I2C_ACK_E; SSCL = 0; I2CWAIT2; //SSDA = 0; return ucErr; } bit Si2c_stop(void) { SSCL = 1; I2CWAIT1; SSDA = 1; I2CWAIT1; return ~SSDA; // 1 = Error, SDA not high } void Si2c_start(void) { SSDA = 1; SSCL = 1; I2CWAIT2; SSDA = 0; I2CWAIT2; SSCL = 0; I2CWAIT2; } void _waitnop(unsigned char nops) { uchar i; for(i=0; i<nops ;i++) // o,4uS = 1 NOP { _nop_(); _nop_(); } } //---------------------------------------------------------------------- -------- // Header file //---------------------------------------------------------------------- -------- #define I2CWAIT1 _waitnop(3) #define I2CWAIT2 _waitnop(3) #define I2CWAIT3 _waitnop(3) #define I2CWAIT4 _waitnop(3) #define ACK 0 #define NACK 1 unsigned char bdata ucI2CVal; sbit sbtD0 = ucI2CVal ^0; sbit sbtD1 = ucI2CVal ^1; sbit sbtD2 = ucI2CVal ^2; sbit sbtD3 = ucI2CVal ^3; sbit sbtD4 = ucI2CVal ^4; sbit sbtD5 = ucI2CVal ^5; sbit sbtD6 = ucI2CVal ^6; sbit sbtD7 = ucI2CVal ^7; sbit SSCL = P0 ^1; sbit SSDA = P1 ^6; unsigned char Si2c_in( bit btACK ); bit Si2c_out( unsigned char ucValue); bit Si2c_stop(void); void Si2c_start(void); extern void _waitnop(unsigned char nops);
Hallo Peter, ich vermute, dass der PIN immer high ist,und das Problem nicht in der eigentlichen I2C Geschichte liegt und hab mein Posting daher auf die vermutete Fehlerquelle beschränkt. Beim 8051 kann der PIN doch gelesen und geschrieben werden ? Bzgl. Schleife, hat mich bei den NOPS im Quellcode auch gestört und hab das Cut&Paste dort auch schon ersetzt. Ich geb zu, dein Code ist da eleganter als der vom Kollegen :)
Hallo, das mit dem Dateinanhang hat wohl nicht geklappt. Ich beziehe mich die ganze Zeit auf das hochgeladene Protokoll vom Analayzer und sehe gerade, da ist nichts. (Bitte den Dateianhang vor dem Absenden noch einmal auswählen! - werlesen kann hat Vorteile). Ich hängs nochmal an.
Timing nochmal prüfen.
Dein µC ist eine 2-State-Maschine, also ein Turbo-8051. Der ist 6x
schneller als ein Klassik. Das hast Du hoffentlich bedacht. Die 16MHz
wären dann einer Taktfrequenz von 96MHz gleichzusetzen.
> for(i=0; i<nops ;i++) // o,4uS = 1 NOP
0.4us würde dann nicht stimmen, sondern 0,125us pro NOP
Die Impulsbreite beträgt 5,5 uSec (siehe auch Hardcopy Analyzer), absichtlich schon etwas über der 4,7 uSec Spec. Stimmt die 0,4 für ein einzelnes NOP im REM sind falsch. Der Sensor versteht ja auch meine gesendeten Daten und liefert mir laut Analyzer die korrekten Daten zurück. Nur der der SDA Pin der ja beim Schreiben auch korrekt arbeitet liefert beim Lesen einfach nur immer High. Stimmt der Pegel evtl. für den Prozessorpin nicht ? Aber für den Analyzer ist die Schwelle ja auch okay ? Die Ports sind bei allen 8051 ja problemlos und ohne zutun bidirektional, oder habe ich da was übersehen ? RATLOS !
> Die Ports sind bei allen 8051 ja problemlos und ohne zutun > bidirektional, oder habe ich da was übersehen ? Nicht ganz. Beim Klassik-8051 musst Du um was von einen PIN einzulesen vorher das Ausgangslatch auch 1 setzen. Sonst liest Du immer 0. SDA = 1; // Portlatch vor lesen auf 1 setzen input = SDA; //liest nun 1 oder 0, jenachmdem was am PIN anliegt Bei solch speziellen µC wie Du hast kann das aber anders sein. Da musst Du genauestens das Datenblatt lesen. Bei der 2Cycle 8051-Serie P89LPC9xx von NXP muß man z.B. auch vorher festlegen, ob der Portpin Ein- oder Ausgang sein soll. Ansonsten nimm mal eine normale Varibale beim Einlesen, oder hier meine Routine:
1 | #define ACK 0
|
2 | #define NACK 1
|
3 | |
4 | // ********************************************************************
|
5 | // I2C-Bus
|
6 | // Read: 1 Byte schreiben
|
7 | // Übergabe: acknow - ACK (weiteres Zeichen anfordern)
|
8 | // NACK (letztes Zeichen)
|
9 | // ********************************************************************
|
10 | byte I2C_read(byte acknow) { |
11 | byte empfdat, i; |
12 | empfdat = 0; |
13 | SDA = 1; // Portpin SDA für Empfang vorbereiten |
14 | SCL = 0; |
15 | for (i = 1; i <= 8; i++) { // 8 Bit seriell empfangen |
16 | SCL = 1; SCL = 1; SCL = 1; SCL = 1; |
17 | empfdat <<= 1; |
18 | empfdat |= SDA; |
19 | SCL = 0; |
20 | }
|
21 | SDA = acknow; // ACK-Bit senden |
22 | SCL = 0; |
23 | SCL = 1; SCL = 1; SCL = 1; SCL = 1; |
24 | if (acknow == NACK) SDA = 1; // nächster Zyklus ist Reset |
25 | SCL = 0; SCL = 0; |
26 | SDA = 1; |
27 | return empfdat; |
28 | }
|
Musst aber bestimmt noch paar waits einfügen.
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.