Arduinos finden sich nicht über I2C

HotSystems:
Das sehe ich nicht.
Du solltest deinen Master auch als I2C-Master machen und die Slave-Daten abfragen.
Also jeden einzelnen Slave ansprechen und Daten holen.
Das ist erst mal einfacher.

Ich will echt nicht unhöflich sein, aber wenn immer der gesamte Code verlangt wird. Dann sollte man ihn sich auch komplett ansehen.

Ich habe bereits 2 mal klar gemacht welches aus der I2C Perspektive der Master und welches der Slave ist.

Und wenn ich an irgend einer Stelle einen Fehler gemacht habe, dann sei bitte so nett und zeige mir diese.

Es sind >WAHRSCHEINLICH< nur nur 2 Sketches entscheidend.

Der vom Mega (I2C Slave)

Und der vom Sensor Nano (I2C Master)

Der Pulsgeber erzeugt nur die Pulse, die im Sensor Nano gemessen werden.

Die restlichen beiden Sketche sind die funktionierenden Testsketche als Vergleich.
Denn alles was in diesen steht, steht auch genauso in den entscheidenden Sketchen.

Trotzdem Danke für die Aufmerksamkeit.
Ich will keinen verschrecken, aber wir kümmern uns hier um Probleme, die keine sind.
Und schriftlich lässt sich der "Ton" immer ein bisschen schwierig darstellen :slight_smile:

schUk0:
Ich will echt nicht unhöflich sein, aber wenn immer der gesamte Code verlangt wird. Dann sollte man ihn sich auch komplett ansehen.

Ich habe bereits 2 mal klar gemacht welches aus der I2C Perspektive der Master und welches der Slave ist.

Und wenn ich an irgend einer Stelle einen Fehler gemacht habe, dann sei bitte so nett und zeige mir diese.

Es sind >WAHRSCHEINLICH< nur nur 2 Sketches entscheidend.

Der vom Mega (I2C Slave)

Und der vom Sensor Nano (I2C Master)

Da du deine Sketche besser kennstals wir, ist es für dich auch einfacher zu durchblicken.

Wenn du mich aber nicht verstehst, brauchst du auch nicht unhöflich werden, also weiß ich nicht was das soll.

Der Pulsgeber erzeugt nur die Pulse, die im Sensor Nano gemessen werden.

Die restlichen beiden Sketche sind die funktionierenden Testsketche als Vergleich.
Denn alles was in diesen steht, steht auch genauso in den entscheidenden Sketchen.

Trotzdem Danke für die Aufmerksamkeit.
Ich will keinen verschrecken, aber wir kümmern uns hier um Probleme, die keine sind.
Und schriftlich lässt sich der "Ton" immer ein bisschen schwierig darstellen :slight_smile:

Wenn du hier keine Probleme hast, frage ich mich, warum du hier bist.

HotSystems:
Da du deine Sketche besser kennstals wir, ist es für dich auch einfacher zu durchblicken.

Kann ich mir vorstellen ^^ .

HotSystems:
Wenn du mich aber nicht verstehst, brauchst du auch nicht unhöflich werden, also weiß ich nicht was das soll.
Wenn du hier keine Probleme hast, frage ich mich, warum du hier bist.

Ich verstehe schon was du meinst.
Ich habe nur (vielleicht etwas unglücklich) versucht klar zu machen, dass ich genau das, was du gesagt hast bereits getan habe.

Der Mega fragt die Daten vom Nano ab.

Also muss meiner Meinung nach in diesen Sketchen der Wurm drin sein. Und ich versuche ihn ja parallel auch zu finden.

Wenn ich jetzt die entscheidenden Teile einzeln rausfilter, dann stehen wir wieder mit dem Testsketch da, der ja funktioniert.

Und die Probleme die keine sind, bezogen sich auf die Frage ob es mehere Master gibt oder ob ich versuche mit dem Slave zum Master zu sprechen.
Diese Probleme gibt es nicht, weil ich so überhaupt nicht vorgegangen bin.
Und wenn dann nicht bewusst.
Aber dann bräuchte ich auch die Stelle an der dieser Fehler auftritt, denn ich finde sie nicht.

Ich wollte es mir hier nicht gleich mit allen verscherzen, aber ich hatte die Befürchtung, dass die Fehlersuche in eine, meiner Meinung nach, falsche Richtung läuft.

Also sorry dafür, dass sich jemand auf den Schlips getreten fühlt :sweat_smile:

Gruß

schUk0

Kein Problem, da ich aktuell keinen Schlips trage, fühle ich mich auch nicht draufgetreten.

Aber nochmal zur besseren Erklärung:

In deinem I2C-Master vermisse ich ein "Wire.beginTransmission(x);" und ein "Wire.requestFrom(x, n);".

Erstere sendet einen Anforderung an den Slave, zweites liest die ankommenden Daten.
Und das musst du für alle Slaves machen.

Mit einem "Wire.onReceive(receiveEvent);" wirst du da nichts.

Siehe auch in der verlinkten Beschreibung den letzten Master.

Ich glaube da ist auch noch ein Verständnisproblem Master/Slave.

Der Mega wird als Master bezeichnet, fungiert aber als I2C-Slave. Er bekommt die Daten vom Nano (I2C-Slave) hin geknallt, egal ob er Zeit hat sie zu verarbeiten oder nicht. Besonders während der Delay(2000) kann er nichts verarbeiten. Nach weiteren Delays habe ich nicht gesucht.

Das Master-/Slavekonstrukt hat auch den Sinn, dass der funktionelle Master (der Mega) als I2C-Master, der er nicht ist, die Daten anfordert, wenn es in seinem Ablauf sinnvoll ist. Der Sensor-Nano hat die aktuellen Werte vorrätig und sendet sie auf Anforderung.
Deinen Puls-Nano, der auch als I2C-Master aufgebaut ist, kann auch als Störquelle die Übertragung beeinflussen.

Ich würde an Deiner Stelle nochmal die I2C-Master/Slaveverteilung überdenken und natürlich alle Delays raus, die länger als 5 sind bzw. alle, je nach Stelle.

Gruß Tommy

HotSystems:
Kein Problem, da ich aktuell keinen Schlips trage, fühle ich mich auch nicht draufgetreten.

Is ja auch Wochenende :sunglasses:

HotSystems:
In deinem I2C-Master vermisse ich ein "Wire.beginTransmission(x);

Funktion:

void sendRPM(int x){
  Wire.beginTransmission(slaveAddress);  // begin transmission to slave device
  Wire.write(x & 0xff);       // send first byte
  Wire.write(x >> 8);         // send second byte shiftet by 8 bits
  Wire.endTransmission();     // stop transmitting
}

Aufruf:

//calculate the RPM
  if (ignitionCount > 20){ 
       
    detachInterrupt(digitalPinToInterrupt(interPin1));//Disable interrupt when calculating
    
    fCrank = (1/(((millis()-t)/ignitionCount)/1000.0)); 
    rpm = fCrank * 60;
    ignitionCount = 0;
    
//    Serial.print("Crank frequency  ");
//    Serial.println(fCrank);
//    Serial.print("RPM  ");
//    Serial.println(rpm);
//    Serial.println("-------------");
    
    sendRPM(rpm);     ////////////////////////////// <-DA
  

    //drive the LED-Bar
    val = map(rpm, 0, 12000, 0, 8);
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, data[val]);
    digitalWrite(latchPin, HIGH);

        
    attachInterrupt(digitalPinToInterrupt(interPin1),isIgnition,RISING);
    t=millis();
  }

Tommy56:
Der Mega wird als Master bezeichnet, fungiert aber als I2C-Slave. Er bekommt die Daten vom Nano (I2C-Slave) hin geknallt, egal ob er Zeit hat sie zu verarbeiten oder nicht. Besonders während der Delay(2000) kann er nichts verarbeiten. Nach weiteren Delays habe ich nicht gesucht.

Guter Einwand.
Das Delay ist übrigens weit und breit das einzige und ist nur dafür da, den Intro-Screen lange genug zu erhalten um ihn zu sehen :smiley:
Diese if Schleife (?) wird, bedingt durch state = false; danach auch nie wieder durchlaufen.

Und in dem Pulsgeber ist nichtmal die Wire.h eingebunden.
Geschweige denn entsprechnder Code vorhanden.
Noch dazu ist er nicht an den I2C Bus angeschlossen, sondern direkt an die Interrupt-Pins vom Sensor.

Ich habe inzwischen auch neue Erkenntnisse.
Die U8g.lib scheint die Wurzel allen Übels zu sein.
Aber ich kann dazu noch nichts definitives sagen...bin noch am testen.

Da ich aber zum jetzigen Zeitpunkt bereits Daten auf dem Mega erhalte und auch auf dem Display dargestellt kriege kann man sagen, dass die Kommunikation also möglich ist.
Allerdings noch sehr hakelig.

Werde mich gleich nochmal melden.

Gruß

schUk0

Das hat jetzt zumindest schon mal dazu geführt, dass mir der Wert übertragen und auf dem Display angezeigt wird.

if (state == false) {
  u8g.firstPage();
    do {
     draw();           
    }    
  while ( u8g.nextPage() ); 
    Wire.begin(2);       
  }

Hatte irgendwo gelesen, dass die U8g.lib den I2C Bus irgendwie für sich beansprucht und danach nicht mehr freigibt...
Also muss man das selber einleiten.

Ok..

Gehen wir die Sache mal anders an.

Der Sensor macht so Sensor Sachen und sollte / möchte dabei auch möglichst nicht gestört werden.
Er soll nur ab und an 2 Werte an den Mega senden... Sagen wir mal alle 100 ms.

Der Mega soll das ganze nun grafisch darstellen und vielleicht auch noch andere Berechnungen mit den erhalten Werten machen, die nicht so zeitkritisch sind.

Beides alleine funktioniert eigentlich ganz gut.

Wie übertrage ich nun am besten diese 2 Werte ?

Ich hänge da jetzt schon 2 Tage dran und hätte eigentlich noch ganz andere Sachen am Projekt zu erledigen.
Aber bevor ich das nicht habe brauche ich gar nicht über andere Sachen nachdenken.

Vielleicht ist ja I2C auch nicht die beste Lösung...ich weiß es nicht.

Gruß

schUk0

schUk0:
Wie übertrage ich nun am besten diese 2 Werte ?

Welchen Typ haben die Werte?

Lesetipp, wobei union data_u der springende Punkt ist.

Wie ich schon mehrfach gesagt habe, der Mega muss die Daten anfordern, wenn er Zeit hat und wenn er nicht gerade das Display aktialisiert. Sonst sendet er zum Display und gleichzeitig der Sensornano zum Mega auf den gleichen Leitungen.
Das ignorierst Du aber immer. Dann wirst Du die Probleme auch nicht los werden.

Gruß Tommy

agmue:
Welchen Typ haben die Werte?

int

Einmal 3-stellig (bis 255 würde reichen)

und einmal 5-Stellig (da wäre ich mit 20000 zufrieden)

Tommy56:
Wie ich schon mehrfach gesagt habe, der Mega muss die Daten anfordern, wenn er Zeit hat und wenn er nicht gerade das Display aktialisiert. Sonst sendet er zum Display und gleichzeitig der Sensornano zum Mega auf den gleichen Leitungen.
Das ignorierst Du aber immer. Dann wirst Du die Probleme auch nicht los werden.

Ich versuche natürlich nichts zu ignorieren.
Scheinbar stehe ich aber grad etwas auf dem Schlauch weil es mich nervt, dass ich an so nem scheinbar banalen Sch***ß festhänge.

Aber ich glaube jetzt hab ich kapiert was du meinst.
Den Mega zum Master machen und damit die Werte vom Sensor anfordern.
Der muss diese dann auf Anfrage senden.

In der Einführung in den I2C Bus war das aber so erklärt, dass die Messung auch erst auf Anfrage durchgeführt wird.
Das fänd ich eher blöd .
Ich werd mich trotzdem mal ran machen.

Das oberste Ziel ist es, die Darstellung trotzdem möglichst (für das menschliche Auge) flüssig zu halten.
Sollte das damit noch klappen?

Und vielen Dank für eure Geduld :smiley:

Gruß

schUk0

Du kannst auf dem Sensornano doch laufend messen. Evtl. während der Messung eine andere Variable nutzen und danach umkopieren. Damit kann der Sensornano immer den letzten gültigen Wert sofort bereit stellen.

Du musst dem Sensornano (SN) auch noch sagen, welchen Messwert Du haben willst (das werden ja 2 verschiedene werden.
Also z.B. 1 zum SN = gib mir RPM, 2 = gib mir den anderen Wert.

Gruß Tommy

agmue:
Lesetipp, wobei union data_u der springende Punkt ist.

Das ist wieder ein schlechtes Beispiel. Das ist für TinyWire, wo man mit send() wirklich nur ein Byte schicken kann. Mit Wire() geht mit write() ein ganzes Array. Dadurch wird es wesentlich einfacher.

Ich mache mal ein aktuelles und korrektes Beispiel. Und dann bitte in Zukunft darauf verlinken. Und nicht auf veralteten oder speziellen Code.

Ok hier mal was rein für Wire. Es werden alle Werte auf einmal übertragen. Dadurch spart man sich erst mal einen Index zu setzen.

Master:

#include <Wire.h>

const int SLAVE_ADR = 5;
const unsigned int NUMBER_OF_VALUES = 2;

union data_u
{
  unsigned int i[NUMBER_OF_VALUES];
  byte b[sizeof(i)];
};

data_u values;

void setup()
{
  Serial.begin(9600);
  Serial.println("Master");
  Wire.begin();

  getData();
}

void loop()
{
}

void getData()
{
  Wire.requestFrom(SLAVE_ADR, sizeof(values.b));
  for (byte i = 0; i < sizeof(values.b); i++)
      values.b[i] = Wire.read();

  Serial.println(values.i[0]);
  Serial.println(values.i[1]);
}

Slave:

#include <Wire.h> 

const int SLAVE_ADR = 5;
const unsigned int NUMBER_OF_VALUES = 2;

union data_u
{
 unsigned int i[NUMBER_OF_VALUES];
 byte b[sizeof(i)];
};

data_u values;

void setup()
{
 Wire.begin(SLAVE_ADR);
 Wire.onRequest(requestEvent);

 values.i[0] = 123;
 values.i[1] = 45678;
}

void loop()
{
}

void requestEvent()
{
 Wire.write(values.b, sizeof(values.b));
}

Der Master fordert einfach das gesamte Array an und der Slave sendet das gesamte Array.

Die Union ist nötig weil man im Request Event Handler nur einmal write() machen kann. Also kann man ein Byte Array auf einmal senden. Auf dem Empfänger schreibt man auch in eine union und hat so direkt den Integer Wert.

______________________________________________________________________

Achtung: der I2C Puffer hat nur 32 Byte! Wenn man also wie hier innerhalb der Grenzen bleibt geht es so einfach (also 16 ints oder 8 longs/floats). Wenn man mehr auf einmal übertragen will, dann kann erst mal vom Master den Index des gesuchten Integers an den Slave senden und dann pro Request nur einen Integer übertragen

Das geht so:

Master:

#include <Wire.h> 

const int SLAVE_ADR = 5;
const unsigned int NUMBER_OF_VALUES = 10;

union data_u
{
  unsigned int i;
  byte b[sizeof(i)];
};

data_u values[NUMBER_OF_VALUES];

void setup()
{
  Serial.begin(9600);
  Serial.println("Master");
  Wire.begin();

  getData();
}

void loop()
{
}

void getData()
{
  for (byte i = 0; i < NUMBER_OF_VALUES; i++)
  {
    Wire.beginTransmission(SLAVE_ADR);
    Wire.write(i);
    Wire.endTransmission();
    Wire.requestFrom(SLAVE_ADR, sizeof(values[0].i));

    for (byte j = 0; j < sizeof(values[0].i); j++)
      values[i].b[j] = Wire.read();
  }

  for (byte i = 0; i < NUMBER_OF_VALUES; i++)
    Serial.println(values[i].i);
}

Slave:

#include <Wire.h> 

const int SLAVE_ADR = 5;
const unsigned int NUMBER_OF_VALUES = 10;

union data_u
{
  unsigned int i;
  byte b[sizeof(i)];
};

data_u values[NUMBER_OF_VALUES];
byte index;

void setup()
{
  values[0].i = 1;
  values[1].i = 4;
  values[2].i = 12;
  values[3].i = 45;
  values[4].i = 123;
  values[5].i = 456;
  values[6].i = 1234;
  values[7].i = 12345;
  values[8].i = 1000;
  values[9].i = 10000;
  
  Wire.begin(SLAVE_ADR);
  Wire.onRequest(requestEvent);
  Wire.onReceive(receiveEvent);
}

void loop()
{
}

void receiveEvent(int)
{
  index = Wire.read();
}

void requestEvent()
{
  Wire.write(values[index].b, sizeof(values[0].b));
}

Dabei beachten, dass die Datenstruktur etwas anders ist. Die Union hat nur einen Integer und man hat ein Array aus unions. Das macht die Sache mit dem Index leichter lesbar. Ansonsten müsste man den Index im Byte Array berechnen.

Der Master schickt erst den Index des Integers und fordert dann einen Integer an. Der Slave sendet alle Bytes dieses Integers.

Hallo,

schönes Bsp. Hat union einen Vorteil gegenüber struct oder ist das egal?

Serenifly:
Das ist wieder ein schlechtes Beispiel. Das ist für TinyWire, wo man mit send() wirklich nur ein Byte schicken kann.

Weil beide #include "Wire.h" enthalten, war mir das nicht aufgefallen :-[

Doc_Arduino:
Hat union einen Vorteil gegenüber struct oder ist das egal?

Mit meinen Worten erklärt: struct faßt verschiedene Variablen zusammen, während union einen Speicherbereich mit zwei Namen und Typen ansprechbar macht. Im Programm nutze ich die Variablen entsprechend ihrem Typ, für die Übertragung wird dann der Typ byte genutzt. Auf der anderen Seite dann umgekehrt.

struct kann ein Teil von union sein:

union Data
{
  byte asArray[8];    //2 * 4 Bytes. Muss unbedingt mit der Größe des structs übereinstimmen!
  struct
  {
    unsigned long value1;
    unsigned long value2;
  };
};

Serenifly:
Ich mache mal ein aktuelles und korrektes Beispiel.

Beim ersten Master fehlen zwei Zeilen:

#include <Wire.h>
const int SLAVE_ADR = 5;

Hallo,

ich hatte deshalb gefragt, weil meine RS485 Verbindung auf dem Code vom Nick Gammon aufbaut. Diese benutzt struct statt union.
In der Zwischenzeit habe ich nachgelesen. Dabei besteht mit union eine Gefahr des überschreiben der anderen Variablen innherhalb von union, falls man eine unerwartet ändert. So verstehe ich das. Stell ich mir aktuell so ähnlich vor als wenn man unkontrolliert im Speicher schreibt wenn man den Null-Terminator bei char arrays vergisst.

Doc_Arduino:
Dabei besteht mit union eine Gefahr des überschreiben der anderen Variablen innherhalb von union, falls man eine unerwartet ändert.

Das ist der ganze Sinn der Sache. Die Variablen belegen den gleichen Speicher! Man kann also eine Variable sowohl als Integer als auch als Byte Array ansprechen

Also,

Der Vorschlag von Serenifly hat genau das gebracht was ich brauche.
Nach meinem Verständnis folgt das auch dem Vorschlag von Tommy56.

Und auf die 2 fehlenden Zeilen bin ich noch gerade so selbst gekommen. :smiley:

Ist es eigentlich egal, wo man Funktionen im Code platziert?

Auf jeden Fall erstmal vielen Dank an alle die mitgeholfen haben.

Gruß

schUk0

schUk0:
Ist es eigentlich egal, wo man Funktionen im Code platziert?

In der ArduinoIde eigentlich jam da die die Deklarationszeilen oben einfügt. Manches Mal packt sie das aber nicht richtig.
Deshalb ist es nicht verkehrt, Funktionen vor ihrer Verwendung zu schreiben.

Gruß Tommy

Tommy56:
Deshalb ist es nicht verkehrt, Funktionen vor ihrer Verwendung zu schreiben.

Scheint für mich auch sinnvoller aber man sieht in vielen Beispielen, dass sie nach dem Loop stehen.

Gruß

schUk0