Problem struct per i2c mit TinyWireS senden

Hallo zusammen,
nachdem ich bis jetzt eine ganze Zeit im Arduino-Forum und im Internet gesucht habe, hier meine Frage:

Vorhaben: union mit verschiedenen Messwerten per i2c vom Slave(ATtiny84) zum Master(Arduino-UNO) zu senden!

Ich habe zwei Sketche 1x für den Master und 1x für den Slave mit der in der Arduino-Bib. vorhanden Wire-Bib getestet.
1xArduino-UNO (Master), 1x Arduino-NANO(Slave) per i2c mit einander verbunden.
Es funktioniert einwandfrei. Beide Sketche weiter unten.

Dann habe ich in dem Slave-Sketch #include <Wire.h> durch #include <TinyWireS.h> ersetzt (Bibliothek von nadavmatalon) und den Sketch darauf hin angepasst.

Ab jetzt werden auf dem Master keine Daten mehr empfangen!
Jetzt halt meine Frage:
-Kennt einer dies Problem mit der/den Tiny-Bibliotheken und dem senden von struct’s und kann mir helfen?

Bzw. wie muss ich den Slave-Sketch umbauen damit er auch mit der Tiny-Bibliothek Funktioniert und ein union/struct sendet und der Master einen struct-konformen Datensatz erhält?

Es stellt sich allerdings auch die Frage, ist es überhaupt möglich mit den „TinyWireS“ ein struct/union zu senden !?

Meiner Meinung nach liegt das Problem im requestEvent bzw. in der Formatierung der write/send-Anweisung in der TinyWire-Bibliothek!?

Ich hoffe Ihr könnt mir da einen Tip geben.
Für Ihre Bemühungen schon mal vielen Dank im Voraus.
Hinweis: Ich bin noch Anfänger im Bezug Programmierung mit Arduino

Master

//UNO_i2c_Master_union_Struct_1.ino
//Option 1: Union mit einem anonymen struct damit man getrennt ansprechbare Variablen hat

//Master:

#include <Wire.h> 

const int SLAVE_ADR = 2;

union data_u
{
  struct
  {
    int value1;
    int value2;
    int value3;
    float value4;
    int value5;
  };
  byte bytes[12];
};

data_u data;

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

  //getData();
}

void loop()
{
  getData();
  delay(4000);
}

void getData()
{
  Wire.requestFrom(SLAVE_ADR, sizeof(data));
  for (unsigned int i = 0; i < sizeof(data); i++)
    data.bytes[i] = Wire.read();

  Serial.println(data.value1);
  Serial.println(data.value2);
  Serial.println(data.value3);
  Serial.println(data.value4);
  Serial.println(data.value5);
}

Slave

//UNO_i2c_Slave_union_struct_1.ino
//Slave: Auf Arduino UNO

#include <Arduino.h>

#include <Wire.h>  //Wire - Bib.
const byte SLAVE_ADR = 2;

union data_u
{
  struct
  {
    int value1;
    int value2;
    int value3;
    float value4;
    int value5;
  };
  byte bytes[12];
};

data_u data;

void setup() {
  data.value1 = 1;
  data.value2 = 4;
  data.value3 = 12;
  data.value4 = 4725.33;
  data.value5 = -10000;

  Wire.begin(SLAVE_ADR);
  Wire.onRequest(requestEvent);
}//endsetup

void loop()
{
}//endloop

void requestEvent() {
  Wire.write(data.bytes, sizeof(data)); // funktioniert
}
// +++Test weiterer Varianten ++++++++++++++++++++++++++++++++++++++++++++++
  //Wire.write((byte *)&data, sizeof(unsigned int)); //Uebertraegt keine Daten
  
  //Wire.write((byte *)&data.bytes, sizeof(data)); // funktioniert
  
  //Wire.write((byte *)&data, sizeof(data)); // funktioniert

Slave-ATtiny

//ATtiny_i2c_Slave_union_struct_1.ino
//Slave: z.Zeit noch UNO soll > ATtiny84

#define __AVR_ATtiny84__
#include <Arduino.h>

//#include <Wire.h>
#include <TinyWireS.h>  //Ist Bib. von nadavmatalon

/*
#if defined(__AVR_ATtiny841__)
#define F_CPU 16000000        // clock speed: 16MHz (external crystal)
#include "WireS.h"           // I2C library for ATtiny841 (and other modern ATtinys)
#else
#define F_CPU 20000000       // clock speed: 20MHz (external crystal)
#include "TinyWireS.h"      // I2C library for ATtiny84A (and other older ATtinys)
#endif
*/
const byte SLAVE_ADDR = 2;


union data_u
{
  struct
  {
    int value1;
    int value2;
    int value3;
    float value4;
    int value5;
  };
  byte bytes[12];
};

data_u data;

void setup() {
  data.value1 = 1;
  data.value2 = 4;
  data.value3 = 12;
  data.value4 = 4725.33;
  data.value5 = -10000;

  TinyWireS.begin(SLAVE_ADDR);
  TinyWireS.onRequest(requestEvent);
}//endsetup

void loop()
{
}//endloop

void requestEvent(){
     TinyWireS.write(data.bytes); //Keine Funktion
}     
// +++++ Test weiterer Varianten ++++++++++++++++++++++++++++++++++++++++++
     //nadavmatalon
//TinyWireS.write((byte *)&data.bytes, sizeof(data));
//Fehlermeldung
//note:   candidate expects 1 argument, 2 provided
//exit status 1
//no matching function for call to 'USI_TWI_S::write(byte*, unsigned int)'

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    // TinyWireS.write(data.bytes, sizeof(data));
//Fehlermeldung
    // note:   candidate expects 1 argument, 2 provided
//exit status 1
//no matching function for call to 'USI_TWI_S::write(byte [12], unsigned int)'

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Da fehlt beim write die Längenangabe.

Gruß Tommy

So:

void requestEvent()
{ 
    for(byte d:data.bytes) TinyWireS.write(d);
}

Da scheinst Du recht zu haben. Woher kennt write aber dann die Länge oder kann es nur ein einzelnes Byte senden?

Moment. Es gibt kein Write, sondern send oder habe ich mich jetzt total verguckt?

Gruß Tommy

Da muss man unterscheiden!
Zwischen:
TinyWireS
TinyWireM
TinyWire
TinyWireS
TinyWireS

Mal 1 Parameter, mal 2
Mal write oder auch send

Da juergen600 ja nicht preis gibt, welcher der vielen Möglichkeiten zutrifft, habe ich einfach meine übliche verwendet.

Tommy56:
Es gibt kein Write, sondern send oder habe ich mich jetzt total verguckt?

Im Slave-Beispiel steht TinyWireS.write(data*);[/color].*

Ja, dann macht das write aber auch nur ein Byte.

Gruß Tommy

Tommy56:
Ja, dann macht das write aber auch nur ein Byte.

Eine Kuh, macht Muh.
Viele Kühe machen Mühe.

Darum ja auch die Schleife über alle Byte.

Ok, wenn das geht, dann ist das ok.
Ich glaube mich zu erinnern, dass das beim normalen Wire nicht ging.

Gruß Tommy

Ja... so ist das manchmal.

Falsch und richtig.
Gut und böse
Sekt oder Selters

Oft eine Frage des Standpunktes, der Umstände und auch der konkreten Implementierung.

Es ist erstaunlich, wie schnell wir uns mit fast jeder
Situation abfinden, wenn wir dazu gezwungen werden.

Mir gefällt das auch nicht, dass die ganzen Wire Dinger so unterschiedliche Schnittstellen haben.
Ganz und gar nicht.
Ich nehme es als Herausforderung.

Hallo zusammen,
erst einmal vielen Dank für Eure schnellen Antworten.

Zu den Antworten:
Stimmt Tommy56, ich hatte das auch nur einmal getestet wg.
Fehlermeldung “ //note: candidate expects 1 argument, 2 provided”

Zu

void requestEvent()
{
    for(byte d:data.bytes) TinyWireS.write(d);
}

Volltreffer von combie.
Ich habe das sogleich einmal mit der Wire.h von Arduino getestet und es funktioniert einwandfrei!
Auf einem ATtiny84 konnte ich es noch nicht testen, da ich meinen Programmer geschrottet habe. Wird wohl bis nächste Woche dauern bis der neue kommt oder ich müsste erst einmal den UNO umbauen.

Aber wenn es so einwandfrei auf dem Arduino mit der Wire.h läuft sollte es auch auf Tiny funktionieren.

Da scheinst Du recht zu haben. Woher kennt write aber dann die Länge oder kann es nur ein einzelnes Byte senden?

Moment. Es gibt kein Write, sondern send oder habe ich mich jetzt total verguckt?

Gruß Tommy

und

Da muss man unterscheiden!
Zwischen:
TinyWireS
TinyWireM
TinyWire
TinyWireS
TinyWireS

Mal 1 Parameter, mal 2
Mal write oder auch send

Da juergen600 ja nicht preis gibt, welcher der vielen Möglichkeiten zutrifft, habe ich einfach meine übliche verwendet.

So wie gesehen habe, gibt es je nachdem welche der vielen Bibliotheken man benutzt den Befehl „write“ oder „send“
Z.B. „nadavmatalon“ = write (Von mir verwendet.); oder die „TinyWire_rambo” = send.
Hier trifft auch der 4te Beitrag von combie zu. Getreu der Devise jeder wie er möchte.
Hier hat auch agume recht bei der von mir verwendeten „nadavmatalon-Bib. Ist es halt „write“.

Ja, dann macht das write aber auch nur ein Byte.

Gruß Tommy

Zu tommy56, ich meine auch es so gelesen zu haben. Selbst die Wire.h-Bib. vom arduino macht pro write immer nur 1 Byte.
Das ist dann auch die Begründung dafür daß die Schleife über alle Byte von combie funktioniert.
Jedenfalls hat ein erster Test mit der Wire.h das bestätigt.

Oft eine Frage des Standpunktes, der Umstände und auch der konkreten Implementierung.
Quote

    Es ist erstaunlich, wie schnell wir uns mit fast jeder
    Situation abfinden, wenn wir dazu gezwungen werden.

Mir gefällt das auch nicht, dass die ganzen Wire Dinger so unterschiedliche Schnittstellen haben.
Ganz und gar nicht.
Ich nehme es als Herausforderung.

Hier muss ich combie völlig Recht geben.
Anscheinend ist es so daß man in den vorhandenen Bib’s das Senden von 2 Argumenten nicht berücksichtigt hat. Ich kann allerdings das Argument des kleinen Tiny-Speichers so nicht verstehen! (ATtiny85/84 – 8K)
In der Wire.h ist jedenfalls das Senden von 2 Argumenten berücksichtigt.

Trotzdem noch einmal vielen Dank für Eure Hilfe.
Gruß juergen

Also die Wire.h vom Arduino UNO kann beide Varianten:

    virtual size_t write(uint8_t);
    virtual size_t write(const uint8_t *, size_t);

Gruß Tommy

Also ich habe mittlerweile den Slave-Sketch mit dem Tip von combie ergänzt und auf einen ATtiny gebrannt.
Der Sketch funktioniert jetzt einwandfrei.
Als Bibliothek verwende ich die GitHub - nadavmatalon/TinyWireS: ATtiny I2C Slave Library.

Hallo Tommy56,
die beiden Zeilen habe ich in der Wire.h auch gefunden (Die Wire.h läuft aber nur auf den ATmega’s).
Allerdings in den Bibliotheken für die ATtiny’s sucht man sie vergebens.

Als Anfänger im Programmieren mit C/Cpp muss ich mich damit auch erst einmal auseinander setzen was die beiden Zeilen bewirken!
Trotzdem vielen Dank für Deine Bemühung.

Hier noch der funktionierende Code für den ATtiny84.

//ATtiny_i2c_Slave_union_struct_1.ino

#define __AVR_ATtiny84__
#include <Arduino.h>

#include <TinyWireS.h>  //Ist Bib. von nadavmatalon

/*
#if defined(__AVR_ATtiny841__)
#define F_CPU 16000000        // clock speed: 16MHz (external crystal)
#include "WireS.h"           // I2C library for ATtiny841 (and other modern ATtinys)
#else
#define F_CPU 20000000       // clock speed: 20MHz (external crystal)
#include "TinyWireS.h"      // I2C library for ATtiny84A (and other older ATtinys)
#endif
*/
const byte SLAVE_ADDR = 2;


union data_u
{
  struct
  {
    int value1;
    int value2;
    int value3;
    float value4;
    int value5;
  };
  byte bytes[12];
};

data_u data;

void setup() {
  data.value1 = 1;
  data.value2 = 4;
  data.value3 = 12;
  data.value4 = 4725.33;
  data.value5 = -10000;

  TinyWireS.begin(SLAVE_ADDR);
  TinyWireS.onRequest(requestEvent);
}//endsetup

void loop()
{
}//endloop

void requestEvent(){

    for(byte d:data.bytes) TinyWireS.write(d); // So funktioniert es.
}

Gruß juergen

// So funktioniert es.

Fein!
So hat das blinde Huhn, mit dem stochern im Nebel, auch mal Glück, und du deine Lösung.