Hallo, Ich möchte von zwei arduino boards auf eine rtc zugreifen. Es handelt sich um eine ds1307 die per i2c angesprochen werden soll. Kann ich die Leitungen sdl und sca der drei Geräte einfach verbinden oder muss ich was besonderes beachten?
Lukas Bukas schrieb: > Kann ich die Leitungen sdl und sca der drei Geräte einfach verbinden ja > oder muss ich was besonderes beachten? ja, denn in dieser Topologie gibt es nur einen Master.
>Kann ich die Leitungen sdl und sca der drei Geräte einfach verbinden Ja. >oder muss ich was besonderes beachten? Die beiden Arduinos dürfen nicht gleichzeitig auf die RTC zugreifen.
Lukas Bukas schrieb: > oder muss ich was besonderes beachten? Da es 2 Master sind, kann einer die Arbitration verlieren, das mußt Du behandeln.
Lukas Bukas schrieb: > ann ich die Leitungen sdl und sca Was für Leitungen? SDA und SCL gibt es. Kreuzen darf man diese beiden Signale lt. I²C-Spezifikation eindeutig nicht.
Wenn ich die time Bibliothek verwende wird doch bei jedem now() oder hour() oder ähnlichem mit der rtc synchronisiert (falls in den letzten fünf Minuten nicht schon geschehen)oder habe ich das falsch verstanden? Wie kann ich da Softwareseitig eingreifen um zu prüfen ob der Bus frei ist? Hardwareseitig verbinde ich natürlich die sda Leitungen untereinander und die scl Leitungen untereinander.. ohne Kreuzungen. Zusätzliche Widerstände brauche ich ja nicht oder?
Wie wärs mit Datenblatt lesen? Dann schreibste dir ne Multimaster RTC Lib selber.
Lukas Bukas schrieb: > Wenn ich die time Bibliothek verwende Die meisten Libs kennen immer nur die ganz bestimmte Anwendung, die der Entwickler im Sinn hatte. Oftmals ist auch nichtmal die minimalste Fehlerbehandlung drin. Will man was anderes, muß man das selber programmieren bzw. die Lib selber ändern. RTC und I2C sind aber nicht so kompliziert. Und man hat danach etwas mehr Einblick, wie die Lego-Steinchen funktionieren.
Lukas Bukas schrieb: > Zusätzliche Widerstände brauche ich ja nicht oder? Wenn ich mich richtig erinnere, brauchst du an beiden Leitungen Pull-up-Widerstände. Es kann aber sein, dass die schon eingebaut sind.
Dussel schrieb: > Es kann aber sein, dass die schon eingebaut sind. Fest eingebaut können die nicht sinnvoll sein. Was würde wohl dann passieren, wenn man mehr als einen I²C Baustein am Bus anschließt.
Auf der Platine eingebaut. So wie ich das verstehe, wird hier eine fertige Platine benutzt. Die Anzahl der Bausteine ist für die Widerstände egal.
Dussel schrieb: > Auf der Platine eingebaut. So wie ich das verstehe, wird hier eine > fertige Platine benutzt. Eben. Und spätestest, wenn man zwei dieser Platinen zu einem I²C Multi-Master System zusammenschaltet, hat man den Salat. Das einzig was da hilft, ist ein Blick in den Schaltplan oder das Nachmessen des High-Pegels bei Belastung von SDA und SCL mit einem bekannten Widerstand. Oder man verfährt nach der Methode "egal - wird schon laufen"
Ja gut, aber das ist sein Problem. Ich habe geschrieben, wie es geht. Wir sind ja auch nicht hier, um jeden Handgriff vorzugeben. Mike schrieb: > Oder man verfährt nach der Methode "egal - wird schon laufen" Für ein Hobbyprojekt ist das auch eine akzeptable Methode.
Was passiert denn beim zusammen schalten zweier Platinen? Widerstände parallel->doppelter Strom? Oder ändern sich die Pegel? Vom Prinzip stell ich mir folgendes vor: Ich sag beiden arduino Boards z.B. PIN5=busy ist ein Eingang und LOW. In der time Bibliothek schreibe ich vor jeder Zeitaktualisierung: if busy == LOW { pinmode(busy,output) digitalwrite(busy,high) Zeitaktualisierung mit rtc Digitalwrite(busy,low) Pinmode(busy,input) } Ich verbinde dann (neben scl und sda) noch direkt die zwei pin5 IOs der arduinos und gut ist? Kann das so funktionieren?
Lukas Bukas schrieb: > Kann das so funktionieren? Ja. Ich würde noch einen Pullup an die Busy-Leitung machen. In seltenen Fällen kann es trotzem zu Kollisionen kommen.
Lukas Bukas schrieb: > Was passiert denn beim zusammen schalten zweier Platinen? Widerstände > parallel->doppelter Strom? Oder ändern sich die Pegel? Bei doppeltem Strom kann sich natürlich der Pegel ändern und wenn irgendwas auf Kante genäht ist, Bustreiber überlastet werden. Aber warum hängst du nicht einfach mal einen Lastwiderstand dran und rechnest den Wert vom ggf. eingebauten Pull-up aus. Wenn du verraten würdest, welchen Arduino du verwendest, kann vielleicht auch jemand anders für dich nachgucken.
Soweit ich das verstehe wird der interne pullup Widerstand (ich meine 20k) aktiviert wenn man den IO als Input deklariert und high setzt. Also nach pinmode(busy,Input); Digitawrite(busy,high) Oder auch mit pinmode(busy, INPUT_PULLUP) Der Unterschied ist mir aber nicht ganz klar.. Ich verwende zwei arduino pro Mini mit atmega328 Rtc ist diese: http://pages.ebay.com/link/?nav=item.view&id=351070299933&alt=web Was wäre denn die Auswirkung einer Kollision? Bekomme ich dann eine falsche Uhrzeit oder wird sie nur nicht synchronisiert?
:
Bearbeitet durch User
Hallo, ich kenne deine Library ja auch nicht* - grundsätzlich müsste die Korrektheit der Uhrzeit natürlich geprüft werden. Ansonsten ist eine Kollision problemlos (wenn sie erkannt wird), es passiert im Wortsinn nichts: diesmal wird eben nicht synchronisiert, dann halt beim nächsten mal. Die lokale Uhr läuft deswgen schon nicht merklich davon. *Das ist halt das Problem, wenn man Software kopiert, aber nicht versteht. Georg
moin, man könnte ja auch über einen gpio die Zugriffe von vornherein überwachen. Der arduino, der auf die rtc zugreift, zieht den auf low und vor jedem Zugriff wird geprüft und gegebenenfalls gewartet. grüße
Lukas Bukas schrieb: > Was wäre denn die Auswirkung einer Kollision? Überlegs dir. Wenn zwei Master unsynchronisiert an SCL und SDA rumziehen, wird die RTC höchstwahrscheinlich nicht mal verstehen, was das Geklapper auf dem Bus heißen soll. Wenn einer zuerst anfängt und der andere dazwischen plappert, kann es sein, dass der erste Teil der Übertragung noch richtig funktioniert und dann nur noch Müll passiert.
Georg schrieb: > Ansonsten ist eine > Kollision problemlos (wenn sie erkannt wird), es passiert im Wortsinn > nichts: Es passiert schon was. Der eine geht in den Zustand "Arbitration lost". Er muß dann mindestens das Interruptflag zurücksetzen und sich selber "Stop" senden. Viele Libs warten aber nur auf den gewünschten Zustand und bleiben dann auf ewig hängen. Eine ordentliche Lib wertet alle 32 Zustände aus, auch wenn sie eigentlich nicht vorkommen sollten. Sie können nämlich bei Störungen vorkommen.
:
Bearbeitet durch User
Vielen Dank schonmal für eure Antworten! Habe die Time library von hier: https://github.com/johnmccombs/arduino-libraries/tree/master/Time Die time.cpp habe ich wie folgt geändert (ab Zeile 250):
1 | time_t now() { |
2 | while (millis() - prevMillis >= 1000){ |
3 | sysTime++; |
4 | prevMillis += 1000; |
5 | #ifdef TIME_DRIFT_INFO
|
6 | sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift |
7 | #endif
|
8 | }
|
9 | if (nextSyncTime <= sysTime) { |
10 | if (getTimePtr != 0) { |
11 | //----------------ab hier habe ich geändert:-----------------
|
12 | pinMode(PINbusbusy, INPUT_PULLUP); |
13 | while(digitalRead(PINbusbusy)==LOW;){delay(2);} //endlosschleife bzw abwarten während bus besetzt |
14 | pinMode(PINbusbusy, OUTPUT); |
15 | digitalWrite(PINbusbusy, LOW); //Ausgang auf Low ziehen = Bus besetzt |
16 | time_t t = getTimePtr(); |
17 | if (t != 0) { |
18 | setTime(t); |
19 | } else { |
20 | nextSyncTime = sysTime + syncInterval; |
21 | Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync; |
22 | }
|
23 | digitalWrite(PINbusbusy, HIGH); // Bus wieder frei |
24 | pinMode(PINbusbusy, INPUT_PULLUP); //GPIO wieder als Eingang nutzen |
25 | }
|
26 | }
|
27 | return (time_t)sysTime; |
28 | }
|
Ich möchte bei beiden boards übrigens diese RTC lib benutzen: https://github.com/johnmccombs/arduino-libraries/tree/master/DS1307RTC In beiden setup() Routinen steht dann der Aufruf:
1 | // Get the time from the RTC
|
2 | setSyncProvider(RTC.get); |
3 | |
4 | // Report whether the Arduino was able to communicate with the RTC
|
5 | if(timeStatus()!= timeSet) |
6 | Serial.println("Unable to sync with the RTC"); |
7 | else
|
8 | Serial.println("RTC has set the system time"); |
und im Loop steht dann eben if(hour()==5){machdiesunddas} oder so ähnlich.. Habe ich korrekt und an der richtigen Stelle in der Time lib eingegriffen? Ich verbinde dann an beiden boards die PINbusbusy Pins und gut ist? Diese sollten immer HIGH-Pegel haben außer ein device nutzt den Bus dann zieht es den Pegel auf LOW? Würde mich riesig freuen, wenn sich jemand die Mühe machen würde und sich den Code anschaut! Ganz vielen Dank schon Mal!
Lukas Bukas schrieb: > Habe ich korrekt und an der richtigen Stelle in der Time lib > eingegriffen? Das hier
1 | while(digitalRead(PINbusbusy)==LOW;){delay(2);} //endlosschleife bzw abwarten während bus besetzt |
2 | pinMode(PINbusbusy, OUTPUT); |
3 | digitalWrite(PINbusbusy, LOW); //Ausgang auf Low ziehen = Bus besetzt |
hat das Potential in 99.9% aller Fälle gut zu gehen und ab und zu sporadisch zu scheitern. I2C kann prinzipiell Multimaster schon handhaben. D.h. dort wäre mein Eingreifpunkt, die fehlgeschlagene Bus-Arbitrierung zu behandeln und nicht auf höherer Ebene zu versuchen das Problem zu lösen. > > Ich verbinde dann an beiden boards die PINbusbusy Pins und gut ist? > Diese sollten immer HIGH-Pegel haben außer ein device nutzt den Bus dann > zieht es den Pegel auf LOW? Ja, und du hast dir eine Race-Condition eingehandelt. Denn zwischen der ABfrage auf Low und dem tatsächlichen Setzen auf Low vergeht Zeit. Nicht viel, aber immerhin. Und wenn in dieser Zeit der andere µC "zuschlägt", dann geht das schief. Multprozessor bzw. Multitasking ist nicht so einfach, wie viele immer glauben.
:
Bearbeitet durch User
Ich würde die 0,1% Kollisionen gerne vermeiden, bzw ignorieren. Gibt es nicht eine Möglichkeit um nach der Synchronisierung zu prüfen ob die neue Uhrzeit ein realisitischer Wert ist? Falls nicht fand eine Kollision statt und dann soll der alte Wert der Uhrzeit beibehalten werden. Nur wie müsste das aussehen? Oder führen die 0,1% zum Aufhängen eines devices, bzw zu einem Zustand den man nicht ignorieren kann? Gibt es keinen einfachen Weg, um zwei arduinos mit der Uhrzeit zu synchronisieren? Eine kleine Zeitdifferenz wäre nicht schlimm. Auch die Zeit selbst muss nicht auf die Sekunde genau sein. Ich will nur nicht, dass eins der Boards irgendwann hochsporadisch die Zeit verliert oder sich aufhängt.
Lukas Bukas schrieb: > Ich würde die 0,1% Kollisionen gerne vermeiden, bzw ignorieren. > Gibt es nicht eine Möglichkeit um nach der Synchronisierung zu prüfen ob > die neue Uhrzeit ein realisitischer Wert ist? Man kann natürlich im Nachhinein versuchen, die Auswirkungen des 'mit dem Auto um den Baum wickelns in einer Kurve' zu vermeiden. Man kann allerdings auch gleich einfach langsamer in die Kurve hineinfahren. Wie gesagt: I2C kann das schon handhaben, wenn 2 Master gleichzeitig versuchen, sich den Bus unter den Nagel zu reissen. Und mir ist natürlich auch klar (ich bin ja nicht doof), warum du darum einen Bogen machst, wie der Teufel ums Weihwasser. Aber es hilft nichts: wenn man etwas machen will, dann muss man das auch LERNEN. Das ist seit tausenden von Jahren so. Alles andere ist Murks.
du könntest auch einen der Arduinos als I2C Slave konfigurieren. Der Master holt sich die Zeit von der RTC und sendet sie dann an weiter an den Slave-Arduino. Ob das aber insgesamt weniger Aufwand ist als nen Arbitrierungsfehler zu erkennen ist fraglich
Kurzer Tip. Eine kurze Google Recherche zum Thema "Arduino I2C Multimaster" hat ergeben, dass die Arduino Funktionen angeblich bereits Multimaster-fähig sind. Soviel also zu Thema: wie gut kenne ich meine Libraries bzw. wie komme ich an Informationen, die mich interessieren.
@karl heinz Du benutzt zwar tolle Metaphern aber was “langsamer in die Kurve fahren“ konkret heißt weiß ich trotzdem nicht.. Würde mich freuen wenn ihr mir helfen könntet das mit der Erkennung des arbitrierfehlers hin zu bekommen. Die libraries habe ich auch gefunden aber ich wollte nicht noch eine library einbinden die ich nicht ganz durchschaue. Was ich auch gefunden habe ist eine thread hier im Forum wo steht das atmel nicht multimaster fähig ist bzw verbuggt ist.
Wie wärs wenn du einen der beiden Arduinos auch zum Slave machst? Der Master Arduino holt sich die aktuelle Zeit vom RTC Modul und schickt sie dann an den Slave.
Habe mich entschieden einen Master zu benutzen, welcher die Uhrzeit an den Slave weitergibt. Hier mein erster Entwurf: 1.Arduino (Master):
1 | #include <Time.h> |
2 | #include <Wire.h> |
3 | #include <DS1307RTC.h> |
4 | |
5 | time_t tmConvert_t(int YYYY, byte MM, byte DD, byte hh, byte mm, byte ss) |
6 | {
|
7 | tmElements_t tmSet; |
8 | tmSet.Year = YYYY - 1970; |
9 | tmSet.Month = MM; |
10 | tmSet.Day = DD; |
11 | tmSet.Hour = hh; |
12 | tmSet.Minute = mm; |
13 | tmSet.Second = ss; |
14 | return makeTime(tmSet); //convert to time_t |
15 | }
|
16 | |
17 | void setup() |
18 | {
|
19 | Serial.begin(9600); |
20 | Wire.begin(); // join i2c bus (address optional for master) |
21 | |
22 | setSyncProvider(RTC.get); |
23 | if(timeStatus()!= timeSet) |
24 | Serial.println("Unable to sync with the RTC"); |
25 | else
|
26 | Serial.println("RTC has set the system time"); |
27 | }
|
28 | void loop() |
29 | {
|
30 | time_t s_tm = tmConvert_t(year(),month(),day(),hour(),minute(),second()); |
31 | Wire.beginTransmission(4); // transmit to device #4 |
32 | Wire.write(s_tm); |
33 | Wire.endTransmission(); // stop transmitting |
34 | delay(5000); |
35 | }
|
2.Arduino (Slave):
1 | #include <Time.h> |
2 | #include <Wire.h> |
3 | |
4 | void setup() |
5 | {
|
6 | Wire.begin(4); // join i2c bus with address #4 |
7 | Wire.onReceive(receiveEvent); // register event |
8 | Serial.begin(9600); // start serial for output |
9 | }
|
10 | |
11 | void loop() |
12 | {
|
13 | delay(100); |
14 | }
|
15 | |
16 | // function that executes whenever data is received from master
|
17 | // this function is registered as an event, see setup()
|
18 | void receiveEvent(int howMany) |
19 | {
|
20 | |
21 | time_t receivedtime = Wire.read(); |
22 | setTime(receivedtime); |
23 | |
24 | }
|
Ist das vom Prinzip her die richtige Herangehensweise? Irgendwelche Verbesserungsvorschläge?
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.