Hallo, möchte ich Daten über I2C aus einem Speicherbauchstein auslesen muss ich 1. Die Adresse in den IC schreiben und dann 2. die Daten empfangen. Da das ja beides über einen PIN (SDA) laufen soll, muss ich zwischen 1 und 2 folglich irgendwie von Output auf Input wechseln. Kann ich das so machen ohne irgendwelches Fehlverhalten zu erzeugen oder muss das anders gelöst werden? Viele Grüße Dennis
Dr.PillePalle schrieb: > Da hilft nur lesen > http://de.wikipedia.org/wiki/I2c Hätte wohl nicht gefragt wenn ich mich nicht schon eingelesen hätte. Für mich steht da (Wikipedia) keine Antwort auf meine Frage.
Warum sollte der Wechsel zwischen Aus- und Eingang Fehlverhalten erzeugen? Was für ein Fehlverhalten stellst Du Dir vor? Wie der Lesevorgang aus Deinem (für und unbekannten) Speicher auszusehen hat, steht normalerweise sehr ausführlich im zugehörigen Datenblatt. Je nach Controller (welcher wissen wir ebenfalls nicht) gibt es auch noch bergeweise Beispielcode oder Bibliotheksfunktionen, die wahrscheinlich genau das machen, was Du gerne hättest...
Hi
>möchte ich Daten über I2C aus einem Speicherbauchstein auslesen
Womit? Bei einem Controller mit I2C-Interface brauchst du dich um so
etwas nicht kümmern.
MfG Spess
Deine Frage ist Vergleichbar mit folgender: "Ich möchte mein Auto rückwärts einparken. Dazu brauche ich ja den Rückwärtsgang. Ist der jetzt vorne Links, oder hinten Rechts bei der H-Schaltung? Und muss ich sonst noch etwas beim Einparken beachten?" Überleg mal was wir alles wissen sollten um dir Fragen überhaupt beantworten zu können.
Ich denke der TO will wissen ob er beim Lesen / Schreiben dass DDR-Register seines Controllers von Output auf Input umstellen muss. -> Im Falle eines Atmel µC und falls du die Hardware TWI Schnittstelle verwendest musst du das nicht, da sich die Hardware selbst darum kümmert.
Dennis A. schrieb: > Dr.PillePalle schrieb: >> Da hilft nur lesen >> http://de.wikipedia.org/wiki/I2c > > Hätte wohl nicht gefragt wenn ich mich nicht schon eingelesen hätte. Für > mich steht da (Wikipedia) keine Antwort auf meine Frage. Naja ob du dich wirklich eingelesen lässt Zweifel. Wegen dieser Aussage: Dennis A. schrieb: > Da das ja beides über einen PIN (SDA) laufen soll, muss ich zwischen 1 > und 2 folglich irgendwie von Output auf Input wechseln. Wenn du dich eingelesen hättest wäre dir jetzt bekannt, dass I2C Pins open drain oder open collector sind... Außerdem haste nocht nicht gesagt mit welchem Prozessor ausgelesen werden soll.
Borsty Bürste schrieb: > Ich denke der TO will wissen ob er beim Lesen / Schreiben dass > DDR-Register seines Controllers von Output auf Input umstellen muss Richtig Borsty Bürste schrieb: > Im Falle eines Atmel µC und falls du die Hardware TWI Schnittstelle > verwendest musst du das nicht, da sich die Hardware selbst darum > kümmert. Es handelt sich um einen Atmel uC, allerdings einen Attiny 2313. Keine TWI Schnitstelle. Ich weiß dafür gibt es dann USI.... Es muss aber auch möglich sein das Ganze über normale I/O Pins zu realisieren. Dann wäre halt meine Frage die oben genannte. Muss ich Da zwischen Input undOutput wechseln?
Dennis A. schrieb: > Muss ich Da > zwischen Input undOutput wechseln? Im Prinzip ja. Es wird folgendermassen vorgegangen. Bei I2C sind an den beiden Leitungen Pullup Widerstaende vorzusehen ad die Bausteine Opendrain/Opencollector Ausgaenge haben. Das heist der Highpegel wird durch den Widerstand erzeugt und der Lowpegel durch das durchschalten des Transistors. Fuer dich im Programm bedeutet das du must einen Opendrain Ausgang simulieren in deiner Software. Wenn du eine '1' uebertragen willst stellst du deinen Pin auf Eingang (der Pullup sorgt fuer die '1'). Willst du einen '0' uebertragen schaltest du das Richtungsregister auf Ausgang und gibts dabei eine '0' raus.
Also anstatt auf PORTX zu schreiben, schreibste invertiert auf DDRX. Ansonsten gibts schon genug Software I2C Librarys im Netz. http://homepage.hispeed.ch/peterfleury/group__pfleury__ic2master.html (je nach include ist die mit Hardwaremodul oder nur in Software) Hätteste das im ersten Post bereits erwähnt, dasse Software I2C machen willst, dann hätteste dir so manchen Spruch sparen können!
:
Bearbeitet durch User
Helmut Lenzen schrieb: > Bei I2C sind an den beiden Leitungen Pullup Widerstaende vorzusehen ad > die Bausteine Opendrain/Opencollector Ausgaenge haben. Das heist der > Highpegel wird durch den Widerstand erzeugt und der Lowpegel durch das > durchschalten des Transistors. Fuer dich im Programm bedeutet das du > must einen Opendrain Ausgang simulieren in deiner Software. > > Wenn du eine '1' uebertragen willst stellst du deinen Pin auf Eingang > (der Pullup sorgt fuer die '1'). Willst du einen '0' uebertragen > schaltest du das Richtungsregister auf Ausgang und gibts dabei eine '0' > raus. Das ist eine Antwort auf meine Frage. Danke! Martin Wende schrieb: > Hätteste das im ersten Post bereits erwähnt, dasse Software I2C machen > willst, dann hätteste dir so manchen Spruch sparen können! Hm ja, das liegt glaube ich daran, dass man irgendwie in seiner Gedankenwelt ist und es für selbstverständlich hält, dass andere dich ad-hoc verstehen. Dafür entschuldige ich mich. Martin Wende schrieb: > Also anstatt auf PORTX zu schreiben, schreibste invertiert auf DDRX. Hab ich auch verstanden. Bleibt nur noch die Frage wie ich dann die Outputs des EEPROMS lese. Hier wurde ja nur von schreiben durch DDR gesprochen..
:
Bearbeitet durch User
Dennis A. schrieb: > Bleibt nur noch die Frage wie ich dann die > Outputs des EEPROMS lese. Hier wurde ja nur von schreiben durch DDR > gesprochen.. Dann must du selbstverstaendlich die '0' vom Bus nehmen indem du eine '1' auf die oben geschilderte Weise ausgibst. Also das DDR wieder auf Eingang stellen.
1 | PORTx DDRx |
2 | Output low: 0 1 |
3 | Output high: 0 0 |
4 | Input: 0 0 |
High und Input ist also dasselbe.
Dennis A. schrieb: > Bleibt nur noch die Frage wie ich dann die > Outputs des EEPROMS lese. Hier wurde ja nur von schreiben durch DDR > gesprochen.. SCL bleibt ja ein Ausgang und wird weiterhin vom MC geclockt. Währenddessen liest du über das PINx Register die Daten von SDA, nachdem du wie oben beschrieben den SDA Pin auf Input gestellt hast.
:
Bearbeitet durch User
Hallo nochmal, ich habe nun etwas experimentiert und wollte in einer ersten Funktion eine Schreiboperation initiieren. Dabei muss ich laut Datenblatt ( http://pdf1.alldatasheet.com/datasheet-pdf/view/246254/STMICROELECTRONICS/M24C01WBN3TG.html) erst einmal die Folge 1010 000 0 übertragen. Die ersten Bits identifizieren den Hersteller, die drei nachfolgenden die Nummer des Slaves (bei mir sind E0,E1 und E2 beide auf LOW) und die letzte 0 gibt an, dass es sich um einen Schreibvorgang handelt. Wie man in meinem Code sieht wird zwischen den Schritten geclockt. Die Funktionen SDALOW setzt den SDA Pin als Ausgang und schreibt an den Port eine 0 Die Funktion SDAHIGH setzt den SDA Pin als Eingang und schreibt an den Port eine 1 (Pullup). Das wurde alles bereits diskutiert. Wenn ich mich nun im 9. Clockzyklus befinde sollte ein ACK vom EEprom gesendet werden. Dabei gebe ich die Werte des SDA PORTS nach dem 8. und nach dem 9. Clockzyklus mit readSDA() per UART in der Konsole aus. Leider wird das Ack nicht empfangen da beide male der Wert 0xFF übertragen wird. (Wenn das Ack gesendet worden wäre, würde 0xFD stehen) Wäre schön wenn mal einer drüber schauen könnte und hoffe auf konstruktive Tipps. Hier die Funktionen:
1 | void SDAHIGH () |
2 | {
|
3 | DDRB &= ~(1); //PB2 auf Eingang (HIGH übertragen) |
4 | PORTB = 0xFF; |
5 | }
|
6 | |
7 | void SDALOW () |
8 | {
|
9 | DDRB|= (1 << 2); //PB2 auf Ausgang (LOW übertragen) |
10 | digitalWrite(1,2,0); |
11 | }
|
12 | |
13 | void initIC2toWrite() |
14 | {
|
15 | SDALOW(); |
16 | SDAHIGH(); //Schreibe eine 1 |
17 | clock(); |
18 | SDALOW(); //Schreibe eine 0 |
19 | clock(); |
20 | SDAHIGH(); //Schreibe eine 1 |
21 | clock(); |
22 | SDALOW(); //Schreibe eine 0 |
23 | clock(); |
24 | SDALOW(); //Schreibe eine 0 |
25 | clock(); |
26 | SDALOW(); //Schreibe eine 0 |
27 | clock(); |
28 | SDALOW(); //Schreibe eine 0 |
29 | clock(); |
30 | SDALOW(); //Schreibe eine 0 |
31 | clock(); |
32 | //FERTIG nun warten auf ACK
|
33 | SDAHIGH(); //Schreibe eine 1 (Als Eingang schalten) |
34 | readSDA(); //Lese Eingang |
35 | clock(); //9. Clockzyklus |
36 | readSDA(); //Lese Eingang (sollte ACK empfangen) |
37 | _delay_ms(100); |
38 | }
|
39 | int main(void) |
40 | {
|
41 | USART_Init(); |
42 | DDRD =(1<<2); //PB1 = CLOCK (Ausgang) |
43 | digitalWrite(2,2,1); //Clock = High |
44 | SDAHIGH(); //SDA=HIGH |
45 | initIC2toWrite(); |
46 | }
|
:
Bearbeitet durch User
Matthias Sch. schrieb: > SCL bleibt ja ein Ausgang und wird weiterhin vom MC geclockt. Halt! Das ist nur bei dummen Slaves erlaubt. Ist der Slave auch ein MC, muß er ja Interrupts verabeiten können und für diese Zeit zieht der Slave SCL auf low. Der Master darf also kein strong High auf SCL legen!
Peter Dannegger schrieb: > Halt! > > Das ist nur bei dummen Slaves erlaubt. Der EEPROM kann ja als dummer Slave gesehen werden. Ralf schrieb: > Was macht genau clock()? Clock macht im Prinzip einen Taktzyklus : der Clockpin wird auf LOW HIGH LOW gesetzt. Dies geschieht analog zu SCL.
Dennis A. schrieb: > Wäre schön wenn mal einer drüber schauen könnte und hoffe auf > konstruktive Tipps. Das ist doch Schei...e Mach dir doch als erstes gleich mal 2 Funktionen, die ein 0-Bit ausgeben bzw. ein 1 Bit ausgeben. Sowas ist doch Blödsinn > SDAHIGH(); //Schreibe eine 1 > clock(); > SDALOW(); //Schreibe eine 0 > clock(); > SDAHIGH(); //Schreibe eine 1 > clock(); > SDALOW(); //Schreibe eine 0 > clock(); > SDALOW(); //Schreibe eine 0 > clock(); > SDALOW(); //Schreibe eine 0 > clock(); > SDALOW(); //Schreibe eine 0 > clock(); > SDALOW(); //Schreibe eine 0 > clock(); Und als nächstes kommt dann eine 3.te Funktion, die 1 Byte mit allen 8 Bits unter Zuhilfenahme der beiden Hilfsfunktionen für 0 und 1 ausgibt. Und mit dieser 3.ten Funktion, die ein komplettes Byte ausgeben kann, arbeitest du dann in weiterer Folge in den höherliegenden Funktionen. Hier siehst du doch vor lauter Lows und Highs und Clocks die Bäume vor lauter Wald nicht mehr. Ausserdem: > void initIC2toWrite() > { > SDALOW(); > SDAHIGH(); //Schreibe eine 1 Das ist doch keine gültige Startbedingung. http://www.rn-wissen.de/index.php/I2C#Startbedingung Am Besten du liest dir auch noch mal diesen Artikel komplett durch
Karl Heinz Buchegger schrieb: > Mach dir doch als erstes gleich mal 2 Funktionen, die ein 0-Bit ausgeben > bzw. ein 1 Bit ausgeben. Machen die beiden Funktionen doch SDAHIGH => 1 und SDALOW => 0 aber verstehe schon das Problem. Noch dazu: Karl Heinz Buchegger schrieb: >> void initIC2toWrite() >> { >> SDALOW(); >> SDAHIGH(); //Schreibe eine 1 > > Das ist doch keine gültige Startbedingung. Naja ich ziehe SDA auf LOW während vorher SCL schon sowieso auf HIGH Steht. Bedingung erfüllt. Im nächsten Schritt geht es dann an die übertragung mit SDAHIGH() wird das 1. Bit gesetzt
> void SDAHIGH () > { > DDRB &= ~(1); //PB2 auf Eingang (HIGH übertragen) Das ist doch nicht PB2! Hier > void SDALOW () > { > DDRB|= (1 << 2); //PB2 auf Ausgang (LOW übertragen) Hast du es fachlich korrekt geschrieben. Warum nicht bei SDAHIGH? DDRB &= ~( 1 << 2 ); > digitalWrite(1,2,0); entweder du benutzt die digital_Dingsbums Funktionen oder du machst das mit den Portzugriffen. Aber nicht mischen. Da kommt nur Verwirrung raus.
1 | Bit setzen |
2 | register |= ( 1 << Bitnummer ) |
3 | |
4 | Bit löschen |
5 | register &= ~( 1 << Bitnummer ) |
6 | |
7 | Bit auf 1 abfragen |
8 | register & ( 1 << Bitnummer ) |
9 | |
10 | Bit auf 0 abfragen |
11 | !( register & ( 1 << Bitnummer ) ) |
:
Bearbeitet durch User
Dennis A. schrieb: > Karl Heinz Buchegger schrieb: >>> void initIC2toWrite() >>> { >>> SDALOW(); >>> SDAHIGH(); //Schreibe eine 1 >> >> Das ist doch keine gültige Startbedingung. > > Naja ich ziehe SDA auf LOW während vorher SCL schon sowieso auf HIGH > Steht. So? Tut es das? Warum macht das die Funktion nicht selbst, sondern verlässt sich darauf, dass das vom Aufrufer schon gemacht wurde?
:
Bearbeitet durch User
Karl Heinz Buchegger schrieb: > So? > Tut es das? > > Warum macht das die Funktion nicht selbst, sondern verlässt sich darauf, > dass das vom Aufrufer schon gemacht wurde? Okay ich mach mich mal dran das alles schöner zu machen und in die Funktion zu schreiben. Hoffe ich komme da weiter. Danke
AUsserdem
1 | int main(void) |
2 | {
|
3 | USART_Init(); |
4 | DDRD =(1<<2); //PB1 = CLOCK (Ausgang) |
5 | digitalWrite(2,2,1); //Clock = High |
6 | SDAHIGH(); //SDA=HIGH |
7 | initIC2toWrite(); |
da geht zuerst der Clock auf High und erst dann kommt die SDA auf High. Das ist ist nicht das was gefordert war. Ja, ich weiss schon. Der Default ist Input und damit zieht der Pullup die Leitung auf high. Trotzdem. Das ist schon wieder implizites Zusatzwissen. Schreibs anders rum
1 | erst SDA auf High |
2 | dann Clock auf High |
3 | dann SDA auf Low |
4 | dann Clock auf Low |
und du hast eine direkte 1:1 Entsprechnung von der I2C Doku zu deinem Code. Und dann kann man das auch lesen und verstehen und muss nicht 200 Zusatzbedingungen im Kopf haben. ?
1 | DDRD =(1<<2); //PB1 = CLOCK (Ausgang) |
Das ist NICHT PB1! Du hast da einen schönen Mischmasch. Mach dir doch ein paar Define
1 | #define SDA_PIN PB2
|
2 | #define SCLK_PIN PB1
|
und mit denen schreibst du
1 | DDRB |= ( 1 << SDA_PIN ); |
dann kannst du dir auch einen Kommentar dazu sparen UND das Beste am ganzen: im Code steht selbst schon, welche Bedeutung dieser Pin hat. Hier wird ganz offensichtlich der SDA_PIN mittels DDR auf Ausgang geschaltet. Welcher konkreter Pin am Port B das dann auch immer war. Keine magischen Konstanten im Code! In 3 Tagen weißt du nicht mehr ob mit
1 | PINB & ( 1 << 1 ) |
da jetzt die Clock Leitung oder die Datenleitung abgefragt wird. Mit
1 | PINB & ( 1 << SCLK_PIN ) |
weisst du es aber. Steht ja im Code, welche der beiden es sein soll.
:
Bearbeitet durch User
Karl Heinz Buchegger schrieb: > erst SDA auf High - Delay(); > dann Clock auf High - Delay(); > dann SDA auf Low - Delay(); > dann Clock auf Low - Delay();
Peter Dannegger schrieb: >> SCL bleibt ja ein Ausgang und wird weiterhin vom MC geclockt. > > Halt! > > Das ist nur bei dummen Slaves erlaubt. > Ist der Slave auch ein MC, muß er ja Interrupts verabeiten können und > für diese Zeit zieht der Slave SCL auf low. > Der Master darf also kein strong High auf SCL legen! Ich habe bis jetzt noch kein I2C EEPROM gesehen, das sich durch die CLK Verlängerung mehr Zeit ausgebeten hätte, z.B. beim Schreibvorgang. Du kannst bei den meisten lediglich auf 'Busy' checken durch ein fehlendes ACK. Obwohl die CLK Verlängerung ein legitimes Verfahren wäre, wird es bei den EEPROMs nicht genutzt, vllt., um den MC nicht zu blocken.
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.