Moin moin alle zusammen,
erstmal nochmal ein Danke an alle die mir gestern geholfen haben die
Thematik zu verstehen, ich habs jetzt glaube ich endlich geblickt.
Ich hab jetzt nen Code für den Master und für den Slave geschrieben,
scheinbar hängt es aber an einer stelle,
Ok So ist mein Aufbau:
2 Atmega ein Master ein Slave.
SDA und SCL sind miteinander verbunden, die Leitungen gehen über jeweils
einen Widerstand an VCC
Was passiert:
Die Verbindung scheint zu "abzubrechen" scheinbar hab ich irgendeinen
Fehler im Code so das Master und Slave auseinanderlaufen?! bzw sich
einfach unterbrechen...
den Master hab ich mit TX und RX an den Arduino, somit kann ich mir ne
monitor ausgabe geben.
Wenn ich den Slave neu programmiere, kommt dort die ganze Zeit
Kann nix vom Bus lesen
Kann auf den Bus nicht schreiben
Was ja auch klar ist wenn der Slave nicht da ist.
Wenn der Slave wieder da ist, gibt es eine aktion,
Entweder
gelesenes Byte : 30,
oder
20 wurde gesendet
beide richtig, mit dem Slave sende ich testeshalber ne 30 rüber und der
master sendet eine 20.
Hier mal der Code, eventuell habt ihr ja auch tipps wie ich das ganze
debuggen kann um den Fehler zu finden.
Meine Kommentare könnt ihr Ignorieren, Sie waren nur für mich da um mir
das ganze mehr einzuprägen.
Außer in der TWIMaster_Stop funktion da wäre es interessant ob das so
richtig ist, oder so wie im Kommentar steht ;)
1
while (TWCR & (1<<TWINT)); // müsste das nicht while(!(TWCR & (1<<TWINT) sein?
ok, das eine TWIMaster_Stop() was ihm Read aufruf gefehlt hab, hab ich
hinzugefügt.
Ich hab auch schon bereits ausprobiert ob eins von den beiden für sich
funktioniert,
Weder der Write noch der Read aufruf stoppen noch einer übertragung.
Du solltest das etwas strukturierter angehen. Als I²C-Neuling
gleichzeitig Master und Slave programmieren zu wollen, funktioniert nur
mit sehr sehr viel Glück :-)
a) besorg dir einen "Hardware-Slave", also irgendeinen Sensor oder was
immer, welches per I2C angesprochen wird, und wo du dich einigermaßen
drauf verlassen kannst dass er funktioniert.
b) besorg dir einen I2C-Master für den PC (ich nutze hierfür das geniale
Teil vom Till Harbaum:
http://www.harbaum.org/till/i2c_tiny_usb/index.shtml) um a) wirklich
ganz ganz fest abzusichern (es gibt nix frustrierenderes als
stundenlanges Fehler suchen im eigenen I2C-Master Code, um dran
draufzukommen dass der Slave kaputt ist... been there, seen it :-(
dann machst du dich erstmal an den Master. Aber auch hier strukturiert.
1. erzeuge ein Start-Condition, und prüfen den Status. Dieser sollte
0x08 "A START condition has been transmitted" sein (für Details bitte
Datenblatt fragen, ich rede hier immer vom ATmega328P). Wenn nicht, ist
schon was faul, und du brauchst nicht weiterzumachen.
2. sende ein SLA+R an eine nicht existente Adresse, und prüfe den
Status. Dieser sollte 0x48 "SLA+R has been transmitted; NOT ACK has been
received" sein. Wenn nicht, ist was faul, und du brauchst nicht
weiterzumachen.
3. sende ein SLA+R an eine sehr wohl existente Adresse (Sensor aus Punkt
a von oben), und prüfe den Status. Dieser sollte 0x40 "SLA+R has been
transmitted; ACK has been received" sein. Wenn nicht, ist was faul, und
du brauchst nicht weiterzumachen.
Wenn du mal soweit gekommen bist, hast du schon den größten Schritt
erfolgreich erledigt: Du hast beim Slave "angerufen" und der hat den
Hörer abgenommen und "ja bitte?" geantwortet. Dann meld dich nochmal,
dann sehen wir weiter (ich hab jetzt keine zeit den ganzen Rest
aufzuschreiben)
Im Übrigen ist Schritt 2 und 3 von oben der Schlüssel zum Verständnis
von I2C (zumindest wars bei mir so): Ein Paket besteht immer aus 9 Bits:
8 Datenbits, und das ACK/NAK. Der Trick ist nun: Die Datenbits werden
immer vom Transmitter erzeugt (das muss nicht der Master sein!), das
ACK/NACK aber vom Receiver. Der Receiver empfängt die 8 Bits, und
erzeugt er im selben Paket noch schnell das 9te Bit. Am Transmitter
umgekehrt: Er sendet 8 bits, und lauscht noch kurz auf der 9te bit. Das
heisst aber auch für die Software: Zwischen Empfang eines Pakets und
Senden des ACK oder NAK hast du keine Möglichkeit zu reagieren, oder
anders gesagt: schon bevor du das Paket empfängst, musst du der
TWI-Hardware sagen, ob sie den nächsten Empfang mit ACK oder NAK
quittieren soll!
Ein Spezialfall ist noch die Reaktion auf ein SLA+RW: Streng genommen
"empfängt" der master kein NAK wenn keiner antwortet, die
Statusbeschreibung "SLA+R has been transmitted; NOT ACK has been
received" ist insofern irreführend, als das nciht wirklich ein NAK
empfangen wird, weil auch niemand ein NAK sendet. NAK bedeutet in diesem
Fall einfach ein Ausbleiben das ACK, elektrisch gesehen bleibt die
SDA-Leitung auf high, weil sie keiner auf Low zieht.
Ich habe ein funktionierendes gegenstück,
ich hab zwar ein paar Schritte übersprungen, allerdings funktioniert der
Master am Arduino ohne Probleme,
Verbinde ich Master mit Arduino und packe auf den Arduino folgende
Software:
1
// Wire Slave Receiver
2
// by Nicholas Zambetti <http://www.zambetti.com>
3
4
// Demonstrates use of the Wire library
5
// Receives data as an I2C/TWI slave device
6
// Refer to the "Wire Master Writer" example for use with this
7
8
// Created 29 March 2006
9
10
// This example code is in the public domain.
11
12
13
#include <Wire.h>
14
15
void setup()
16
{
17
Wire.begin(50); // join i2c bus with address #4
18
Wire.onReceive(receiveEvent);
19
Wire.onRequest(requestEvent); // register event
20
Serial.begin(9600); // start serial for output
21
}
22
23
void loop()
24
{
25
}
26
27
// function that executes whenever data is received from master
28
// this function is registered as an event, see setup()
29
void receiveEvent(int howMany)
30
{
31
while(1 < Wire.available()) // loop through all but the last
32
{
33
char c = Wire.read(); // receive byte as a character
34
Serial.print(c); // print the character
35
}
36
int x = Wire.read(); // receive byte as an integer
37
Serial.println(x); // print the integer
38
}
39
40
void requestEvent()
41
{
42
Wire.write(50); // respond with message of 6 bytes
43
// as expected by master
44
}
In meinem Atmega Log steht fröhlich
gelesenes Byte : 50,
20 wurde gesendet
(in endlos ausführung) ;)
und in meinem Arduino werden die Daten auch ausgegeben
(ich sollte vill erwähnen, ich hab hier 2 arduinos,
einmal den mega2560 der master bzw slave spielt. und ein Arduino Uno in
dil variante, wo der prozessor abgezogen ist und nur tx,rx und masse
verbunden sind. Der 2te arduino dient mir als monitor ausgabe für den
Atmega
wenn ich den Arduino mit dem Slave verbinde und dem Arduino folgenden
Code gebe:
1
#include <Wire.h>
2
3
void setup()
4
{
5
Wire.begin(); // join i2c bus (address optional for master)
6
Serial.begin(9600); // start serial for output
7
}
8
int x = 40;
9
void loop()
10
{
11
Wire.requestFrom(50, 1); // request 6 bytes from slave device #2
12
13
while(Wire.available()) // slave may send less than requested
14
{
15
char c = Wire.read(); // receive a byte as character
16
Serial.print(c); // print the character
17
}
18
int y = Wire.read(); // receive a byte as character
19
Serial.print(y);
20
Wire.beginTransmission(50); // transmit to device #4
21
Wire.write(x); // sends one byte
22
Wire.endTransmission(); // stop transmitting
23
}
läuft laut meines Atmega Monitors alles super:
byte geschrieben
Byte gelesen: 40
40 ist richtig,
was mir dabei aber grade aufgefallen ist (und das auch nur durch zufall
weil der Arduino Monitor noch offen war)
ist der Arduino Master und ließt werte ein, kommt da nur -1 an ?! das
ist mir vorher noch nicht aufgefallen weil ich dummerweise nur auf das
TX lämpchen geschaut habe und gesehn hab ok er schickt was raus.
Denn fehler im Code vom Slave beim schreiben konnte ich allerdings nicht
ausfindig machen...
Nachdem du meinen rat, das ganze strukturiert anzugehen, ignorierst
(oder erst gar nicht gelesen) hast, und stattdessen weiter einfach
wahllos Code aus dem Internet per Copy&Paste zusammenwürfelst, dabei
auch noch munter nativen AVR und Arduiono-Code mischst, bin ich raus.
ich wünsch dir noch viel Erfolg.
Michael Reinelt schrieb:> 1. erzeuge ein Start-Condition, und prüfen den Status. Dieser sollte> 0x08 "A START condition has been transmitted" sein (für Details bitte> Datenblatt fragen, ich rede hier immer vom ATmega328P). Wenn nicht, ist> schon was faul, und du brauchst nicht weiterzumachen.>> 2. sende ein SLA+R an eine nicht existente Adresse, und prüfe den> Status. Dieser sollte 0x48 "SLA+R has been transmitted; NOT ACK has been> received" sein. Wenn nicht, ist was faul, und du brauchst nicht> weiterzumachen.
Vielleicht hätte ich erwähnen sollen, das ich
if (TWSR == 0x48)
{
LED_PORT = _BV(LED5);
while(1)
{
_delay_ms(200);
LED_PORT ^= ( 1 << LED4 );
}
in meine TWIMaster_Start Routine reingepackt habe...
natürlich habe ich auch das ganze mal mit einer falschen adresse
ausprobiert. Dann springt er auch in diese schleife.
Michael Reinelt schrieb:> 3. sende ein SLA+R an eine sehr wohl existente Adresse (Sensor aus Punkt> a von oben), und prüfe den Status. Dieser sollte 0x40 "SLA+R has been> transmitted; ACK has been received" sein. Wenn nicht, ist was faul, und> du brauchst nicht weiterzumachen.
gut das habe ich übersprungen.
I²C funktioniert meines wissens überall gleich, warum also keinen
Arduino nehmen? Ich möchte halt weiterkommen und nicht 2 tage warten bis
die entsprechende Hardware da ist.
mag auch gut sein das ich von einer Libary abgeschrieben habe.
Allerdings nur von einer und diesen Code habe ich 3 mal abgeschrieben
und mir kommentare & gedanken dazu gemacht. Anfangs und das hast du
gestern gesehen, habe ich mir fragen aufgeschrieben weil ich nicht
wusste was die einzelnen Register bedeuten. Als ich die Register
beschreibung im Datenblatt gefunden habe. hab ich mir alles auf DINA4
blätter geschrieben und hier im Zimmer aufgeghangen damit ich
nachschauen kann. Anschließend bin ich nochmal durch den gesamten code
gegangen und hab alles verstanden und mir nur als komentar
hingeschrieben was genau passiert und bis auf die eine Zeile die ich
oben hingeschrieben habe. Habe ich alles verstanden. Ich mag noch ein
Noob sein was die ganze mpu geschichte angeht, aber ich mach hier
bestimmt kein copy und paste.
Martin Kathke schrieb:> Vielleicht hätte ich erwähnen sollen, das ich [das] in meine TWIMaster_Start
Routine reingepackt habe...
Ja hättest du :-)
Martin Kathke schrieb:> natürlich habe ich auch das ganze mal mit einer falschen adresse> ausprobiert. Dann springt er auch in diese schleife.
Gut.
Martin Kathke schrieb:> gut das habe ich übersprungen.
schlecht. Dann hol das bitte nach.
Martin Kathke schrieb:> I²C funktioniert meines wissens überall gleich, warum also keinen> Arduino nehmen? Ich möchte halt weiterkommen und nicht 2 tage warten bis> die entsprechende Hardware da ist.
Aber du kannst nicht sicher sein dass der Arduino-Slave funktioniert.
Solange ist das Glaskugel-Lesen, auf das hier keiner Lust hat. Aber
versuch trotzdem mal, ob du wenigstens ein ACK kriegst.
if (TWSR == 0x40)
{
LED_PORT = _BV(LED6);
}
hatte ich erst drin,
da ging die led nicht an,
dann ist mir aufgefallen das er wenn ich starte meistens nur einmal
schreibt und dann stopt
also hab ich
if (TWSR == 0x18)
{
LED_PORT = _BV(LED6);
}
draus gemacht und die LED6 geht an ;)