Mehrere Boards verbinden / Library gesucht

Hallo zusammen,

in einem Projekt benutze ich zwei Controller, einen für eine schnelle und genaue Zeitmessung, dazu verwende ich einen Arduino nano und einen, der den Rest verwurstelt, ein STM Nucleo152re.
Nun muss ich einen Messwert vom Nano zum Nucleo übertragen.

Verbinden will ich beide Boards entweder über I²C oder vorzugsweise Rx/Tx. Nun suche ich einen Weg, einfach auf beiden Boards einen Speicherbereich zu reservieren, der automatisch, wenn sich mindestens ein Byte ändert, zu übertragen.

Gibt es da vielleicht eine fertige Bibliothek, die ich dafür verwenden kann? Ich benötige eigentlich nur zwei UINT und ein Byte jeweils in beide Richtungen.

Speicher in einem Microcontroller ändern sich nicht automatisch sondern nur wenn Du etwas schreibst. Also weißt Du wann sich etwas ändert und kannst dann auch das Senden der Daten veranlassen.

Das ist viel einfacher, als was Du jetzt möchtest. Eine Bibliothek müsste sich jetzt merken, welche Daten in Deinem Speicher stehen und dann ständig vergleichen. Den im Gegensatz zu Dir weiß die Bibliothek nicht wann Du in den Speicher schreibst. Die Bibliothek kann ja immer nur dann laufen, wenn Du gerade keine Befehle ausführst.

Auf einem STM32 könnte man die Debuginfrastruktur missbrauchen um Schreibzugriffe zu detektieren. Dies ist aber keine gute Idee, da Du dann keinen Debugger mehr verwenden kannst, wenn Du in Zukunft mal einen verwenden möchtest.

Eine Bibliothek müsste sich jetzt merken, welche Daten in Deinem Speicher stehen und dann ständig vergleichen. Den im Gegensatz zu Dir weiß die Bibliothek nicht wann Du in den Speicher schreibst. Die Bibliothek kann ja immer nur dann laufen, wenn Du gerade keine Befehle ausführst.

Nicht unbedingt.

Sie könnte auch die Daten in einer Struktur/Klasse kapseln und den Zugriff nur über Getter und Setter erlauben.

  1. Damit könnten man die Zugriffe Transparent gestalten. Das heißt, die Anwendung merkt gar nicht, dass die Daten auf einem anderen µC liegen.
  2. Die Lib würde ihr eigenes Dirty Flag verwalten.

Noch gibts da Konzept Probleme!

Ich benötige eigentlich nur zwei UINT

  1. Einen Type UINT gibt es auf keinem der beiden Systeme, oder?
  2. "unsigned int" ist auf den beiden Systemen unterschiedlich groß (sizeof() zeigt dir das auch)

combie:
Sie könnte auch die Daten in einer Struktur/Klasse kapseln und den Zugriff nur über Getter und Setter erlauben.

  1. Damit könnten man die Zugriffe Transparent gestalten. Das heißt, die Anwendung merkt gar nicht, dass die Daten auf einem anderen µC liegen.

Was effektiv bedeutet, daß man die Daten selber zu dem anderen Controller sendet.

Ein Nachteil der Kapselung ist, daß man zwei Vorgäng, eine Variable lesen/schreiben und das Senden zu einem anderen Microcontroller verschleiert. Das Senden/Empfangen dauert viel länger als ein einfacher Variablenzugriff. Dies ist jetzt nicht mehr so einfach im Sourcecode sichtbar. Da freut man sich später bei der Fehlersuche. :slight_smile:

Aus

a = a + 1; // dauert 1 Taktzyklus
Serial.println( a ); // oder irgendein anderer Funktionsaufruf zum senden IIC, SPI ...

wird

a = a + 1; // dauert vielleicht ein paar tausend Takte

a = a + 1;
Von read-modify-write Zugriffen war bisher keine Rede.
Taugt also nur arg bedingt als Gegenargument.

Und, du weißt ja, wenn es gemacht werden muss, dann muss es auch gemacht werden.
Völlig unabhängig davon ob, oder wie, gekapselt.

Ich entnehme deinem Posting, dass du Abstraktionen, im allgemeinen, eher ablehnst.
Das ist dein gutes Recht.

Frank501:
…..
Gibt es da vielleicht eine fertige Bibliothek, die ich dafür verwenden kann?

Ja, die gibt es zumindest für den Nano. Die "wire.h" ist für I2C die richtige.
Den Rest darfst du selbst programmieren.

HotSystems:
Ja, die gibt es zumindest für den Nano. Die "wire.h" ist für I2C die richtige.
Den Rest darfst du selbst programmieren.

Ja, ähm... Danke. :confused:

Nachdem ich mich mal etwas eingelesen habe, frage ich mich, ob es möglich ist, ein struct zu definieren und dieses einfach per serial zu senden und auf der anderen Seite auch zu empfangen.

Ein struct hat ja im Idealfall immer die gleiche Länge. Reicht es hier, die Größe mit Sizeof zu ermitteln und mit Hilfe eines Pointers ein Byte auszulesen, dieses zu senden und auf der anderen Seite wieder in das gleich aufgebaute struct zu schreiben?
Oder geht es vielleicht noch einfacher, indem ich das struct an serial.write übergebe und auf der anderen Seite wieder mit serial.read einlese?

Ein struct hat ja im Idealfall immer die gleiche Länge. Reicht es hier, die Größe mit Sizeof zu ermitteln und mit Hilfe eines Pointers ein Byte auszulesen, dieses zu senden und auf der anderen Seite wieder in das gleich aufgebaute struct zu schreiben?

Kann man tun.

Gleicher Kompiler
Gleicher µC
Gleiche Einstellungen

Ein Protokoll, z.B. mit Prüfsumme usw. entwickeln.
Dann kann das klappen.

Ich nutze häufiger mal den CmdMessenger für serielle Übertragungen zwischen µC.
Auch gerne über serielle Funkmodule.

Frank501:
...
Oder geht es vielleicht noch einfacher, indem ich das struct an serial.write übergebe und auf der anderen Seite wieder mit serial.read einlese?

Wieso probierst Du's nicht einfach? Soooo wahnsinnig viel Tipperei ist das ja wohl echt nicht.

Gruß

Gregor

Hallo,

habe auch eine Anwendung mit 2 unterschiedlichen Microcontroller. Einmal ein Wemos 8266 als Master und ein Arduino Mini als Slave über I2C gekoppelt. Datenaustausch erfolg über 2 Strukturen.

Strukturen wie folgt

// ----- BEGIN I2C Datenstrukturen ------------------------------------------
// STRUKTUR MUSS FUER WEMOS UND MICRO IDENTISCH SEIN
#pragma pack(1)

struct struct_I2C_Micro
{
  uint8_t  SYS_Mode;
  int16_t  Data1;
  uint8_t  Data2;
};

union {
  struct_I2C_Micro  sI2C;
  uint8_t           aI2C[sizeof(struct_I2C_Micro)];
} uI2C_Micro;

struct struct_I2C_Wemos
{
  uint8_t  SYS_Mode;
  int16_t  Data3;
  int16_t  Data4
};

union {
  struct_I2C_Wemos  sI2C;
  uint8_t           aI2C[sizeof(struct_I2C_Wemos)];
} uI2C_Wemos;

#pragma pack(pop)
// ----- END   I2C Datenstrukturen ------------------------------------------

Der Code auf dem Master Wemos 8266

// I2C Routine auf Wemos 8266
// ----- BEGIN "I2C Handling" -----------------------------------------------
void I2C_SendReceive_Data()
{
  byte I2C_Status = 0;

  Wire.beginTransmission( I2C_Slave_Adr );
  int I2C_Written = Wire.write( uI2C_Wemos.aI2C, sizeof(struct_I2C_Wemos) );
  I2C_Status = Wire.endTransmission();

  if( I2C_Status==0 )
  {
    delayMicroseconds( 10 );  // Comment this out and watch requestFrom() fails.
    
    if( Wire.requestFrom( I2C_Slave_Adr,sizeof(struct_I2C_Micro) )==sizeof(struct_I2C_Micro) )
    {
      Wire.readBytes( uI2C_Micro.aI2C, sizeof(struct_I2C_Micro) );
    } 
    else 
    {
      #if( DEBUG == 1 )
        Serial.println("I2C bus error in return");
      #endif
      I2C_Status = 4;
    }
  }
  else
  {
    // I2C_Status : 1-Data too long
    // I2C_Status : 2-NACK on address
    // I2C_Status : 3-NACK on data
    // I2C_Status : 4-Some error
  }

  if( I2C_Status!=0 ){ SYS_Error=SYSTEM_ERROR_I2C; }
}
// ----- END   "I2C Handling" -----------------------------------------------

und dem Slave Arduino Mini

// I2C Routine auf Arduino Mini
// ----- BEGIN I2C Handling -------------------------------------------------
void I2C_ReceiveEvent( int howMany )
{
  int j = Wire.available();

  // Receive Data from Master
  if ( j == sizeof(struct_I2C_Wemos) )
  {
    Wire.readBytes( uI2C_Wemos.aI2C, sizeof(struct_I2C_Wemos) );
  }
}

void I2C_RequestEvent()
{
  int i;

  // BEGIN I2C Struktur füllen für Wemos
  uI2C_Micro.sI2C.bSYS_Mode  = (uint8_t)...;
  uI2C_Micro.sI2C.Data1      = (int16_t)...;
  ...
  // END   I2C Struktur füllen für Wemos
  
  // Write Data to Master
  int I2C_Written = Wire.write( uI2C_Micro.aI2C, sizeof(struct_I2C_Micro) );
}
// ----- END   I2C Handling -------------------------------------------------
// STRUKTUR MUSS FUER WEMOS UND MICRO IDENTISCH SEIN

Verstehe ich nicht, bzw. warum machst du das dann nicht?
Oder: warum definierst du zwei verschiedene Strukturen?

Hallo,

die beiden Strukturen Wemos->Mini bzw. Mini -> Wemos können natürlich unterschiedlich sein. Die Deklaration muss jedoch in den beiden Quelltexten identisch sein - im Quelltext von Wemos und im Quelltext vom Mini. Sonst verstehen sich die beiden nicht.
Verwendung von uint8_t, int16_t etc. da bei Atmel 8bit und ESP 8266 z.B. 32bit "int" unterschiedlich lang ist - 2 vs. 4 Byte. Die pragma Anweisung sorgt dafür, dass die Struktur "gepackt" wird.

Gruß Arduino4Fun