Go Down

Topic: I2C zwischen mehreren Arduions (Read 3656 times) previous topic - next topic

woehrer

Hallo
Ich suche schon seit Tagen einen Scatch um mehrere variablen von nem Arduino Mega zu nem Arduino Uno senden kann
I2C kommunikation funktioniert schon.
Nun habe ich aber mehrere Variablen zB: x;y;z;
Jede Variable kann einen Wert zwischen 1 und 2000 haben.
Wie müssen die Sketche aussehn das das eine Arduino die auf den Bus bringt und das andere den bus wieder auf die richtigen variablen bringt.

Serenifly

Eigentlich auch nicht anders als wenn du nur eine Variable sendest. Du musst halt mehrmals write() und read() machen. Einfach hintereinander senden und dann in der gleichen Reihenfolge einlesen.

Bei dem Wertebereich musst du dann noch deine int Variable in zwei Bytes aufteilen und diese einzeln senden. Und dann am anderen Ende wieder zusammebasteln.

woehrer

Kannst du mir den Besipielsketch so umbauen das es mit drei variablen funktioniert und die ich da auf dem serial monitor sehe?

Serenifly

So ähnlich vielleicht. Nicht getestet:

Code: [Select]

const byte DEVICE_ADR....

void loop()
{
 int value1 = ...
 int value2 = ...
 int value3 = ...

 Wire.beginTransmission(DEVICE_ADR);
 Wire.write(highByte(value1));
 Wire.write(lowByte(value1));
 Wire.write(highByte(value2));
 Wire.write(lowByte(value2));
 Wire.write(highByte(value3));
 Wire.write(lowByte(value3));
 Wire.endTransmission();

 delay(1000);
}


Code: [Select]

void receiveEvent(int numberOfBytes)
{
 if(Wire.available() >= 6)
 {
      int value1 = word(Wire.read(), Wire.read());
      int value2 = word(Wire.read(), Wire.read());
      int value3 = word(Wire.read(), Wire.read());

      Serial.println(value1);
      Serial.println(value2);
      Serial.println(value3);
 }
}


Das High Byte wird zuerst gesendet, da es in der word() Methode der erste Parameter ist.

woehrer

Der Monitor spuckt leider garnichts aus


Code: [Select]

#include <Wire.h>

int a;
int b;
int c;

void setup ()
{
pinMode (5, OUTPUT);
pinMode (A0, INPUT);    //a
pinMode (A1, INPUT);    //b
pinMode (A2, INPUT);    //c
}


void loop (){
 
Wire.beginTransmission(4); // transmit to device #4
Wire.write(highByte(a));
Wire.begin(lowByte(a));
Wire.write(highByte(b));
Wire.begin(lowByte(b));
Wire.write(highByte(c));
Wire.begin(lowByte(c));

 Wire.endTransmission();    // stop transmitting

}

//....weitere verarbeitung



Code: [Select]

#include <Wire.h>

void setup()
{}

void loop()
{
delay(10);
}

void receiveEvent(int numberOfBytes)
{
 if(Wire.available() >= 6)
 {
      int a = word(Wire.read(), Wire.read());
      int b = word(Wire.read(), Wire.read());
      int c = word(Wire.read(), Wire.read());

      Serial.println(a);
      Serial.println(b);
      Serial.println(c);
 }
}

Serenifly

Du musst die I2C Schnittstelle schon mit Wire.begin() initialisieren. Den Teil hatte ich weggelassen, da ich dachte, dass das schon vorhanden ist. In setup() wire.begin() auf dem Master und Wire.begin(4) auf dem Slave.

Dann musst du den Event Handler auf dem Slave registrieren:
Wire.onReceive(receiveEvent);

Und die serielle Schnittstelle initialisieren:
Serial.begin(9600);

Außerdem schickt er so drei mal 0, da die globalen Variablen ihre Default-Werte haben. Da sieht man nicht ob die Reihenfolge der Bytes passt.

woehrer

Im laufe des Projekt soll das ganze erweitert werden
und auch mit senden in die andere richtung
was ist zu beachten?

michael_x

Quote
Wie müssen die Sketche aussehn das das eine Arduino die auf den Bus bringt und das andere den bus wieder auf die richtigen variablen bringt.

Wenn du was lernen willst statt fertiger Sketche ( oder Hinweise zum Suchen fertiger Sketche ):

- Wire ( I2C ) arbeitet mit Bytes ( byte arrays ).
- Mehrere zusammengehörige Daten sind in c eine struct
Code: [Select]
     struct { int x; int y; int z;} data;
     data.x = -2000;
     data.y = 100;

- einen definierten Datenbereich als Byte Array ansprechen, geht über gecastete Pointer
Code: [Select]
     byte * p = (byte *) &data;  // cast
     unsigned int size = sizeof(data);        // Anzahl Bytes
     Wire.beginTransmission(DEVICE_ADR);
     for (int i=0; i < size; i++)
        Wire.write (*p++);   // ein Byte schreiben und pointer erhöhen
     Wire.endTransmission();

- eine Alternative zu gecasteten Pointern ist union, falls du noch mehr c lernen willst...    ;)

woehrer

Code: [Select]

#include <Wire.h>
...
void setup ()
{
Wire.begin(1); 
Serial.begin(9600);
}
...
byte x = 0;

void loop (){
.....
.....
Wire.beginTransmission(4);
  Wire.write(highByte(a));
  Wire.write(lowByte(a));
  Wire.write(highByte(b));
  Wire.write(lowByte(b));
  Wire.write(highByte(c));
  Wire.write(lowByte(c));
  Wire.write(highByte(notaus));
  Wire.write(lowByte(notaus));
 
  Wire.endTransmission();
}

void receiveEvent(int numberOfBytes)
{
  if(Wire.available() >= 6)
  {
       led = word(Wire.read(), Wire.read());
     
           
  }
}



Code: [Select]

#include <Wire.h>
....

void setup()
{
Wire.begin(4); 
Serial.begin(9600); 
....
}
byte x = 0;

void loop()
{
....
Wire.beginTransmission(1);
  Wire.write(highByte(led));
  Wire.write(lowByte(led));

  Wire.endTransmission();

.....
}

void receiveEvent(int numberOfBytes)
{
  if(Wire.available() >= 6)
  {
       int a = word(Wire.read(), Wire.read());
       int b = word(Wire.read(), Wire.read());
       int c = word(Wire.read(), Wire.read());
       notaus = word(Wire.read(), Wire.read());


       Serial.print("a=");
       Serial.println(a);
       Serial.print("b=");
       Serial.println(b);
       Serial.print("c=");
       Serial.println(c);
       Serial.print("notaus=");
       Serial.println(notaus);
       Serial.print("led=");
       Serial.println(led);
       
       
       
  }
}


Vom oberen zum unteren gehts aber anderstrum nicht
Was mach ich falsch?

Serenifly

#9
Oct 31, 2013, 06:49 pm Last Edit: Oct 31, 2013, 08:18 pm by Serenifly Reason: 1
Du hast da zwei Slaves, da du zweimal eine Adresse bei begin() angibst. Initalisiere den oberen als Master, indem du nur Wire.begin() ohne Paramter machst.

Siehe hier:
http://arduino.cc/en/Reference/WireBegin
"address: the 7-bit slave address (optional); if not specified, join the bus as a master"


Bin mir aber gerade nicht sicher ob Slave -> Master Senden funktioniert ohne dass der Master vorher die Daten explizit anfordert. Bei write() heißt es:
"Writes data from a slave device in response to a request from a master, or queues bytes for transmission from a master to slave device "

Normalerweise fordert der Master Daten mit requestFrom() an, der Slave bekommt diesen request (im onRequest() Event Handler) und schickt daraufhin die Daten mit write(). Aber einfach so Daten vom Slave zum Master zu schicken geht wahrscheinlich nicht.


Wenn du da mehr Daten sendest solltest du auch diese Zeile entsprechend erweitern:
(Wire.available() >= 6)
Bei 4 int Variablen dann auf 8 setzen.


Die Lösung von michael_x ist natürlich eleganter und beliebig skalierbar. Aber ich wollte die nicht noch mit Arrays und Pointern verwirren

michael_x

I2C ist eine Kommunikation zwischen einem Master und (evtl. mehereren) Slave.
Master bestimmt die Aktion und ein Slave reagiert, wenn seine Adresse angesprochen wird.
Ein Slave kann nicht von sich aus eine Aktion starten (d.h. nicht ungefragt senden).

Ein Arduino kann entweder Master oder Slave sein.

Der Master kann Daten Senden oder Abfragen.
Bei bidirektionalem Datenaustausch wird also nicht die Rolle Master/Slave getauscht, sondern eine andere Funktion verwendet.

Die zu Wire.h mitgelieferten Beispiele zeigen natürlich jeweils nur eine Funktion, aber zu beiden gibt es fertige Beispiele, sowohl für den Master wie für den Slave.

Go Up