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.
Damit könnten man die Zugriffe Transparent gestalten. Das heißt, die Anwendung merkt gar nicht, dass die Daten auf einem anderen µC liegen.
combie:
Sie könnte auch die Daten in einer Struktur/Klasse kapseln und den Zugriff nur über Getter und Setter erlauben.
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.
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
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.
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?
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.
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 -------------------------------------------------
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.