Guten Tag!
Leider fehlen mir noch viele Kenntnisse. Früher habe ich einiges auf C gemacht, aber C++ Variante, die Arduino 2 benutzt, ist für mich Neufeld...
Die Frage: wie können verschiedene Libs miteinander kommunizieren?
Ich habe nun universelle Scala gemacht, und zwar in zwei Varianten: auf C und als C++ Classe. Mit C ist mir einigermaßen klar, was ich weiter machen muß. Aber in C++ braucht Scala einige Funktionen von Arduino_GigaDisplay_GFX, die die Funktionen von Adafruit_GFX benutzt.
Um Rechtecke und Text in Scala zu benutzen, brauche ich Ein C++-Objekt, das erst in Hauptprogramm (*.ino) geschafft wird. D.h. Lib kann das Objekt nicht benutzen?
Jetzt ist alles in Hauptfile und funktioniert wie erwartet. Wenn ich aber versuche, class separat in *.h und *.cpp zu speichern, und in *.cpp besondere Objekt für Benutzen mit Scala zu machen, bekomme ich zwar keine Fehlermeldungen von Compiler, aber die Platine Arduino Giga blockiert sich (blinkt rot, so daß ich dann sie entsperren muß. Ich wiederhole - und wieder das Gleiche).
Doch, natürlich kann eine "Lib" das tun. Sie muss die Klassendeklaration kennen, und ihr muss ein Pointer auf die Objektinstanz übergeben werden. Dann kann die "Lib" munter Funktionen aufrufen, die das Objekt zur Verfügung stellt.
Mit Deiner Fehlerbeschreibung kann und mag ich hingegen nichts anfangen.
Nicht ganz. Interessant, wie ich ein Lib aus anderem Lib benutzen kann. In einem Lib brauche ich Funktionen aus anderem Lib, und im Hauptprogramm muß Objekt erst gemacht werden. Wie bekommt diese Funktionen Class aus Lib?
Also, im Hauptprogramm sind beide Lib deklariert.
Dann sind Objekte aus beiden gemacht.
Was sollte ich weiter tun, um Objekte aus dem ersten Lib für Objekte aus dem zweiten Lib sichtbar zu machen?
In Lib selbst etwas vorbereiten? Zeiger auf Funktionen, die in Hauptprogramm auf Objekte aus dem 1.Lib zeigen?
Libraries sollten niemals direkt auf Objekte des Hauptprogramms zugreifen. Es geht, aber ich weigere mich, dir diesen schmutzigen Trick zu zeigen.
Funktionen und Methoden in Libraries sollten immer nur auf die Dinge Zugreifen, die man ihr als Argument übergeben hat.
Wenn deine Skala z.B. eine Instanz der I2C Schnittstelle braucht, dann erzeuge im Hauptprogramm zuerst die I2C Instanz und übergebe diese dann der Skala Klasse im Konstruktor. Die Skala Klasse kann die Referenz auf die I2C in eine eigene Member Variable kopieren, um sie später wieder zu verwenden.
Vielleicht solltest du erst mal C++ auf dem PC lernen, bevor du es auf einem Mikrocontroller anwendest. Auf dem PC lernt man die Sprache viel leichter.
Funktionen und Methoden in Libraries sollten immer nur auf die Dinge
Zugreifen, die man ihr als Argument übergeben hat.
D.h. sollte ich in meinem Lib Zeiger auf Funktionen vorbereiten, die dann in Hauptprogramm mit entsprechenden Set-Funktionen aus meinem Lib eingestellt werden?
Wenn deine Skala z.B. eine Instanz der I2C Schnittstelle braucht, dann
erzeuge im Hauptprogramm zuerst die I2C Instanz und übergebe diese dann
der Skala Klasse im Konstruktor. Die Skala Klasse kann die Referenz auf
die I2C in eine eigene Member Variable kopieren, um sie später wieder zu
verwenden.
In C++ arbeitet man mit Referenzen auf Klassen und ruft darüber die Methoden der Klasse auf.
Deine Fragen sind zu unklar. Du benutzt falsche Begriffe und der Kontext fehlt. So kann man nicht vernünftig helfen. Das hier wird endlos dauern. Das ist mir zu anstrengend.
PCF8574 ist ein Mikrochip mit I2C Schnittstelle. Er dient dazu, den Mikrocontroller mit mehr I/O Pins zu erweitern.
Der Konstruktor von der PCF8574 Klasse kann mit einem Zeiger auf eine Instanz der I2C Schnittstelle (Twowire) aufgerufen werden. (Ich hätte eine Referenz genommen, aber ein Zeiger geht auch). Diese wird von fast allen anderen Funktionen benutzt, um mit dem Chip über die I2C Schnittstelle zu kommunizieren.
Die Twowire Klasse wird in einer anderen Lib von Arduino bereit gestellt.
Ich habe am Anfang meine *.ino - File gezeigt.
Aus Hauptfunktion void Maxim_scala::scala(uint16_t xx, uint8_t rahmen); werden Funktionen
void Maxim_scala::scala_rahmen(uint8_t einaus);
void Maxim_scala::scala_m_metka(uint8_t einaus);
void Maxim_scala::scala_metka(uint8_t einaus); gerufen, die alle eine Funktion aus anderem Lib display.fillRect(x,y,br,h,farbe); aufrufen.
Außerdem braucht meine Funktion void Maxim_scala::scala_ziffer(uint8_t einaus); Funktionen aus anderem Lib für Textausgabe:
display.setFont(NULL);
display.setTextSize(2);
display.setTextColor(farbe,hintergrundfarbe);
display.setCursor(x,y);
display.print(x);
Und das ist für mich gerade unklar: solange alles in *.ino bleibt, funktioniert das. Wie mache ich richtige Aufrufe von Funktionen
display.fillRect(x,y,br,h,farbe);
display.setFont(NULL);
display.setTextSize(2);
display.setTextColor(farbe,hintergrundfarbe);
display.setCursor(x,y);
display.print(x);
aus anderem Lib, wenn ich meine classe mit Funktionen aus dem +.ino-File in separate Files *.h und *.cpp auslagere?
Vielleicht solltest du erst mal C++ auf dem PC lernen
Für mich ist einfacher zu lernen, wenn es um etwas geht, was ich benutzen kann. Leider sind alle Schulbücher mit absolut irrelevanten Beispielen gefuttert, so wie Databank von Personen und so etwas, was ich wahrscheinlich nie im Leben brauchen werde. Und dort geht alles am Ende immer mit "print" aus, das stört auch enorm, um alles richtig zu verstehen...
Aber ich glaube, die Idee habe ich verstanden. Nun muß ich das in Code ausprobieren... Ich habe gerade das Buch von Torsten T. Will gekauft und lese das...
Leider sind alle Schulbücher mit absolut irrelevanten
Beispielen gefuttert, so wie Databank von Personen und so etwas, was ich
wahrscheinlich nie im Leben brauchen werde. Und dort geht alles am Ende
immer mit "print" aus, das stört auch enorm
Das machen die so, damit du dich auf das eigentliche Thema konzentrieren kannst und nicht gleichzeitig noch 5 andere Baustellen hast, wo etwas schief gehen kann.
um alles richtig zu verstehen...
Brauchst du Zeit. Die Sprache C++ war schon am Anfang so komplex, das viele sie damals abgelehnt hatten. Sowohl Linux als auch Windows wurden ganz bewusst in C programmiert, obwohl C++ da schon lange existierte.
Die Sprache ist 40 Jahre lang gewachsen. Ich habe in den 90er drei Jahre lang mit C++ gearbeitet und später noch ein paar Jahre als Hobby. Doch ich hatte nie das Gefühl, sie vollständig zu beherrschen. Und mittlerweile fühle ich mich sogar abgehängt. Liegt wohl zu Teil daran, dass ich seit dem mit vielen anderen Sprachen arbeiten musste. Irgendwann vergisst man Sprachen wieder, die man nicht ständig benutzt.
Nach dem Umbau kannst du deine Skalen übrigens auf mehreren Displays verteilt darstellen. Zum Beispiel
Für mich bleibt das als Hobby: ich bin ein Kirchenmusiker und lebe von Musik. Und alles, was ich auch als Hobby mache, ist irgendwie mit Musik verbunden.
Ich habe als Kind mit alten Telefonen experimentiert, und ich wusste theoretisch wie ein Computer funktioniert, lange bevor ich selbst einen hatte.
So landete ich zur Ausbildung bei der Bundespost-Telekom, und arbeitere danach bei Vodafone. Danach habe ich Backend Software für Smartphone Dienste geschrieben, dann für einen online Händler. Heute baue ich eine Cloud Plattform für den Handel von Dienstleistungen (z.B. DSL und Mobilfunkverträge).
So baut halt eins aufs andere auf. Ich hatte immer das Glück, in einem Bereich arbeiten zu dürfen, der sich mit privaten Interessen überlappte.
Apropos Kirchenmusik: Ich liebe Orgelkonzerte - auch wenn sie "nur" elektrisch ist. Das ist ein mächtiges Instrument. Wer es beherrscht hat meinen vollen Respekt.
Als Kind hatte ich zuerst Interesse für Elektronik, wie ich in der Musikschule war. Für Musikgeschichte brauchte man Schallplatten zu hören, aber damals war nicht möglich, einen Schalplattenspieler zu kaufen, das war Defizit (ich komme aus Rußland). Ich habe schließlich eins selber gemacht, fertige Mechanik gefunden und primitive Elektronik selber gebaut. Das dauerte aber lange...
Dann brauchte ich für Musikunterricht ein Metronom, und gleiche Geschichte: nicht möglich zu kaufen. Ich habe selber mehrere Versionen gebaut, zuerst primitiv mit 1x Analog von 4069, dann auch kompliziertere mit digitaler Anzeige, mit K561-Serie (Analog 4000B ). So blieb ich auch weiter dran: es gibt immer Kleinigkeiten, die man in Einzelzahl braucht und die für Wirtschaft wegen kleinen Bedarf nicht interessant sind... Nur war eine Pause, wie ich in Dresden studierte: kein Platz für Basteln. Trotzdem auch dort habe ich ein Box für Phantomspeisung für 6 Mikrofone gemacht :)
Die Orgeln: für mich ist am wichtigsten, daß eine Orgel gut funktioniert. Deshalb spiele ich lieber intakte Elektronik als mangelhafte Pneumatik. Obwohl manche Kollegen Elektronik strickt ablehnen. Im Sommer 2024 habe ich für Ebersdorf eine 3-man. Viscount Cantorum Trio Plus gekauft, mit Pedal. Dort sollte ich viel selber nachfeilen.
Also, einige Elektronikkenntnisse können einem Kirchenmusiker kaum stören :)
Jetzt bastele ich einen MIDI-Rekorder, da mit Orgel gekaufte nicht so funktioniert wie erwünscht. Langsam, Modul für Modul, Funktion um Funktion. Ich lerne dabei auch viel.
Wichtige Merkmale, die ich unbedingt brauche:
Tempowechsel, schnell, ohne in Menu gehen zu müssen (hier wird auch Scala-Funktion benutzt). Wahrscheinlich wird x1,6 in beide Seiten ausreichend.
Während "Note ein" und "Note aus" in MIDI standartisiert, mit Registerwechsel macht jeder Hersteller wie er will. Das Gerät sollte mit bestimmten Orgeln arbeiten können und auch Register- und Manualwechsel betätigen können.
Es sollte im Lauf Wiederholungen von Strophen anzugeben möglich sein, auch Vorspiel und Nachspiel. Daraus sollte Menu für bestimmten Gottesdienst machbar sein.
Das Gerät sollte leicht die Tonhöhe ändern können. +-6HT sollte ausreichend sein, vielleicht sogar +3-6HT. In Praxis spiele ich oft etwas tiefer als geschrieben, aber ich kann nicht erinnern, daß ich höher spielen sollte.
Da Registerwechsel in MIDI-Format sowieso nicht standartisiert, überlege ich, die Stücke statt in MIDI-Format in einem Text-Format zu speichern: so wird es leichter, später kleine Anpassungen per Hand zu machen. Kompatibilität mit anderen MIDI-Geräten ist hier nicht wichtig, da sowieso alles selber einzuspielen ist.
Apropos Kirchenmusik: Ich liebe Orgelkonzerte - auch wenn sie "nur"
elektrisch ist.
Orgel in Ebersdorf. Hintergrund: Pneumatik, die schon am Ende und keine Renovierung sinnvoll. Dennoch soll sie stehen bleiben, aus Denkmalschutzgründen.
Zweite Foto: Notenpult auf Gravitationsprinzip. Einfach Stück Stahl, darüber auch runde Stück Stahl (kein Rohr), steht einfach so auf dem Tisch :) Man kann den Pult frei bewegen.
HW ist II.Man. HW und Pedal erklingen über Hauptpaar von Lautsprechern. Positiv und Schwellwerk (I. und III. ) haben zweite Lautsprecherpaar, auf Emporebrüstung. So habe ich quasi Rückpositiv, ohne typischen Nachteile von akustischen Rückpositiv (Verstimmung wegen Temperaturdifferenz). Als Lautsprecher habe ich aktive Nahfeldmonitore von Adam Audio genommen: T8V als Hauptpaar und T7V als Emporebrüstungspaar. Trotz Aufschrei (das ist ja Zweckentfremdung, das sind ja keine PA-Lautsprecher) funktionieren sie ausgezeichnet. Nur sollte ich selbst 35 mm Rohr - Befestigung einbringen, weil das eben Monitorlautsprecher sind.
Viscount Cantorum Trio Plus (auch Uno Plus, die ich privat habe, und Duo Plus), das ist letzte Generation. Man kann Register selbst intonieren, praktisch wie bei einer akustischen Orgel! Aber in Lieferzustang klingt die Orgel etwas langweilig, man sollte wirklich alles ausführlich einstimmen.
Außerdem habe ich privat Viscount Cantorum Duo (ohne Plus. 20 kG), zu der ich relativ leichtes (20 kG) Pedal gebastelt habe und auch passende Ständer (10 kG) und Orgelbank (15 kG) angepaßt. Und noch dazu Notenpult (5 kG) für die ganze Breite gemacht, wie in Ebersdorf, nur viel leichter (nicht aus Eiche sondern aus Paulownia). Zu dem Satz gehören auch nach Bedarf je zwei Adam Audio T8 und T5. Diesen Satz benutze ich als mobile Orgel (nur für Konzerte, für reguläre GDs wäre Aufwand zu groß. Für die benutze ich Uno oder Duo ohne Pedal).
Nun habe ich auch die Variante mit Referenz ausprobiert.
Das funktioniert auch!!! :)
Auch interessant: Compilat hat gleiche Flash-Größe wie auch die Variante mit Zeiger. Ich dachte, es kommen kleine Unterschiede...
"Giga_012" ist Referenz-Variante. Zum Vergleich auch noch mal "Giga_011" als Zeiger-Variante, nun auch mit früher vergessenem "Header-Guard".
Weil Referenzen und Zeiger im Maschinencode exakt identisch sind.
Gibt es hier Vorteile von Zeiger- oder Referenzvariante?
Ich bin recht begeistert. Noch mal Vielen Dank!
Noch eine Frage:
werden #define aus Libs-*.h und *.cpp außen sichtbar? Gilt Verkapselung auch für Präprozessor-Befehle oder nicht?
ich habe nun auf einige #define in *.cpp verzichtet und direkten Zahlen für Bits verwendet (in "set_" und "get_" - Funktionen), weil es für mich unklar war: gilt Verkapselung auch für Präprozessor-Code oder nicht? Ich fürchtete daß eher nicht. Ich fürchtete, in der Zukunft wäre Namenskonflikt bei #define nicht auszuschließen.
Beispiel:
ich habe
1
voidMaxim_scala::set_scalaein(booleanxx){// 1 = Scala einschalten (Scala selbst, ohne Rahmen)
2
if(xx){mode|=(1<<0);}else{mode&=~(1<<0);}}
3
booleanMaxim_scala::get_scalaein(void){
4
if(mode&(1<<0)){return1;}else{return0;}}
geschrieben, obwohl eigentlich besser wäre
1
#define SCALABIT 0
2
voidMaxim_scala::set_scalaein(booleanxx){// 1 = Scala einschalten (Scala selbst, ohne Rahmen)
Weil Referenzen und Zeiger im Maschinencode exakt identisch sind.
Gibt es hier Vorteile von Zeiger- oder Referenzvariante?
"Hier" im Maschinencode kann es keine Vorteile geben, weil Referenzen und Zeiger exakt identisch sind.
Im Quelltext gibt es Unterschiede. Eine Referenz kann z.B niemals null sein und kann auch nicht geändert werden. Ein Zeiger kann hinfegen zur Laufzeit geändert werden. Anfangs zeigt er vielleicht auf nichts (0, null), dann zeigt er auf dich, und morgen auf mich. Ein nicht initialisierter Zeiger (mit zufälligem Inhalt) löst beim Lesen/Benutzen Probleme aus. Bei Referenzen kann das nicht passieren.
Vielen Leuten fällt es mit Zeigern leichter, Bockmisst zu bauen. Referenzen sind für sie sicherer.
Mit gefällt die Variante mit Zeiger besser. Ich muß sowieso statt Adafruit_GFX_Library etwas anderes nehmen, da Adafruit_GFX_Library nur mit den ersten 128 Zeichen aus der Codetabelle arbeiten kann. Schon für "MENÜ" und "für" sollte ich "MEN\x09a f\x081r" schreiben, aber auch das ist nur für "NULL"-Font möglich, andere Schriftarten erlauben in Adafruit_GFX_Library auch das nicht. Die Möglichkeit, im Lauf grafische Lib umzuschalten kann nützlich werden...
Früher, auf C, habe ich schon Bibliothek und Fonts gemacht, wo sogar gleichzeitig Umlaute und Kyrillisch möglich waren (was normalerweise nicht möglich ist: entweder Umlaute oder Kyrillisch, aber nicht zusammen). Für Umschalten war eine Funktion vorgesehen, die nach Bedarf Code aus String tauschte, und in oberen Teil von Tabelle habe ich Maps für Umlaute und Kyrillisch auf den freien Stellen wie es mir bequemer war platziert. Jetzt brauche ich allerdings kein Kyrillisch, nur Umlaute, aber ich brauche sie wirklich. Entweder muß ich meine alte Code in C++-Lib umbauen, oder finde ich was besseres in Internet...
Könntest du ein Beispiel als Bild posten, damit man mal sehen kann, wie
so was aussieht?
Ja, hier sind zwei Bilder
Scala kann man beliebig einstimmen. Z.B. wenn rdicke = 0 und grundfarbe = hintergrundfarbe (und Rahmen und Zeichen abgeschaltet), wird nur wirksame Teil der Scala gezeigt. Man kann so mehrere Scalas zusammen als ein Fenster benutzen.
Ich sehe aber, daß je weiter um so mehr Fragen kommen... Nun habe ich zwei dicke Bücher gekauft und CodeBlocks installiert. Ich möchte wirklich, wie Hans W. empfohlen hat, etwas mit Grundsachen von C++ üben - obwohl diese Sprache mich vor allem in Mikrocontroller-Bereich interessiert. Einfach um Umprogrammierungsressource von Giga zu sparen.