Moin zusammen, ich betreibe ein Arduino Uno Board. An den I2C-Bus (TWI) habe ich einen Temperatursensor MLX90614 angeschlossen. Die I2C-Adresse des Sensors ist 0x5A. Im Anhang ist das Programm dazu. Mein Problem: Das Programm wird 2 - 5 mal durchlaufen und hängt sich dann hinter der Start-Condition auf.(Die LED bleibt an.) Die Datenleitung wird, wahrscheinlich vom Slave, auf GND gehalten. Der Sensor schickt 1. an der richtigen Stelle ein Acknowledge 2. korrekte Temperaturwerte, die lassen sich sehr gut am Oszi ablesen. Und das eben 2 - 5 mal. Was ja eigentlich nicht sein kann. Entweder es funzt oder eben nicht. Aber nicht ein paar Mal und dann nicht mehr. Für Ideen wäre ich sehr dankbar. Einen schönen Tag Andreas
Ganz unten muss es natürlich heißen: TWCR = (1<<TWINT) | (1<<TWEN); //Initialize the transmission, now the last data to be received while (!(TWCR & (1<<TWINT))); //Wait for Interrupt Flag, address has been sent while ((TWSR & 0xF8)!= 0x58); //Check for acknowledgement Temperatur_HI = TWDR;
Hi Andreas, ich sags mal so - wäre der Einsatz von: https://www.arduino.cc/en/Reference/Wire in Deinem Fall nicht besser? VG, Stephan
> Und das eben 2 - 5 mal. Was ja eigentlich nicht sein kann. Entweder es > funzt oder eben nicht. Aber nicht ein paar Mal und dann nicht mehr. Das beschriebene Verhalten ist fuer I2C vollkommen normal. Du musst dich erstmal damit abfinden. Es liegt an dir deine Software so zu programmieren das sie bei so einem Fehler wieder korrekt aufsetzt und weitermachen kann. Sei sogar dankbar das dir schon jetzt auffaellt. Sobald du dein Softwareproblem geloest hast kannst du als naechste mal die Qualitaet deiner FLanken/Uebertragung anschauen. Vermutlich stimmen die Pegel nicht, du hast Groundbounce, kein Abblock-C, whatever. Sobald du diese Hardwareprobleme geloest hast wird dein Problem nur noch alle paar Tage oder Monate auftreten. Je nachdem wie EMV-Gerecht deine Hardware aufgebaut ist. Ganz weg bekommt man das bei I2C niemals. Olaf
Andreas S. schrieb: > Die Datenleitung wird, wahrscheinlich vom Slave, auf GND gehalten. Prüfe es, indem du die Verbindung zum Master trennst oder dessen Reset Knopf gedrückt hältst (falls dadurch nicht auch der Slave resetted wird).
Helge schrieb: > Wie löst du das konkret? Erst einmal die Ursache ermitteln, bevor man die passende Lösung sucht.
Vielen Dank für die schnellen Antworten! Hallo Stephan, ja, natürlich ist das einfacher. Die Übertragung dauert mir aber zu lange, gesamt ca. 600us. Wenn alles läuft, würde ich das Ganze in den Interrupt packen, zumindest die Teile die bei 100kHz bis zu 100us dauern. Hallo Olaf, meine Erfahrung mit dem I2C ist, dass er zuverlässig arbeitet. Bei meinen Projekten, die ich mit einem PIC gemacht habe, habe ich keine Störungen(mehr). Ich habe allerdings auch lange daran rumgebastelt, bis ich die Übertragung so hatte, dass sie zuverlässig ist. Ein falscher Befehl und nix funzt mehr. Mit dieser Erfahrung hatte ich gedacht, dass womöglich jemand den kleinen Fehler in meinem AVR Programm findet, der da noch drin sein muss. Und natürlich hast du recht, dass sich das mit Fehlerroutinen umgehen lässt. Die würde ich aber erst einbauen, wenn das Ganze grundsätzlich funzt. Hallo Helge, statt einer einfachen while-Schleife, die auf ein ganz bestimmtes Ereignis wartet, einzubauen, kann man z.B. Zeitstrukturen einbauen. Wenn eine bestimmte Zeit lang, das erwartete Ereignis nicht eintrifft, kann man die Übertragung abbrechen und neu anfangen...
Moin, Um rauszufinden, wer den Bus nicht loslaesst, kanns nicht schaden, ganz kleine Serienwiderstaende (<50 Ohm) in die SDA und SCL Leitungen reinzubauen. Gruss WK
Philips hat damals eine Recovery Routine in den Specs für I²C vorgeschlagen. Dabei wird bis zu 9 mal SCL gepulst und darauf gehört, ob SDA wieder auf high springt. Wimre soll man dann eine STOP Bedingung anschliessen und der Bus spielt wieder.
Hallo DerguteW, hört sich sehr spannend an! Was mache ich denn dann mit den Serienwiderständen? Was muss ich da wie messen? Vielen Dank Andreas
Moin, Andreas S. schrieb: > Was muss ich da wie messen? Wenn der Bus haengt, dann misst du das bisschen Spannung zwischen GND und jeweils einem Pin des Widerstands. So kriegst du raus, ob Strom durch den R fliesst und wenn ja, in welche Richtung... Gruss WK
> meine Erfahrung mit dem I2C ist, dass er zuverlässig arbeitet. Bei > meinen Projekten, die ich mit einem PIC gemacht habe, habe ich keine > Störungen(mehr). Nein. I2C ist per Design nicht zuverlaessig. Wenn ein Slave ein falsche Kommando empfaengt kann es passieren das er sein Datenleitung runterzieht und das naechste Kommando auch nicht mehr richtig empfaengt. Fehler bei der Uebertragung koennen also dafuer sorgen das sich ein Bus weghaengt. (z.B ein Burst, RF-Einstrahlung, Angorapullover) Du kannst den dann wieder aufbauen. Ueblicherweise indem man einfach Clocks raushaut in der Hoffnung das damit die Statemachine im Slave wieder aufsetzt. Es gibt aber auch Bausteine die koennen die Clockleitung runterziehen. Das war es dann. Dann kannst du nur noch bei deinem Baustein die Vcc abschalten und wieder einschalten. Jetzt gibt es natuerlich Bausteine die machen sowas lieber als andere. Ausserdem haengt es natuerlich stark von deinem Hardwaredesign ab. Bei einem schlechten Design hast du die Probleme oft, bei einem guten vielleicht nur alle paar Jahre mal. Und es haengt auch von der Anwendung hab. Bei einem MP3-Player den du in der Woche nur 3h nutzt und den du bei einem Problem automatisch mal aus/einschaltet wird das nicht so recht auffallen. Bei der Temperatursteuerung sagen wir mal deines Kuehlschranks die 24h laeuft waere es bloed wenn die alle 5Jahre mal versagt und deine Pommes auftauen. Weil das den Herstellern auch aufgefallen ist gibt es mittlerweile moderne I2C Erweiterungen. Da haben die Bausteine eine minimal Taktfrequenz. Wenn der Baustein da eine Weile nix mehr empfaengt dann resetet er sich intern um die Finger vom Bus zu nehmen. Ich will damit nicht sagen das man I2C nicht verwenden kann. Man sollte sich dessen nur bewusst sein und Fehler einplanen. Olaf
Andreas S. schrieb: > Was mache ich denn dann mit den Serienwiderständen? Wieso Serienwiderstände? I2C hat nur 2 Pullups. Mit irgendwelchen Serienwiderständen versaust Du nur Dein Signal.
Wiederstände von <50Ohm habe ich schon öfters in Schaltungen gesehen. Die Funktion ist mir in Abhängigkeit des Einbauortes nicht ganz klar. Wenn ich die Widerstände zwischen Master und den Slaves schalte kann ich zwar die Richtung feststellen, doch welcher IC es ist kann ich nicht messen. Können diese Widerstände nicht mein Pegel des Busses beeinflussen? LG Fr
Fragender schrieb: > Können diese Widerstände nicht mein Pegel des Busses beeinflussen? genau, der Low-Pegel wird für bestimmte Teilnehmer des Busses höher, weil der Serienwiderstand und der Pullup als Spannungsteiler wirken, d.h. die verschlechteren das Signal.
Fragender schrieb: > Wiederstände von <50Ohm habe ich schon öfters in Schaltungen gesehen. Normale IO-Pins sind oft leistungsstark, was Reflexionen bewirken kann. Z.B. wenn man den Master in SW implementiert. Da verbessert dann ein Serienwiderstand die Störsicherheit. Pins vom HW-I2C sollten aber schon intern die Slew-Rate begrenzen. Das sollte dann im Datenblatt stehen.
Peter D. schrieb: > Normale IO-Pins sind oft leistungsstark, was Reflexionen bewirken kann. Der typische I2C-Bus ist reflexionsfrei, wenn die Pullup-Widerstände der Spannung, Busfrequenz und Teilnehmerzahl entsprechend korrekt berechnet sind, vor allem dürfen sie nicht zu hoch sein. Bei normaler Belegung hängen am I2C-Bus nur hochohmige Eingänge und Open-Drain-Ausgänge, bei Software-I2C sind die Ausgänge push-pull, was auch für saubere Pegel sorgt.
Moin, L.K. schrieb: > Der typische I2C-Bus ist reflexionsfrei, wenn die Pullup-Widerstände der > Spannung, Busfrequenz und Teilnehmerzahl entsprechend korrekt berechnet > sind, vor allem dürfen sie nicht zu hoch sein. Bei normaler Belegung > hängen am I2C-Bus nur hochohmige Eingänge und Open-Drain-Ausgänge, bei > Software-I2C sind die Ausgänge push-pull, was auch für saubere Pegel > sorgt. Das glaube ich nicht, Tim. Fragender schrieb: > doch welcher IC es ist kann ich nicht > messen. Dann sind's zu wenige Widerstaende ;-) > Können diese Widerstände nicht mein Pegel des Busses beeinflussen? Die sollten halt so klein sein, dass der Pegel nicht zu stark beeinflusst wird. Ich finds erstaunlich, dass zwar auf der einen Seite Leute irgendwelche I2C Monster mit zig Slaves via meterweise tüddelkabel zwischendrinnen aufbauen wollen, aber auf der anderen Seite Leute gleich halbtot vor Entsetzen vom Stangerl fallen, wenn man mal ein paar Serienwiderstaende anraet. Wers mit seinem Gewissen garnicht vereinbaren kann, der darf auch 0 Ohm Widerstaende hernehmen und die dann nur im "'s dud ned" Fall durch gerinfuegig hoehere Werte ersetzen. Ist deutlich weniger Gefuddel als die Leitungen aufzutrennen. Gruss WK
L.K. schrieb: > bei > Software-I2C sind die Ausgänge push-pull, was auch für saubere Pegel > sorgt. Da hast du ein häufig auftretendes Problem bei Schludersoftware gut beschrieben. Push-Pull am I2C ist ein absolutes noGo. Für LOW darfst du niederohmig nach GND ziehen, für HIGH schaltest du den Port auf Eingang. Sonst sind einige Funktionen unmöglich (Clock Stretching als Beispiel).
Georg G. schrieb: > Push-Pull am I2C ist ein absolutes noGo. Der aktive Part hat als Ausgang bei Software-I2C sehr wohl push-pull. Bei HW-I2C open-drain oder OC. Als Eingang hochohmig.
Probleme beim I2C können natürlich durch die SW verursacht sein. Aber man sollte auch klären, wie die HW aussieht: - Welche Leitungslängen liegen vor? (Temp-Sensoren könnten weit weg installiert sein ...) - Welche Pullups am I2C-Bus sind verwendet worden bei welchem Logikpegel? Oder habe ich Aussagen dazu übersehen?
L.K. schrieb: > Der aktive Part hat als Ausgang bei Software-I2C sehr wohl push-pull. Was war an "Push Pull ist ein Fehler" missverständlich? Sieh dir bitte die Spec an oder eine der gängigen Libs (Fleury als Beispiel).
> bei Software-I2C sind die Ausgänge push-pull, was auch für saubere > Pegel sorgt. Und genau das ist der groesste Murks den man machen kann. Natuerlich ist der Ausgang immer Low und man schaltet den Port fuer Highpegel auf Eingang um. Sonst braucht man sich nicht zu wundern wenn das Zeug nicht richtig laeuft. Olaf
Hi >Der aktive Part hat als Ausgang bei Software-I2C sehr wohl push-pull. AVR 300: Software I2C™ Master Interface MfG Spess
L.K. schrieb: > Wieso Serienwiderstände? I2C hat nur 2 Pullups. Mit irgendwelchen > Serienwiderständen versaust Du nur Dein Signal. Unfug. Da sollen keine MegaOhm Widerstände rein. Ein Spannungsabfall von wenigen 100mV ist absolut unkritisch. Guck dir mal die Spezifikation für die Erkennung eines Low-Pegels auf den Leitungen an.
Matthias S. schrieb: > Philips hat damals eine Recovery Routine in den Specs für I²C > vorgeschlagen. > Dabei wird bis zu 9 mal SCL gepulst und darauf gehört, ob SDA wieder auf > high springt. Ja, die kannste auch vergessen. Ich habe das Problem seit langem mit meiner Wetter Uhr. I2C über Cortex Hardware. 1-2 Monat hängt I2C sich auf am EEPROM.(Lochrasteraufbaue in freier Luft) Und da hilft nur ein Stecker raus/rein. Die EEPROM Statemachine kriegt man nicht mehr in die Spur. I2C hängt sich immer dann auf, wenn die beiden SM außer Takt geraten. Und da reicht ein Glitch aus von wenigen Nanosekunden.
Andreas S. schrieb: > Was mache ich denn dann mit den Serienwiderständen? Das hat er so gemeint:
1 | 3,3V |
2 | +-----+ |
3 | | | |
4 | |~| |~| PullUps 2,7kΩ |
5 | |_| |_| |
6 | | | |
7 | I²C Bus ================================================= SDA und SCL |
8 | | | | | | | |
9 | |~| |~| |~| |~| |~| |~| |
10 | |_| |_| |_| |_| |_| |_| 47Ω |
11 | | | | | | | |
12 | SDA SCL SDA SCL SDA SCL |
13 | Mikrochip 1 Mikrochip 2 Mikrochip 2 |
Wenn jetzt irgend ein Mikrochip den Bus permanent auf Low zieht, kannst du ihn anhand der Spannungsabfälle an den unteren Widerständen identifizieren. Bei einem wirst du aufgrund des Stromflusses ca. 50mV Spannungsabfall messen, bei den anderen nicht. Es sei denn, mehrere Mikrochips blockieren den Bus gleichzeitig. Aber das siehst du dann schon. Viel Glück.
Christian J. schrieb: > Und da hilft nur ein > Stecker raus/rein Würde es auch helfen per watchdog IC den MCU zu resetten ohne VCC abzuschalten?
Helge schrieb: > Würde es auch helfen per watchdog IC den MCU zu resetten ohne VCC > abzuschalten? Nicht, wenn ein anderes IC den Bus blockiert.
> Würde es auch helfen per watchdog IC den MCU zu resetten ohne VCC > abzuschalten? Nein. Die Statemachine in der eine MCU kannst du ja neu initialisieren und wenn der Hersteller da keinen grossen Murks gebaut hat, kommt vor, sollte sie dann wieder gehen. Das Problem sind aber deine Slave. Olaf
Ok, wie wird das aber denn in professionellen Produkten gemacht? Da müsste man ja jeden Slave abschaltbar machen? Eine Zeitschaltuhr für die Steckdose zB, die eine RTC verwendet müsste dann ja höchst unzuverlässig sein, wenn sich da nach 5 Monaten Betrieb plötzlich der Bus aufhängt. Irgendwo wurde beschrieben als Lösung, wenn der Bus hängt, einen GPIO pin mit SDA zu verbinden, und im Fehlerfall damit SDA auf LOW zu ziehen..aber das resettet doch auch nicht die Slaves?
Helge schrieb: > Da müsste man ja jeden Slave abschaltbar machen? Ja, in der Tat. habe ich auch schon so gesehen. Helge schrieb: > im Fehlerfall damit SDA auf LOW zu > ziehen..aber das resettet doch auch nicht die Slaves? Vielleicht hatte dieser Slave eine spezielle Funktion/Schaltung die das als Reset-Signal interpretiert hat.
Stefan ⛄ F. schrieb: > Nicht, wenn ein anderes IC den Bus blockiert. deswegen muss man die Möglichkeit haben dem I2C Blockierer wenigstens einen power on reset aufzudrücken. Bei kleinen I2C kann man das sogar aus einem Port speisen, bei dicken Verbrauchern hilft vielleicht ein Photomos Relais, ist jedenfalls sicherer zu erzeugen als an den I2C Pins zu wackeln, auch das SOLL Ja einen Reset auslösen, aber wenn der Slave nicht reagiert hilft nur Stecker ziehen oder Power für den abschalten!
Dumme I2C-Slaves (EEPROM, IO-Port, ADC) kann man einfach 9-mal takten, dann ist SDA wieder high. VCC abschalten ist Quatsch. Nur Slaves mit MC können sich aufhängen. Meistens liegt das daran, daß das Slave-I2C buggy ist. Bei den AVRs habe ich deshalb ein Timeout einbauen müssen. Wenn sich da der Slave aufhängt, d.h. SDA >1ms low bleibt, wird das I2C disabled und wieder neu aufgesetzt.
@Peter, dann wäre das bei RTC, OLED und EEPROM doch kein Thema? Ganz schön verwirrend das ganze
> Ok, wie wird das aber denn in professionellen Produkten gemacht? Da > müsste man ja jeden Slave abschaltbar machen? Professionell ist ein weites Feld. Bei irgendeinem Aldi-Grabbelzeug wird das den Hersteller gar nicht interessieren. Bei wichtigem SIL2 Kram verbaut man einfach kein I2C. Dazwischen gibt es dann die Moeglichkeit zu schalten. Zum Beispiel ueber Loadswitches oder manchmal kann man sogar direkt einen Portpin als VCC verwenden. Olaf
Wie würde man das mit den Pullup Widerständen machen? VCC des EEPROMs könnte man an einen pin vom MCU direkt hängen. Display und RTC über Highside switches abtrennen. So könnte man alle Slaves abtrennen, die Pullups wären trotzdem dann noch mit VCC verbunden. Brauchen die ebenfalls einen Switch? Könnte mir vorstellen, dass die Slaves rückgespeist werden. Beim Display ist das manchmal der Fall zb
Die Pull-Ups musst du natürlich auch abschalten, denn (fast) kein IC verträgt an seinen Eingängen wesentlich mehr Spannung als die eigene Versorgungsspannung.
Gute Erfahrungen hatte ich mit original Phillips-MCs gemacht, die laufen einfach 24/7 ohne jeden Timeout oder sonstige Würgarounds. Z.B. der bekannte P80C652 oder der Nachfolger P89C668. Leider hat NXP die verbannt. Atmel hat I2C leider nicht mehr verstanden und sowohl bei den 8051 als auch den AVRs gepatzt. Das Atmel I2C ist SW-mäßig zum Philips I2C identisch, aber eben nicht in der HW-Implementierung. Auch hat sich Tekmos am TK89C668 als NXP-Ersatz versucht und ist gescheitert. Deren I2C blieb schon beim Init hängen. Single-Master schaffen viele MCs gerade noch, aber Multimaster oder Slave sind ein Problem. Ich hab daher alle Neuentwicklungen auf CAN umgestellt.
>Ich hab daher alle Neuentwicklungen auf CAN umgestellt.
Hast du hierzu mehr Informationen?
> Gute Erfahrungen hatte ich mit original Phillips-MCs gemacht, die laufen Die Probleme treten aber in aller Regel im Slave auf und nicht im Master. Den Master kannst du ja jederzeit neu konfigurieren oder besser aufsetzen auf das du dort keine Probleme hast. > Single-Master schaffen viele MCs gerade noch, aber Multimaster oder > Slave sind ein Problem. Das ist richtig. Auch wenn ich vermute das da ein Teil der Probleme immer auch vor dem Monitor sitzt. I2C, besonders als Teil eine Multiseriellen-Einheit die auch noch SPI und RS232 kann, ist auch fuer den Anwender komplex. Allerdings halte ich Multimaster bei I2C sowieso fuer quatsch. Wenn man eine solche Funktionalitaet braucht hat man IMHO die Grenze ueberschritten wo dieser Busttyp noch sinnvoll ist. Olaf
Moin Alle, vielen Dank für eure Beiträge. Wieder einmal bin ich in die Datenblattfalle getappt: Wer braucht schon sowas? Das geht doch auch ohne! In meinen PIC-Projekten hatte ich das große Glück, dass ich von Anfang an zwischen zwei Temperaturabfragen vom MLX90614 20ms Pause eingeschoben habe. Nach 20ms geht aber der Temperatursensor von sich aus in IDLE, wenn nichts mehr von ihm verlangt wird! Will man ihn aber häufiger benutzen, muss man alle Daten von ihm verlangen, sonst wird er bockig: Er stellt nicht nur zwei Temperaturwerte (LO-Byte, HI-Byte) zur Verfügung, sondern auch noch einen PEC (Prüfwert). Den muss man auch noch abfragen, bevor man die Kommunikation mit ihm beendet. Zwei bis fünf Mal macht er trotzdem mit, macht dann aber zu! Sobald ich das dritte Datum auch noch abgefragt hatte, war alles in Butter. Jetzt würde ich euch ja meinen Source-Code im nötigen Format zeigen, weil ich gelernt hab, dass PDF nicht gewünscht ist, aber wie mache ich das? Einen schönen Tag Andreas
Andreas S. schrieb: > Jetzt würde ich euch ja meinen Source-Code im nötigen Format zeigen, > weil ich gelernt hab, dass PDF nicht gewünscht ist, aber wie mache ich > das? Als Datei anhängen, würde ich mal sagen. Oder wenn er kurz ist, in entsprechende Tags einbetten, also
1 | [c] und [/c] |
.
Andreas S. schrieb: > Jetzt würde ich euch ja meinen Source-Code im nötigen Format zeigen, > weil ich gelernt hab, dass PDF nicht gewünscht ist, aber wie mache ich > das? Einfach den/die C-Quellfiles hier anhängen. Die Forensoftware hat eine Funktion 'Codeansicht' mit gutem Syntax-Highlighting. PDF ist tatsächlich Sch.... hier.
Ich versuche es mal:
1 | while (1) { |
2 | _delay_us(50); |
3 | //Start:
|
4 | TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); //Start transmission |
5 | while (!(TWCR & (1<<TWINT))); //Wait for Interrupt Flag, startcondition is sent |
6 | while((TWSR & 0xF8)!= 0x08); //Start condition has been transmitted |
7 | //Send slave address and read/write (1/0)
|
8 | TWDR = (0x5A<<1); //0x5A << 1 plus LSB = 0 Master write |
9 | TWCR = (1<<TWINT) | (1<<TWEN); //Initialize the transmission |
10 | while (!(TWCR & (1<<TWINT))); //Wait for Interrupt Flag, address has been sent |
11 | while((TWSR & 0xF8)!= 0x18); //Slaveaddress + W has been send, ACK |
12 | //Send 8-bit-data to the slave
|
13 | TWDR = 0x07; //Adress of the temperatur register |
14 | TWCR = (1<<TWINT) | (1<<TWEN); //Initialize the transmission |
15 | while (!(TWCR & (1<<TWINT))); //Wait for Interrupt Flag, register has been sent |
16 | while((TWSR & 0xF8) != 0x28);//Data has been transmitted, ACK |
17 | //Send repeated start condition
|
18 | TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); //Repeated Start Condition |
19 | while (!(TWCR & (1<<TWINT))); //Wait for Interrupt Flag, startcondition is sent |
20 | while((TWSR & 0xF8)!= 0x10); //Rep. start condition has been send, ACK |
21 | //Send slave address and read/write (1/0)
|
22 | TWDR = (0x5A<<1)|(1<<0); //0x5A << 1 plus LSB = 1 Master read |
23 | TWCR = (1<<TWINT) | (1<<TWEN); //Initialize the transmission |
24 | while (!(TWCR & (1<<TWINT))); //Wait for Interrupt Flag, address has been sent |
25 | while ((TWSR & 0xF8)!= 0x40); //Slaveaddress + R has been send, ACK |
26 | //Read 8-bit-data from the slave
|
27 | TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); //Initialize the transmission, not the last data to be received |
28 | while (!(TWCR & (1<<TWINT))); //Wait for Interrupt Flag, address has been sent |
29 | while ((TWSR & 0xF8)!= 0x50); //Data has been received, ACK |
30 | Temperatur_LO = TWDR; |
31 | //Read again 8-bit-data from the slave
|
32 | TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); //Initialize the transmission, not the last data to be received |
33 | while (!(TWCR & (1<<TWINT))); //Wait for Interrupt Flag, address has been sent |
34 | while ((TWSR & 0xF8)!= 0x50); //Data has been received, ACK |
35 | Temperatur_HI = TWDR; |
36 | //Read PEC from the slave
|
37 | TWCR = (1<<TWINT) | (1<<TWEN); //Initialize the transmission, now the last data to be received |
38 | while (!(TWCR & (1<<TWINT))); //Wait for Interrupt Flag, address has been sent |
39 | while ((TWSR & 0xF8)!= 0x58); //Data has been received, NACK terminates the transmission |
40 | PEC = TWDR; |
41 | //Send stop condition
|
42 | TWCR= (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); |
43 | while(!(TWCR & (1<<TWSTO))); // Wait till stop condition is transmitted |
44 | }
|
Na sieht doch ganz gut aus. Vielen Dank.
Andreas S. schrieb: > Na sieht doch ganz gut aus. Wenn du jetzt noch die wiederholten Registerzugriffe in Funktionen mit sprechenden Namen packst, wird der Code besser lesbar, weniger Fehleranfällig und du kannst dir die wiederholten Kommentare sparen. Etwa so:
1 | void TWI_Start() |
2 | {
|
3 | TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); //Start transmission |
4 | while (!(TWCR & (1<<TWINT))); //Wait for Interrupt Flag, startcondition is sent |
5 | while((TWSR & 0xF8)!= 0x08); //Start condition has been transmitted |
6 | }
|
7 | |
8 | #define READ true
|
9 | #define WRITE false
|
10 | void TWI_Send_Address(uint8_t slaveAddr, bool readMode) |
11 | {
|
12 | if (readMode) |
13 | {
|
14 | TWDR = (slaveAddr<<1)+1; // LSB = 1 Master read |
15 | }
|
16 | else
|
17 | {
|
18 | TWDR = (slaveAddr<<1)+0; // LSB = 0 Master write |
19 | }
|
20 | TWCR = (1<<TWINT) | (1<<TWEN); //Initialize the transmission |
21 | while (!(TWCR & (1<<TWINT))); //Wait for Interrupt Flag, address has been sent |
22 | if (readMode) |
23 | {
|
24 | while ((TWSR & 0xF8)!= 0x40); //Slaveaddress + R has been send, ACK |
25 | }
|
26 | else
|
27 | {
|
28 | while((TWSR & 0xF8)!= 0x18); //Slaveaddress + W has been send, ACK |
29 | }
|
30 | }
|
31 | |
32 | void TWI_Send_Data(uint8_t data) |
33 | {
|
34 | TWDR = (data); |
35 | TWCR = (1<<TWINT) | (1<<TWEN); //Initialize the transmission |
36 | while (!(TWCR & (1<<TWINT))); //Wait for Interrupt Flag, address has been sent |
37 | while((TWSR & 0xF8) != 0x28);//Data has been transmitted, ACK |
38 | }
|
39 | |
40 | void TWI_Repeat_Start() |
41 | {
|
42 | TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); //Repeated Start Condition |
43 | while (!(TWCR & (1<<TWINT))); //Wait for Interrupt Flag, startcondition is sent |
44 | while((TWSR & 0xF8)!= 0x10); //Rep. start condition has been send, ACK |
45 | }
|
46 | |
47 | #define ACK true
|
48 | #define NACK false
|
49 | uint8_t TWI_Read(bool sendAck) |
50 | {
|
51 | TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); //Initialize the transmission, not the last data to be received |
52 | while (!(TWCR & (1<<TWINT))); //Wait for Interrupt Flag, address has been sent |
53 | if (sendAck) |
54 | {
|
55 | while ((TWSR & 0xF8)!= 0x50); //Data has been received, ACK |
56 | }
|
57 | else
|
58 | {
|
59 | while ((TWSR & 0xF8)!= 0x58); //Data has been received, NACK terminates the transmission |
60 | }
|
61 | return TWDR; |
62 | }
|
63 | |
64 | void TWI_Stop() |
65 | {
|
66 | TWCR= (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); |
67 | while(!(TWCR & (1<<TWSTO))); // Wait till stop condition is transmitted |
68 | }
|
69 | |
70 | while (1) |
71 | {
|
72 | _delay_us(50); |
73 | TWI_Start(); |
74 | TWI_Send_Address(0x5A,WRITE); // Address of the I²C slave |
75 | TWI_Send_Data(0x07); //Adress of the temperatur register |
76 | TWI_Repeat_Start(); |
77 | TWI_Send_Address(0x5A,READ); |
78 | Temperatur_LO = TWI_Read(ACK); |
79 | Temperatur_HI = TWI_Read(ACK); |
80 | PEC = TWI_Read(NACK); |
81 | TWI_Stop(); |
82 | }
|
Stefan ⛄ F. schrieb: > Wenn du jetzt noch die wiederholten Registerzugriffe in Funktionen mit > sprechenden Namen packst, wird der Code besser lesbar Ja, da hast du natürlich Recht. Aber mir ging es erst mal darum, das Programm ans Laufen zu kriegen... Mein Ziel war es, das Ganze ins Interrupt zu packen, da sieht es sowieso nochmal anders aus. (s. Anhang) Das Programm ist geschrieben für Atmel Studio 7.0, in dem es den Data Visualizer gibt. Baud Rate 38400! Nicht 9600. Schönen Tag Andreas
> habe. Nach 20ms geht aber der Temperatursensor von sich aus in IDLE, > wenn nichts mehr von ihm verlangt wird! Will man ihn aber häufiger Glaubst du es macht Sinn eine Temperatur so haeufig abzufragen? Zumal dann auch die Gefahr besteht das sich der arme Sensor durch das haeufige auslesen auch selbst staerker erwaermt und ungenauer misst? Olaf
Hallo Olaf, wenn man einen Roboter mit 0,5m/s fahren lässt und man damit auf der Suche nach Wärmequellen ist, die ca. 2cm breit sind, dann hast du keine andere Wahl. Daher ist es auch wichtig, dass Programmteile, die ein eigenes Modul im MC haben, in den Interrupt gepackt werden, damit alle möglichen Sensoren "gleichzeitig" ausgelesen werden können und zur Verarbeitung zur Verfügung stehen und auch dafür noch genug Zeit ist. Ich kann mir übrigends nicht vorstellen, dass bei einer Duty-Zeit von ca. 600us und einer Not-Duty-Zeit von 20ms, sich ein Sensor signifikant erwärmt. Jedenfalls sind die Werte die so ermittelt werden plausibel und ausreichend. Müsste ich mal testen... Vielen Dank. Einen schönen Tag Andreas
Moin, Andreas S. schrieb: > wenn man einen Roboter mit 0,5m/s fahren lässt und man damit auf der > Suche nach Wärmequellen ist, die ca. 2cm breit sind, dann hast du keine > andere Wahl. Hat schon einen Grund, warum HD-Videosignale nur eher selten ueber I2C gehen. Bei dir sind nur Aufloesung und betrachtete Wellenlaenge anders ;-) Gruss WK
Olaf schrieb: > Allerdings halte ich Multimaster bei I2C sowieso fuer quatsch. Nö, es ist sogar recht effizient für die Verbindung von mehreren MCs. Niemand muß auf den anderen warten, jeder kann senden, wenn er die Antwort parat hat. Multimaster-I2C ist quasi der Vorläufer des CAN. Und die Phillips-MCs beweisen ja, das es geht, wenn man die I2C-Hardware entsprechend der Spezifikation entwickelt. Die laufen 24/7 jahrelang durch. Daß die Atmel AVRs buggy sind, ist ja bekannt: http://www.robotroom.com/Atmel-AVR-TWI-I2C-Multi-Master-Problem.html
Moin, Peter D. schrieb: >> Allerdings halte ich Multimaster bei I2C sowieso fuer quatsch. > > Nö, es ist sogar recht effizient für die Verbindung von mehreren MCs. Auch wenn du es recht effizient nennst, ich halte es auch fuer Quatsch. Ich bin der Ansicht: Wenn man sowas wie Multimaster braucht, ist i2c nicht mehr der Bus der Wahl. Dann sollte man andere Busse verwenden. Ist ja nicht nur der Bus entscheidend, ich muss ja irgendwie auch verhindern, dass z.b. 2 Master ins Gehege kommen, wenn jeder am selben Device ueber mehrere Kommandos rumschrauben will. Auch wenns I2C Leitungstreiber gibt, um ueber 15m lange, nasse Schnuersenkel einen Slave anzubinden, werd' ich sowas sicherlich nie verwenden, nur weil's sowas beklopptes gibt. Und nicht nur bei AVR gibts Multimasterprobleme. Ich erinnere mich noch mit Grauen an ein i2c-peripheral in einem coldfire prozessor, was nur Multimaster konnte und alle Furz lang dann der Ansicht war, ein anderer (real nicht vorhandener) Master haette grad den Bus, weshalb jetzt erstmal nix mehr ginge bis zum naechsten Reset. Gruss WK
Andreas S. schrieb: > Ich versuche es mal Das sieht so ziemlich nach dem Standardcode fürs (imo beknackte) TWI Interface aus. Jetzt muss mir aber mal einer erklären, warum man sich das antut. Das ganze ist doch so zeitraubend, das man auch gleich Bitbanging machen kann oder (wie ich das tue) gleich eine passende I2C Lib einsetzt, die beide Optionen (Hardware IF oder Bitbanging) bietet.
Dergute W. schrieb: > Wenn man sowas wie Multimaster braucht, ist i2c > nicht mehr der Bus der Wahl. Was denn dann? Multimaster-I2C macht die Programmierung sehr einfach. Jeder darf senden, wann er Zeit dazu hat. Wichtige Echtzeitaufgaben müssen auf die Kommunikation keinerlei Rücksicht nehmen, sie erfolgt ohne Priorität im Hintergrund. Durch das Clock-Stretching darf der I2C-Interrupt jederzeit unterbrochen werden. Im Gegensatz dazu muß bei RS-485 der Slave so schnell wie möglich antworten. Und der Master muß jedesmal die maximale Antwortzeit abwarten, nachdem er die Senderichtung auf Slave umgeschaltet hat. Die Kommunikation benötigt also die höchste Priorität und kann andere Echtzeitaufgaben stören. Da ich zuerst Philips genommen hatte, konnte ich ja nicht wissen, daß andere Hersteller bei ihrer I2C-Implementierung patzen. Die I2C-Spezifikation von Philips sieht auch sehr wasserdicht aus. Alle Bedingungen und Timings sind eindeutig definiert. Warum sich andere nicht danach richten, kann ich mir nicht erklären.
Bin auch Philips Fan und richte mich bei Problemen immer zuerst nach den Specs aus den Niederlanden. Ich hänge mal die 'amtliche' Referenz von Philips an. Die ist nicht sehr gross, aber interessant.
Moin, Peter D. schrieb: > Was denn dann? Einer ist der Master, der schraubt am Slave via i2c bus. Wenn noch irgendwer anderes was von dem Slave haben will, dann soll der sich an den Master wenden. Ueber irgendein anderes Interface als ausgerechnet diesen i2c Bus. Weil der Master Bescheid weiss, wie's dem Slave grad geht, ob der grad Zeit hat oder erst spaeter, weil der Master grad an ihm am schrauben ist. > Multimaster-I2C macht die Programmierung sehr einfach. Jeder darf > senden, wann er Zeit dazu hat. Naja, nur auf den ersten Blick. Les' ich grad ein i2c-eeprom komplett aus, kann ich mich bei Multimasterbetrieb nicht aufs Autoincrement der Adressen verlassen, wenn da potentiell wer anderes zwischenrein quaken kann. Beim Schreiben noch weniger. Lad' ich grad in einen DVB-T Demodulator den DSP Code, will ich nicht, dass mir da irgend ein Armloch mittendrinn den Bus klaut, bloss weil der wissen will, wie spaet's grad ist. Und weil die Uhr grad auch mal erst noch aufwachen muss und clk-stretched, fuehlt sich der Demod nicht mehr geliebt und macht Faxen. Alles streng nach Philips I2C Multimasternorm, aber eher stressfoerdernd in der Realitaet. Gruss WK
Dergute W. schrieb: > Naja, nur auf den ersten Blick. Les' ich grad ein i2c-eeprom komplett > aus, kann ich mich bei Multimasterbetrieb nicht aufs Autoincrement der > Adressen verlassen, wenn da potentiell wer anderes zwischenrein quaken > kann. Beim Schreiben noch weniger. Nö, solange Du kein STOP sendest, bleibst Du der aktive Master. Fürs Pagewrite mußt Du ein STOP senden, aber für die nächste Page mußt Du eh die komplette Startadresse senden. EEPROMs lege ich nicht auf den Modulbus, sondern schließe sie direkt an den MC an.
Moin, Peter D. schrieb: > Fürs Pagewrite mußt Du ein STOP senden, aber für die nächste Page mußt > Du eh die komplette Startadresse senden. Jepp, beim Schreiben sollte nix passieren koennen, stimmt. Aber beim "current adress read" muss ich mich verlassen, das keiner seit meinem letzten Read am Adresszeiger im eeprom gedreht hat. Genauso bei anderen Slaves, die Subaddressierung mit autoincrement unterstuetzen. Das machen ein bis zwei, hab' ich geruechteweise gehoert. Ja, ich weiss, das liegt nicht am Bus, dass da was schief gehen kann. Aber es schraenkt die Rieeeesenvorteile des Multimasterbetriebs doch arg ein. Mal ganz davon abgesehen, wenn man es mit real existierender HW und ihren Spirenzchen zu tun hat. > EEPROMs lege ich nicht auf den Modulbus, sondern schließe sie direkt an > den MC an. Aber warum das denn, streng nach Philips ist das doch gar kein Problem <unschuldig guck' & pfeif> ;-) Gruss WK
Dergute W. schrieb: > Aber warum das denn Der EEPROM speichert z.B. lokale Kalibrationen des Moduls und außerdem schränkt das den Adreßraum unnötig ein. Je nach Typ können nur 1..8 EEPROMs am selben Bus hängen, z.B. nur ein 24LC16.
> Je nach Typ können nur 1..8 > EEPROMs am selben Bus hängen, z.B. nur ein 24LC16. Hast du schon jemals gesehen das jemand 8Stk davon auf einer Platine hatte? Das waer doch ziemlich doof. Da kann doch dann besser ein fettes FRAM nehmen. Olaf
Andreas S. schrieb: > Ich versuche es mal:while (1) { > Na sieht doch ganz gut aus. Ja, viel besser, aber so ist es eher für kurze Codeabschnitte gedacht und sinnvoll. Deinen würde ich so als Grenzfall betrachten ... Eingangs hattest du doch PDFs angehängt, genau so geht das mit dem C-Quellfile. Sieht dann so aus wie z.B. in dem Beitrag (auf Codeansicht klicken): Beitrag "Re: Atmega Taster einlesen und in Register schreiben funktioniert nicht wie geplant" Wobei: ganz aktuell scheint die 'Codeansicht' beim Syntax-Highlightning beschädigt zu sein. Ich hoffe, das ist nur temporär.
Matthias S. schrieb: > Jetzt muss mir aber mal einer erklären, warum man sich das antut. Wegen: ● Slew-rate limited output drivers ● Noise suppression circuitry rejects spikes on bus lines (https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf Kapiterl 21.1)
Dergute W. schrieb: > Aber beim "current adress read" muss ich mich verlassen, das keiner seit > meinem letzten Read am Adresszeiger im eeprom gedreht hat. Das finde ich auch logisch, denn STOP kennzeichnet das Ende der Transaktion. Verkettete Transaktionen gibt es nicht. Die gleichen "Probleme" hast du auch bei Multi-Threaded Systemen, wenn du die Boundaries von Transaktionen missachtest, und das betrifft nicht nur I²C.
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.