Brauche Hilfe beim Abbilden der Registerstruktur eines am Arduino angeschlossenen ICs in C++

OP #7749909
Lesenswert?

Ich habe hier ein mit dem Arduino verbundenes IC. In dem gibt es Register, die ich lesen und schreiben kann. Jedes dieser Register hat eine Nummer (Adresse). Die Bits in den Registern haben natürlich jeweils ihre Bedeutung.

Jetzt wollte ich das in C++ abbilden. Eine Klasse, die die Gemeinsamkeiten aller Register darstellt. Dazu soll es Funktionen/Methoden geben, um den Registerwert ins IC zu schreiben und um ihn auszulesen. Denen will ich dann ein Objekt eines Erben dieser Klasse übergeben.

Von dieser Klasse müssen also andere Klassen erben.

Die Registeradresse soll öffentlich nur lesbar sein, da ja für jedes Register konstant. Sie ist bei jedem Erben anders.

Der Registerwert als Ganzes soll öffentlich les- und schreibbar sein.

Jeder Erbe soll zusätzlich noch Methoden bekommen, um einzelne Bits zu lesen und/oder zu setzen. Diese Methoden sollen nach der Bedeutung der Bits/Bitfelder im IC benannt sein. Sie lesen bzw. verändern erstmal den im Objekt gespeicherten Registerwert. Sprich man gibt, wenn nötig, vor deren Benutzung das Objekt an die Leseroutine und danach an die Schreibroutine, die ja alle Erben der Registerklasse schlucken können sollen. Diese Routinen sollen dann auf Registeradresse und Registerwert des Objekts zugreifen, um damit ihre Arbeit zu verrichten.

Erstmal hat der C++ Compiler meine Versuche ohne Warnungen oder gar Fehler geschluckt. Aber sobald ich ein Objekt eines Erben nur mal als Ahnen ablegen wollte, ging das Gemeckere los, dass er mir den Operator= gelöscht hätte, weil der ja doch nur Mist machen würde. Oder die Erben hatten die Registeradresse des Vorfahren übernommen. Wild verteilte "virtual" führten zu noch mehr Gemeckere beim Kompilieren.

1
class AS5X47_Register {
2
  public:
3
    const uint16_t addr = 0x0042U;
4
    uint16_t raw = 0U;
5
    uint16_t get_raw_value() const;
6
    void set_raw_value(uint16_t val);
7
    AS5X47_Register();
8
};
9

10
class AS5X47_Prog : public AS5X47_Register {
11
  public:
12
    const uint16_t addr = 0x0003U;
13
    uint_fast8_t get_prog_ver() const;
14
    void set_prog_ver(uint_fast8_t val);
15

16
    uint_fast8_t get_prog_otp() const;
17
    void set_prog_otp(uint_fast8_t val);
18
};

Kann mir von Euch jemand helfen, daraus gültigen und funktionierenden C++ - Code zu machen ?

(Firma: Gast) #7749933
Lesenswert?

Ich verstehe deinen Text nicht!

Vererbung: class AS5X47_Prog : public AS5X47_Register

Ist eine "Ist ein" Beziehung. Also: AS5X47_Prog ist ein AS5X47_Register Ist der Satz so logisch korrekt?

Alternativ: In C++ werden auch Schnittstellen so "vererbt" Dann: AS5X47_Prog implementiert AS5X47_Register Ist der Satz so logisch korrekt?

Wenn du beide Fragen verneinst, dann ist Vererbung der falsche Weg.

Flunder schrieb:

uint16_t raw = 0U;

Das ist ein NoGo. Öffentliche Instanzeigenschaften sollte man tunlichst vermeiden. Die Instanz kann die Gültigkeit nicht Überwachen bzw. sicherstellen.

OP #7749962
Lesenswert?

Arduino F. schrieb:

Ich verstehe deinen Text nicht!

Entschuldigung, besser habe ich es nicht hin bekommen.

Vererbung: class AS5X47_Prog : public AS5X47_Register

Ist eine "Ist ein" Beziehung. Also: AS5X47_Prog ist ein AS5X47_Register Ist der Satz so logisch korrekt?

Ja Prog ist eines der Register.

Alternativ: In C++ werden auch Schnittstellen so "vererbt" Dann: AS5X47_Prog implementiert AS5X47_Register Ist der Satz so logisch korrekt?

Eine Schnittstelle ist doch quasi eine Verpflichtung, dass meine Klasse vorgegebene Methoden/Eigenschaften implementiert ? Das hatte ich jetzt nicht gewählt, da get_raw_value() und set_raw_value() eigentlich immer gleich sind.

Wenn du beide Fragen verneinst, dann ist Vererbung der falsche Weg.

Flunder schrieb:

uint16_t raw = 0U;

Das ist ein NoGo. Öffentliche Instanzeigenschaften sollte man tunlichst vermeiden. Die Instanz kann die Gültigkeit nicht Überwachen bzw. sicherstellen.

Also auch nicht, wenn alle mit 16 Bit darstellbaren Werte an der Stelle zumindest einen Funken Sinn ergeben ? Ok, wird nervig, wenn ich im Nachhinein beim Ändern noch eine Aktion beim Schreiben oder Lesen auslösen mag. Bei Delphi und C# konnte man da mit Eigenschaften noch was kitten, aber die kennt C++ ja nicht.

OP #7749967
Lesenswert?

Oliver S. schrieb:

Nachtrag: Darüber, wie sinnvoll ein operator= oder jede andere Art von Copy operator dabei ist, braucht man eigentlich auch nicht zu diskutieren. Register und ähnliches sind üblicherweise Highlander: es kann nur einen geben...

Oliver

Meine Sicht war eher : ich habe Superhelden, nämlich Highlander, Spider Man und Dark Wing Duck. Jeden der drei gibt es nur einmal, aber ihre Gemeinsamkeiten kann ich vorher schonmal an zentraler Stelle implementieren und dann beerben.

OP #7749973
Lesenswert?

Oliver S. schrieb:

Abgesehen von der berechtigten Diskussion, ob Vererbung hier überhaupt sinnvoll ist, steckt der Knackpunkt (der auch den default operator= verhindert) hier:

const uint16_t addr = 0x0042U;

Da solltest du noch mal drüber nachdenken.

Oliver

Ok, jeder Erbe hat einen anderen aber für sich gleichbleibenden Wert an dieser Stelle. Ich habe es nicht geschafft, dass die Erben unterschiedliche Konstruktoren haben, in denen der Wert gesetzt wird.

#7750253
Lesenswert?

Flunder schrieb:

Meine Sicht war eher : ich habe Superhelden, nämlich Highlander, Spider Man und Dark Wing Duck. Jeden der drei gibt es nur einmal, aber ihre Gemeinsamkeiten kann ich vorher schonmal an zentraler Stelle implementieren und dann beerben.

Diese Sichtweise ist korrekt, und Vererbung kann durchaus angebracht sein. Dein Problem ist die Instanzierung, d. h. der Versuch mit Objekten zu arbeiten.

Dein chip hat nur genau eine Instanz dieses oder jenes Registers. Es gibt keine Kopien davon. Sehr wohl aber kann dein Programm mit verschiedenen Stände der darin enthaltenen Daten arbeiten.

Besser du baust die Vererbung / Komposition mit zumeist statischen Methoden auf. Konstruktoren aktiviert Du nur wenn es tatsächlich erforderlich ist. Neueres c++ erlaubt nontype - template - parameter, damit kannst du z.B. die Register - Adressen als unsigned int übergeben. Deine statischen ::get() / ::set() - Methoden arbeiten dann auf Instantiierungen der template (und nicht der Klasse).

#7750308
Lesenswert?

Flunder schrieb:

Jetzt wollte ich das in C++ abbilden. Eine Klasse, die die Gemeinsamkeiten aller Register darstellt. Dazu soll es Funktionen/Methoden geben, um den Registerwert ins IC zu schreiben und um ihn auszulesen. Denen will ich dann ein Objekt eines Erben dieser Klasse übergeben.

Man muss nicht alles OOP machen. Soweit ich es verstehe ist das Lesen und Schreiben von Registern immer gleich; nur die Adresse unterscheidet sich. Das sind dann halt einfach zwei Funktionen. Da braucht man keine Vererbung.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren