Hallo
Ich habe eine Menge RGB LEDs und um diese anzusteuern,
habe ich für jede eine Funktion geschrieben.
Letzt möchte ich diese Funktionen natürlich gerne in einer for-Schleife
aufrufen,
aber so klappt das nicht:
Du rufst die Funktion auf, an einer Stelle wo der Compiler sie noch
nicht kennt. Entweder du deklarierst deine Funktion über einen
Prototypen vor deiner loop. Oder fügst die loop unterhalb der Funktion
ein. Für die Software ist die Reihenfolge auch wichtig.
Danke, das mit der Reihenfolge wusste ich nicht :-)
Aber jetzt wird an dieser Stelle:
void led_[1](int r, int g, int b) { pwm0.setPWM(14, r, 0);
pwm0.setPWM(13, g, 0); pwm0.setPWM(15, b, 0);}
ein Fehler ausgegeben:
declaration of 'led_' as array of functions
Da sich die Funktionen nur in ein paar Zahlen unterscheiden, packt man
die Zahlen in ein struct, definiert sich eine einzelne Funktion die die
Daten aus dem struct verwendet und ruft diese wiederholt auf:
normalerweise macht man das so vorausgesetzt dein pwm0.xxx-Kram
funktioniert
ich gehe mal davon aus das der 1. setPWM den Pin der LED ist und die
LED pins jeweils nebeneinander liegen.
1
setLed(intled,intr,intg,intb){
2
//led: 1 bis 6
3
intpin=18-led*3;
4
pwm0.setPWM(pin,g,0);// hier je nach Belegung anpassen
5
pwm0.setPWM(pin+1,r,0);
6
pwm0.setPWM(pin+2,b,0);
7
}
was du da versuchst sieht nach Funktionspointern aus, es macht aber
normalerweise keinen sind für jede Led eine eigene Funktion zu
schreiben.
Außer die LEDs unterscheiden sich vollständig.
Guten Abend und danke für die beiden Codebeispiele!
Das erste mit dem struct verstehe ich noch nicht,
aber ich bin ja gewillt zu lernen.
Bei dem Zweiten muss ich leider sagen, nein die LEDs liegen nicht
nebeneinander.
Beim Löten hatte ich mir gedacht, es ist einfacher in der Software zu
machen
und keine Rcüksicht auf die Reihenfolge gelegt.
Es sind 4 PCA9685 Boards verbaut, von denen 2 auf dem Kopf liegen und
einzelne Pins übersprungen wurden.
Jetzt ärgere ich mich darüber :-(
Hier mal alle meine Funktionen um das Disaster sichtbar zu machen:
Die Funktion einer jeden Funktion habe ich überprüft und alles läuft,
wenn ich anstatt von Schleifen die Funktionen nacheinander aufrufe.
Danke für eure Hilfe!
Hier mal eine Variante für ein Array, gefüllt mit Strukturen.
2 LEDs habe ich übertragen, denn Rest darfst du machen.
Gezeigt wird eine Schleife über alle Elemente, und der Einzelzugriff.
1
structRgbLed
2
{
3
byter;// pin
4
byteg;// pin
5
byteb;// pin
6
7
RgbLed(byter,byteg,byteb):r(r),g(g),b(b){}
8
9
voidset(int_r,int_g,int_b)
10
{
11
pwm0.setPWM(r,_r,0);
12
pwm0.setPWM(g,_g,0);
13
pwm0.setPWM(b,_b,0);
14
}
15
};
16
17
18
//void led_01(int r, int g, int b) { pwm0.setPWM(14, r, 0); pwm0.setPWM(13, g, 0); pwm0.setPWM(15, b, 0);}
19
//void led_02(int r, int g, int b) { pwm0.setPWM(10, r, 0); pwm0.setPWM(9, g, 0); pwm0.setPWM(11, b, 0);}
Nachtrag:
Auch die pwm Dinger brauchen ein Array, oder einen Platz in diesem
Array.
pwm0.setPWM();
pwm1.setPWM();
pwm2.setPWM();
pwm3.setPWM();
Da sehe ich aber nicht wie diese definiert sind.
Auch daran sieht man mal wieder, dass es meist eine dumme Idee ist,
Variablen durchzunummerieren. Manchmal mag das ja OK sein, aber meist
nagelt man sich damit eine Frikadelle ans Knie.
Hi,
für jede einzelne LED eine Funktion zu definieren ist eine ziemliche
Speicherverschwendung und unnötige Schreibarbeit.
Was du brauchst ist eine Funktion und eine Look-Up-Table.
Das ist auch leicht auf eine beliebige Anzahl von LEDs anpassbar.
Arduino F. schrieb:> Denn es ist nur ein Flicken auf einer Designschwäche.
Ja, das ist richtig.
Da ich nicht weiss, woher die Funktionen pwmX.setPWM() stammen, bzw wie
diese aussehen, habe ich es mal so vorgeschlagen.
Idealerweise gibt es natürlich auch nur eine setPWM Funktion für die 4
PCA9685 (ungünstig auch die Funktionsnamensgleichheit), und die nimmt
als Argument led_lut[led][0] entgegen und spricht dann den
entsprechenden PCA9685 an. Dann kann der ganze switch-Kram entfallen.
Joe F. schrieb:> Da ich nicht weiss, woher die Funktionen pwmX.setPWM() stammen, bzw wie> diese aussehen, habe ich es mal so vorgeschlagen.
Geht mir auch so.
Arduino F. schrieb:> Ich stimme ausdrücklich gegen das switch Statement.> Denn es ist nur ein Flicken auf einer Designschwäche.
Das verstehe ich natürlich nicht ;-)
Joe F. schrieb:> Was du brauchst ist eine Funktion und eine Look-Up-Table.
Das Prinzip schon ehr!
Ich hatte mir mit Excel eine Zuordnungstabelle gemacht,
als ich die einzelnen Pins den (Hardware)Ausgängen zugeordnet habe.
Hätte ich dieses Weg doch weiter verfolgt.
edit:
Die Änderung im Aufruf der stePWM Funktion liegt daran, dass mit der
obrigen Variante die LEDs nur an und aus geschaltet, aber nicht gedimmt
werden können.
Kolja L. schrieb:> for (int j = 1; j <= 4; j++) {> pwm_driver[j].begin();
Klassiker... In allen vernünftigen™ Programmiersprachen (inkl. C++,
worauf Arduino basiert) beginnen Arrays bei 0. D.h. ein Array mit 4
Elementen hat die Indices 0,1,2,3. Das j in deiner Schleife nimmt aber
die Werte 1,2,3,4 an. Davon stürzt das Programm ab.
Kolja L. schrieb:> for (int j = 1; j <= 4; j++) {
PS: Man sollte grundsätzlich "size_t" statt "int" für Array-Indices (und
somit auch für Schleifenzähler zum Iterieren durch Arrays) nutzen.
Gerade z.B. beim AVR geht "int" nur bis 32768, während man aber auch
größere Arrays anlegen kann (zumindest im Flash). Ähnliche Probleme hat
man auf AMD64 - da geht "int" nur bis 2147483647, aber Arrays können
größer werden (wenn auch selten). Solche Probleme erschlägt man einfach
mit "size_t".
Man kann sich außerdem angewöhnen immer mit "++i" zu inkrementieren
statt "i++", denn in C++ kann man diese Operatoren überladen, und wenn
"i" mal ein Iterator statt eines Integers ist könnte "i++" u.U.
langsamer sein, weswegen es vorteilhaft ist einfach immer "++i" zu
schreiben (ist für Integer natürlich irrelevant). Gilt natürlich nur
wenn man nicht explizit das Verhalten von "i++" haben will, nämlich die
Rückgabe das vorherigen Werts statt des neuen Werts wie bei "++i".
Dr. Sommer schrieb:> Man sollte grundsätzlich "size_t" statt "int" für Array-Indices (und> somit auch für Schleifenzähler zum Iterieren durch Arrays) nutzen.
Nunja, wenn man (möglichst) keinen Index händisch nutzt, kann man sich
auch (hoffentlich) nicht die Ohren brechen.
Arduino F. schrieb:> Nunja, wenn man (möglichst) keinen Index händisch nutzt, kann man sich> auch (hoffentlich) nicht die Ohren brechen.
Korrekt, aber es lässt sich halt nicht immer vermeiden. Die "Unsitte",
für alles und jedes "int" zu nutzen, stammt wohl aus Java... da können
Arrays auch nur max 2^31-1 Elemente enthalten, selbst wenn man Terabytes
an RAM hat... Soviel zu dessen Portabilität!
Dr. Sommer schrieb:> Man sollte grundsätzlich "size_t" statt "int" für Array-Indices (und> somit auch für Schleifenzähler zum Iterieren durch Arrays) nutzen.
Oh ja, es ist auch sehr sinnvoll, für einen Zähler der von 0 bis 3 zählt
mindestens 16 Bit zu verwenden. Besser noch 32 oder 64.
Karl schrieb:> Oh ja, es ist auch sehr sinnvoll, für einen Zähler der von 0 bis 3 zählt> mindestens 16 Bit zu verwenden.
Der OP hat ja auch 16bit genutzt. Da kann man es auch gleich richtig
machen. Und man kann sich generell durchaus eine Vorgehensweise
angewöhnen, die garantiert immer funktioniert. Im Einzelfall kann man
das falls nötig optimieren.
Karl schrieb:> Besser noch 32 oder 64.
Je nach Plattform sind größere Integer effizienter als kleinere. ARM
kann z.B. mit 32bit besser als mit 16bit rechnen. i.A. ist size_t
optimal effizient, da sind Plattformen wie AVR der Sonderfall weil diese
einen 16bit-Adressraum und eine 8bit-ALU haben.
Ein eher akademisches Problem...
Denn hier haben wir es nicht mit so großen Indices zu tun.
Byte dürfte reichen.
Auch die Java Geschichte muss uns hier nicht belasten.
Der ESP rechnet übrigens gerne mit 32 Bit.
Arduino F. schrieb:> Ein eher akademisches Problem...
Das scheint auch mir so zu sein ;-)
Jetzt aber Danke an Alle, die mir hier geholfen haben!
Las Lauflicht läuft jetzt wie es soll:
Im setup() leuchten alle LED in weiß kurz auf und gehen dann aus.
(Gut für die Funktionskontrolle)
Im loop() laufen 5 Farben durch.
Jetzt mache ich mich an die Umsetzung der Steuerung über eine Webseite
:-)
Gruß Kolja
P.S.
Dr. Sommer schrieb:> So gehts noch etwas einfacher/schöner:
Das habe ich leider nicht zum Laufen bringen können.
(Bis auf die erste Zeile)
Dr. Sommer schrieb:> Gerade z.B. beim AVR geht "int" nur bis 32768, während man aber auch> größere Arrays anlegen kann (zumindest im Flash).
Standardkonform können solche Arrays aber weder angelegt noch
zugegriffen werden; in avr-g++ von dem hier wohl die Rede ist, geht das
nur mit (inline) Assembler.
1
extern const char a[0x8000];
2
3
error: size of array 'a' is too large
Selbst mit GNU-C und __memx können solche Arrays nicht angelegt werden,
und bei Zugriff sind die Indices auf signed 16 Bit beschränkt.
1
intread_memx(const__memxint*mem,longi)
2
{
3
returnmem[i];
4
}
5
6
/*
7
read_memx:
8
lsl r20
9
rol r21
10
mov r26,r24
11
movw r24,r22
12
add r24,r20
13
adc r25,r21
14
adc r26,__zero_reg__
15
sbrc r21,7
16
dec r26
17
movw r30,r24
18
mov r21,r26
19
rcall __xload_2
20
movw r24,r22
21
ret
22
*/
Von i werden also nur 16 Bits verwendet, und i wird signed
expandiert. Der Offset (in Bytes gerechnet) ist also immer in [-32768,
32767]. Nicht weiter verwunderlich, denn size_t ist "unsigned int".
Johann L. schrieb:> Standardkonform können solche Arrays aber weder angelegt noch> zugegriffen werden;
Na sowas, okay, das wusste ich nicht. Für Indices finde ich unsigned
Zahlen aber trotzdem irgendwie schöner...
Kolja L. schrieb:> for (int j = 0; j <= 3; j++)Kolja L. schrieb:> for (int j = 0; j <= 17; j++)
Ich möchte dir von den magischen Zahlen 3 und 17 abraten.
Nicht unbedingt bei dieser Anwendung.
Eher grundsätzlich.
Duplikate solcher Konstanten(magischen Zahlen) sind ähnlich böse, wie
durchnummerierte Variablen.
Jedes (Code) Duplikat ist eine potentielle Fehlerquelle, ins besondere
wenn man was ändern muss.
So könntest du die "<= 17" durch "< anzahlLED" ersetzen, und bräuchtest
dich nicht zu kümmern, wenn eine LED hinzugefügt oder weg genommen wird.
Was allerdings erst geht, wenn das Array global gemacht wird.