Zwei arduinos ,eine RTC

OP #3682243
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?
#3682367
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.
Gast #3682623
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"
Gast #3682625
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.
OP #3682725
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?
Gast #3682742
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.
OP #3682796
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?
Gast #3682820
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
Gast #3682856
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
Gast #3682858
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.
#3682972
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.
OP #3684957
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!
#3684993
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.
OP #3685026
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.
#3685035
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.
Gast #3685167
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
#3685246
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.
OP #3685838
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.
OP #3687368
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren