switch mit struct kompiliert nicht mit Konstanten

Hallo,

damit ihr einmal seht was ich treibe - eine Spielerei.
Alps Led Animation Alps Led Animation - YouTube

Serenifly:
Für mich ist da leider nichts offensichtlich. Tut mir leid. Wenn ich nur byte verwende wo soll dann int herkommen. Du hast das nun versucht zu erklären. Ich nehme das zur Kenntnis. Verstanden habe ich das Problem noch nicht wirklich. Aber ein klein wenig.

combie:
Ich habe versucht alles in eine Struktur zu packen was zusammengehört wie von Serenifly seit Jahren gefordet. Für mich ist das eine Punktmatrix. Die sprechenden Namen für Segmente und Digits sind besser lesbar als irgendwelche Zahlen. Deswegen habe ich das angelegt und angewendet.

Mit dem LED Array kann ich der Reihenfolge nach über einen Index auf alle nacheinander zugreifen.

Die Codeduplikate sind mir schon länger im Weg. Ich dachte ein Umbau von vielen if auf switch case lässt mich das Offensichtliche besser erkennen. Aber dann kam das Zugriffsproblem dazwischen. Womit erstmal Experimente mit enum oder constexpr angesagt waren.

Aktuell sieht der Aufbau so aus. Was sollte ich ändern?

struct t_setup
{
  const byte CLK  = 24;
  const byte CS   = 25;
  const byte MOSI = 26;

  enum seg {
    DP = 128,     // Bit.7 - Datenblatt Tabelle 6
    A  = 64,
    B  = 32,
    C  = 16,
    D  =  8,
    E  =  4,
    F  =  2,
    G  =  1      // Bit.0
  };

  enum digit {
    D0 = 0x01,
    D1 = 0x02,
    D2 = 0x03,
    D3 = 0x04
  };

  void shift_out( byte adresse, byte daten )
  { // Bits rausschieben, MSB first
    uint16_t data = 0;
    data = (data | adresse) << 8;
    data = data | daten;

    digitalWrite(CS, LOW);

    for (uint8_t i = 0; i < 16; i++) {
      if (data & 0x8000) {              // nur oberstes Bit betrachten
        digitalWrite(MOSI, HIGH);       // und Datenleitung entsprechend setzen
      }
      else {
        digitalWrite(MOSI, LOW);
      }
      digitalWrite(CLK, HIGH);          // Takt erzeugen
      data = data << 1;                 // nächstes Bit links schieben
      digitalWrite(CLK, LOW);
    }

    digitalWrite(CS, HIGH);
  }

  void clear_all ()
  {
    shift_out(digit::D0, 0);   
    shift_out(digit::D1, 0);   
    shift_out(digit::D2, 0);   
    shift_out(digit::D3, 0);   
  }
} MAX7221;


struct t_led
{
  const byte digit;
  const byte segment;
};


const t_led LED[] = {
  {MAX7221.digit::D0, MAX7221.seg::A},  // LED  1
  {MAX7221.digit::D1, MAX7221.seg::A},
  {MAX7221.digit::D2, MAX7221.seg::A},
  {MAX7221.digit::D3, MAX7221.seg::A},
  {MAX7221.digit::D0, MAX7221.seg::B},  // LED  5
  {MAX7221.digit::D1, MAX7221.seg::B},
  {MAX7221.digit::D2, MAX7221.seg::B},
  {MAX7221.digit::D3, MAX7221.seg::B},
  {MAX7221.digit::D0, MAX7221.seg::C},
  {MAX7221.digit::D1, MAX7221.seg::C},  // LED 10
  {MAX7221.digit::D2, MAX7221.seg::C},
  {MAX7221.digit::D3, MAX7221.seg::C},
  {MAX7221.digit::D0, MAX7221.seg::D},
  {MAX7221.digit::D1, MAX7221.seg::D},
  {MAX7221.digit::D2, MAX7221.seg::D},  // LED 15
  {MAX7221.digit::D3, MAX7221.seg::D},
  {MAX7221.digit::D0, MAX7221.seg::E},
  {MAX7221.digit::D1, MAX7221.seg::E},
  {MAX7221.digit::D2, MAX7221.seg::E},
  {MAX7221.digit::D3, MAX7221.seg::E},  // LED 20
  {MAX7221.digit::D0, MAX7221.seg::F},
  {MAX7221.digit::D1, MAX7221.seg::F},
  {MAX7221.digit::D2, MAX7221.seg::F},
  {MAX7221.digit::D3, MAX7221.seg::F},
  {MAX7221.digit::D0, MAX7221.seg::G},  // LED 25
  {MAX7221.digit::D1, MAX7221.seg::G},
  {MAX7221.digit::D2, MAX7221.seg::G},
  {MAX7221.digit::D3, MAX7221.seg::G},
  {MAX7221.digit::D0, MAX7221.seg::DP},
  {MAX7221.digit::D1, MAX7221.seg::DP}, // LED 30
  {MAX7221.digit::D2, MAX7221.seg::DP}  // LED 31
};

const byte ANZAHL_LED = sizeof(LED) / sizeof(t_led);

Integer != int. Integer heißt einfach Ganzzahl und sind char, int, short, long, long long. Die klassischen C enums sind implizit in Integer konvertierbar. Eigentlich sollen das nur konstante Namen sein. Die Werte dahinter sollten für den Benutzer normal keine Rolle spielen. Ich habe sie auch schon so verwendet, dass man die Zahlen dahinter verwendet. Oder von einem Wert auf den anderen mit +/- kommt. Aber sauber ist das nicht wirklich.

Strongly typed enums haben werden im Hintergrund immer noch auf Integer abgebildet. Aber sie sind nicht implizit in diese konvertierbar.

Als ich das vorgeschlagen haben, hatte ich etwas übersehen wie du die eigentlich verwendest. Für echte Zustände sind sie gut. Ich hatte das erwähnt weil du, so wie ich es gelesen hatte, angemerkt hast dass man mit klassischen enums Konstanten nicht mehrfach verwendet kann. Mit strongly typed enums geht das dagegen, da die Konstanten in ihrem Gültigkeitsbereich auf den enum-Namen beschränkt sind statt global zu sein.
Vielleicht hatte ich dich da auch falsch verstanden

Aber als numerische Konstanten musst du entweder klassische enums oder ein constexpr struct verwenden (da eben beachten, dass const in einem struct nur read-only heißt und keine Compile-Zeit Konstanten sind!)

Hallo,

jetzt habe ich das Konvertierproblem verstanden. Das const nur read-only bedeutet nun auch. Danke.

Ich habe versucht alles in eine Struktur zu packen was zusammengehört wie von Serenifly seit Jahren gefordet.

Ja!
Nur, befürchte ich, dass du da übertreiben willst.

Bedenke:
Sobald man gelernt hat, wie ein Hammer funktioniert, sieht alles andere plötzlich wie ein Nagel aus.

Die sprechenden Namen für Segmente und Digits sind besser lesbar als irgendwelche Zahlen. Deswegen habe ich das angelegt und angewendet.

Verstehe ich!
Allerdings habe ich Vorbehalte gegen durchnummerierte Dinge, wenn doch ein Index genau so gut funktionieren würde. Die Durchnummerierung verhindert hier wirksam die Anwendung von einfachen Verarbeitungen.

Mit dem LED Array kann ich der Reihenfolge nach über einen Index auf alle nacheinander zugreifen.

Aha, ja, das war die Kerninformation!
Jetzt kann ich abschätzen, was du meinst.
Das Video war maßgeblich!

Ich mache mir mal Gedanken, über eine alternative Umsetzung.
Wird sich aber etwas strecken, da z.Z. arg eingebunden.
Lass dich also nicht von eigenen Entwicklungen abhalten.....

Hallo,

verstehe. Ich möchte immer die "gesammelten Hämmer" unbedingt einsetzen. :slight_smile:
Bin gespannt auf deinen Vorschlag und mache selbst weiter. Danke für die Hinweise.
Noch ein nachgereichter Schaltplan für den Aufbau. Vielleicht hilft das den Strukturaufbau noch besser zu verstehen. Ohne die enums bzw. struct constexpr könnte ich mit dem LED Array Indexdurchlauf nur eine einzelne LED wandern lassen. Weil ich nicht vergleichen kann auf welchem Digit (Spalte) ich mich gerade befinde und welchen aktuellen Wert die zugehörigen Segmente (Zeilen) haben. Um dann Segmentwerte aufaddieren zu lassen für zum Bsp. wachsende Balkeneffekte. So meine derzeitige Denkweise, die möglicherweise zu kompliziert ist, mag sein. Ein aktueller lauffähiger Sketch hängt auch dran, vielleicht hilfreich.

MAX7221_005c.ino (5.57 KB)

Ja, danke, für das Bild!

Meine Intuition schreit schon!

Es wird in die Richtung gehen:
Eine universelle Klasse für das IC.
Und eine Funktion, welche die LED Position, von speziell Alps, zu allgemein, umformt.

Hallo,

vielleicht geht das in die Richtung was du vorhast. Aktueller Stand ist dieses Gerüst was erstmal funktioniert.
Wenn das Unsinn ist bitte sagen.

class IC
{
  private:
    const byte CLK;
    const byte CS;
    const byte MOSI;

  public:
    IC(const byte CLK, const byte CS, const byte MOSI): CLK(CLK), CS(CS), MOSI(MOSI){}
    
    void init () {
      digitalWrite(CS, HIGH);
      pinMode(CS, OUTPUT);
      pinMode(CLK, OUTPUT);
      pinMode(MOSI, OUTPUT);
    }

    void transfer ( byte adresse, byte daten )
    { // 16 Bits rausschieben, MSB first
      digitalWrite(CS, LOW);
      shiftOut(MOSI, CLK, MSBFIRST, adresse);
      shiftOut(MOSI, CLK, MSBFIRST, daten);
      digitalWrite(CS, HIGH);
    }

    void wakeUp () {
      transfer(0x0C, 1);
    }
    
    void clearAll () {
      transfer(0x01, 0);    // Digit.0
      transfer(0x02, 0);
      transfer(0x03, 0);
      transfer(0x04, 0);    // Digit.3
    }

    void testOn () {
      transfer(0x0F, 1);
    }

    void testOff () {
      transfer(0x0F, 0);
    }

    void intensity (byte i) {
      if (i < 16) {
        transfer(0x0A, i);
      }
    }

    void scanLimit () {
      transfer(0x0B, 3);
    }

    void noDecodeMode () {
      transfer(0x09, 0);
    }
};

IC MAX7221(24, 25, 26);     // Objekt erstellen (CLK, CS, MOSI)

void setup() {

  MAX7221.init();
  MAX7221.wakeUp();
  MAX7221.clearAll();
  MAX7221.testOn();   delay(500);
  MAX7221.testOff();  delay(500);
  MAX7221.testOn();   delay(500);
  MAX7221.testOff();
  MAX7221.intensity(9);
  MAX7221.scanLimit();
  MAX7221.noDecodeMode();
}

void loop() {

}

Hallo,

switch case Codeduplikate sind erfolgreich entfernt. :slight_smile:
Damit geht mein Vorhaben bis jetzt auf ohne vordefinierte Pattern einen Effekt zu generieren.

combie, Vorschlag, du machst erstmal in Ruhe wenn du Zeit hast deinen "Aufbau" fertig.
Dann kann ich vergleichen und Verbesserungen übernehmen etc. Sonst geht das nur hin und her.

Es kann natürlich auch jeder andere mitreden. Logisch. :wink:

class IC
{
  private:
    const byte CLK;
    const byte CS;
    const byte MOSI;

  public:
    IC(const byte CLK, const byte CS, const byte MOSI): CLK(CLK), CS(CS), MOSI(MOSI) {}

    void init () {
      digitalWrite(CS, HIGH);
      pinMode(CS, OUTPUT);
      pinMode(CLK, OUTPUT);
      pinMode(MOSI, OUTPUT);
    }

    void transfer ( byte adresse, byte daten )
    { // 16 Bits rausschieben, MSB first
      digitalWrite(CS, LOW);
      shiftOut(MOSI, CLK, MSBFIRST, adresse);
      shiftOut(MOSI, CLK, MSBFIRST, daten);
      digitalWrite(CS, HIGH);
    }

    void wakeUp () {
      transfer(0x0C, 1);
    }

    void clearAll () {
      transfer(0x01, 0);    // Digit.0
      transfer(0x02, 0);
      transfer(0x03, 0);
      transfer(0x04, 0);    // Digit.3
    }

    void testOn () {
      transfer(0x0F, 1);
    }

    void testOff () {
      transfer(0x0F, 0);
    }

    void intensity (byte i) {
      if (i < 16) {
        transfer(0x0A, i);
      }
    }

    void scanLimit () {
      transfer(0x0B, 3);
    }

    void noDecodeMode () {
      transfer(0x09, 0);
    }
};

// ----------------------------------------------------

struct t_matrix
{
  enum seg {
    DP = 128,     // Bit.7 - Datenblatt Tabelle 6
    A  = 64,
    B  = 32,
    C  = 16,
    D  =  8,
    E  =  4,
    F  =  2,
    G  =  1       // Bit.0
  };

  enum digit {
    D0 = 0x01,
    D1 = 0x02,
    D2 = 0x03,
    D3 = 0x04
  };
};
constexpr t_matrix MATRIX;

// ----------------------------------------------------

struct t_led
{
  const byte digit;
  const byte segment;
};


const t_led LED[] = {
  {MATRIX.D0, MATRIX.A},  // LED  1
  {MATRIX.D1, MATRIX.A},
  {MATRIX.D2, MATRIX.A},
  {MATRIX.D3, MATRIX.A},
  {MATRIX.D0, MATRIX.B},  // LED  5
  {MATRIX.D1, MATRIX.B},
  {MATRIX.D2, MATRIX.B},
  {MATRIX.D3, MATRIX.B},
  {MATRIX.D0, MATRIX.C},
  {MATRIX.D1, MATRIX.C},  // LED 10
  {MATRIX.D2, MATRIX.C},
  {MATRIX.D3, MATRIX.C},
  {MATRIX.D0, MATRIX.D},
  {MATRIX.D1, MATRIX.D},
  {MATRIX.D2, MATRIX.D},  // LED 15
  {MATRIX.D3, MATRIX.D},
  {MATRIX.D0, MATRIX.E},
  {MATRIX.D1, MATRIX.E},
  {MATRIX.D2, MATRIX.E},
  {MATRIX.D3, MATRIX.E},  // LED 20
  {MATRIX.D0, MATRIX.F},
  {MATRIX.D1, MATRIX.F},
  {MATRIX.D2, MATRIX.F},
  {MATRIX.D3, MATRIX.F},
  {MATRIX.D0, MATRIX.G},  // LED 25
  {MATRIX.D1, MATRIX.G},
  {MATRIX.D2, MATRIX.G},
  {MATRIX.D3, MATRIX.G},
  {MATRIX.D0, MATRIX.DP},
  {MATRIX.D1, MATRIX.DP}, // LED 30
  {MATRIX.D2, MATRIX.DP}  // LED 31
};

const byte ANZAHL_LED = sizeof(LED) / sizeof(t_led);
// const byte ANZAHL_DIGITS = sizeof(MATRIX.digit) / sizeof(t_matrix);

IC MAX7221(24, 25, 26);     // Objekt erstellen (CLK, CS, MOSI)

void setup() {
  Serial.begin(9600);
  MAX7221.init();
  MAX7221.wakeUp();
  MAX7221.clearAll();
  MAX7221.testOn();   delay(500);
  MAX7221.testOff();  delay(500);
  MAX7221.testOn();   delay(500);
  MAX7221.testOff();
  MAX7221.intensity(9);
  MAX7221.scanLimit();
  MAX7221.noDecodeMode();
}

void loop() {

  wachsender_Bogen();
}


// ****** Funktionen ******

void wachsender_Bogen ()
{
  static unsigned long last_ms = 0;
  const unsigned int PAUSE = 100;
  static unsigned int interval = PAUSE;
  static byte index = 0;
  static byte segm_value[] = {0, 0, 0, 0};              // Segmentwert Zwischenspeicher der Digits
  const byte ANZAHL_DIGITS = sizeof(segm_value) / sizeof(segm_value[0]);

  if (millis() - last_ms < interval) return;

  last_ms = millis();

  if (index < ANZAHL_LED) {
    byte x = LED[index].digit - 1;                    // aktuelles Digit ermitteln und Indexkorrektur
    segm_value[x] += LED[index].segment;              // davon den aktuellen Segmentwert aufaddieren
    MAX7221.transfer(LED[index].digit, segm_value[x]);
  }

  ++index;

  if (index == ANZAHL_LED) {
    interval *= 10;                                     // optische Pausenkorrektur wenn Bogen vollständig
  }

  if (index > ANZAHL_LED) {
    MAX7221.clearAll();
    index = 0;
    for (byte i = 0; i < ANZAHL_DIGITS; ++i) {          // alle Segmentwerte löschen
      segm_value[i] = 0;
    }
    interval = PAUSE;
  }
}