Hallo,
ich hab ein kleines Verständnisproblem mit "class" in C++.
Ich habe in einem Programm die FastLED Libary (Arduino) eingebunden.
Die Leds werden in einem struct festgehalten und wie folgt initialisiert
1
const int NUM_LEDS = 8;
2
CRGB leds[NUM_LEDS]
Ich möchte nun mit einer eigenen Libary auf die Datenwerte mit einer
class zugreifen und diese je nach aufgerufener Methode verändern. Doch
hier enden meine Kenntnisse komplett.
1
#include <FastLED.h>
2
const int NUM_LEDS = 10;
3
CRGB leds[NUM_LEDS];
4
5
class LedFX{
6
public:
7
int numLeds = NUM_LEDS;
8
// Fade aller Leds
9
bool fadeAll(int red, int green, int blue, unsigned long interval);
10
11
private:
12
// Interne Funktions zur Berechnung des Fades
13
int fadeVal(int val, unsigned long interval);
14
};
15
16
bool LedFX::fadeAll(int red, int green, int blue, unsigned long interval)
17
{
18
static int lastVal;
19
for (int led = 0; led < numLeds; led++)
20
{
21
leds[led][0] = fadeVal(red, interval);
22
leds[led][1] = fadeVal(green, interval);
23
leds[led][2] = fadeVal(blue, interval);
24
}
25
return true;
26
}
27
28
int LedFX::fadeVal(int val, unsigned long interval)
if (leds.fadeAll(255, 0, 255, 100)) FastLED.show();
75
}
76
return 0;
77
}
Jedoch funktioniert dieses vom Prinzip her überhaupt nicht. Habe mir das
"C++ Das umfassende Handbuch" aus dem Galileo Computing Verlag bereits
besorgt, dort wird leider auf dieses Thema nicht direkt eingegangen.
(Auf Klassen schon, aber nicht, wie ich ein solches struct mit den
Werten verändern kann).
Wäre für ein jeden Tipp dankbar.
Was "funktioniert nicht"?
Compiliert es nicht? ... Wenn ja, welche Compilermeldungen verstehst du
nicht?
Compiliert es, aber tut nicht was du denkst? wenn ja, was tut es, und
was erwartest du dass es tut?
In C++ ist der einzige Unterschied zwischen class und struct, dass in
struct per default alles public ist.
Stefan S. schrieb:> int numLeds = NUM_LEDS;
Das geht nicht, Member-Variablen dürfen nicht im class-Body
initialisiert werden, es sei denn sie sind constexpr. Sonst nur im
Konstruktor
Stefan S. schrieb:> static int lastVal;
Die Variable wird gar nicht benutzt...
Stefan S. schrieb:> static unsigned long lastMillis
Dir ist klar dass es im programm nur genau eine solche variable gibt,
die dann für r,g,b gilt - und somit g,b gar nicht bedient werden?
Stefan S. schrieb:> return true;
Wozu ein Rückgabewert wenn du eh immer nur true zurückgibst?
Stefan S. schrieb:> Auf Klassen schon, aber nicht, wie ich ein solches struct mit den Werten> verändern kann
Welches struct wie wo verändern? Du meinst wie in fadeAll? Genauso wie
du geschrieben hast.
Stefan S. schrieb:> if (leds.fadeAll(255, 0, 255, 100))
leds ist doch gar keine Instanz von LedFX, das ist doch Unsinn.
Und ganz allgemein - wozu ist deine Klasse LedFX da? Was stellt eine
Instanz der Klasse dar? Was soll passieren wenn man 5 LedFX Instanzen
anlegt? Die Klasse greift auf die globale Variable leds zu, mehrere
Instanzen würden sich vermutlich stören. Du solltest per Konstruktor
übergeben, worauf die Klasse zugreifen soll. SO ist die Klasse
jedenfalls sinnlos - sie repräsentiert kein Objekt und enthält keine
Daten - da kannst du sie auch weglassen umd die Funktionen global
machen...
Hallo Sebastian,
der Compiler haut mir natürlich Fehler raus, welche ich aber soweit
begründen kann, jedoch weiß ich nicht, wie es richtig an dieser Stelle
funktioniert.
[quote]Compiling 'test' for 'Arduino Pro or Pro Mini w/ ATmega328 (5V,
16 MHz)'
test.ino:10: error: ISO C++ forbids initialization of member 'numLeds'
test.ino:10: error: making 'numLeds' static
test.ino:10: error: ISO C++ forbids in-class initialization of non-const
static member 'numLeds'
test.ino:In function 'int main()'
test.ino:77: error: request for member 'fadeAll' in 'leds', which is of
non-class type 'CRGB [10]'
Error compiling
[/quote]
Das Programm funktioniert somit auch nicht wie gewollt.
Was in der class fehlt, ist eine Initialisierung/Konstruktor(!?).
Ich brauche aber einen Zeiger auf einen Struct. (CRGB leds[NUM_LEDS])
Habe Code etwas angepasst, was aber nicht so erfolgt wie gewünscht. Die
class soll später ausgelagert werden in eine Libary. Der Fade
funktioniert gerade garnicht gescheit. Es sieht ein bisschen wie ein
Lauflicht aus, kann aber auch sein, dass ich irgendwo die Funktion
zerschossen haben.
Ich bau das noch einmal eben um und stelle entsprechend den Code neu
rein.
Lese doch bitte lieber schritt für schritt ein C++ Buch durch als wild
irgendwelchen Code zusammenzuwürfeln. Insbesondere über 'static'. Und
dann überlegst du dir warum/ob du eine Klasse brauchst und was die
Instanzen der Klasse darstellen sollen. Einfach 'static' an die numLeds
Variable dranzuschreiben macht vermutlich nicht das was du willst und
erspart dir nicht das Schreiben eines Konstruktors.
Ich kann dem Dr. Sommer eigentlich nur zustimmen - deine Klasse hat
keine Daten (außer der numLeds Konstanten, die es unter anderem Namen
aber eh schon gibt). So macht Sie nicht viel Sinn. wenn du nur
Funktionen irgendwie "zusammenfassen" willst, wär vielleicht ein
namespace das richtige.
Zu deinem Problem:
> Ich brauche aber einen Zeiger auf einen Struct.> (CRGB leds[NUM_LEDS])
Wozu? (Was willst du mit dem Zeiger tun? An was übergeben?...)
Und ist CRGB nicht ein Struct Typ? (Ich kenn den Header FastLED nicht)
Falls CRGB ein struct ist, dann ist das seltsam:
> leds[led][0]
das würde eher passen, wenn es ein Array wäre.
Oder willst du wissen, wie du 3 elemente eines Arrays in 3 elemente eies
structs kopierst?
Stefan S. schrieb:> Ich brauche aber einen Zeiger auf einen Struct. (CRGB leds[NUM_LEDS])
Wir haben hier durchaus öfter den Fall, dass ein Themenersteller meint
unbedingt einen bestimmten Lösungsansatz zu brauchen, was sich aber
nicht selten als totaler Quatsch herausstellt. ;-)
Es gibt hier nur einen richtigen Ansatz: Beschreibe die Aufgabe, also
das was zu tun ist. Über das "wie" sollte erst danach entschieden
werden. Ich verwette eine Flasche Bier darauf, dass eine wunderbar
funktionierende Lösung völlig ohne irgendwelche Zeiger auf irgendeine
struct auskommt.
In den Code-Beispielen, die man auf dieser Seite herunterladen kann:
https://github.com/FastLED/FastLED
wird CRGB im übrigen wie folgt verwendet (per Volltextsuche
aufgelistet). Da ist also nix mit "Zeiger auf Struktur". Was zu erwarten
war. ;-)
Mark Brandis schrieb:> Stefan S. schrieb:>> Ich brauche aber einen Zeiger auf einen Struct. (CRGB leds[NUM_LEDS])>> Wir haben hier durchaus öfter den Fall, dass ein Themenersteller meint> unbedingt einen bestimmten Lösungsansatz zu brauchen, was sich aber> nicht selten als totaler Quatsch herausstellt. ;-)>> Es gibt hier nur einen richtigen Ansatz: Beschreibe die Aufgabe, also> das was zu tun ist. Über das "wie" sollte erst danach entschieden> werden. Ich verwette eine Flasche Bier darauf, dass eine wunderbar> funktionierende Lösung völlig ohne irgendwelche Zeiger auf irgendeine> struct auskommt.
Hallo,
natürlich funktioniert das ganze auch gänzlich ohne die Zeiger auf
struct und dem Einsatz der Class. Ich habe alles mit Funktionen
aufgebaut, die alle in der main.c liegen.
Mein Aufbau derzeit:
/* main.c */
Include FastLED Libary
Struct anlegen und Größe definieren
Hier folgen nun meine eigenen Funktionen
int main(void) {
Initialisierung der FastLED Libary (Chipsatz, DATA_PIN)
while(1) { /* Hier werden die Funktionen aufgerufen */ }
return 0;
}
Was ich jedoch gerne möchte:
Die eigenen Funktionen sollen in einer einer eigenen c/cpp-Datei
unterkommen.
Die neue Datei soll als Libary funktionieren, sprich ich muss sie später
nur noch in meinem Header einbinden.
Das Problem ist, die Funktionen beinhalten einige Funktionen der FastLED
Libary. Das FastLED.show() rauszubekommen ist kein Problem. Dafür will
ich bei den Methoden/Funktionen ein return nutzen. FastLED.show() muss
nur genutzt werden, wenn eine Änderung erfolgt ist.
Jedoch weiß ich nicht, wie ich leds[x] hier ersetzen kann, ohne alle
Daten neuzudeklarienen.
Aufbau:
/* main.c */
Include FastLED Libary
Include Eigene Funktionen Libary
Struct anlegen und Größe definieren
int main(void) {
Initialisierung der FastLED Libary (Chipsatz, DATA_PIN)
>>> Eine Initialisierung der Eigenen Funktionen,
in dem das Struct als Zeiger übergeben wird sowie die NUM_LEDS.
while(1) { /* Hier werden die Funktionen aufgerufen */ }
return 0;
}
Stefan S. schrieb:> Jedoch weiß ich nicht, wie ich leds[x] hier ersetzen kann, ohne alle> Daten neuzudeklarienen.
Das Problem ist, das zu oft mit globalen Variablen gearbeitet wird, bzw.
die Grundlagen nicht gelernt wurden.
Denn dann wüsstest du, wie man ein Array an eine Funktion übergibt
1
intwerte[5];
2
3
voidfoo(int*daten)
4
{
5
daten[0]=1;
6
daten[1]=2;
7
}
8
9
intmain()
10
{
11
foo(werte);
12
}
du hast dann eben kein Array von int, sondern ein Array von CRGB's. Aber
das ändert nichts daran. Array ist Array und es wird an eine Funktion
übergeben, indem die Funktion einen Pointer auf das erste Array Element
bekommt. Ob das jetzt ein int-Array ist oder ein CRGB-Array ist hingegen
völlig wurscht.
Also: übergib deiner FUnktion das Array zusammen mit der Länge des
Arrays und alles wird gut.
1
voidfadeIt(CRGB*theLeds,intnumLeds)
2
{
3
for(i=0;i<numLeds;i++)
4
{
5
theLeds[i][0]=0;
6
theLeds[i][1]=0;
7
theLeds[i][2]=0;
8
}
9
10
....
11
}
12
13
voidloop()
14
{
15
16
...
17
fadeIt(leds,NUM_LEDS);
18
...
19
}
Wenn du die Funktion unbedingt in eine Klasse stecken willst - ok, kann
man machen. Dann kann man der fade Funktion das Array übergeben oder man
'zeigt' dem Objekt im Konstruktor mit welchem CRGB Array es arbeiten
soll. Beides ist möglich, wenn ich auch die Konstruktor-Variante
bevorzugen würde.
sebastian schrieb:> aber eh schon gibt). So macht Sie nicht viel Sinn.
Zugegeben.
Im Moment macht das noch nicht viel Sinn, die ganze Fade-Funktion in
eine Klasse zu stecken.
Interessanter wird das ganze dann, wenn man zb eine Effekt-Klasse hat,
von der dann unter anderem dieser Fader abgeleitet wird (oder auch zb
ein Lauflicht oder ...), und dann anfängt die fadeAll Funktion etwas zu
verändern. so wie sie jetzt ist, ist sie noch ein wenig behäbig
geschrieben. Das müsste unterteilt werden in einen Fade-Setup Teil und
einen 'Mach jetzt den nächsten Schritt der Arbeit' Teil. Denn letzterer
ist bei allen Effekten gleich und eine virtuelle Funktion, so dass man
mehrere Effekt-Objekte in einem Array sammeln kann und dann über die
virtuelle Funktion jedem Objekt den Auftrag gibt, in der jetzigen
Zeitsituation seinen Effekt einzustellen.
Aber: das ist alles noch Zukunftsmusik und dazu benötigt es dann schon
ein bischen bessere C++ Kentnisse des TO.
Aber was predige ich. Mitlerweile predige ich in jedem 3.ten Thread das
immer gleiche: Leute, lernt eure Programmiersprache!
Schön langsam bin ichs leid, den 350-ten durch die banalsten Untiefen
seiner Programmiersprache zu leiten, nur weil er nicht begreift, dass er
sich eine Menge Zeit und Frustr sparen würde, wenn er mal ein C++ Buch
durcharbeiten würde.