Nachdem ich bei der Frage nach " 1<<PA3 " gründlich abgewatscht wurde, dabei aber auch reichlich gelernt habe, trau ich mich noch ein Problem anzusprechen. Ich programmiere an einem Modellbauprojekt auf dem ArduinoMega256 in C++ unter Code::Blocks. Es gibt eine main-Routine, an der ein paar ISR dranhängen, die z.b. Ereignisse zählen (Inkremente usw.) In der main werden ein paar Klassen instanziert, z.b. die Klasse "segel", die Objekte sind dann "fock", "gross", "besan" usw.. Die Methoden darin heißen dann "bergen", "setzen" und sowas. Ich würde gerne die genannten Objekte (z.b. fock) nicht in der main, sondern in einem anderen Objekt (z.b. "mannschaft" oder so) instanzieren, um die main übersichtlicher zu machen. (Anschaulich : die main ist der Skipper, die Mannschaft sind die Matrosen, und erst die machen die Arbeit..) Mein Problem : Wenn ich ein Objekt nicht in der main, sondern in einem anderen Objekt erzeuge, kann das nicht auf die ISR-Werte aus der main zugreifen (oder andersrum). Ich hoffe, mich einigermaßen verständlich ausgedrückt zu haben. Was muß ich lernen, um das zu lösen ??
Reiner D. schrieb: > Ich hoffe, mich einigermaßen verständlich ausgedrückt zu haben. Nein. Selbst in C++ hängen ISRs nicht an main, sondern sind völlig losgelöste Funktionen. > Was muß ich lernen, um das zu lösen ?? Eine beliebige Programmiersprache. Aber zeig doch mal einen beispielhaften Code, der deine Probleme veranschaulicht. Oliver
:
Bearbeitet durch User
Schwierig, ist viel Code... Hier die letzten Zeilen der main, und der Beginn der ersten ISR. Die ISR sind in der Datei main integriert, hängen unten dran (nicht im Programmkörper von main). In der mit "#####" gekennzeichneten Zeile wird ein Attribut der Klasse "segel", instanziert im Objekt "Gross", beschrieben. Das geht so nicht, wenn die Instanzierung von Gross nicht in der main, sondern einem anderen Objekt, geschieht. Was tun ? }//ende der 10hz-task in der "while 1" -main-schleife };//ende "while 1" - schleife innerhalb main return 0; }//ende von main ******************************************************** //Hardwarebelegung : //Timer 0 : PPM-Generator (für Servo und RC-Winden) //Timer 1 : 10HZ-Generator für NPRM-Scheduler //Timer 2 : PWM-Generator (A für Maschine ) //Timer 3 : Zähler für PPM-Decoder (vom RC-Sender) //Timer 4 : PPM für Winden in Gruppen //Timer 5 : Entprellung der Inkrementgeber //UART0 : USB zum PC //UART1 : GPS ISR (PCINT0_vect) //Inkremente aus Gruppe 0 { if (int_done0 == 0) //falls das ein neuer interrupt ist { TCNT5 = 0; //Timer 5 auf Null int_done0 = 1; //merk dir, jetzt war ein signal } else { if (TCNT5 > 500) // letztes Signal länger als 32ms her ? { Gross.KlauInkrement ++ ; //############################ Besan.KlauInkrement ++ ; int_done0 = 0; } } }
Reiner D. schrieb: > Ich hoffe, mich einigermaßen verständlich ausgedrückt zu haben. leider nicht, nein. Reiner D. schrieb: > Das geht so nicht, > wenn die Instanzierung von Gross nicht in der main, sondern einem > anderen Objekt, geschieht. hä? Alle Salamischeiben liefern, bitte.
Fällt mir echt schwer, das sauber zu beschreiben. Normalerweise referenziere (instanziere) ich Objekte in der main. Deren Methoden kann ich dann aufrufen, die Attribute zugreifen. Von der Klasse "segel" gibts z.b. zwei Objekte in der main : Gross und Fock. Ich kann jetzt in der main "Gross.setzen()" aufrufen, und "Fock.setzen()" . Als Wert dafür brauche ich in "setzen" einen Inkrementzähler , der in einer ISR an der main geschrieben wird. den kann ich z.b. mit "Gross.Klauinkrement" in der ISR schreiben und in "Gross.setzen()" lesen. Alles prima. Jetzt möchte ich eine weitere Hierarchieebene einziehen, und die Segelbedienung nicht in der main machen. Ich schreibe ein Objekt "Deckshand", dass die ganze Arbeit tun soll, main setzt bloß noch wenige Befehle an Deckshand. Dazu muß ich "segel" in "deckshand" instanzieren, nicht mehr in der main. (Bildlich : der Skipper rührt die Segel nicht an, er befiehlt bloß) Aber : das Objekt "Gross", das jetzt in dem Objekt "deckshand" instaziert wurde, kann nicht auf die ISR-Variablen zugreifen ! Als, was tun (außer die Struktur ändern ;-) ??
Reiner D. schrieb: > Was tun ? Wie ich schon schrieb, eine Programmiersprachen lernen. In dem Fall C und/oder C++. Die Aufteilung von Sourcecode auf verschiedene Dateien und in Source/headerdateien sind die absoluten Basics. Die sollte man kennen. https://de.wikibooks.org/wiki/C-Programmierung:_Eigene_Header Oliver
Reiner D. schrieb: > Fällt mir echt schwer, das sauber zu beschreiben. Nö. Ist ganz einfach. Sourcecode in den Anhang. Fertig. Reiner D. schrieb: > Aber : das Objekt "Gross", das jetzt in dem Objekt "deckshand" > instaziert wurde, kann nicht auf die ISR-Variablen zugreifen ! Tut mir leid, als Prosa ist das vollkommen unverständlich. Und was das mit Objektorientierung zu tun haben soll, verstehe ich auch nicht.
In welcher Datei eine ISR liegt, spielt keine Rolle. Jedenfalls sind ISR keine C++ Methoden. Wenn ISR auf Objekte zugreifen, brauchst du Zeiger auf diese Objekte, welche für die ISR erreichbar sind. Für solche global verfügbaren Dinge benutze ich gerne eine Datei die ich global.c nenne und dazu natürlich auch eine global.h die ich dann bei Bedarf inkludieren kann.
:
Bearbeitet durch User
In C++ wird der Begriff "Methode" nicht verwendet. So etwas heißt dort Funktion, auch wenn es zu einer Klasse gehört. Reiner D. schrieb: > Normalerweise referenziere (instanziere) ich Objekte in der main. Auch hier ist die Terminologie kaputt. Eine Referenz ist etwas anderes als eine Instanz.
Ich probiers mal mit Code. Zuerst eine symbolische main : //Klassen : #include "segel.h" #include "deckshand.h" //Objekte : deckshand Matrose1; deckshand Matrose2; segel Fock; segel Gross; segel Besan; //Variablen usw. int main(void) { while(1) //endlosschleife (wie bei ner sps) { if (trigger_10hz == 1) //timergesteuerte ausführung { trigger_10hz = 0; //------Hier spielt die Musik----------------- Gross.setzen(); //Irgendwas ... //-------------------------------------------- }//ende der 10hz-task in der "while 1" -main-schleife };//ende "while 1" - schleife innerhalb main return 0; }//ende von main ISR (PCINT0_vect) //Inkremente aus Gruppe 0 { Gross.Klauinkrement ++ ; } Im Objekt "Gross" wird die Methode "setzen" aufgerufen. In Methode "setzen" wird das Attribut "Klauinkrement" benötigt. Sowohl das Objekt "Gross" als auch das Objekt "Fock" haben dieses Attribut. Beide sind aus der ISR zugreifbar, ohne sich zu überschreiben. Insgesamt soll das eine exemplarische Grundstruktur von OO sein. Danach werden Methoden durch Vererbung erzeugt usw, usw ... Wenn jetzt "segel" in "deckshand" instanziert wird statt in main : #include "segel.h" segel Grossegel; //Klasse instanzierenn-> Objekt deckshand::deckshand() //Konstruktorlauf { fockfallsollwert=0; //die Fallwinden aus grossfallsollwert=0; besanfallsollwert=0; } void deckshand::segelsetzen() { if (Klauinkrement < 600) { //irgendwas } } .. dann klappt das nicht, weil das Attribut Klaukinkrement (siehe ISR oben) natürlich nicht zugegriffen werden kann, es gibt in main ja kein Objekt "Gros" mehr. Ich bräuchte : "Matrose1.Gross.Klauinkrement" , aber das ist wohl Quatsch ;-)
Harald K. schrieb: > In C++ wird der Begriff "Methode" nicht verwendet. So etwas heißt dort > Funktion, auch wenn es zu einer Klasse gehört. > Da schau her. Zitat Wikipedia : Was ist eine Methode in C++? Methoden (englisch method oder member function) sind in der objektorientierten Programmierung Unterprogramme in der Form von Funktionen oder Prozeduren, die das Verhalten von Objekten beschreiben und implementieren. Über die Methoden des Objekts können Objekte untereinander in Verbindung treten.
Wie kann man sich Objekte und ISR gleichzeitig antun ? Aber das Konzept der Objekte wurde verstanden ? Und das Konzept der ISR wurde auch verstanden ? Objekte kapseln Code und zugehoerige Daten. Ein Objekt hat dafuer passende Code Konstrukte. Und jetzt willst du quer hinein pfuschen mit Interrupts ? Lass mal - das wird so nichts.
Wikipedia ist nicht der C++-Sprachstandard, sondern spiegelt nur das wieder, was die dortigen Texteschreiber gerade der Ansicht sind, als NPOV durchgehen zu lassen.
Reiner D. schrieb: > .. dann klappt das nicht weil dir halt so ziemlich alle Grundlagen fehlen. Schlag mal in deinem C/C++-Buch das Stichwort „extern“ nach. Oliver
Harald K. schrieb: > Auch hier ist die Terminologie kaputt. > Eine Referenz ist etwas anderes > als eine Instanz. Reiner D. schrieb: > Was ist eine Methode in C++? Oliver S. schrieb: > Schlag mal in deinem C/C++-Buch das Stichwort „extern“ nach. usw. usf. Reiner D. schrieb: > Ich hoffe, mich einigermaßen verständlich ausgedrückt zu haben. > > Was muß ich lernen, um das zu lösen ?? Für kleine 8Bitter die Programmiersprache anpassen? Sonst läuft man wie gesehen schnell in die Falle sich mehr mit Sprachbürokratien denn mit dem eigentlichen Problem herumzuschlagen. Oliver S. schrieb: > In dem Fall C oder je nach Programmumfang noch ne Stufe drunter!
:
Bearbeitet durch User
Reiner D. schrieb: > .. dann klappt das nicht, weil das Attribut Klaukinkrement (siehe ISR > oben) natürlich nicht zugegriffen werden kann, Es heißt ja auch Gross.Klauinkrement > es gibt in main ja kein > Objekt "Gros" mehr. Hä? Ja doch. Steht doch da. segel Gross; > Ich bräuchte : "Matrose1.Gross.Klauinkrement" , aber > das ist wohl Quatsch ;-) Ja. Keine Ahnung, wo jetzt der matrose1 herkommt.
Harald K. schrieb: > In C++ wird der Begriff "Methode" nicht verwendet. So etwas heißt dort > Funktion, auch wenn es zu einer Klasse gehört. Ist doch Scheiß egal. Jeder weiß, was gemeint war. Nach zig Jahren Berufserfahrung mit zahlreichen Programmiersprachen hat man andere Probleme als solche albernen Eitelkeiten.
:
Bearbeitet durch User
> Was muß ich lernen, um das zu lösen ?? Klingt der Funktion nach nach einem Task/process-Scheduler. Der Linus hat mal zwischen Januar und september1991 einen solchen für x386 geschrieben und später zum Linux-Kernel erweitert. Nachlesbar im Link wie im Anhang gezeigt, die direkte Wiedergabe des Links wird von der Forumssoftware blockiert. Seufz .... https://de?.to/satorutakeuchi/a-brief-history-of-the-linux-kernel-s-process-scheduler-the-very-first-scheduler-v0-01-9e4 ? durch v ersetzen
Jetzt kam ein Haufen. Ja, das ist ein Scheduler (wenn wir das gleiche meinen). Aber non-premptive, um sich den ganzen Quatsch mit Deadlock, Race und so zu ersparen. NPRM im Klartext. Globale Variable (extern ?) sind möglicherweise nicht zielführend, weil ich dann ja für die Attribut eines jeden neuen Objekts neue Variablen brauche. Aber es geht natürlich. Ich denke bloß, da muß es im Konzept eine elegantere Methode geben. Konzeptuell müßte bei der Instanzierung (nicht Referenzierung, sorry) des Objekts irgendwo eine globale Variablenerzeugung möglich sein. Ich sehe auch nicht, wie das mit einem Zeiger geht, wenn wie hier mehrere Objekte die im "Orginal" (der Klasse) gleichen Attribute hat. Aber hier weiß ich sicher viel zu wenig über Zeiger in C. Ist aber anders formuliert eigentlich meine Frage : Wie kann ich im OO-Konzept Objektattribute so erzeugen (instanzieren), daß sie von überall (global) zugreifbar sind ?
Reiner D. schrieb: > Konzeptuell müßte bei der Instanzierung (nicht Referenzierung, sorry) > des Objekts irgendwo eine globale Variablenerzeugung möglich sein. > Wie kann ich im OO-Konzept Objektattribute so erzeugen (instanzieren), > daß sie von überall (global) zugreifbar sind ? Kann es sein, dass du gar nicht so richtig weißt, was diese Fachbegriffe alle bedeuten? Ich verstehe jedenfalls nur Bahnhof und diese Aneinanderreihung der Begriffe ergibt für mich wenig Sinn. Zeig doch einfach einmal ein einfaches(!) minimales(!) Stück Code, was dein Problem zeigt.
Was ist daran so schwer zu verstehen ? Ich möchte bei Erzeugen eines Objekts eine "Variable" (besser ein "Attribut", wenn die Zahl der Erbsen eine Rolle spielt) generieren, die die Eigenschaften einer globalen hat. Bitte jetzt keine Diskussion über das alte public/private Spiel.. Wenn "extern" das kann, wäre einer so lieb, mir ein Stück Beispielcode zu zeigen ?
Reiner D. schrieb: > Ich möchte bei Erzeugen eines Objekts eine "Variable" (besser ein > "Attribut", wenn die Zahl der Erbsen eine Rolle spielt) generieren Dein Text ergibt überhaupt gar keinen Sinn. Das ist das Problem. Was ist "das Erzeugen eines Objekts"? Ist es der Aufruf des Konstruktors? Was meinst du mit "Attribut"? Was ist "generieren"? Warum setzt du "Variable" in Anführungszeichen. Meinst du was anderes?
:
Bearbeitet durch User
Bei der Instanzierung des Objektes wird die Variable erzeugt. Dann muss man ihr nur noch einen Wert zuweisen.
Eventuell die u.g. Links lesen und verstehen. War nur ein schnelle Suche um Dir die Stichwörter zu präsentieren. https://stackoverflow.com/questions/3698043/static-variables-in-c https://stackoverflow.com/questions/20362973/static-functions-in-c https://stackoverflow.com/questions/5980520/define-static-method-in-source-file-with-declaration-in-header-file-in-c https://stackoverflow.com/questions/23572680/in-c-how-to-friend-a-static-function-from-another-class Viel Erfolg Markus
Folgende Situation, selbst erlebt : Ein promovierter Jurist frägt den Ingenieur nach einem Vortrag. "Was ist denn ein Operationsverstärker ? ". Darauf die Antwort (nicht erfunden !!) : "Stellen sie sich einfach einen LM324 vor". Wer's im Kontext lustig findet, möge lachen ;-)
Purzel H. schrieb: > Bei der Instanzierung des Objektes wird die Variable erzeugt. Dann muss > man ihr nur noch einen Wert zuweisen. Was ggf. der Konstruktor tut. Und weil sie in OO eine spezielle Charakteristik hat, wird sie Attribut genannt, um sie von der klassischen Variablen abzuheben. Aber : darum gehts überhaupt nicht. Ich will hier keine Wortkunde betreiben ...
@Markus W. Ein Traum. Jede Kritik, warum ich zu blöd war, sowas selber zu finden, nehme ich bereitwillig an. Vielen Dank !
Reiner D. schrieb: > Aber : darum gehts überhaupt nicht. > Ich will hier keine Wortkunde betreiben ... Wenn man verstanden werden will, muss man eine gemeinsame Sprache sprechen.
So geht das
1 | #include <iostream> |
2 | using namespace std; |
3 | |
4 | int* globalerZeiger; |
5 | |
6 | class Schiff { |
7 | int geschwindigkeit; |
8 | |
9 | public:
|
10 | Schiff() { |
11 | globalerZeiger = &geschwindigkeit; |
12 | }
|
13 | |
14 | ~Schiff() { |
15 | globalerZeiger = nullptr; |
16 | }
|
17 | |
18 | int getGeschwindigkeit() { |
19 | return geschwindigkeit; |
20 | }
|
21 | };
|
22 | |
23 | int main() { |
24 | Schiff einSchiff; |
25 | *globalerZeiger = 99; |
26 | cout << "Geschwindigkeit:" << einSchiff.getGeschwindigkeit() << endl; |
27 | }
|
Stefan F. schrieb: > int* globalerZeiger; > class Schiff { > int geschwindigkeit; > > public: > Schiff() { > globalerZeiger = &geschwindigkeit; Das ist ja schon fast Körperverletzung. Es gibt keinen einzigen Grund und keine Entschuldigung so etwas zu tun.
Die static-Deklaration ist es wohl nicht, siehe : "Static variable in a class: Static variable in a class is not a part of the subobject of the class. There is only one copy of a static data member shared by all the objects of the class." Also das friend-Konzept. Ich dachte bisher, das wär was für Functions in namespaces, und mit solchen Dingen hab ich auf den kleinen uP nie zu tun gehabt. Liege ich richtig, wenn ich vermute, daß ein friend-Konstrukt den Zugriff aus einem Objekt auf ein Attribut eines anderen Objekts zuläßt (alles public, oder ?) ? ..Viel zu tun.
Reiner D. schrieb: > Folgende Situation, selbst erlebt : > > Ein promovierter Jurist frägt den Ingenieur nach einem Vortrag. "Was ist > denn ein Operationsverstärker ? ". Eben, der Juristen formuliert eine trollig falsch formulierte Frage und bekommt denoch eine korrekte Anwort. Hätte der Jursit statt der Frage "Was ist ein Operationsverstärker", die mit der Nennung der Typbezeichnung völlig korrekt beantwortet ist, gebeten "Bitte erklären Sie mir als elektronisch Ungebildeten die Aufgabe und Funktion eines Operationsverstärkers" hätte er mehr Erfolg gehabt. Aber wer gibt schon zu, da er zu doof für das Thema "Elektronik" ist. > Wer's im Kontext lustig findet, möge lachen ;-) Das finden nur Kinder die bespasst werden müßen, lustig. Dist Du so eins?
MaWin O. schrieb: > Das ist ja schon fast Körperverletzung. :-) Er hat bekommen, wonach er gefragt hat.
MaWin O. schrieb: > Es gibt keinen einzigen Grund und keine Entschuldigung so etwas zu tun. Manche sind halt Masochisten und fordern für sich das Rechtein, sich ins eigen Knie zu schiessen ...
MaWin O. schrieb: > Das ist ja schon fast Körperverletzung. > Es gibt keinen einzigen Grund und keine Entschuldigung so etwas zu tun. Jetzt kannst du einen besseren Vorschlag machen, wo eine ISR in C die Geschwindigkeit des Schiffes ändert. Denn ich denke, darauf will der TO hinaus.
@ Stefan F. Ich brauche ne Weile, um deinen Code zu verstehen, sorry. Mein Syntaxvorrat reicht immer genau so weit wie ich zur Lösung von irgendwas brauche, ich hatte nie systematisch C gelernt. (Merkt man ja ;-). Wenn ichs richtig interpretiere, wird statt des Attributs eine indirekte Adressierung ausgeführt, also ein Pointer benutzt, wie das in C wohl heißt. Legt der Compiler dann da ne Liste an, welche Adresspeicher (Pointer) zu welchem Objekt gehören ?
Reiner D. schrieb: > Liege ich richtig, wenn ich vermute, daß ein friend-Konstrukt > den Zugriff aus einem Objekt auf ein Attribut eines anderen Objekts > zuläßt (alles public, oder ?) Ja. Aber eben fordertest du noch: Reiner D. schrieb: > Bitte jetzt keine Diskussion über > das alte public/private Spiel.. Stefan F. schrieb: > Jetzt kannst du einen besseren Vorschlag machen, wo eine ISR in C die > Geschwindigkeit des Schiffes ändert. Denn ich denke, darauf will der TO > hinaus.
1 | ISR() |
2 | {
|
3 | schiff.schneller(10); |
4 | }
|
Man braucht weder einen Zeiger auf schiff.geschwindigkeit, noch braucht man von außen direkt auf schiff.geschwindigkeit zuzugreifen.
Reiner D. schrieb: > Syntaxvorrat Dein was? Schon wieder ein Wort falsch verwendet? > ich hatte nie systematisch C gelernt. (Merkt man ja ;-). Allerdings. Aber das kannst du ja ändern. Reiner D. schrieb: > wird statt des Attributs Das ist kein Attribut. Das ist eine Member-Variable. Ein Attribut ist in C++ etwas anderes. https://en.cppreference.com/w/cpp/language/attributes Du verwendest ständig Worte falsch. Und deshalb versteht dich niemand. Reiner D. schrieb: > Legt der Compiler dann da ne Liste an, welche Adresspeicher (Pointer) zu > welchem Objekt gehören ? hä? Wozu soll eine Liste benötigt werden? Wozu sollte das gut sein?
Nur zur Erklärung : Nein, hat nix mit Schiffsgeschwindigkeiten oder ähnlichem zu tun. Im Kern geht's um Hierarchisierung von Funktionen. Ich schreibs nochmal als "Prosa", Modellierung ist ja auch ein Bestandteil von OO. Oberste Ebene : "main" (im Modell : Der Käptn') erste drunter : Objekte der Klasse "deckshand" : "matrose1", "matrose2" matrose1 ist eine Instanz von deckshand, die in main instanziert wurde. Voteile : wenn man neue Funktionen will, wird ein neuer matrose instanziert. Methoden von deckshand können vererbt usw. werden. wieder drunter : Objekte der Klasse "segel". Die werden jetzt in den Matrosen instanziert. Vorteile wie üblich in OO. z.b "fock" oder "gross". so, jetzt kann ich in "matrose1" die methode "fock.setzen()" aufrufen. -> Ich will aber in main auf Attribute von "fock" in "matrose" zugreifen !
Reiner D. schrieb: > -> Ich will aber in main auf Attribute von "fock" in "matrose" zugreifen Dann mache das doch. Sehe das Problem nicht.
1 | int main() { |
2 | |
3 | matrose1.fock.setzen(); |
4 | }
|
Reiner D. schrieb: > Legt der Compiler dann da ne Liste an, welche Adresspeicher (Pointer) zu > welchem Objekt gehören ? Mein Beispiel funktioniert nur mit einer Instanz des Schiffes. Der MaWin O. hat meinen obigen Vorschlag zu Recht kritisiert. Denn der Sinn von Objekten ist, dass sie ihre Daten Kapseln. Man sollte niemals von außen direkt auf die Attribute der Objekte zugreifen, schon gar nicht über Zeiger an der Programmiersprache vorbei. Man kann aber die Instanzen der Objekte global erreichbar machen. Zum Beispiel so:
1 | #include <iostream> |
2 | using namespace std; |
3 | |
4 | class Schiff { |
5 | int geschwindigkeit; |
6 | |
7 | public:
|
8 | int getGeschwindigkeit() { |
9 | return geschwindigkeit; |
10 | }
|
11 | |
12 | void setGeschwindigkeit(int i) { |
13 | geschwindigkeit = i; |
14 | }
|
15 | |
16 | void changeGeschwindigkeit(int i) { |
17 | geschwindigkeit += i; |
18 | }
|
19 | };
|
20 | |
21 | Schiff* schiffe[20]; |
22 | |
23 | // Bei Interrupt wird das erste Schiff verlangsamt
|
24 | void isr() { |
25 | schiffe[0]->changeGeschwindigkeit(-1); |
26 | }
|
27 | |
28 | int main() { |
29 | // Erzeuge drei Schiffe
|
30 | schiffe[0] = new Schiff(); |
31 | schiffe[1] = new Schiff(); |
32 | schiffe[2] = new Schiff(); |
33 | |
34 | // Alle drei Schiffe sind unterwegs
|
35 | schiffe[0]->setGeschwindigkeit(99); |
36 | schiffe[1]->setGeschwindigkeit(99); |
37 | schiffe[2]->setGeschwindigkeit(99); |
38 | |
39 | // Interrupt simulieren
|
40 | isr(); |
41 | |
42 | cout << "Geschwindigkeit erstes Schiff:" << schiffe[0]->getGeschwindigkeit() << endl; |
43 | cout << "Geschwindigkeit zweites Schiff:" << schiffe[1]->getGeschwindigkeit() << endl; |
44 | cout << "Geschwindigkeit drittes Schiff:" << schiffe[2]->getGeschwindigkeit() << endl; |
45 | }
|
Reiner D. schrieb: > Ich bräuchte : "Matrose1.Gross.Klauinkrement" , aber das ist wohl > Quatsch ;-) Nein, genau so geht es. LG, Sebastian
Beitrag #7384370 wurde vom Autor gelöscht.
Stefan F. schrieb: > // Erzeuge drei Schiffe > schiffe[0] = new Schiff(); > schiffe[1] = new Schiff(); > schiffe[2] = new Schiff(); Ich sollte dazu noch etwas ergänzen: Diese Zeilen müssen nicht in der main stehen. Du kannst wie gewünscht ein Schiffsbauer-Objekt programmieren, dass die Schiffe baut (mit new erzeugt) und dem Array zuweist. Anstelle des Arrays könntest du auch drei einzelne globale Variablen verwenden, wenn dir das lieber ist. Aber auf jeden Fall müssen die Zeiger oder die Referenzen auf auf die Schiffe global sein, sonst kommst du innerhalb deiner ISR nicht heran.
:
Bearbeitet durch User
Was lange währt, wird endlich gut. Natürlich lag es an meiner unpräzisen Beschreibung meines Problems. Ich dachte nur, meine Syntaxerfindung : "Matrose1.Gross.Klauinkrement" wäre ein frommer Wunsch. Daß das in C++ geht, ist überraschend.
Reiner D. schrieb: > Was lange währt, wird endlich gut. > Natürlich lag es an meiner unpräzisen Beschreibung meines Problems. > > Ich dachte nur, meine Syntaxerfindung : "Matrose1.Gross.Klauinkrement" > wäre ein frommer Wunsch. Daß das in C++ geht, ist überraschend.
1 | Schiff erstesSchiff; |
2 | Schiff* zeigerAufZweitesSchiff; |
3 | |
4 | int main() { |
5 | zeigerAufZweitesSchiff = new Schiff(); |
6 | |
7 | cout << "Geschwindigkeit erstes Schiff:" << erstesSchiff.getGeschwindigkeit() << endl; |
8 | cout << "Geschwindigkeit erstes Schiff:" << zeigerAufZweitesSchiff->getGeschwindigkeit() << endl; |
9 | }
|
Oder wenn Geschwindigkeit public ist:
1 | Schiff erstesSchiff; |
2 | Schiff* zeigerAufZweitesSchiff; |
3 | |
4 | int main() { |
5 | zeigerAufZweitesSchiff = new Schiff(); |
6 | |
7 | cout << "Geschwindigkeit erstes Schiff:" << erstesSchiff.geschwindigkeit << endl; |
8 | cout << "Geschwindigkeit erstes Schiff:" << zeigerAufZweitesSchiff->geschwindigkeit << endl; |
9 | }
|
Du benutzt "." um direkt auf Eigenschaften deiner Objekte zuzugreifen. Bei Zeigern auf Objekte benutzt du hingegen "->".
:
Bearbeitet durch User
Beitrag #7384388 wurde vom Autor gelöscht.
Reiner D. schrieb: > Ich dachte nur, meine Syntaxerfindung : "Matrose1.Gross.Klauinkrement" > wäre ein frommer Wunsch. Daß das in C++ geht, ist überraschend. Sauber ist es trotzdem nicht, weil es die Kapselung durchbricht. Solche Konstrukte zeigen in der Regel einen Fehler in der Architektur auf.
Reiner D. schrieb: > Ich brauche ne Weile, um deinen Code zu verstehen, sorry. Mein > Syntaxvorrat reicht immer genau so weit wie ich zur Lösung von irgendwas > brauche, ich hatte nie systematisch C gelernt. Du meinst C++. Vielleicht hilft dir mein Tutorial http://stefanfrings.de/qt_lernen/index.html Deine folgenden Fragen beziehen sich auf meinen (fragwürdigen) Vorschlag:
1 | int* globalerZeiger; |
2 | |
3 | class Schiff { |
4 | int geschwindigkeit; |
5 | |
6 | public:
|
7 | Schiff() { |
8 | globalerZeiger = &geschwindigkeit; |
9 | }
|
10 | }
|
11 | |
12 | *globalerZeiger = 99 |
> Wenn ichs richtig interpretiere, wird statt des Attributs eine indirekte > Adressierung ausgeführt, also ein Pointer benutzt Ja, in meinem Vorschlag ist int* ein Zeiger auf eine Integer Variable. Und &geschwindigkeit ist die Adresse der Geschwindigkeit im RAM. > Legt der Compiler dann da ne Liste an, welche Adresspeicher (Pointer) zu > welchem Objekt gehören ? Der Zeiger hat initial den Wert 0, was allgemein als "zeigt nirgendwo hin" interpretiert wird. Der Konstruktor des Schiffes setzt den Zeiger auf die Adresse seiner Geschwindigkeits-Variable. Erst nach Ausführung des Konstruktors kann man über den Zeiger auf den Speicher der Variable im RAM zugreifen. Die letzte Zeile im obigen Code-Fragment heißt: Setze den Speicher auf den der Zeiger zeigt, auf den Wert 99. Dadurch wird effektiv die Variable geschwindigkeit von dem Schiff geändert, weil sie sich genau dort im Speicher befindet, wo der Zeiger hin zeigt. Unsauber ist daran, dass ich dadurch eine eigentlich private Eigenschaft des Objektes global zugänglich gemacht habe, und zwar nicht nur für lesende Zugriffe, sondern auch noch für schreibende.
:
Bearbeitet durch User
So Singletons sind meistens unschön. Und wenn schon mit C++ abstrahiert werden soll, dann würde ich die Methodenaufrufe auch nicht direkt in der ISR machen. Schöner geht das z.B. mit einer EventQueue die auch zyklische Aufrufe erlaubt. Ein instantiiertes Objekt kann sich dann selber in die Queue eintragen. Methodenaufrufe sind nur etwas tricky, die callbacks brauchen den this pointer und die Adresse der Funktion.
J. S. schrieb: > Schöner geht das z.B. mit einer EventQueue die auch zyklische Aufrufe > erlaubt. Ein instantiiertes Objekt kann sich dann selber in die Queue > eintragen. Methodenaufrufe sind nur etwas tricky, die callbacks brauchen > den this pointer und die Adresse der Funktion. Die Sprachkenntnisse des TO liegen irgendwo zwischen Frühgeburt und Analphabet. Da ist dein Vorschlag vielleicht doch etwas verfrüht. Oliver
Rainer D. :
> Legt der Compiler dann da ne Liste an, welche Adresspeicher (Pointer) zu
welchem Objekt gehören ?
Es ist viel einfacher. Dein Objektname ist schon der Pointer auf das
Objekt.
Hmm, na ja, es werden viele Sachen hier durchmischt, glaube ich. Worum es geht, soweit ich das nachvollziehen kann, ist es, dass der OP ein Objektmodell erzeugen möchte, welches ein Schiffsmodell mit verschiedenen Szenarien beschreibt. Ein Objekt hat ja grundsätzlich eine Lebenszeit, startend beim Konstruktor und endend beim Destruktor - solange das Objekt 'lebt', hat es Zustand (Membervariablen), deren Inhalt sich im Laufe der Lebenszeit ändern kann. Diese 'Member' sind üblicherweise private und sollten nur über definierte Memberfunktionen/Methoden verändert werden. So die die Theorie. Singletons bzw. statische Klassen sind im Prinzip ja genau dasselbe, nur dass es eben bloß 1 Exemplar dieser Klasse zur Laufzeit (=1 Objekt) gibt. Ändert fürs Objektmodell eigentlich nicht viel. Wenn du ein Objekt anlegst/instanziierst, kann das so aussehen, wie Stefan F. das beschrieben hat, mit dem new-Operator instanziiert. Ne andere Variante wäre einfach:
1 | class Segel |
2 | { |
3 | public: |
4 | enum class Status |
5 | { |
6 | Gerefft = 0, |
7 | VollesSegel |
8 | }; |
9 | |
10 | void setzen(enum class Status state ) |
11 | { |
12 | if(m_status != state) |
13 | { |
14 | m_status = state; |
15 | //... auf aenderung etwas ausloesen |
16 | } |
17 | } |
18 | |
19 | |
20 | private: |
21 | Status m_status; |
22 | }; |
23 | |
24 | class Kapitaen |
25 | { |
26 | int m_flaschenGrogIntus = 0; |
27 | public: |
28 | |
29 | void auftanken() |
30 | { |
31 | ++m_flaschenGrogIntus; |
32 | } |
33 | |
34 | void ablassen() |
35 | { |
36 | if(m_flaschenGrogIntus>0) |
37 | { |
38 | --m_flaschenGrogIntus; |
39 | } |
40 | } |
41 | |
42 | }; |
43 | |
44 | class Schiff |
45 | { |
46 | Segel m_segel; |
47 | Kapitaen m_kapitaen; |
48 | |
49 | public: |
50 | |
51 | Schiff() |
52 | {} |
53 | |
54 | void volleFahrt() |
55 | { |
56 | m_segel.setzen(Segel::VollesSegel); |
57 | m_kapitaen.auftanken(); |
58 | } |
59 | |
60 | void angreifen(Schiff & gegner) |
61 | { |
62 | gegner.bumm(); |
63 | } |
64 | |
65 | void bumm() |
66 | { |
67 | m_kapitaen.auftanken(); |
68 | m_kapitaen.auftanken(); |
69 | //untergehen |
70 | } |
71 | }; |
72 | |
73 | int main() |
74 | { |
75 | Schiff seaMonkey; |
76 | Schiff leChuckSchiff; |
77 | seaMonkey.volleFahrt(); |
78 | seaMonkey.angreifen(leChuckSchiff); |
79 | } |
Legst du eine Instanz vom Schiff an (seaMonkey), wird der Konstruktor aufgerufen. Bei der schließenden Klammer } fliegt das Objekt aus dem Scope, die Lebenszeit ist vorbei - der Destruktor wird aufgerufen. Dazwischen kannste Methoden der Klasse aufrufen, wie z.B. volleFahrt, wobei auch gleich der Käptn mitgetankt wird. In erster Linie erzeugst du hierarchische Abbildung durch Komposition - quasi das große ist die Summe der Teile - im Beispiel enthält das Schiff einen Käptn und ein Segel. Heißt - erzeugst du ein Schiff, wird Segel und Käptn mit erzeugt. Man kann auch Aggregation machen, dann können die Teile auch länger leben als das Schiff. Mal grob als Idee, hilfreich zum Verständnis sind vielleicht UML Objektdiagramme oder auch ein E/R-Modell.
So mal abseits der Programmierkenntnisse würde ich darauf tippen, das einfach die verschiedene Sichtweisen zu Problemen führen. Reiner D. schrieb: > Oberste Ebene : "main" (im Modell : Der Käptn') Das ist nämlich der komplett falsche Ansatz um deine Objekte zu betrachten. Die main.c (oder main.cpp) ist deine Welt in der du dich bewegst. In der main.h(pp) musst du alles benennen (nicht definieren) was in der Welt existieren soll. Dabei musst du es nicht unmittelbar machen. Du kannst mit einem #include auch andere Sammlungen von Benennungen, aka andere Headerdateien einbinden. Deine main.c sollte dann auch nur die Geschehnisse deiner Welt beschreiben. Also wie sie entsteht, dass passiert in der main-Funktion und was sie so macht, das sind die Interruptroutinen. Da deine Welt über die Header weiß was es alles auf ihr gibt solltest du auch darauf zu greifen können. Wenn es richtig von Grundauf OO ist, dann in der Art Schiff.GetMatrose(Kapitän).GebBefehlAn(Steuermann) Wie viele schon geschrieben habe, mache die mit den Konzepten betraut und male dir einen Bauplan auf ein Stück Papier. ### Nebenfrage: welches main meinst du wieder. Du selber schreibst weiter oben das es ja main-Funktion und main.h gibt Die beiden hängen nicht wirklich systematisch zusammen ###
Falk S. schrieb: > Mal grob als Idee, hilfreich zum Verständnis sind vielleicht UML > Objektdiagramme oder auch ein E/R-Modell. Danke !
@Jens : Syntax ist mir egal, mich interessiert nur das Konzeptuelle. "Die main.c (oder main.cpp) ist deine Welt in der du dich bewegst. In der main.h(pp) musst du alles benennen (nicht definieren) was in der Welt existieren soll." In Code::Blocks Projekten gibts gar keine main.h Ich wollte so modellieren wie im Wordbild dargestellt. Die main.cpp ist bei mir das Deck meines Schiffes, auf dem alle Akteure kommunizieren. Sie sind in der #include - Liste mit ihren .h aufgeführt (quasi meine Decksrolle, Besatzungsliste). Die Objekte gliedern das Konzept sehr schön, man könnte die Arbeit auch gut verteilen, wenn die Schnittstellen sauber definiert sind. Käptn gibt Befehle an Matrosen, die haben Elemente des Schiffs (Segel, Ruder, Maschine, Navigationsraum...), dort steht die Hardware (Winden, Motor, GPS...). Leider ist ein Teil der Messtechnik (z.b. die Inkrementgeber der Winden) in ISR (geht wegen Timing nicht anders). Und die ISR sind hier auf main-Ebene. Der Pfeil von ISR zur class segel (eigentlich besser zum Objekt Fock z.B.) ist mein Problem. Aber ich denke mit den Zeigern von Stefan F. wird das. Konzept schlecht ? (sind ja wohl verschiedene Ansätze möglich...)
Reiner D. schrieb: > an Matrosen, die haben Elemente des Schiffs (Segel, > Ruder, Maschine, Navigationsraum...) Ich finde es äußerst bizarr, dass du eine Komposition von Matrosen und Schiffselementen machst. Ein natürlicheres Modell wäre eine Komposition aus Schiff + Schiffsteile und eine weitere Komposition der Besatzung. Die Besatzung würde dann per (kurzlebiger) Referenzen auf die Schiffsteile einwirken. Reiner D. schrieb: > Aber ich denke mit den Zeigern von Stefan F. wird das. In modernem C++ arbeitet man auch gutem Grund praktisch nie mit Zeigern.
MaWin O. schrieb: > In modernem C++ arbeitet man auch gutem Grund praktisch nie mit Zeigern. In C++ gibt es auch keine Interrupthandler. Da stoßen zwei Welten aneinander, die man ganz ohne Regelbruch nicht zusammen kriegt.
Der Käptn "bedient" den Matrosen Der Matrose1 bedient die Fock Der Matrose2 bedient das Gross Der Matrose3 bedient den Besan (wobei die Methoden leicht differieren) Modellgrundlage ist, wer mit was arbeitet
Stefan F. schrieb: >> In modernem C++ arbeitet man auch gutem Grund praktisch nie mit Zeigern. > > In C++ gibt es auch keine Interrupthandler. Da stoßen zwei Welten > aneinander, die man ganz ohne Regelbruch nicht zusammen kriegt. Und wieso sollte man dort zwingend Rohzeiger brauchen?
Reiner D. schrieb: > Modellgrundlage ist, wer mit was arbeitet Ja. Das ist meiner Ansicht nach ein schlechtes Modell. Komposition sollte IMO eher durch physikalische Zusammenhänge gebildet werden und "arbeitet mit" sollte mit Referenzen gebildet werden. Der Vorteil ist, dass man so sehr viel flexibler ist. Was, wenn ein Matrose mal das Deck schrubben soll? Was, wenn das immer ein anderer Matrose sein soll, weil die Drecksarbeit geteilt wird? Mit einer Komposition ist das nicht abbildbar.
Stefan F. schrieb: > In C++ gibt es auch keine Interrupthandler. Da stoßen zwei Welten > aneinander, die man ganz ohne Regelbruch nicht zusammen kriegt. In C gibts die auch nicht. Die gibt es halt nur im realen Leben, als Notbehelf. Oliver
@MaWin : Nochmal für C++ - Analphabeten : "schrubben" als Methode in die deckshand-class zu schreiben ist Mist, oder ? (so daß jeder Matrose das kann) Also "schrubben" quasi als "subroutine" (wenns das in C++ noch gibt), und aufrufen wenn gebraucht (=Referenz ?)
Dem Schiff ist doch egal wer die Winde oder Ruder bedient. Für eine Rechts oder Linkskurve muss ein bestimmter Ablauf eingehalten werden. Ich würde auch die Schiffskomponenten als Objekte sehen.
Reiner D. schrieb: > "schrubben" als Methode in die deckshand-class zu schreiben ist Mist, > oder ? > (so daß jeder Matrose das kann) Mal als Konzeptbeispiel:
1 | class Deck { ... }; |
2 | |
3 | class Matrose { |
4 | ...
|
5 | void schrubbe(deck &Deck) { |
6 | ...
|
7 | }
|
8 | };
|
9 | |
10 | int main() { |
11 | Deck deck; |
12 | Matrose matrose1; |
13 | Matrose matrose2; |
14 | |
15 | if (/* Montag */) { |
16 | matrose1.schrubbe(deck); |
17 | } else { |
18 | matrose2.schrubbe(deck); |
19 | }
|
20 | }
|
Tippfehler sind absichtlich ;)
J. S. schrieb: > Für eine > Rechts oder Linkskurve muss ein bestimmter Ablauf eingehalten werden. Bei meinem Schiffchen : Der Käptn will (z.b. wenn der Sender ausfällt, oder ich das Schiff nicht mehr sehe) per Autopilot irgendwohin (oder nach home). Er frägt den Navigator nach dem Zielkurs, Navigator liest GPS, rechnet PID und kriegt Zielkurs raus. Er befiehlt dem Rudergänger den Zielwinkel, der liest den Kompass, PID für Sollwinkel. Daneben befiehlt der Käptn den Matrosen1 bis 3 ihre jeweiligen Segel zu bergen, und dem Maschinisten, den Motor zu starten.
MaWin O. schrieb: > class Matrose { > ... > void schrubbe(deck &Deck) { > ... > } So hab ich das gedacht. z.b. hat jedes Objekt von segel eine Methode "fall_hoch", mit der es per geregelter Winde das Segelchen ein gewünschtes Stück hochziehen kann. ok ?
Reiner D. schrieb: > Ist AVR-GCC kein C++ ? Die AVR GNU Compiler Collection ist ein Set aus mehreren Compilern, unter anderem (hier relevant) der zu C kompatible C++ Compiler mit Spezieller Unterstützung für AVR Mikrocontroller. Interrupthandler sind im Sprachumfang vom C++ Standard nicht vorgesehen. In C sind sie auch nicht vorgesehen, daher die Mikrocontroller spezifische Erweiterung. Eine Objekt-Funktion (Methode) kann deswegen nicht als Interrupthandler dienen, weil die Interrupt-Vektoren des AVR Mikrocontrollers a) nur auf Funktionen, nicht auf Objekte zeigen kann. Die Tabelle müsste für jedes Objekt zwei Zeiger enthalten (Funktion und Daten (this)). b) schreibgeschützt ist. Objekte, die erst zur Laufzeit erzeugt werden, können sich nicht in die Interrupt-Vektoren eintragen. MaWin O. schrieb: > In modernem C++ arbeitet man auch gutem Grund praktisch nie mit Zeigern. Dazu habe ich eine ernst gemeinte Frage: Referenzen sind technisch gesehen auch Pointer, haben lediglich eine andere Syntax. Wie erzeugst du Objekt-Instanzen zur Laufzeit, ohne new und ohne Referenzen/Pointer?
:
Bearbeitet durch User
Stefan F. schrieb: > Dazu habe ich eine ernst gemeinte Frage: Referenzen sind technisch > gesehen auch Pointer, haben lediglich eine andere Syntax. Nein. Das ist nicht nur eine andere Syntax. In C++ gibt es viele verschiedene Arten Objekte zu referenzieren. Klassische Referenzen und auch verschiedene Smartpointer. Mit Rohzeigern haben die alle eigentlich nichts zu tun. Aber ich würde auch behaupten, dass man für eine ISR weder Rohzeiger, noch Referenzen, noch Smartpointer braucht. Man kann doch ganz einfach ganz normal auf statisch alloziierte globale Ressourcen zugreifen. Stefan F. schrieb: > Wie erzeugst > du Objekt-Instanzen zur Laufzeit, ohne new und ohne > Referenzen/Pointer? Einfach auf dem Stack?
Stefan F. schrieb: > Die AVR GNU Compiler Collection ist ein Set aus mehreren Compilern, > unter anderem (hier relevant) der zu C kompatible C++ Compiler mit > Spezieller Unterstützung für AVR Mikrocontroller. Was genau soll ein „zu C kompatibler C++ Compiler“ sein? Der erste April war gestern. Die AVR-gcc-toolchain kommt, wie jeder gcc, mit einem C- und einem C++ -Compiler. Der eine spricht nur vollwertiges C, der andere nur vollwertiges C++. „Kompatibel“ ist das nur in so weit, wie C und C++ gemeinsame Sprachkonstrukte haben. Oliver
:
Bearbeitet durch User
Stefan F. schrieb: > Eine Objekt-Funktion (Methode) kann deswegen nicht als Interrupthandler > dienen, weil die Interrupt-Vektoren des AVR Mikrocontrollers Richtig. Nicht direkt. Aber:
1 | class MyClass { |
2 | void handle_irq() { |
3 | ...
|
4 | }
|
5 | }
|
6 | |
7 | MyClass myclass; |
8 | |
9 | ISR() { |
10 | myclass.handle_irq(); |
11 | }
|
> b) schreibgeschützt ist. Objekte, die erst zur Laufzeit erzeugt werden, > können sich nicht in die Interrupt-Vektoren eintragen. Da könnte man Smartpointer verwenden. Aber auf AVR8 ist es wohl eher generell eine schlechte Idee dynamische Objekte anzulegen. Nicht nur in C++. ;)
MaWin O. schrieb: > Aber ich würde auch behaupten, dass man für eine ISR weder Rohzeiger, > noch Referenzen, noch Smartpointer braucht. Man kann doch ganz einfach > ganz normal auf statisch alloziierte globale Ressourcen zugreifen. Kommt drauf an, was man machen will. Der TO möchte, dass die ISR Eigenschaften seiner Objekt-Instanzen ändert. > Wie erzeugst du Objekt-Instanzen zur Laufzeit, ohne new und ohne > Referenzen/Pointer? Einfach auf dem Stack? Der Stack verliert beim Verlassen einer Funktion seine Gültigkeit. Mit der Beschränkung verlierst du die Möglichkeit, Objekte innerhalb von Funktionen zu erzeugen und danach außerhalb dieser zu benutzen. Früher oder später brauchst du das aber. Der TO braucht es. Seine ISR soll auf Objekte zugreifen, die innerhalb einer Objekt-Funktion (Methode) erzeugt wurden. > Aber auf AVR8 ist es wohl eher generell eine schlechte > Idee dynamische Objekte anzulegen. Ich möchte es nicht generell verbieten, aber man sollte sich diese Fälle gut überlegen. Insbesondere wegen der möglichen Fragmentierung des Heap.
:
Bearbeitet durch User
Oliver S. schrieb: > Was genau soll ein „zu C kompatibler C++ Compiler“ sein? Der erste April > war gestern. C++ ist in meinen Augen ein Aufsatz auf C. So habe ich dessen Entwicklung erlebt. Als Kontrast dazu möchte ich Java nennen, welches keine Funktionen außerhalb von Objekten kennt.
Stefan F. schrieb: > Dazu habe ich eine ernst gemeinte Frage: Referenzen sind technisch > gesehen auch Pointer, haben lediglich eine andere Syntax. Wie erzeugst > du Objekt-Instanzen zur Laufzeit, ohne new und ohne > Referenzen/Pointer? Z.B. als lokale Variable, die dann auf dem Stack landet. Oliver
Stefan F. schrieb: >> Aber ich würde auch behaupten, dass man für eine ISR weder Rohzeiger, >> noch Referenzen, noch Smartpointer braucht. Man kann doch ganz einfach >> ganz normal auf statisch alloziierte globale Ressourcen zugreifen. > > Kommt drauf an, was man machen will. Der TO möchte, dass die ISR > Eigenschaften seiner Objekt-Instanzen ändert. Das widerspricht sich doch gar nicht.
1 | class MyClass { |
2 | public:
|
3 | void handle_irq() { |
4 | eigenschaft++; |
5 | }
|
6 | |
7 | protected:
|
8 | int eigenschaft = 0; |
9 | }
|
10 | |
11 | MyClass myclass; |
12 | |
13 | ISR() { |
14 | myclass.handle_irq(); |
15 | }
|
> Der Stack verliert beim Verlassen einer Funktion seine Gültigkeit. Mit > der Beschränkung verlierst du die Möglichkeit, Objekte innerhalb von > Funktionen zu erzeugen und danach außerhalb dieser zu benutzen. Früher > oder später brauchst du das aber. Das ist eine Behauptung. Kannst du auch ein Beispiel liefern, wo ich das unbedingt brauche? > Der TO braucht es. Das würde ich in Frage stellen. > Seine ISR soll auf Objekte zugreifen, die innerhalb > einer Objekt-Funktion (Methode) erzeugt wurden. Das würde ich als kaputtes Konzept beschreiben, weil die Methode ja per Definition zum ISR-Aufruf nicht läuft. Und damit auch alle Objekte innerhalb die Gültigkeit verlieren, wie du schon richtig erkanntest. Das kann man nicht einmal mit Rohzeigern hinfrickeln. Das geht einfach nicht.
MaWin O. schrieb: >> Der TO braucht es. > Das würde ich in Frage stellen. Zumindest will er es so machen. Lass ihn doch! Du kannst von einem Anfänger nicht erwarten, die hohe Kunst der C++ Programmierung so zu beherrschen, wie einer, der das jahrelang studiert hat. Auch Anfänger können damit gut funktionierende Sachen hinbekommen - auch wenn sich dem Akademiker dabei die Fußnägel hoch rollen. Ich sage nur: Arduino.
:
Bearbeitet durch User
Stefan F. schrieb: > C++ ist in meinen Augen ein Aufsatz auf C Das ist es schon lange nicht mehr. Diese Denkweise ist >25 Jahre alt. Aber das erklärt sehr wohl einige deiner vorherigen Ausführungen und die Fixierung auf Rohzeiger. ;) Du solltest dir unbedingt man etwas >= C++11 anschauen. Es lohnt sich.
Stefan F. schrieb: > Zumindest will er es so machen. Lass ihn doch! Ich lasse jeden das tun, was er will. Keine Angst. :) > Du kannst von einem > Anfänger nicht erwarten, die hohe Kunst der C++ Programmierung so zu > beherrschen, wie einer, der das jahrelang studiert hat. Das tue ich auch nicht. Ganz im Gegenteil. Das ist ja der Grund, weshalb ich überhaupt hier Antworte. Ich möchte Anstöße in andere Richtungen geben. > Auch Anfänger können damit gut funktionierende Sachen hinbekommen Das bestreitet ja auch niemand. Man kann auch in Assembler programmieren und alles funktioniert. Man kann auch C schreiben (Rohzeiger nutzen) und das mit einem C++-Compiler übersetzen. Man braucht auch keine Smartpointer und Referenzen zu benutzen und kann trotzdem alles in einen funktionsfähigen Zustand bekommen. Geht alles. Aber das schien mir jetzt nicht die Intention des Threaderstellers zu sein.
MaWin O. schrieb: > Du solltest dir unbedingt man etwas >= C++11 anschauen. Es lohnt sich. Wohl kaum. In meinem Beruf sind ganz andere Programmiersprachen angesagt, da will niemand mehr etwas von C++ hören. Die Sprache ist nur noch für mein Hobby (Mikrocontroller) am Rande neben C ein bisschen interessant. Mag sein, dass die Sprache im Laufe vieler Jahre allmählich besser geworden ist. Aber sie ist auch zusammen mit der Generation ihrer Entwickler gealtert. In 20 Jahren wenn meiner-einer in Rente geht, arbeitet damit kein Mensch mehr. Also anstatt ständig den Neuen Aspekten der Sprache hinterher zu laufen, während ich alte Projekte pflegen muss die das eh nicht nutzen können/sollen, lerne ich doch lieber die neuen Programmiersprachen, mit denen die Kollegen links und rechts neben mit erfolgreich Geld für die Firma verdienen. Sonst bin ich nämlich schneller raus aus dem Geschäft, als das Renten-Eintrittsalter vorsieht.
:
Bearbeitet durch User
@Stefan : no pain, no gain. So eine Lernkurve tut weh ... Also für Doofe : Ganz oben, in der main : -------------------- int* Fallinkrement; -------------------- ganz unten, in der class segel.cpp : ------------------------------- int Fallinkrement; segel::segel() { Fallinkrement = &Fallinkrement; ------------------------------- Im Konstruktorlauf wird dem Objekt ein Zeiger zugeordnet (symbolisch (!!) quasi bei Objekt Fock also "Fock.*Fallinkrement" : Zeiger Fallinkrement, der dem Objekt Fall zugeordnet ist) und jetzt in der ISR : ----------------------------- Fock.*Fallinkrement ++ ; ----------------------------- Hab ich jetzt ein Syntaxproblem, oder hab ich das Zeiger-Konzept noch nicht verstanden ? Im Kern stört bei mir, dass jedes Segel 3 Taue hat, die jeweils gleich heißen (Fall, Klau, Piek). Und die Auffächerung in Gross.Piek und Besan.Piek geschieht ja erst bei Objekterzeugung. In " int* " gibts die noch nicht.
Stefan F. schrieb: > Wohl kaum. In meinem Beruf sind ganz andere Programmiersprachen > angesagt, da will niemand mehr etwas von C++ hören. Ja gut. Dann verstehe ich allerdings nicht, warum du hier Ratschläge zu C++ gibst. Für mich gehört es dazu, dass man auf der Höhe der Zeit ist, wenn man Ratschläge gibt. > Die Sprache ist nur > noch für mein Hobby (Mikrocontroller) am Rande neben C ein bisschen > interessant. Das mag in deiner Blase stimmen. Das ist aber (leider) ganz und gar nicht die Realität. > Mag sein, dass die Sprache im Laufe vieler Jahre allmählich besser > geworden ist. C++ hat sich nicht nur "allmählich" entwickelt, sondern hat riesige Sprünge in den letzten 15 Jahren gemacht. Das ist nun eine vollkommen neue Sprache, die noch rückwärtskompatibel zu 90er-Jahre-C++ ist. (Zu C war C++ noch nie vollständig rückwärtskompatibel) > Aber sie ist auch zusammen mit der Generation ihrer > Entwickler gealtert. In 20 Jahren wenn meiner-einer in Rente geht, > arbeitet damit kein Mensch mehr Sportliche Vorhersage. Ich hoffe, dass du recht behältst. Ich befürchte aber, dass es nicht so sein wird.
Reiner D. schrieb: > Hab ich jetzt ein Syntaxproblem, oder hab ich das Zeiger-Konzept noch > nicht verstanden ? Bitte trenne dich davon. Es gibt hier keinen einzigen Grund einen Zeiger zu verwenden.
Reiner D. schrieb: > Fock.*Fallinkrement ++ ;
1 | (*Fallinkrement)++; |
Fock gibt es in der ISR nicht wenn es nicht statisch ist.
Reiner D. schrieb: > Fock.*Fallinkrement ++ ; So wäre es richtig: *Fallinkrement++ Du willst in der ISR auf den globalen Zeiger "Fallinkrement" zugreifen, nicht auf das Attribut der Instanz der "segel" Klasse. An dieser Stelle ist es unvorteilhaft, dass die globale Variable genau so heißt, wie das Attribut der Klasse. Nenne die Variable z.B. "FallinkrementPtr", dann wird es vielleicht klarer.
:
Bearbeitet durch User
Und wenn schon gerätselt wird ob meiner Intention : Das Schiffchen krieg ich auch ohne Objekte zum fahren, das ist nicht das Thema. Es geht ums Lernen, hier insbesonders um Konzepte in OO. Für UML bin ich aber leider zu faul. Wenn hier einer was von SPS versteht : so wie Lasal zum Beispiel, das fand ich konzeptuell extrem spannend. Brauchen tu ich's nicht. Brauchen tu ich gar nix, hab die Rentengrenze längst überschritten :-))
Stefan F. schrieb: > *Fallinkrement++ Es gibt aber drei Fallinkremente. Je eines vom Inkrementgeber an Fockfallwinde, Grossfallwinde und Besanfallwinde. Wenn ich nur Objekte in main nutze (die Matrosen also quasi an Deck mitreden lasse) werden die durch Fock.Fallinrement, Gross.Fallinkrement usw. sauber unterschieden, wie es Attribute von Objekten eben tun. Habe ich dich falsch verstanden, daß ich einen Zeiger im Konstruktorlauf machen kann, der dann dem Objekt zugeordnet ist ?
MaWin O. schrieb: > Dann verstehe ich allerdings nicht, warum du hier Ratschläge zu > C++ gibst. Für mich gehört es dazu, dass man auf der Höhe der > Zeit ist, wenn man Ratschläge gibt. OK, kann ich nachvollziehen. MaWin O. schrieb: >> das Zeiger-Konzept > Bitte trenne dich davon. Es gibt hier keinen einzigen Grund einen Zeiger > zu verwenden. Ja dann gebe ihm doch ein besseres Beispiel, dass er umsetzen kann!
:
Bearbeitet durch User
Das ist schon der richtige Weg an solchen Übungsaufgaben zu lernen. Solange das ganze Schiff und seine Besatzung statisch sind kann man alles global anlegen und braucht keine Zeiger. Wenn Segel statisch angelegt wird und den Fallinkrement Zeiger setzt, dann kann in der ISR auch gleich direkt auf das Objekt zugegriffen werden. Wie von MaWin O schon gezeigt. Interessant wird es wenn das ganze dynamisch wird, das Schiff z.B. aus einer Konfigurationsdatei zusammengesetzt wird. Dann spielt das OO Konzept seine Stärken aus.
:
Bearbeitet durch User
Stefan F. schrieb: > Ja dann gebe ihm doch ein besseres Beispiel, dass er umsetzen kann! Habe ich doch bereits. Beitrag "Re: C++ Objektorientierung ?" So geht das. Damit kann man auch alle Kompositionen abbilden. MyClass kann natürlich Instanzen von anderen Klassen enthalten.
1 | class MyClass2 { |
2 | public:
|
3 | void handle_irq2() { |
4 | eigenschaft++; |
5 | }
|
6 | |
7 | protected:
|
8 | int eigenschaft = 0; |
9 | };
|
10 | |
11 | class MyClass1 { |
12 | public:
|
13 | void handle_irq1() { |
14 | myclass2.handle_irq2(); |
15 | }
|
16 | |
17 | protected:
|
18 | MyClass2 myclass2; |
19 | };
|
20 | |
21 | MyClass1 myclass1; |
22 | |
23 | ISR() { |
24 | myclass1.handle_irq1(); |
25 | }
|
In main wird nur ein Schiff instanziiert, main ist nur der Lebensraum für Objekte. Das Schiff hat Kapitän, Rudergänger, Matrose. Jetzt muss man überlegen was diese sein sollen, so wie du es wolltest sind es Dienstleister die etwas ausführen können (Methoden). Das Schiff hat auch verschiedene Segel oder Motoren, das sind auch Objekte die ein Schiff hat. Diese kann man auch statisch anlegen weil sie ja fest zum Schiff gehören. Wenn ein Matrose jetzt ein Segel setzen soll, dann muss man ihm auch sagen welches. Das gross, besan usw. statisch angelegt wurden, können diese als Referenz übergeben werden. Das sind auch Zeiger, aber die werden nicht dynamisch angelegt und können damit nicht nullptr sein, das macht den Umgang angenehmer. Kann dann aber nicht dynamisch zusammengesetzt werden.
1 | class Segel { |
2 | }
|
3 | |
4 | class Matrose { |
5 | setzeSegel(Segel &segel); |
6 | }
|
7 | |
8 | class Schiff { |
9 | Matrose hein; |
10 | Matrose pit; |
11 | |
12 | Segel besan; |
13 | Segel gross; |
14 | }
|
15 | |
16 | Schiff.hein.setzeSegel(besan); |
17 | Schiff.pit.setzeSegel(gross); |
so grob.
J. S. schrieb: > Interessant wird es wenn das ganze dynamisch wird, das Schiff z.B. aus > einer Konfigurationsdatei zusammengesetzt wird. Dann spielt das OO > Konzept seine Stärken aus. Richtig. Aber auch dann braucht man in C++ keine Rohzeiger. Dann spielen Smartpointer ihre Stärken aus.
Reiner D. schrieb: > Diesen Teil verstehe ich nicht Dort wird eine eine Referenz auf das Segel an die Memberfunktion übergeben. Über diese Referenz kann die Funktion auf das Segel zugreifen und es auch verändern.
MaWin O. schrieb: > Dann spielen Smartpointer ihre Stärken aus. ja, ist mMn aber eine Feinheit die jetzt für ein Modell keine Rolle spielt. Die Smartpointer sollen ja z.B. die Speicherleck Probleme entschärfen. In C gibts malloc/free, es ist einfach die nicht balanziert aufzurufen. Ich denke dem TO fehlt der Unterschied Zeiger und Referenz bzw. die Anwendung dieser.
Reiner D. schrieb: > Es gibt aber drei Fallinkremente. Folglich brauchst du drei Zeiger (oder Referenzen), die jeweils direkt auf die gewünschten Attribute zeigen, oder auf die Objekte, welche die Attribute enthalten. Ich möchte daran erinnern, dass man eigentlich nicht an der Programmiersprache vorbei direkt auf Attribute der Objekte zugreifen soll. Außerdem sind diese drei Winden Bestandteil eines Schiffes, also genügt es, global auf das eine Schiff zu zeigen oder zu referenzieren: Mit Referenzen:
1 | class Winde { |
2 | public:
|
3 | int fallinkrement; |
4 | };
|
5 | |
6 | class Schiff { |
7 | public:
|
8 | Winde fockfallwinde; |
9 | Winde grossfallwinde; |
10 | Winde besanfallwinde; |
11 | };
|
12 | |
13 | Schiff schiff; |
14 | |
15 | ISR whatever() { |
16 | schiff.fockfallwinde.fallinkrement++; |
17 | schiff.grossfallwinde.fallinkrement++; |
18 | schiff.besanfallwinde.fallinkrement++; |
19 | }
|
Oder mit Zeigern und dynamischer Speicherverwaltung (bei Mikrocontrollern mit Fallstricken behaftet):
1 | class Winde { |
2 | public:
|
3 | int fallinkrement; |
4 | };
|
5 | |
6 | class Schiff { |
7 | public:
|
8 | Winde* fockfallwinde; |
9 | Winde* grossfallwinde; |
10 | Winde* besanfallwinde; |
11 | |
12 | // Konstruktor
|
13 | Schiff() { |
14 | fockfallwinde = new Winde(); |
15 | grossfallwinde = new Winde(); |
16 | besanfallwinde = new Winde(); |
17 | }
|
18 | |
19 | // Destruktor
|
20 | ~Schiff() { |
21 | delete fockfallwinde; |
22 | delete grossfallwinde; |
23 | delete besanfallwinde; |
24 | }
|
25 | };
|
26 | |
27 | Schiff* schiff; |
28 | |
29 | int main() { |
30 | schiff = new Schiff(); |
31 | }
|
32 | |
33 | ISR whatever() { |
34 | schiff->fockfallwinde->fallinkrement++; |
35 | schiff->grossfallwinde->fallinkrement++; |
36 | schiff->besanfallwinde->fallinkrement++; |
37 | }
|
Stefan F. schrieb: > Winde* fockfallwinde; > > // Konstruktor > Schiff() { > fockfallwinde = new Winde(); Und wozu dynmische statt statische Allokation? Ich sehe hier keinen Grund für Zeiger und new.
Reiner D. schrieb: >> (Segel &segel) > > Diesen Teil verstehe ich nicht ist vom erzeugten code wie ein Pointer
1 | // Pointer
|
2 | setze(Segel *segel) { |
3 | segel->setze(50pct); // wenn segel = nullptr ist, dann knallts |
4 | }
|
5 | |
6 | // Referenz
|
7 | setze(Segel &segel) { |
8 | segel.setze(50pct); // muss nicht auf nullptr geprüft werden |
9 | }
|
:
Bearbeitet durch User
Stefan F. schrieb: > Ich möchte daran erinnern, dass man eigentlich nicht an der > Programmiersprache vorbei direkt auf Attribute der Objekte zugreifen > soll. Jetzt eine Variante mit indirekten Zugriffen über Objektmethoden, was ich viel sauberer finde:
1 | class Winde { |
2 | int fallinkrement; |
3 | |
4 | public:
|
5 | void ändereIncrement(int wert) { |
6 | fallinkrement = fallinkrement+value; |
7 | }
|
8 | };
|
9 | |
10 | class Schiff { |
11 | Winde fockfallwinde; |
12 | Winde grossfallwinde; |
13 | Winde besanfallwinde; |
14 | |
15 | public:
|
16 | void ändereIncrementDerWinden(int wert) { |
17 | fockfallwinde.ändereIncrement(wert); |
18 | grossfallwinde.ändereIncrement(wert); |
19 | besanfallwinde.ändereIncrement(wert); |
20 | }
|
21 | |
22 | Winde getFockfallwinde() { |
23 | return fockfallwinde; |
24 | }
|
25 | |
26 | Winde getGossfallwinde() { |
27 | return grossfallwinde; |
28 | }
|
29 | |
30 | Winde getBesanfallwinde() { |
31 | return besanfallwinde; |
32 | }
|
33 | };
|
34 | |
35 | Schiff schiff; |
36 | |
37 | ISR whatever() { |
38 | schiff.ändereIncrementDerWinden(+1); |
39 | }
|
40 | |
41 | // oder:
|
42 | |
43 | ISR whatever2() { |
44 | schiff.getFockfallwinde().ändereIncrement(+1); |
45 | schiff.getGossfallwinde().ändereIncrement(+1); |
46 | schiff.getBesanfallwinde().ändereIncrement(+1); |
47 | }
|
An den MaWin O hätte ich die Bitte, dieses Beispiel auf die neuen besseren Features von C++ 11 zu heben, die mir nicht bekannt sind. Dann müssten wir zu einem guten Schluss kommen, denke ich.
Ein Objekt 'Winde' statt 'Segel' wie Stefan schrieb passt besser. Klasse Winde kann gleich sein für die Segel, als Segel würde dann ein enum { gross, besan, fock} reichen.
MaWin O. schrieb: > Und wozu dynmische statt statische Allokation? Ich sehe hier keinen > Grund für Zeiger und new. Ich habe ja das nur als Beispiel geschrieben, um die Syntax zu zeigen. Wie gesagt ist das auf Mikrocontrollern keine so gute Idee.
Stefan F. schrieb: > dieses Beispiel auf die neuen > besseren Features von C++ 11 zu heben Bis auf dass du die Referenzen der Rückgabewerte vergessen hast, sehr ich kein Problem. Ohne Referenzen funktioniert whatever2 auch in 90er-C++ nicht.
1 | Winde getFockfallwinde() { |
2 | return fockfallwinde; |
3 | }
|
->
1 | Winde& getFockfallwinde() { |
2 | return fockfallwinde; |
3 | }
|
J. S. schrieb: > Ein Objekt 'Winde' statt 'Segel' wie Stefan schrieb passt besser. Klasse > Winde kann gleich sein für die Segel, als Segel würde dann ein enum { > gross, besan, fock} reichen. Ja sorry, ich habe von Schiffen absolut keine Ahnung, deswegen sind meine Beispiele diesbezüglich vielleicht etwas holprig.
MaWin O. schrieb: > Bis auf dass du die Referenzen der Rückgabewerte vergessen hast Upps, ja stimmt. So gebe ich nur Kopien der Winden zurück. Wenn danach die Kopien geändert werden, hat das keinen sinnvollen Effekt auf das Schiff.
:
Bearbeitet durch User
Stefan F. schrieb: > Ja sorry, ich habe von Schiffen absolut keine Ahnung, deswegen sind > meine Beispiele diesbezüglich vielleicht etwas holprig. ich auch nicht, im Detail wird es irgendwann Geschmacksfrage und mehrere Lösungen sind möglich. Wenn die Winden unterschiedliche Eigenschaften haben, dann können das verschiedene Objekte sein. Oder eine Basisklasse und die Varianten sind Ableitungen. Möglichkeiten gibt es viele. Das dynamisch zu machen wäre wie genannt z.B. das Schiff aus einer Konfigdatei zu erstellen. Schönes Beispiel dafür ist 3D Drucker SW Marlin vs. Smoothieware: Marlin hat config in defines und Änderungen müssen neu kompiliert werden, Smoothie kann config aus Datei lesen und zur Laufzeit Pins zuordnen.
Hab ich auch so probiert, und jetzt liegts wohl an meinem C-Gestammel : class segel { public : int FallInkrement; }; class deckshand { public : segel Fock; segel Besan; }; In der main : deckshand Matrose; In der ISR darunter : ISR(..) { Matrose.Fock.FallInkrement ++; } nix geht, Compilerfehler hier : Matrose.Fock.FallInkrement ++ ;
sieht nicht verkehrt aus. Üblicherweise schreibt man die Klassen groß, die Instanzen klein. Und zwischen Variable und ++ kein Leerzeichen, ist kein Fehler, sieht aber blöd aus. Matrose muss global über der ISR angelegt sein. Wie ist die Fehlermeldung?
J. S. schrieb: > sieht nicht verkehrt aus Finde ich auch. Bei mir compiliert das, wenn ich "ISR(..)" durch "void test()" ersetze, das liegt aber daran, dass ich mein Testprojekt als "Linux Desktop Anwendung" angelegt habe, statt für AVR. Reiner D. schrieb: > nix geht, Compilerfehler hier : Matrose.Fock.FallInkrement ++ ; Kann ich so nicht nachvollziehen. Zeige die ganze Fehlermeldung oder hänge dein Projekt in compilierbarer Form an, so dass wir den gleichen Fehler bekommen, wie du.
:
Bearbeitet durch User
Stefan F. schrieb: > Kann ich so nicht nachvollziehen. Reiner D. schrieb: > In der main : > > deckshand Matrose; Da Rainer nach wie vor main() und main.cpp fröhlich durcheinander wirft, könnte es sein, daß er diesmal tatsächlich main() meint. Und dann gehts natürlich nicht. Oliver
Jetzt kapier ich erst, was du meinst. Die Datei main.cpp (in der auch die ISR enthalten sind), und die main, in der die Endlosschleife zur Programmausführung läuft. Ich war vermutlich ungenau mit der Bezeichnung ... Ich hab das C::B - Projekt gezippt und angehängt. Macht euch aber bitte nicht zuviel Arbeit. Fehlermeldung : main.cpp|138|error: 'class deckshand' has no member named 'Gross'|
:
Bearbeitet durch User
Hallo,
1 | Fehlermeldung : |
2 | main.cpp|138|error: 'class deckshand' has no member named 'Gross'| |
Dafür musst du nur in die deckshand.h reinschauen. Gibt es einen Member namens "Gross"? Nein. Du kannst mit deinen Objekten nur Member und Methoden verwenden die public zur Verfügung stehen. Wenn das deine eigenen Klassen sind solltest du das Wissen. Selbst wenn du das
1 | Matrose.Gross.KlauInkrement ++ ; |
2 | Matrose.Besan.KlauInkrement ++ ; |
korrigierst auf
1 | Matrose.KlauInkrement++ ; |
2 | Matrose.KlauInkrement++ ; |
gibt es keinen Member namens "KlauInkrement". Weil Matrose ist ja eine Instanz von deckshand. Fock, Gross und Besan sind Objekte von segel. Die können nur auf public von segel zugreifen.Hier steckt auch der Member KlauInkrement drin. Wahrscheinlich meinst du
1 | Gross.KlauInkrement++ ; |
2 | Besan.KlauInkrement++ ; |
Hier ist einfach zu viele Copy & Paste im Spiel. Erschwerend kommt hinzu das Gewürfel mit Groß- und Kleinschreibung. Schreibe Klassennamen Anfangs Groß und Member und Methoden Anfangs Klein. Zudem KlauInkrement unglücklich ist. Was machst beim Dekrementieren dieser Variablen?
Reiner D. schrieb: > class deckshand' has no member named 'Gross' So ist es. In der Datei deckshand.h gibt es kein Gross. Wenn du auf ein Gross in deckshand zugreifen willst, muss es dort existieren. Folgende Zeilen sind ähnlich fehlerhaft, das zeigt mir meine IDE (Qt Creator) schon vor dem Compilieren direkt im Texteditor an: > Matrose.Gross.KlauInkrement ++ ; > Matrose.Besan.KlauInkrement ++ ; > Matrose.Fock.FallInkrement ++ ; > Matrose.Gross.PiekInkrement ++ ; > Matrose.Besan.PiekInkrement ++ ; Matrose ist eine Instanz von deckshand. Deckshand enthält weder ein Gross, noch ein Besan, noch ein Deckshand. KlauInkrement, PiekInkrement sind FallInkrement sind Attribute der Klasse segel. In deckshand.cpp gibt es drei globale (!) segel mit Namen Fock, Gross, und Besan. Diese sind also nicht Bestandteil von deckshand sondern davon völlig losgelöst. Du musst die Segel in die Klasse deckshand verschieben. Siehe Anhang.
:
Bearbeitet durch User
Was hab ich bei der Übertragung des Beispiels von Stefan auf meinen Code falsch gemacht ? Ich hab versucht, die Strutur so einzubauen, wie ich es bei Stefan verstanden habe.... (btw. nix copy+paste, alles selber zusammengefrickelt)
Reiner D. schrieb: > Was hab ich bei der Übertragung des Beispiels von Stefan auf meinen Code > falsch gemacht Habe ich gerade erklärt, vermutlich hat sich meine Antwort mit deiner Frage zeitlich überschnitten. Scrolle mal nach oben.
Gute Güte; hast Du jemals in irgendeiner Sprache programmiert? Und C++ lernt man nicht in einem µC Projekt. Nimm ein C++ Buch und fange ganz einfach auf dem PC bei Null an.
Stefan F. schrieb: > Du musst die Segel in die Klasse deckshand verschieben. Siehe Anhang. Ich habe versucht, deine Struktur : class Winde { public: int fallinkrement; }; class Schiff { public: Winde fockfallwinde; Winde grossfallwinde; Winde besanfallwinde; }; Schiff schiff; ISR whatever() { schiff.fockfallwinde.fallinkrement++; schiff.grossfallwinde.fallinkrement++; schiff.besanfallwinde.fallinkrement++; } ...auf die Meine zu übertragen. Winde wird segel, schiff wird deckshand. In der ISR dann die entsprechenden Angabe. Oh weh, ich kapier's nicht ...
Weiter oben hat jemand bemängelt, dass hier das Schiff und die Matrosen zu sehr miteinander vermischt werden. Da hat er wohl Recht. Die Matrosen sollten auf/mit dem Schiff arbeiten, aber nicht Bestandteil des Schiffes sein. Ebenso ist das Schiff kein Körperteil der Matrosen. Das sollte man nochmal gründlich umstrukturieren.
Hmm deine Segel sind ja auch eigenschändig und schwirren irgendwo in deiner Welt herum. Wenn du die Segel als Objekte deines Matrosen haben willst, dann solltest du das auch machen. Das in deckshand.cpp
1 | segel Fock; |
2 | segel Gross; |
3 | segel Besan; |
muss dazu in deine Klasse deckshand hinein. also in deckshand.h
1 | class deckshand |
2 | {
|
3 | [.. hier dein ganzer anderer Kram] |
4 | |
5 | segel Fock; |
6 | segel Gross; |
7 | segel Besan; |
8 | }
|
Aber man sollte auf Klassenmember nur über Methoden zu greifen. Also alles das was du da drin hast, sollte private sein. Und nur die Methoden sollten public sein. Wie schon gesagt, OO heißt auch dass man sich Gedanken über den Blick auf seine Welt macht. ;-) [hui, sind hier einige schnell]
:
Bearbeitet durch User
Reiner D. schrieb: > Oh weh, ich kapier's nicht Anbei die korrigierten Dateien. Anderes Thema: Füge bei Gelegenheit Include Guards in alle deine Header Dateien ein, damit sie keine Probleme machen, wenn sie mehrfach eingebunden werden. Beispiel: schweinesteak.h
1 | #ifndef SCHWEINESTEAK_H
|
2 | #define SCHWEINESTEAK_H
|
3 | |
4 | class Schweinesteak { |
5 | ...
|
6 | }
|
7 | #endif /* von SCHWEINESTEAK_H */ |
:
Bearbeitet durch User
Reiner D. schrieb: > Winde wird segel, schiff wird deckshand. In der ISR dann die > entsprechenden Angabe. > > Oh weh, ich kapier's nicht ... Dann solltest du aber auch beachten das Stefan die Winden-Objekte in der Klasse Schiff erzeugt hat. Und eben nicht im Luftleeren Raum einer anderen Datei.
Stefan F. schrieb: > Weiter oben hat jemand bemängelt, dass hier das Schiff und die Matrosen > zu sehr miteinander vermischt werden. Da hat er wohl Recht. Definitiv. > Die Matrosen sollten auf/mit dem Schiff arbeiten, aber nicht Bestandteil > des Schiffes sein. Ebenso ist das Schiff kein Körperteil der Matrosen. Richtig, das Schiff hat mehrere Matrosen und ein Matrose hat maximal ein Schiff. Die können aber wechseln, dann hin und wieder geht so ein Matrose über Bord und muß im nächsten Hafen durch einen neuen ersetzt werden. > Das sollte man nochmal gründlich umstrukturieren. Ähnlich ist es mit den Aufgaben der einzelnen Matrosen. Die können auch nicht statisch verteilt werden, denn mitunter werden auch erfahrene Segler seekrank, verletzen sich, oder fallen anderweitig aus. Und wer Törns über längere Strecken fährt, braucht irgendwann einen Wachwechsel... auch dann müssen die Aufgaben neu verteilt werden.
Alles, was hir bisher geschrieben wurde, sind die absoluten Basics von OOP - eigentlich nicht mal das. Ich steige mal an anderer Stelle: was soll denn die Klasse i2c modellieren? Ok, die TWI-Schnittsteller als I2C. Aber was erwartest Du von dem Konstruktor. Was passiert, wenn Du mehr als i2c-Objekt erzeugts? Das ist übrigens bei allen Deine HW-Abstraktionen so.
@Stefan (und die anderen Konstruktiven) : Zuerst : DANKE !! Beim Einbau deines Codes gabs zunächst Probleme, weil Code::Blocks sich daran stört, daß die Klasse und ein Attribut beide "segel" heißen. Kein Problem, Attribut in "segelbefehl" umbenannt. Läuft immer noch nicht. Die Definitionszeile "class segel" wird bemängelt : segel.h|1|error: redefinition of 'class segel'| Wenn ich jetzt "#include segel.h" aus der main nehme, gehts. Wieso ? Die include-Zeile ist doch keine Definition der class segel, oder ? Also : jetzt ist der Compiler zufrieden. Hätte ich ohne eure Hilfe so nicht hingekriegt. Und vor Allem : sowohl über Modellierung als auch über Pointer viel gelernt !!
Reiner D. schrieb: > Wenn ich jetzt "#include segel.h" aus der main nehme, gehts. > Wieso ? Die include-Zeile ist doch keine Definition der class segel, > oder ? Bitte beachte Stefans Ausführungen zum Thema "Include Guards". Diese verhindern, daß dieselbe Datei mehrmals inkludiert wird, und es zu Fehlern wie "redefinition of 'class segel'" kommt.
Wilhelm M. schrieb: > Alles, was hir bisher geschrieben wurde, sind die absoluten Basics von > OOP - eigentlich nicht mal das. Das ist mir klar. Vor langer Zeit war das mal ein Versuch, die grundlegendsten Basics von Objektorientierung auszuprobieren. Im Kern sollten nur die Begriffe : Klasse, Objekt, Methode, Attribut am Beispiel genutzt werden, völlig ohne Mdellierung usw... So wie : Klasse ist Obst Objekt ist Apfel Methode ist faulen Attribut ist Farbe (Wert ist rot) Na ja, und viel weiter bin ich dann in der Anwendung auch nicht gekommen. Ich hab zwar mit Lasal und Codesys automatisiert und ein paar solche Modellprojekte programmiert, aber im strikt low(est) level. Bin aber eben auch kein Programmierer ...
Reiner D. schrieb: > Läuft immer noch nicht. Die Definitionszeile "class segel" wird > bemängelt : > segel.h|1|error: redefinition of 'class segel'| > Wenn ich jetzt "#include segel.h" aus der main nehme, gehts. > Wieso ? Weil die Stefan F. schrieb: > Include Guards fehlen. > Die include-Zeile ist doch keine Definition der class segel, oder ? Die include Zeile nicht, aber der Inhalt der Datei die du an dieser Stelle includierst. Bevor dein Quelltext compiliert wird, wird die Zeile > #include "segel.h" durch den Inhalt der genannten Datei ersetzt. Du inkludierst aber auch > #include "deckshand.h" welche wiederum > #include "segel.h" includiert. Nun hast du den Inhalt der Datei segel.h zweimal in main.cpp eingefügt. Man kann halt nicht zwei (oder mehr) Klassen mit gleichem Namen haben.
:
Bearbeitet durch User
Reiner D. schrieb: > Wenn ich jetzt "#include segel.h" aus der main nehme, gehts. > Wieso ? Die include-Zeile ist doch keine Definition der class segel, > oder ? Wie der Stefan dir vorgeschlagen hat solltest du deine Header mit include Guards versehen. Ja die include-Zeile erzeugt eine Definition der class segel jedesmal wenn sie includiert wird. wenn deine include.h so aussieht:
1 | class segel |
2 | {
|
3 | [irgendwas] |
4 | }
|
dann wird genau dieser Text bei jedem #inculde segel.h eingefügt. Also im einfachsten Fall wird aus:
1 | #include "segel.h" |
2 | [irgendwas anderes] |
3 | #include "segel.h" |
folgendes:
1 | class segel |
2 | {
|
3 | [irgendwas] |
4 | }
|
5 | [irgendwas anderes] |
6 | class segel |
7 | {
|
8 | [irgendwas] |
9 | }
|
also füge in deiner segel.h ein
1 | #ifdef SEGEL_INCLUDE
|
2 | #define SEGEL_INCLUDE
|
3 | |
4 | class segel |
5 | {
|
6 | [irgendwas] |
7 | }
|
8 | #endif // ende von SEGEL_INCLUDE
|
Damit verhinderst du dass es mehrmals eingefügt wird Das sind aber absolute Basics in der ganzen C-Welt
Ich kann dir auch nur dringend empfehlen, die Programmiersprache auf einem PC zu lernen/üben. Mikrocontroller legen da noch einiges an Komplexität oben drauf und sind schwerer zu debuggen. Es ist gut, wenn man die Sprache dann schon in den Grundzügen verstanden hat und wenigstens ein bisschen Erfahrung gesammelt hat. Du könntest z.B. mein Tutorial durch gehen, und danach ein Program,m schreiben, dass ein Schiff auf den Bildschirm malt. Natürlich indem du es schön aus Objekten zusammen setzt. Du wirst dabei viel lernen. Siehe http://stefanfrings.de/qt_lernen/index.html
Sheeva P. schrieb: > Bitte beachte Stefans Ausführungen zum Thema "Include Guards" Im Eifer des Gefechts vernachlässigt. Hab jetzt erst mal nachgelesen, was das tut. Bisher hab ich diese Zeilen immer aus neuen class-Definitionen rausgelöscht, weil ich bloß Code haben will, den ich auch verstehe. Rein zufällig gabs bisher damit keine Probleme. Conclusio : nochmal was gelernt !
Hallo, Hinweis am Rande. Verwende gleich pragma in den Headerfiles.
1 | #pragma once
|
2 | |
3 | class segel |
4 | {
|
5 | // ... irgendwas etwas sinnvolles ...
|
6 | }
|
Reiner D. schrieb: > Klasse ist Obst > Objekt ist Apfel Schon falsch. Apfel ist auch eine Klasse, und zwar von Obst abgeleitet. Das Bild zeigt drei Instanzen von der Klasse Apfel, oder anders gesagt, drei Objekte oder drei Ausprägungen. Ein Objekt ist ein Ding, das man erzeugen, anfassen und benutzen kann. Eine Klasse beschreibt nur die Eigenschaften einer Klasse von Objekten, ist aber keine konkrete Ausprägung.
Stefan F. schrieb: > Siehe http://stefanfrings.de/qt_lernen/index.html Ein Traum. Kleiner bescheidener Satz : Ihr würdet nicht glauben, wie weit man mit so einer Murkserei kommt. Hab bisher noch alles zum Laufen gekriegt, aber (wichtig !) nie in professionellem (!) Kontext von Softwareentwicklung. Ich sehe das wie meinen Fernseher : da kapier ich 90% vom Menü auch nicht
Veit D. schrieb: Korrektur. Segel als Klassenname sollte Groß geschrieben werden. > Hallo, > > Hinweis am Rande. Verwende gleich pragma in den Headerfiles.
1 | #pragma once
|
2 | |
3 | class Segel |
4 | {
|
5 | // ... irgendwas etwas sinnvolles ...
|
6 | }
|
Ansonsten empfehle ich Reiner sich nochmal im Kleinen mit Klassen zu beschäftigen. Man sieht ja das du in deinen eigenen Klassen nicht durchblickst. Nochmal paar Schritte zurückgehen und den Aufbau überdenken.
:
Bearbeitet durch User
Hatte ich irgendwann im PHP-Zusammenhang zitiert : Classes are nothing without objects! We can create multiple objects from a class. Each object has all the properties and methods defined in the class, but they will have different property values. $apple and $banana are instances of the class Fruit Auch "godfather of education", (die Uni Harvard), nimmt dieses Beispiel in der Einführungsvorlesung "Objektorientierung"
Reiner D. schrieb: > Ihr würdet nicht glauben, wie weit man mit > so einer Murkserei kommt Oh doch. Ich (bzw mein Chef) hat damit gut Geld verdient. Ich sage immer: Softwareentwicklung ist wie ein Adventure spiel. Zuerst muss man herausfinden, was überhaupt machen soll, was das Ziel ist. Dann muss man heraus finden, wie man da hin kommt. Dabei macht man viele Fehler, manche mehrfach. Und wenn man es dann am Ende geschafft hat, kommt schon das nächste Projekt mit neuen Herausforderungen.
Zur Abrundung sei noch der Gegenstand gezeigt, damit man sehen kann, wovon hier geredet wird : https://www.schiffsmodell.net/index.php?/forums/topic/18743-baubericht-eines-anf%C3%A4ngers-hf31-maria/
Beitrag #7384998 wurde vom Autor gelöscht.
Das Konzept ist ja auch wirr ;-) Wenn du eine Simulation schreiben wolltest und Kapitän, Matrosen usw wären Spielfiguren dann wären Klassen dafür sinnvoll. Aber für ein Modellschiff mit einem AVR zu steuern ??? Du bist der Kapitän mit deiner Fernsteuerung in der Hand, der Empfänger mit dem AVR sind deine Offiziere die deine Befehle als Aktionen an die Matrosen(Servo) weiter geben.
Weit gefehlt ! Der AVR ist sogar eigentlich zu klein, mir gehen sowohl die externen Interrupts (deshalb die PCINT) als auch die Timer aus, ich muß sogar Timer multiplexen... Wenn ichs nochmal bauen würde, würde ich die Navigation und den Skipper wohl mit einem Raspi unter Python machen, zwecks der Gaudi. Das Ding soll : Ferngesteuert fahren (na ja, kein Ding, da hast du recht..). Alle Segel bergen und setzen können (kann kaum ein Modellboot). Auf Wunsch viele Waypoints (GPS-Koordinaten) unter Motor anfahren können mit FPV, also einer Funkkamera, die zeigt, was da zu sehen ist. Bei Senderausfall (oder einfach ausschalten) automatisch Segel bergen und zum Ausgangspunkt ("home") unter Motor zurückfahren. Die härteste Forderung, nämlich unter Segeln Waypoints anzufahren, habe ich zurückgestellt. Einen reibungsfreien Verklicker habe ich zwar gebaut, aber die Kreuz gegen den Wind macht Schwierigkeiten.
Ich habe das Gefühl, dass du zu viel mit Interrupts umsetzen willst. Man kann Eingänge auch nacheinander abfragen. Multitasking kann man mit mehreren parallel ablaufenden Zustandsautomaten erreichen. Interrupts benutzt man typischerweise nur dort, wo es unbedingt notwendig ist, die laufende Arbeit sofort zu unterbrechen um auf das Ereignis schnellstmöglich (binnen weniger Millisekunden oder noch schneller) zu reagieren. Zum Beispiel nutzt man eine ISR, um seriell empfangene Bytes in einen Puffer zu übertragen. Schließlich wartet der Sender der Daten nicht den Moment ab, wo du empfangsbereit ist. Die Verarbeitung der Daten sollte aber nicht in der ISR stattfinden. Einen Schaltkontakt sollte man aber normalerweise nicht an eine ISR koppeln, sondern aktiv abfragen. Mit zu vielen Interrupts verzettelt man sich ganz schnell. Bedenke, dass dein AVR sowieso nur eine ISR gleichzeitig ausführen kann. Alle anderen Interrupts müssen eh warten, bis er wieder ins Hauptprogramm zurückgekehrt ist. Durch viele Interrupts wird die Abarbeitung von Ereignissen unter Umständen sogar langsamer, als eine sequentielle Abfrage der Eingänge im Hauptprogramm. Wenn man mal bedenkt, dass kein Motor so schnell anlaufen und stoppen kann, frage ich mich, was das in deiner Anwendung wohl sein mag. Empfangene Kommandos in einen Puffer eintragen wäre ein Fall. Und sonst? Wofür brauchst du Interrupts?
:
Bearbeitet durch User
Reiner D. schrieb: > Weit gefehlt ! Der AVR ist sogar eigentlich zu klein, mir gehen sowohl > die externen Interrupts (deshalb die PCINT) als auch die Timer aus, ich > muß sogar Timer multiplexen... Dann ist was falsch an Deinem Konzept. Den Empfänger hast Du bestimmt über SBus, IBus oder Hott angeschlossen, das ist eine serielle Schnittstelle -> UART Das hast Du ggf. Telemetrie über SPort, IBus oder Hott-Sensor, ebenfalls seriell -> der 2. UART Dann liest Du GPS -> der 3. Uart Dann produzierst Du PWM für die Servos -> 1 Timer (bis zu 16 Servos) Was brauchst Du noch?
//Timer 0 : PPM-Generator (für Servos und RC-Winden) //Timer 1 : 10HZ-Generator für NPRM-Scheduler //Timer 2 : PWM-Generator (CompA für Maschine ) //Timer 3 : PPM-Decoder (vom RC-Sender) //Timer 4 : PWM für Fall-Winden in Gruppen //Timer 5 : Entprellung der Inkrementgeber //UART0 : USB zum PC //UART1 : GPS Klar könnte ich z.b. die Motorsteuerung mit nem Brushless und einem Stellerl machen, oder ein "Fahrtregler" für den DC-Motor. Aber warum kaufen, wenn das auch mit Software geht. Mein Empfänger kann nicht seriell, also Auswertung des PPM-Summensignals. Die Winden brauchen Inkrementgeber, weil ich die Wege und die Geschwindigkeit steuern will, also Interrupts. Die Inkrementgeber "prellen" beim 1/0-Übergang, wohl optische Gründe, könnte man auch filtern, aber SW ist lustiger. Und für Regler und digitale Filter brauche ich harte Echtzeit, also der Scheduler.
:
Bearbeitet durch User
Ich steuere dir mit einem einzigen 8 Bit Timer 10 Servos an. Jemandem, der in Software nicht nicht so fit ist, würde ein PC9685 Modul empfehlen. > Timer 1 : 10HZ-Generator für NPRM-Scheduler > Timer 5 : Entprellung der Inkrementgeber Ich würde wie bei Arduino einen millis() Timer und alle andere Zeiten per Software davon ableiten.
Ein paar andere Spielsachen wären noch in der Queue : Ein Katamaran, der geregelt auf einer Kufe fährt Eine Modellrakete, die wie ein Cruise-missile fliegt immer mit nem Arduinio nano denke ich ...
Reiner D. schrieb: > Ein Katamaran, der geregelt auf einer Kufe fährt > Eine Modellrakete, die wie ein Cruise-missile fliegt Werde nicht albern, lerne erst mal programmieren. Hast du eigentlich einen Debugger? Wenn nicht, dann ist jetzt vielleicht noch eine gute Gelegenheit, den ATmega 2560 (?) durch ein STM32 Nucleo Board zu ersetzen, da hast du den Debugger direkt mit drauf.
:
Bearbeitet durch User
Ja, also das wird sicher mit AVR machbar sein. Aber ich würde mir das in diesem Fall heute auch nicht mehr mit AVR antun, wenn es nicht unbedingt sein muss. Da würde ich eher einen billigen 32-Bit Mikrocontroller wie z.B. den ESP32 nehmen. Die maximal paar Milliwatt Mehrverbrauch fallen hier gar nicht ins Gewicht. Den kann man dann auch in Python programmieren, wenn man das möchte. Oder halt auch in vielen compilierten Sprachen wie C, C++ und Rust. AVR nutze ich eigentlich nur noch da, wo es auf absolut geringen Energieverbrauch ankommt, oder wo die Anwendung trivial ist. Außerdem würde ich unabhängig vom Controller so wenig Hardwaretimer wie möglich einsetzen. Ein simples Realtime-Scheduling mit festen Zeitscheiben ist viel einfacher und IMO auch robuster als etliche Interrupts, die sich ständig unterbrechen können. Das Scheduling kann von einem HW-Timer ableiten. Die restlichen HW-Timer dann für z.B. PWM, was autonom in HW generiert wird. Außerdem würde ich die Aktivitäten in den verbliebenen Interrupt Service Routinen auf das absolute Minimum beschränken. Einfacher ist besser.
Reiner D. schrieb: > Eine Modellrakete, die wie ein Cruise-missile fliegt Na klar. Raketentechnik. Wenn das mal kein Anfängerprojekt ist.
MaWin O. schrieb: > Na klar. Raketentechnik. > Wenn das mal kein Anfängerprojekt ist. Die Ariane 5 konnte fliegen, leider nur ein Stück weit. https://www.golem.de/news/softwarefehler-in-der-raumfahrt-in-den-neunzigern-stuerzte-alles-ab-1511-117537-3.html
:
Bearbeitet durch User
Stefan F. schrieb: > Ich steuere dir mit einem einzigen 8 Bit Timer 10 Servos an. Ja, ich auch. Brauche aber nicht so viele ;-) ISR(TIMER0_COMPA_vect) { TCCR0B = 0; //zähler aus PORTA = PORTA & 248; //alle Pins auf 0 servo = servo + 1; if (servo > 4) { servo = 1; } //-------------------------------------- if (servo == 1) { PORTA |= 1; //Pin 22, Port A0 -> Ruder ist servo 1 OCR0A = Matrose.ruderwinkelsollwert; TCCR0B = 4; //timer zählt los mit prescaler 256 (16us) } if (servo == 2) { PORTA |= 2; //Pin 23, Port A1 -> Gaffel ist servo 2 OCR0A = Matrose.gaffelschotsollwert; TCCR0B = 4; //timer zählt los mit prescaler 256 (16 us) } if (servo == 3) { PORTA |= 4; //Pin 24, Port A2 -> Fock ist servo 3 OCR0A = Matrose.fockschotsollwert; TCCR0B = 4; //timer zählt los mit prescaler 256 (16 us) } //----------------------------------------- if (servo == 4) { OCR0A = 255; //Maximalwert, rund 13 ms Pause TCCR0B = 5; //timer zählt los mit prescaler 1024 (80us) } }
Bei all diesen Projekten ist der uC nicht das Problem, oder ob das schönes C wird, sondern eher die Regelungstechnik (und bei der Rakete vielleicht die Servogeschwindigkeit). Versuche sind schon gelaufen. Andere Beispiele für echt harte Regelprojekte : Quadrocopter oder self-balancing (siehe segway).
Stefan F. schrieb: > Gut, hätte ich ähnlich gemacht. versteh mich nicht falsch. du kannst das 10mal besser.
Reiner D. schrieb: > ... > OCR0A = Matrose.ruderwinkelsollwert; > TCCR0B = 4; //timer zählt los mit prescaler 256 > ... Mich würden da ja die Magic Numbers stören. Aber sonst schauts eigentlich OK aus.
M. K. schrieb: > Mich würden da ja die Magic Numbers stören. Aber sonst schauts > eigentlich OK aus. weiß schon, ist halt ne alte angewohnheit aus maschinensprache-tagen
Überschrift war OO mit C++ Wahrscheinlich wird dieses Kapitän-Matrosen Pattern in die Software Geschichte eingehen .... ;-)
Beitrag #7385223 wurde vom Autor gelöscht.
Hans-Georg L. schrieb: > Überschrift war OO mit C++ Bitte entschuldige, was möchtest Du uns damit sagen? > Wahrscheinlich wird dieses Kapitän-Matrosen Pattern in die Software > Geschichte eingehen .... ;-) Ja, vermutlich, vor allem, wenn es jemand in C++ sauber implementiert und seine Lösung hier zeigt (ich persönlich würde ja auf Wimalopaan tippen). Nun, ich hab's mal in Python gebastelt, nur so aus Spaß, und natürlich ist das ein totaler Pipifax. Trotzdem: HF und YMMV. PS: Sorry für das off-topic, lieber TO. Viel Glück und Erfolg bei Deinem spannenden und interessanten Segelprojekt! ;-) PPS: Verdammt, jetzt aber... ;-)
:
Bearbeitet durch User
Reiner D. schrieb: > //Timer 0 : PPM-Generator (für Servos und RC-Winden) > //Timer 1 : 10HZ-Generator für NPRM-Scheduler > //Timer 2 : PWM-Generator (CompA für Maschine ) > //Timer 3 : PPM-Decoder (vom RC-Sender) > //Timer 4 : PWM für Fall-Winden in Gruppen > //Timer 5 : Entprellung der Inkrementgeber > //UART0 : USB zum PC > //UART1 : GPS Timer5 brauchst Du nicht bzw. kannst das mit Deinem Timer1 zusammenfassen. Und warum brauchst Du so viele externe PinChange-Interrupts?
Wilhelm M. schrieb: > Ich steige mal an anderer Stelle: was soll denn die Klasse i2c > modellieren? Ok, die TWI-Schnittsteller als I2C. Aber was erwartest Du > von dem Konstruktor. Was passiert, wenn Du mehr als i2c-Objekt erzeugts? > Das ist übrigens bei allen Deine HW-Abstraktionen so. Diesem Problem solltest Du Dich auch noch mal stellen (s.a. scheduler).
:
Bearbeitet durch User
Sheeva P. schrieb: > Nun, ich hab's mal in Python gebastelt @sheeva : Find ich extrem spannend. Ich hab die letzten Jahre viel mir Python gespielt, natürlich nicht auf deinem Niveau, und rumgesucht, ob das auch auf dem AVR möglich ist. Ich hab leider nix vernünftiges gefunden. Wenn du erlaubst, stelle ich dir dazu später ein paar Fragen. Soll ich da ein extra topic machen, oder wie geht das ?
Wilhelm M. schrieb: > brauchst Du so viele externe PinChange-Interrupts? Ich hab aktuell 5 Winden, es sind aber noch drei Segel ausstehend (nochmal Winden) jede Winde einen Inkrementgeber, weil ich nicht bloß ein/aus steuern möchte. Die normalen externen Interrupts sind schon überwiegend belegt an den Ports, und umlöten tun ich da nix mehr (du kannst dir vermutlich vorstellen, wie die Platine von hinten aussieht, wenn ein 65-jähriger mit Zitterfingern so einen Haufen Zeug mit Draht frei verlötet ;-).
Wilhelm M. schrieb: > Timer5 brauchst Du nicht bzw. kannst das mit Deinem Timer1 > zusammenfassen. Das Problem liegt andersrum. Ich habe da einen Fehler im System : die Inkrementgeber "prellen", wahrscheinlich springt die Optik kurz nach der Kante ein paarmal hin-und her. Wenn ich nur einen Timer dafür benutze (klassische bounce-Lösung mit Totzeit), kann nur eine Winde zu einer Zeit laufen : sehr unsportlich ! Ich bräuchte im Kern sehr viele Timer um parallel setzen/bergen/reffen zu können, einen pro aktiver Winde. Grübel. Hardwarelösung, also rummessen, analogen Filter entwerfen, oder einen Coprozessor (AtMegas hab ich genug). Weiß nicht. uP ist lustiger.
Wilhelm M. schrieb: > Diesem Problem solltest Du Dich auch noch mal stellen (s.a. scheduler). Ich weiß. Die OO für die HW-Komponenten kommt aus einem anderen (alten) Projekt, und passt nicht ins Modell, das ist mir klar. Damals hatte ich einfach ausprobiert, ob ich die SW-Struktur mit Objekten, Methode usw. überhaupt zum Laufen kriege.
Vielleicht nochmal grundsätzlich: der Titel ist "C++ Objektorientierung". Dir sollte bewusst sein, dass C++ keine rein objektorientierte Programmiersprache ist. Sondern C++ ist eine Sprache, mit der man auch(!) objektorientiert programmieren kann. Aber auch anders: imperativ-prozedural, funktional, generisch, meta-programmatisch, ... Und der Code, den Du vorgestellt hast, ist mitnichten OOP. Denn die Grundprinzipien von OOP sind Kapselung in Klassen, Vererbung, Polymorphie und spätes Binden. Von diesen Prinzipien hast Du nichts umgesetzt. Außerdem ist Deine Anwendung wohl so, dass Du auch nicht direkt OOP benötigst, da so ziemlich alles statisch. Aber auch ist Dein Ansatz noch nicht einmal konsequent objektbasiert. Zudem hast Du auch Klassen die etwas der internen Peripherie modellieren sollen. Hier ist es konzeptionell falsch, Instanzen von Klassen zu erzeugen, es sei denn, Du verwendest ein Muster zur Kapselung von globalen Zuständen in multiplen Instanzen wie etwas das Monostate-Pattern. Also alles in allem: so wie Du das anfängst, hast Du keinerlei Vorteile gegenüber rein imperativ-prozeduraler Vorgehensweise. Und OOP lernt man nicht mit µC, sondern ganz normal auch dem PC. Aber da wiederhole ich mich.
Wilhelm M. schrieb: > Hier ist es konzeptionell falsch, Instanzen von Klassen zu > erzeugen, Wieso ? Daß es zum Modell nicht passt ist eine Sache, aber warum darf eine funktionierende Programmiertechnik quasi "grundsätzlich" nicht für dies oder das benutzt werden ? Ähnlich Frage : (Ich weiß, ist sakrosankt) Wieso immer Kapselung ? Ich verstehe die Vorteile in entsprechendem Kontext. Aber in so einem kleinen Projektchen, das nicht im Team entwickelt wird ? so what ? alles public und fertig ... Laß mich ein Beispiel geben : wenn ich am Holm eines großen Segelflugzeuges klebe, nehme ich das beste Epoxi und mache vorher einen Klebekurs. Bei Spielzeug klebe ich mit Uhu, fertig.
Reiner D. schrieb: > Wieso ? > Daß es zum Modell nicht passt ist eine Sache, aber warum darf eine > funktionierende Programmiertechnik quasi "grundsätzlich" nicht für dies > oder das benutzt werden ? Stellt Dir vor, Du erzeugst an unterschiedlichen Stellen in Deinem Code mehrere Instanzen der Klasse "scheduler" oder "i2c". Was erwartest Du, was dann passiert? Ich habe nicht gesagt "grundsätzlich" falsch, sondern konzeptionell falsch.
Das ist jetzt Nachhilfe pur, und ich danke dir dafür ! Ich schätze mal, mehrere Instanzen von I2C werden rein softwaremäßig funktionieren.( Wobei ich das Problem, das bei mehrmaligem include einer .h passiert, und mit "Include Guards" gelöst wird, noch nicht so genau verstanden habe) Wenn dann aber die verschiedenen Objekte auf die nur einmal vorhandene Hardware zugreifen, knirscht es aber. Es mag mulitinstanzfähige Lösungen geben, die auf dem AVR ist es sicher nicht. So war es aber auch nie gedacht, es ging damals nur um die Funktionsfähigkeit des Syntax-Gebäudes "Klasse-Objekt-Attribut usw...". Und, auch akzeptiert : das muß raus aus dem Schifferl ;-)
Reiner D. schrieb: > Ich schätze mal, mehrere Instanzen von I2C werden rein softwaremäßig > funktionieren.( Wobei ich das Problem, das bei mehrmaligem include einer > .h passiert, und mit "Include Guards" gelöst wird, noch nicht so genau > verstanden habe) Hier verwechselst Du "nicht compilieren" mit "zur Laufzeit was Falsches machen". Das Thema "include guard" ist ein simples Thema der Strukturierung des Codes innerhalb der Übersetzungseinheiten. Hier hast Du in C++ alle Freiheiten, Hauptsache Du machst es richtig. Trotzdem gibt es ein übliches Verfahren, etwa die Klassendefinition und Definition der Elementfunktionen in Header und Implementierungsdatei zu unterteilen. Zusammen mit include-guards hilft dies zuverlässig, die ODR einzuhalten und Mehrfachdefinitionen innerhalb einer Übersetzungseinheit auszuschließen. Das hat aber nicht mit dem Laufzeitproblem zu tun, was ich angesprochen habe. Mehrere Exemplare des Typ i2c werden natürlich irgendwie "funktionieren", aber nicht das tun, was Du willst. Das ist dann ein semantisches Problem. Und ja, Du hast es erkannt: Objekte, die nicht ihren eigenen Zustand, sondern einen globalen Zustand (der, der internen Peripherie) modellieren sollen, benötigen besonderes Augenmerk. Eine Lösung ist das Monostate-Pattern. Eine andere ist es, eine Klasse nur mit static Elementen zu schreiben und es zu verbieten, Objekte davon zu erzeugen.
Sheeva P. schrieb: > Hans-Georg L. schrieb: >> Überschrift war OO mit C++ > > Bitte entschuldige, was möchtest Du uns damit sagen? > Das die Überschrift mit dem Thread nichts mehr zu tun hat. > Ja, vermutlich, vor allem, wenn es jemand in C++ sauber implementiert > und seine Lösung hier zeigt (ich persönlich würde ja auf Wimalopaan > tippen). Auch dann wird es kein OO und kein C++ sein ;-) Das Thema selbst ist sehr interessant und ich wünsche viel Erfolg !
Reiner D. schrieb: > Es mag mulitinstanzfähige Lösungen > geben, die auf dem AVR ist es sicher nicht. Mit AVR hat das nichts zu tun: es ist einfach ein konzeptionelles Problem, also wie modelliere ich was.
Reiner D. schrieb: > So war es aber auch nie gedacht, es ging damals nur um die > Funktionsfähigkeit des Syntax-Gebäudes "Klasse-Objekt-Attribut usw...". Auch hat das nichts mit Syntax zu tun. Bitte kläre einige Begriffe, bevor Du sie benutzt.
Reiner D. schrieb: > Laß mich ein Beispiel geben : wenn ich am Holm eines großen > Segelflugzeuges klebe, nehme ich das beste Epoxi und mache vorher einen > Klebekurs. > Bei Spielzeug klebe ich mit Uhu, fertig. Ob Hobbybastler oder Profi.... Beide wollen am Ende eine funktionierende/stabile Software. So verwenden auch beide die gleichen Techniken. Manches mal sind die Hobby Leute gar noch verbissener. Reiner D. schrieb: > alles public und fertig ... Herrlich! Natürlich kann man mit einer Tasse einen Nagel in die Wand hauen. Es zumindest versuchen. Oder bei einem Auto 3 Türen zuschweißen. Einer der gewichtigsten Gründe für OOP ist eben die Kapselung. Die hoffentlich damit einhergehende leichte Wiederverwend-, Test- und Wartbarkeit. Natürlich darfst du das in den Wind schlagen.
Wilhelm M. schrieb: > Mit AVR hat das nichts zu tun: Im Sinne der Nachhilfe nachgefragt : Ich kenne aus der Industriewelt multiinstanzfähige HW, die also mehrere "gleichzeitige" Requests auffangen und geordnet abarbeiten kann. Hätte der I2C-Teil im AVR diese Fähigkeit, wären die parallelen Instanzen wohl möglich, oder ?
Reiner D. schrieb: > Wilhelm M. schrieb: >> Mit AVR hat das nichts zu tun: > > Im Sinne der Nachhilfe nachgefragt : > > Ich kenne aus der Industriewelt multiinstanzfähige HW, die also mehrere > "gleichzeitige" Requests auffangen und geordnet abarbeiten kann. Hätte > der I2C-Teil im AVR diese Fähigkeit, wären die parallelen Instanzen wohl > möglich, oder ? Die hast Du ja auch bei AVR: es gibt mehrere HW-Instanzen eines UART ;-) Jetzt benötigst Du idealerweise eine Lösung, die es Dir erlaubt, passend zu den 3 HW-Uarts auch drei unterschiedliche Instanzen zu erzeugen: Instanz 1 bezieht sich auf Uart 1, Instanz 2 bezieht sich auch Uart 2, u.s.w., Instanz 42 bezieht sich auf ... was? Und idealerweise sollte dies Problem nicht erst zur Laufzeit auftauchen, sondern zur Compilezeit. In C++ gibt es noch eine Art von "Instanz", und zwar wenn man aus einem Template eine Klasse erzeugt spricht man auch von Instanziieren eines Templates. Denn instanziieren bedeutet nur, aus etwas Abstraktem etwas Konkretes zu erzeugen: aus einer Klasse ein Objekt, oder aus einem Template eine Klasse. Der Template-Instanziierungsprozess läuft zur Compilezeit, und deswegen kann man hier dann die obige Prüfung einbauen, damit eine fehlerhafte Parametrierung gar nicht erst compiliert. Laufzeitfehler zu suchen is hässlich ;-)
Reiner D. schrieb: > Hätte > der I2C-Teil im AVR diese Fähigkeit, wären die parallelen Instanzen wohl > möglich, oder ? Auch mit nur einem Hardware-I2C steht dir frei, weitere (Software-Simulierte) I²C-Busse zu instanziieren, bei Arduino: "class SoftWire". Und bei AVRs mit mehreren UARTs ist es auch üblich, dass da mehrere Serial-Objekte (+ ggfs. SoftSerial) instanziiert sind.
Reiner D. schrieb: > die also mehrere > "gleichzeitige" Requests auffangen und geordnet abarbeiten kann. Hätte > der I2C-Teil im AVR diese Fähigkeit, Hätte hätte Fahrradkette .... I2C kann genau das, was im I2C Standard beschreiben ist Mehrere I2C Ports, dann auch mehrere z.B. Wire Instanzen.
:
Bearbeitet durch User
Arduino F. schrieb: > Mehrere I2C Ports, dann auch mehrere z.B. Wire Instanzen. nochmal nachgefragt : Ich kann z.B auf dem AtMega256 aus zwei Instanzen "gleichzeitig" (also innerhalb des Befehlszyklus) auf die I2C-Schnittstelle zugreifen (also z.b. zwei verschiedene Peripheriegeräte abfragen) ??
Reiner D. schrieb: > alles public > und fertig ... Also mal ein recht simples Beispiel: Wie sinnvoll wäre es bei deinem Segelschiff, wenn das Focksegel dem Kapitän sagen kann: Alle über Board? Wenn du alles public machst ist es nur eine Frage der Zeit bis dein Schoner auf Grund läuft.
Reiner D. schrieb: > Arduino F. schrieb: >> Mehrere I2C Ports, dann auch mehrere z.B. Wire Instanzen. > > nochmal nachgefragt : Ich kann z.B auf dem AtMega256 aus zwei Instanzen > "gleichzeitig" (also innerhalb des Befehlszyklus) auf die > I2C-Schnittstelle zugreifen (also z.b. zwei verschiedene > Peripheriegeräte abfragen) ?? I2C ist "single master / multiple client". Also Dein AVR kann viele Clients abfragen.
Reiner D. schrieb: > Ich kann z.B auf dem AtMega256 aus zwei Instanzen > "gleichzeitig" (also innerhalb des Befehlszyklus) auf die > I2C-Schnittstelle zugreifen Kannst du, das wird aber Chaos verursachen. Du kannst entweder nacheinander auf eine I2C-Schnittstelle zugreifen, oder gleichzeitig auf verschiedene. Alles weitere bliebt dir überlassen. Oliver
M. K. schrieb: > Wenn du alles public machst ist es nur eine Frage der Zeit bis dein > Schoner auf Grund läuft. Danke für das schöne Bild ;-) Ich weiß, ich kämpfe gegen Windmühlen, trotzdem : Ich brauche keine getter/setter, wenn ich eh keine Fehlerprüfung mache. Was hat ein setter dann für einen Sinn ? Wiederverwendbarkeit und sowas ist gut für Profi-Projekte, ich brauch das nicht in meinem Spielzeugkontext. Trotzdem bin ich brennend an diesen Aussagen interessiert, weil mir ja gerade der professionelle Blick auf das Thema fehlt !
Wilhelm M. schrieb: > I2C ist "single master / multiple client". .. wie wohl jedes Bussystem. Aber deshalb ist der Master "nach hinten" noch lange nicht multiinstanzfähig.
Reiner D. schrieb: > M. K. schrieb: >> Wenn du alles public machst ist es nur eine Frage der Zeit bis dein >> Schoner auf Grund läuft. > > Danke für das schöne Bild ;-) > Ich weiß, ich kämpfe gegen Windmühlen, trotzdem : > > Ich brauche keine getter/setter, wenn ich eh keine Fehlerprüfung mache. > Was hat ein setter dann für einen Sinn ? In C++ sagt man auch nicht unbedingt getter/setter. Die Unterscheidung kann hier der Compiler anhand des const-Attributes machen. "Setter" haben die Aufgabe, nicht vorgesehene Objektzustände in Form von Zusicherungen auszuschließen und ggf. Abbildungen zwischen extern sichtbarem und intern modelliertem Zustand zu machen. Stell Dir vor eine Klasse Point, die intern die Koordinaten in Polarkoordinaten modelliert, jedoch nach außer auch Cartesische Koordinaten anbietet. > > Wiederverwendbarkeit und sowas ist gut für Profi-Projekte, ich brauch > das nicht in meinem Spielzeugkontext. Dur wirst Dich freuen, wenn Du nach 2 Wochen Pause Deinen eigenen Code wieder anschaust.
Reiner D. schrieb: > Wilhelm M. schrieb: >> I2C ist "single master / multiple client". > > .. wie wohl jedes Bussystem. Aber deshalb ist der Master "nach hinten" > noch lange nicht multiinstanzfähig. Nö. Es gibt Multi-Master Busse.
Reiner D. schrieb: > nochmal nachgefragt : Eigentlich dachte ich, dass ich mich deutlich ausgedrückt hätte! Das war ein Irrtum....
Du könntest dir auch das Leben leichter machen und Platinchen (Matrosen) bauen. Ein kleiner MC und die Motortreiber darauf. Das würde dein Softwareproblem und den Kabelverhau reduzieren und skalierbar sein.
Arduino F. schrieb: > Wilhelm M. schrieb: >> I2C ist "single master / multiple client". > > I2C ist Multimaster fähig. Da hast Du natürlich recht!
Reiner D. schrieb: > Ich brauche keine getter/setter, wenn ich eh keine Fehlerprüfung mache. > Was hat ein setter dann für einen Sinn ? > > Wiederverwendbarkeit und sowas ist gut für Profi-Projekte, ich brauch > das nicht in meinem Spielzeugkontext. Es geht ja weder darum, dass man so etwas zwingend braucht oder ob etwas ein "Profiprojekt" ist. Natürlich kann man ohne auskommen. Aber insgesamt lebt es sich mit einer sauberen Datenkapselung (getter/setter) deutlich einfacher, je größer das Projekt wird. Die mentale Last wird sehr reduziert, wenn du dir nicht ständig Gedanken darüber machen musst, wer denn jetzt wieder von wo direkt auf irgendeine Variable zugreifen könnte. Was heute eine einfache Variable ist, kann morgen komplexer sein. Und mit einer sauberen Kapselung sind solche Anpassungen meist Klasseninterna. Außerdem finde ich es lustig, wie zwischen Hobby- und Profiprojekt unterscheidest. :) Ich kann dir versichern, dass so manches Profiprojekt aussieht, als wäre es von Amateuren zusammengestümpert worden. Wenn ich eins gelernt habe, dann: Überall wird gefrickelt. Nirgendwo wird alles perfekt oder nach der "reinen Lehre" gemacht. Und am Ende funktioniert es dann meistens doch irgendwie zuverlässig. Man kann sich aber sehr sehr viel Arbeit sparen, wenn man einige Dinge von vorne herein richtig macht. Und da gehört eine vernünftige Datenkapselung IMO mit an die erste Stelle.
Beitrag #7385405 wurde vom Autor gelöscht.
Nochmal : ok, ihr habt mit den meisten Aussagen wohl recht Nochmal : danke ! Verzeiht provozierende Rückfragen, ich versuche nur, den Kern der jeweiligen Thematik freizulegen. Wie ist das allgemein hier ? Technisches Forum mit möglichst knapper, präziser Info, oder ist auch Geplauder erlaubt ? Wenn nicht erwünscht, sollten wir das Kaffeekränzchen stoppen, ansonsten macht's Spaß.
Geplauder (Abschweifungen und ähnliches) gehört IMHO immer dazu wenn man tiefer ins Thema einsteigt und sich auch prima austauscht so wie das hier im Thread grade der Fall ist. Wichtig ist eigentlich nur, dass man auch den Bogen zum Threadthema wieder zurück findet.
:
Bearbeitet durch User
Hans-Georg L. schrieb: > Du könntest dir auch das Leben leichter machen und Platinchen (Matrosen) > bauen. Ein kleiner MC und die Motortreiber darauf. Das würde dein > Softwareproblem und den Kabelverhau reduzieren und skalierbar sein. Da hast du mit Sicherheit recht. Wär ja auch spaßig, jede relevante Arbeit von nem kleinen Nano oder sowas machen lassen, quasi "Hardwareobjekte", und das über ein Bussystem zu vernetzen. (Sowas hatte ich schon mal : ein Raspi mit Python hat kommuniziert (OPCuA)und gerechnet, ein Ardu seriell dran hat eine Delta-HW gesteuert. Aber Hardware ist aktuell nicht mein Ding, ich tippe grad lieber und gehe auf die Reise durch die neue Welt der Objektorientierung. Den Python-Gedanken hat keiner aufgegriffen : AVR und Python, geht das ?
Reiner D. schrieb: > AVR und Python, geht das ? Das Plenken solltest du dir wirklich abgewöhnen. Ansonsten schau dich hier um: https://micropython.org/ -> Sollte wohl etwas "dicker" als ein kleiner AVR werden.
Reiner D. schrieb: > ist das "Plenken" ? Reiner D. schrieb: > um das zu lösen ?? Reiner D. schrieb: > Was tun ? Reiner D. schrieb: > Stück Beispielcode zu zeigen ? Reiner D. schrieb: > der dann dem Objekt zugeordnet ist ? usw.
In meinem Alter nehme ich mir das Recht auf "ästhetische Rechtschreibung". Und dazu zählt das, was du "Plenken" nennst. Mal ehrlich, schaut das gut aus : Beispiel: das ist nicht geplenkt! Ist doch geplenkt viel schöner : Beispiel : das ist geplenkt ! Ich hab doch Platz, wieso sollte ich das schöne Satzzeichen da dranquetschen ? (Und wieder : beim Komma passt das finde ich, beim Fragezeichen nicht !!) Ich hab hier eh schon nachgegeben, und verwende Großbuchstaben. Einer hat geschrieben, er kann das nicht lesen ... Aber jetzt gleiten wir echt krass vom Thema ab ;-)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.