Forum: Mikrocontroller und Digitale Elektronik Zwei arduinos ,eine RTC


von Lukas B. (kasul)


Lesenswert?

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?

von D. V. (mazze69)


Lesenswert?

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.

von holger (Gast)


Lesenswert?

>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.

von mike (Gast)


Lesenswert?

Natürlich, was bringt sonst ein Bus-System?
Tipp: Multimaster

von Peter D. (peda)


Lesenswert?

Lukas Bukas schrieb:
> oder muss ich was besonderes beachten?

Da es 2 Master sind, kann einer die Arbitration verlieren, das mußt Du 
behandeln.

von Mike (Gast)


Lesenswert?

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.

von Lukas B. (kasul)


Lesenswert?

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?

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Wie wärs mit Datenblatt lesen?
Dann schreibste dir ne Multimaster RTC Lib selber.

von Peter D. (peda)


Lesenswert?

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.

von Dussel (Gast)


Lesenswert?

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.

von Mike (Gast)


Lesenswert?

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.

von Dussel (Gast)


Lesenswert?

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.

von Mike (Gast)


Lesenswert?

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"

von Dussel (Gast)


Lesenswert?

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.

von Lukas B. (kasul)


Lesenswert?

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?

von Mark (Gast)


Lesenswert?

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.

von Mike (Gast)


Lesenswert?

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.

von Lukas B. (kasul)


Lesenswert?

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
von Georg (Gast)


Lesenswert?

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

von Nicht"Gast" (Gast)


Lesenswert?

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

von I.P. (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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
von Lukas B. (kasul)


Lesenswert?

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!

von Karl H. (kbuchegg)


Lesenswert?

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
von Lukas B. (kasul)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von chris (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Lukas B. (kasul)


Lesenswert?

@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.

von Eumel (Gast)


Lesenswert?

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.

von Lukas B. (kasul)


Lesenswert?

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
Noch kein Account? Hier anmelden.