Serialport übergeben

Hallo,
gibt es eine Möglichkeit einer Funktion zu übergeben welcher Serialport verwendet werden soll? Ich möchte einen Arduino Mega mit vier Unos kommunizieren lassen. Die Funktionen, die das Senden und Empfangen übernehmen sind, bis auf den verwendeten Serialport (Serial, Serial1, Serial2, Serial3), gleich. Ich würde nur ungern SoftwareSerial verwenden. Hat jemand eine Idee wie man das elegant lösen kann?

Grüße
Christian

Serial ist eine Unterklasse von Stream:

class HardwareSerial : public Stream
{
  ...
}

Daher musst du eine Referenz auf Stream übergeben:

void func(Stream& serial)
{
}

Okay, aber warum muss ich eine Referenz auf Stream anstelle des HardwareSerial Objekts, das ich verwenden möchte, übergeben? In Stream sind die ganzen Funktionen aus der HardwareSerial Klasse ja nicht mit drin?!

Grüße
Christain

Warum machst du nicht das, was du für richtig hältst?

In Stream sind die ganzen Funktionen aus der HardwareSerial Klasse ja nicht mit drin?!

Ok, HardwareSerial geht auch. War mit dem "muss" etwas unsauber ausgedrückt. Aber mit Stream kann man auch SoftwareSerial und AltSoftSerial Objekte übergeben. Die funktionieren genauso, weil Stream und deren Oberklasse Print teilweise Interfaces sind (d.h. sie enthalten abstrakte Methoden die in den Unterklassen erst implementiert werden).

Und eine Referenz auf Stream bedeutet du kannst Objekte von Klassen übergeben die von Stream abgeleitet sind. Stichworte: Vererbung und Liskovsches Substitutionsprinzip. Das ist eine der Haupt-Eigenschaften von OOP.

Es funktioniert. Vielen vielen Dank.

Auch wenn es nicht mehr zu meiner ursprünglichen Frage passt, ist ein weiteres Problem aufgetreten, dass ich nicht zu lösen weiß: Da alle 4 Unos softwareintern prinziepiell gleich repräsentiert werden, habe ich versucht dafür eine Klasse zu schreiben. Nun möchte ich, dass eine Methode im erzeugten Objekt wiederholt ausgeführt wird. Bisher habe ich sowas immer über die SimpleTimer Library gemacht. Der Aufbau ist wie folgt:

#include <SimpleTimer.h>
SimpleTimer timer;

class Bsp{
private:
 SimpleTimer timer;
 int i = 0;
 
 void inc(){
   i++;
 }

public:
 Bsp(SimpleTimer& timer){
   this->timer = timer;
 }

 void init(){
   timer.setInterval(1000, inc);
 }
};

void setup() {
 Bsp bsp(timer);
}

void loop() {
 timer.run();
}

Wobei der Compiler meckert (invalid use of non-static member function).

Hat jemand eine Idee was ich falsch mache oder wie man das lösen könnte?

Grüße
Christian

Das ist Blödsinn:

SimpleTimer timer;
 Bsp(SimpleTimer& timer){
   this->timer = timer;
 }

Das Timer Objekt existiert an der Stelle schon. Das wird erstellt sobald das Objekt deiner Klasse instantiiert wird. Wenn du im Konstruktor-Körper bist kannst nichts mehr anderes zuweisen. Außerdem willst du auch gar kein neues Timer Objekt. Das liegt ja außerhalb der Klasse.

Wenn du eine Referenz zuweisen willst, dann deklariere auch eine Referenz. Dann kannst du es aber auch nicht so zuweisen da Referenzen bei der Deklaration gleich initialisiert werden müssen

Entweder du deklarierst das als Zeiger und übergibst im Konstruktor einen Zeiger. Oder du verwendest eine Referenz. Und am besten gleich Initialisierungslisten verwenden. Wenn man auf Referenzen zuweisen will geht es gar nicht anders

SimpleTimer* timer;
 Bsp(SimpleTimer* timer) : timer(timer)
{
}

Oder:

const SimpleTimer& timer;
 Bsp(SimpleTimer& timer) : timer(timer)
{
}

Letzteres ist besser. Dann musst du nicht -> verwenden um die Methoden von timer anzusprechen

Okay, das ist gut zu wissen. Ich hätte mir dann wahrscheinlich den Kopf zerbrochen, warum die Zahl der aktiven Timer nicht stimmt. Bei meinem anderen Problem bin ich leider auch nicht weiter gekommen. Hab inzwischen verstanden, dass das Problem darin liegt, dass ich eine Membermethode ohne Referenz auf ihr Objekt übergeben möchte. Leider kann ich die Methode aber auch nicht statisch machen, da sie auf Membervariablen zugreift.
Hat da evt jemand eine Idee wie das zu lösen ist?

Grüße Christian

Versuchst du eine Memberfunktion an eine Funktion zu übergeben die einen normalen Funktionszeiger erwartet?

Wenn deine Klasse eigentlich ein Singleton ist vom dem es immer nur ein Objekt gibt, kann man es mit einer Lambdafunktion schön umgehen:
http://forum.arduino.cc/index.php?topic=468599.msg3210420#msg3210420

Aber sobald es mehrere Objekte davon gibt, geht es einfach nicht. Die Zuordnung zum Objekt fehlt einfach und dafür ist nunmal der this-Zeiger da.

Um das Problem zu lösen, habe ich versucht SimpleTimer nach diesem Beispiel umzubauen:

#include <iostream>
using namespace std;

// Callback-Klasse für Memberfunktionen ohne Argumente und Rückgabewert
// (Die Signatur der Memberfunktion kann je nach bedarf geändert werden)

// Basisklasse (wird im Aufrufer des Callbacks benutzt)
class CallbackBase {
  public:
    virtual void operator()() = 0;
};

// abgeleitete Klasse (von dieser Klasse werden die Callback-Objekte
// instanziiert)
template <class C>
class Callback: public CallbackBase {
  public:
    Callback(C &obj, void (C::*method)()):
      m_obj(obj), m_method(method) {}
    virtual void operator()() { (m_obj.*m_method)(); }
  private:
    C &m_obj;  // Objekt, dessen Memberfunktion aufgerufen werden soll
    void (C::*m_method)();  // Zeiger auf die Memberfunktion
};


// Nun kommt ein Anwendungsbeispiel: 
class Timer {
  public:
    Timer(): m_pcb(NULL) {}
    void registerCallback(CallbackBase &cb) { m_pcb = &cb; }
    void useCallback() { if(m_pcb) (*m_pcb)(); }
  private:
    CallbackBase *m_pcb;
};

// Zwei Beispielklassen, von denen eine Memberfunktion aufgerufen werden soll
// Beide Klassen sind der Timer-Klasse unbekannt.
class Test1 {
  public:
    Test1(int val): m_val(val) {}
    void show() { cout << "Test1: " << m_val << endl; }
  private:
    int m_val;
};

class Test2 {
  public:
    Test2(int val): m_val(val) {}
    void show() { cout << "Test2: " << m_val << endl; }
  private:
    int m_val;
};

int main() {
  Timer timer;

  // Je zwei Instanzen der beiden Beispielklassen
  Test1 t11(111), t12(222);
  Test2 t21(111), t22(222);

  // Für jedes Beispielobjekt ein Callback-Objekt auf die memberfunktion 'show'
  Callback<Test1> cb11(t11, &Test1::show), cb12(t12, &Test1::show);
  Callback<Test2> cb21(t21, &Test2::show), cb22(t22, &Test2::show);

  // Registrieren der vier Callback-Objekte und schauen, was passiert
  timer.registerCallback(cb11);
  timer.useCallback();

  timer.registerCallback(cb12);
  timer.useCallback();

  timer.registerCallback(cb21);
  timer.useCallback();

  timer.registerCallback(cb22);
  timer.useCallback();

  return 0;
}

https://www.mikrocontroller.net/topic/155049

Eigentlich funktioniert das auch, aber wenn ich versuche eine Memberfunktion später als Timer Festzulegen, stürzt der arduino ab und beginnt von vorne.

Ein Beispiel dazu:

#include <MySimpleTimer.h>
MySimpleTimer timer;

class Bsp{
private:
  MySimpleTimer& timer;

public:
  Bsp(MySimpleTimer& timer) : timer(timer){
  }

  void init(){

 Callback<Bsp> oEins(*this,&Bsp::eins);
 timer.setTimer(1000, oEins, 5);

    Callback<Bsp> oZwei(*this, &Bsp::zwei);
    timer.setInterval(1000, oZwei);

    Callback<Bsp> oDrei(*this, &Bsp::drei);
    timer.setTimeout(10000, oDrei);


  }
  void eins(){
    Serial.println("5 Mal und dann nie wieder");
    Serial.flush();
  }
  void zwei(){
    Serial.println("Immer");
    Serial.flush();
  }

  void drei(){
 Serial.println("Jetzt kommt der Fehler");
     Callback<Bsp> oTest(*this, &Bsp::ichBinPutt);
     int t = timer.setInterval(1000, oTest);
     //timer.disable(t);
  }

  void ichBinPutt(){
    Serial.println("Ich sollte erscheinen");
    Serial.flush();
  }

};

Bsp bsp(timer);

void setup() {
  Serial.begin(9600);
  bsp.init();
}

void loop() {
  timer.run();
}

"ichBinPutt" wird zwar als Timer hinzugefügt, aber nie ausgeführt und ich hab keine Ahnung warum.

MySimpleTimer.zip (4.27 KB)