Klasse aus Codesegment erstellen funktioniert nicht

Hi zusammen,
ich bastle im Moment an einem kleinen Projekt (wie bereits in einem anderen Thread angesprochen) bestehend aus 3 Charlieplex Gruppen zu je 6 LEDs. Das Programm dazu ist fertig und funktioniert. Jetzt möchte ich den Code allerdings noch ein bisschen aufräumen und übersichtlicher gestalten. Das habe ich soweit auch schon hinbekommen, allerdings macht mir ein Abschnitt noch ein bisschen Kopfzerbrechen.

byte Grp1 = 0b00000000;
  int NrGrp1[6];
  int indexGrp1 = 0;
  int LEDout1 = 0;
  int bitcount1 = 0;

  for (int index = 0; index < 6; index++)
  {
    if (LED[index + 1] == true) // Check if LED should be driven
    {
      bitSet(Grp1, indexGrp1); // Write bit in byte
      NrGrp1[indexGrp1] = index + 1; // Write LED Nr in int array
      bitcount1 ++; // Number of active LEDs
      indexGrp1 ++; // indexcounter
    }
  }
  if (indexGrp1 >= 6)
    indexGrp1 = 0;

  if ((indexOut1 >= bitcount1) || (bitRead(Grp1, indexOut1) == false))
    indexOut1 = 0;
  // Write LED Nr sequentially in Output Array
  if ((bitRead(Grp1, indexOut1) == true) && (indexOut1 < bitcount1))
  {
    LEDout1 = NrGrp1[indexOut1];
    indexOut1 ++;
    delay(outputDelay);
  }

In meinem Programm werden die LEDs mittels Bool-Array angesteuert. Wenn also zB die LEDs 1, 3 und 6 leuchten sollen, sind LED[1], LED[2] und LED[6] true.
Der gezeigte Code Abschnitt macht jetzt folgendes: Es werden die bits im Array nacheinander auf true verglichen. Wenn das bit true ist, wird das erste Bit im Byte Grp1 gesetzt und die Nr der LED ins int Array NrGrp1 geschrieben.
Somit werden die zu steuernden LEDs nacheinander ins Array geschrieben.
Im unteren Bereich werden dann die LED Nummern nacheinander in den int LEDout1 geschrieben.
Eine weitere Funktion im Programm steuert die LEDs entsprechend der Nr an.
Der Sinn der Übung ist nun der, dass nur die LEDs angesteuert werden die auch benötigt werden. Wenn ich einfach nur das Array auslese und weitergebe werden auch die nicht benötigten LEDs ausgewertet. Duty-Cycle der LEDs sinkt somit.
Ich hoffe ich konnte es einiger Maßen verständlich erklären.

Diesen Abschnitt verwende ich in meinem Programm 4 mal. Nur eben mit abgeänderten Variablen. Also möchte ich diesen Abschnitt in eine Klasse packen und so verwenden. Ich habe jetzt einiges versucht, aber leider wird immer nur die niedrigste LED angesteuert. (Also wenn alle leuchten sollen, leuchtet nur die erste)
So sieht die Klasse aus:

class OutputCalculation {
  private:

  public:
    bool LED[6]; // Bool Array for LEDs to be controled
    int offset; // Offset for LED[X], if 0 begin with LED[0]
    int outputDelay; // Usually not needed

    int calc(bool LED[6], int offset, unsigned int outputDelay)
    {
      byte Grp = 0b00000000;
      int NrGrp[6];
      int indexGrp = 0;
      unsigned int bitcount = 0;
      int indexOut =0;

      for (int index = 0; index < 6; index++)
      {
        if (LED[index + offset] == true) // Check if LED should be driven
        {
          bitSet(Grp, indexGrp); // Write bit in byte
          NrGrp[indexGrp] = index + offset; // Write LED Nr in int array
          bitcount ++; // Number of active LEDs
          indexGrp ++; // indexcounter
        }
      }
      if (indexGrp >= 6)
        indexGrp = 0;

      if ((indexOut >= bitcount) || (bitRead(Grp, indexOut) == false))
        indexOut = 0;
      // Write LED Nr sequentially in Output Array
      if ((bitRead(Grp, indexOut) == true) && (indexOut < bitcount))
      {
        return NrGrp[indexOut];
        indexOut ++;
        delay(outputDelay);
      }
    }
};

Deklaration über loop

OutputCalculation outputGrp1;

Aufruf in loop

LEDout1 = outputGrp1.calc(LED, 1, outputDelay);

LED ist doch eine Membervariable jedes OutputCalculation - Objekts ?
Wieso gibst du das als Parameter der Methode calc mit?
Oder haben die zwei nichts miteinander zu tun (und OutputCalculation::LED ist ein Irrtum) ?

Ausserdem ist LED auf 6 Elemente festgelegt. Mit offset kannst du da nur Mist machen, indem du bei offset > 0 auf undefinierte Speicherbereiche schreibst

Aber so ganz verstanden habe ich deine Programmlogik nicht.
Warum du ein bool Array und zusätzlich ein byte mit einzelnen Bits hast?
Warum du was in NrGrp speicherst, und was das Ergebnis von calc sein soll?

So ganz verstehe ich das auch nicht. Insgesamt kommt mir das aber bisher eher wie eine einfache Funktion und nicht wie ein Klasse vor. Sollen da mehrere Objekte instanziiert werden? Und warum alles public?

@michael_x: der offset hat den Sinn, da das Bool Array LED 20 Felder groß ist und ab 1 beschrieben wird. Bei offset 1 wird also die erste 6-LED Gruppe ausgwertet, bei offset 7 die zweite.
Das bool Array wird an andere Stelle vom Programm beschrieben, dort werden die LEDs gesetzt die leuchten sollen, das Byte habe ich als Zwischenspeicher verwendet, aber es müsste scheinbar auch ohne gehen.
Ins Array NrGrp werden nacheinander die Nummern der LEDs geschrieben die angesteuert werden sollen.
Das Ergebnis von calc sollen die LED Nr in Abfolge sein. Also eine LED Nr pro Zyklus

@MicroBahner Ja es sollen mehrere Objekte instanziert werden. Wie gesagt der Code ganz oben ist vier mal in Verwendung nur eben mit geänderten Variablen und es funktioniert alles wie es soll. Warum alles public? Das ist eine gute Frage :wink: die drei Variablen in public müssen doch von "außen" zugänglich sein, oder irre ich mich da.

Ich habe bereits versucht mich in die Klassen-Thematik einzulesen, aber ich komme einfach auf keinen grünen Zweig. Wie ist eine Klasse aufgebaut? Wann public, wann private usw... Vielleicht wisst ihr, wo ich mich etwas weiterbilden kann :wink:

Du solltest Dich von Anfang an daran gewöhnen, dass in der IT ab 0 gezählt wird, auch beim Inhalt von Arrays.

Gruß Tommy

firefist235:
oder irre ich mich da.

Ja

firefist235:
Wann public, wann private usw... Vielleicht wisst ihr, wo ich mich etwas weiterbilden kann :wink:

Ein Prinzip der OOP ist Kapselung. Also sowenig publich wie möglich. Member-Variablen nur über Zugriffmethoden erreichbar.

Ich fand das Buch "Der C++-Programmierer" hilfreich.

Gruß Tommy

Tommy56:
Ich fand das Buch "Der C++-Programmierer" hilfreich.

Danke, ist im Warenkorb :wink:

class OutputCalculation {

public:
    bool LED[6]; // Wofür sind die gedacht?
    ...

}

byte Grp; // enthält eigentlich dieselbe Information, richtig?

Oder umgekehrt: Wofür hast du ein globales

bool LED[20];

Wenn du immer nur 6 davon gemeinsam behandelst?

Wenn deine Klasse überhaupt Sinn machen soll (oder wenigstens mir verständlich sein),
würde sie für eine Gruppe von 6 LED zuständig sein, deren Zustand kennen und ausgeben können und man könnte die 6 LED setzen oder löschen. Oder so ähnlich.

Dass du beliebig oft die Methode outputGrp1.calc() aufrufst und reihum die Indexnummern der aktuell aktiven LED zurückerhältst, halte ich für relativ schwierig realisierbar und ziemlich unsinnig:

  • Wie schaltest du LED jemals wieder aus?
  • Was willst du mit einer IndexNummer 1..6 ?
  • Was willst du mit der Serie 1,3,5,1,3,5, ... anfangen?
    (Oder habe ich das nicht/falsch verstanden?)

Meine Idee: Wenn ich es nicht verstehe, ist es vermutlich Unsinn oder unnötig kompliziert. :slight_smile:
Das ist zugegebenermaßen egozentrisch, und du kannst es auch gerne ignorieren. Aber vermutlich hast du mehr von diesem Thread, wenn du versuchst, dich darauf einzulassen.

byte Grp dient zum Vergleich bei der Ausgabe, wieviel LEDs überhaupt angesteuert werden müssen. Wie gesagt, wahrscheinlich auch ander lösbar.
Ein globales bool array deswegen, weil die LEDs die angesteuert werden sollen, in einem anderen Bereich festgelegt werden. Die Klasse soll dann einen integer mit den LED Nummern in schneller Abfolge ausgeben (1-6; 7-12; 13-18; 19-20) Die Ansteuerung selber übernimmt eine weitere Funktion.
Ausgeschaltet werden die LEDs wenn sie nicht im int ausgegeben werden.

Aber bevor ich mich nicht besser mit Klassen usw. auskenne werden wir glaub ich auf keinen grünen Zweig kommen :wink:

Der Code an sich funktioniert, ich tu mir ein bisschen schwer die genaue Funktion zu beschreiben :wink:
Es geht mit sicherheit auch anders und einfacher.

Anbei auch noch der Schaltplan und der Sketch. Der Auskommentierte Bereich von Zeile 231 bis 258 ist der den ich in die Klasse packen wollte. Wie gesagt, wir müssen uns hier nicht das Gehirn verbiegen :slight_smile: es fehlt mir einfach noch zu sehr an Grundwissen :wink:

Christbaum_V1.1.ino (17.6 KB)

Ich stimme noiasca zu und möchte noch ergänzen, dass
Klassen was mit Objekt-orientierter Programmierung zu tun haben.
Also der Vernüpfung von Eigenschaften (konstante und variable Daten-Strukturen) mit Methoden (Aktionen, die man damit machen kann).

Was du machen willst ( calc() ), ist eine Funktion, die eventuell vernünftige Parameter braucht, um mehrfach verwendet werden zu können.

Oder du überdenkst das Ganze in Ruhe in den Weihnachtsferien,
um für 2020 eine ChristbaumV2.0 - Beleuchtung komplett neu zu erstellen.

Der Code an sich funktioniert

Na, dann ist doch gut. Frohe Weihnachten!

Ich denke auch, das ist einfach eine Funktion. So wie ich das sehe, werden die Variablen, die Du in der Klasse als 'public' definiert hast, gar nicht genutzt, sondern belegen nur unnütz Speicher ( wenn sie der Compiler nicht sowieso wegoptimiert ). In der Funktion werden stattdessen die übergebenen Parameter und lokale Variable verwendet.

Mit OOP und Klassen musst Du dich halt noch ein wenig beschäftigen. Ist ja bald Weihnachtsurlaub :wink: :smiley:
Schöne Feiertage!