Forum: Mikrocontroller und Digitale Elektronik Über Funktionen "loopen" (Arduino IDE)


von Kolja L. (kolja82)


Lesenswert?

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:
1
void loop() {
2
int zeit = 30;
3
4
  for (int j = 1; j <= 18; j++) {
5
    led_[j](4096,0,0);
6
    delay(50);
7
  }
8
9
  for (int j = 18; j <= 1; j--) {
10
    led_[j](0,0,0);
11
    delay(50);
12
  }
13
14
15
} // loop
16
17
18
int  led_[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18};
19
void led_[1](int r, int g, int b) { pwm0.setPWM(14, r, 0);  pwm0.setPWM(13, g, 0);  pwm0.setPWM(15, b, 0);}
20
void led_[2](int r, int g, int b) { pwm0.setPWM(10, r, 0);  pwm0.setPWM(9,  g, 0);  pwm0.setPWM(11, b, 0);}
21
void led_[3](int r, int g, int b) { pwm0.setPWM(7,  r, 0);  pwm0.setPWM(6,  g, 0);  pwm0.setPWM(8,  b, 0);}
22
void led_[4](int r, int g, int b) { pwm0.setPWM(4,  r, 0);  pwm0.setPWM(3,  g, 0);  pwm0.setPWM(5,  b, 0);}

Die Fehlermeldung lautet: 'led_' was not declared in this scope
und zeigt auf den Aufruf der Funktion.

Wie mache ich soetwas richtig?

von Chris K. (Gast)


Lesenswert?

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.

von Kolja L. (kolja82)


Lesenswert?

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

von Dr. Sommer (Gast)


Lesenswert?

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:
1
struct PwmData {
2
  int a, b, c;
3
  void led (int r, int g, int b) {
4
    pwm0.setPWM(a,  r, 0);  pwm0.setPWM(b,  g, 0);  pwm0.setPWM(c,  b, 0);
5
  }
6
};
7
8
PwmData ledPwm [] = {
9
  { 14, 13, 15 },
10
  { 10, 9, 11 },
11
  { 7, 6, 8},
12
  { 4, 3, 5 }};
13
14
void loop() {
15
int zeit = 30;
16
  // Iteriere durch ganzes Array, d.h. von 0 bis 3
17
  for (size_t j = 0; j < (sizeof(ledPwm)/sizeof(ledPwm[0])); ++j) {
18
    ledPwm [j].led(4096,0,0);
19
    delay(50);
20
  }
21
}

von Scyte R. (scyte)


Lesenswert?

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(int led, int r, int g, int b){
2
   //led: 1 bis 6
3
   int pin = 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.

: Bearbeitet durch User
von Kolja L. (kolja82)


Lesenswert?

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:
1
void led_01(int r, int g, int b) { pwm0.setPWM(14, r, 0);  pwm0.setPWM(13, g, 0);  pwm0.setPWM(15, b, 0);}
2
void led_02(int r, int g, int b) { pwm0.setPWM(10, r, 0);  pwm0.setPWM(9,  g, 0);  pwm0.setPWM(11, b, 0);}
3
void led_03(int r, int g, int b) { pwm0.setPWM(7,  r, 0);  pwm0.setPWM(6,  g, 0);  pwm0.setPWM(8,  b, 0);}
4
void led_04(int r, int g, int b) { pwm0.setPWM(4,  r, 0);  pwm0.setPWM(3,  g, 0);  pwm0.setPWM(5,  b, 0);}
5
void led_05(int r, int g, int b) { pwm0.setPWM(1,  r, 0);  pwm0.setPWM(0,  g, 0);  pwm0.setPWM(2,  b, 0);}
6
void led_06(int r, int g, int b) { pwm1.setPWM(14, r, 0);  pwm1.setPWM(13, g, 0);  pwm1.setPWM(15, b, 0);}
7
void led_07(int r, int g, int b) { pwm1.setPWM(11, r, 0);  pwm1.setPWM(10, g, 0);  pwm1.setPWM(12, b, 0);}
8
void led_08(int r, int g, int b) { pwm1.setPWM(8,  r, 0);  pwm1.setPWM(7,  g, 0);  pwm1.setPWM(9,  b, 0);}
9
void led_09(int r, int g, int b) { pwm1.setPWM(5,  r, 0);  pwm1.setPWM(4,  g, 0);  pwm1.setPWM(6,  b, 0);}
10
void led_10(int r, int g, int b) { pwm1.setPWM(2,  r, 0);  pwm1.setPWM(1,  g, 0);  pwm1.setPWM(3,  b, 0);}
11
void led_11(int r, int g, int b) { pwm2.setPWM(1,  r, 0);  pwm2.setPWM(2,  g, 0);  pwm2.setPWM(0,  b, 0);}
12
void led_12(int r, int g, int b) { pwm2.setPWM(5,  r, 0);  pwm2.setPWM(6,  g, 0);  pwm2.setPWM(4,  b, 0);}
13
void led_13(int r, int g, int b) { pwm2.setPWM(8,  r, 0);  pwm2.setPWM(9,  g, 0);  pwm2.setPWM(7,  b, 0);}
14
void led_14(int r, int g, int b) { pwm2.setPWM(11, r, 0);  pwm2.setPWM(12, g, 0);  pwm2.setPWM(10, b, 0);}
15
void led_15(int r, int g, int b) { pwm2.setPWM(14, r, 0);  pwm2.setPWM(15, g, 0);  pwm2.setPWM(13, b, 0);}
16
void led_16(int r, int g, int b) { pwm3.setPWM(1,  r, 0);  pwm3.setPWM(2,  g, 0);  pwm3.setPWM(0,  b, 0);}
17
void led_17(int r, int g, int b) { pwm3.setPWM(4,  r, 0);  pwm3.setPWM(5,  g, 0);  pwm3.setPWM(3,  b, 0);}
18
void led_18(int r, int g, int b) { pwm3.setPWM(7,  r, 0);  pwm3.setPWM(8,  g, 0);  pwm3.setPWM(6,  b, 0);}

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!

von Einer K. (Gast)


Lesenswert?

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
struct RgbLed
2
{
3
  byte r; // pin
4
  byte g; // pin
5
  byte b; // pin
6
  
7
  RgbLed(byte r,byte g, byte b):r(r),g(g),b(b){}
8
9
  void set(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);}
20
21
RgbLed leds[2] = {{14,13,15},{10,9,11}};
22
23
24
25
void setup() 
26
{
27
  // alle weiß
28
  for(RgbLed & led:leds) led.set(255,255,255);
29
  
30
  
31
  delay(1000);
32
33
  
34
  // erste rot
35
  leds[0].set(255,0,0);
36
}
37
38
void loop() 
39
{
40
41
}

von Philipp K. (philipp_k59)


Lesenswert?

Kolja L. schrieb:
> Jetzt ärgere ich mich darüber :-(

Mappe Dir das doch mit nem kleinen Array.. fällt kaum auf und ist 
übersichtlicher.

von Einer K. (Gast)


Lesenswert?

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.

Beitrag #5303472 wurde vom Autor gelöscht.
von Joe F. (easylife)


Lesenswert?

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.
1
void setPWM(uint8_t led, uint8_t r, uint8_t g, uint8_t b)
2
{
3
  const uint8_t led_lut[18][4] = {
4
    { 0, 14, 13, 15 }, // LED 1
5
    { 0, 10,  9, 11 }, // LED 2
6
    { 0,  7,  6,  8 }, // LED 3
7
    
8
    // ...
9
    
10
    { 3,  7,  8,  6 }  // LED 18
11
  }
12
  
13
  switch (led_lut[led][0])
14
  {
15
    case 0:
16
      pwm0.setPWM(led_lut[led][1], r, 0);
17
      pwm0.setPWM(led_lut[led][2], g, 0);
18
      pwm0.setPWM(led_lut[led][3], b, 0);
19
      break;
20
      
21
    case 1:
22
      pwm1.setPWM(led_lut[led][1], r, 0);
23
      pwm1.setPWM(led_lut[led][2], g, 0);
24
      pwm1.setPWM(led_lut[led][3], b, 0);
25
      break;
26
    
27
    case 2:
28
      pwm2.setPWM(led_lut[led][1], r, 0);
29
      pwm2.setPWM(led_lut[led][2], g, 0);
30
      pwm2.setPWM(led_lut[led][3], b, 0);
31
      break;
32
33
    case 3:
34
      pwm3.setPWM(led_lut[led][1], r, 0);
35
      pwm3.setPWM(led_lut[led][2], g, 0);
36
      pwm3.setPWM(led_lut[led][3], b, 0);
37
      break;
38
39
    default:
40
      break;
41
  }
42
}

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Joe F. schrieb:
> switch (led_lut[led][0])

Ich stimme ausdrücklich gegen das switch Statement.
Denn es ist nur ein Flicken auf einer Designschwäche.

von Joe F. (easylife)


Lesenswert?

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.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

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.

von Kolja L. (kolja82)


Lesenswert?

Schönen Sonntag :-)


Arduino F. schrieb:
> Da sehe ich aber nicht wie diese definiert sind.

Hier mal der komplette Code:

1
#include <Wire.h>
2
#include <Adafruit_PWMServoDriver.h>
3
4
Adafruit_PWMServoDriver pwm0 = Adafruit_PWMServoDriver(0x41);
5
Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x40);
6
Adafruit_PWMServoDriver pwm2 = Adafruit_PWMServoDriver(0x44);
7
Adafruit_PWMServoDriver pwm3 = Adafruit_PWMServoDriver(0x42);
8
9
void setup() {
10
  Wire.pins(13, 12);                      // Wire.pins(13, 12);
11
  Serial.begin(115200);
12
  pwm0.begin();  pwm0.setPWMFreq(800);
13
  pwm1.begin();  pwm1.setPWMFreq(800);
14
  pwm2.begin();  pwm2.setPWMFreq(800);
15
  pwm3.begin();  pwm3.setPWMFreq(800);
16
#ifdef TWBR                                
17
  uint8_t twbrbackup = TWBR;               
18
  TWBR = 12;                               
19
#endif
20
21
  for (int j = 0; j <= 15; j++) {         //Alle Pins aus 
22
    pwm0.setPWM(j, 0, 4096);
23
    pwm1.setPWM(j, 0, 4096);
24
    pwm2.setPWM(j, 0, 4096);
25
    pwm3.setPWM(j, 0, 4096);
26
    //   led_ . j(4096,0,0)
27
  }
28
} // setup
29
30
void loop() {
31
}
32
33
void led_01(int r, int g, int b) {
34
  pwm0.setPWM(14, 4095 - r, 4095);
35
  pwm0.setPWM(13, 4095 - g, 4095);
36
  pwm0.setPWM(15, 4095 - b, 4095);
37
}
38
void led_02(int r, int g, int b) {
39
  pwm0.setPWM(10, 4095 - r, 4095);
40
  pwm0.setPWM(9,  4095 - g, 4095);
41
  pwm0.setPWM(11, 4095 - b, 4095);
42
}
43
void led_03(int r, int g, int b) {
44
  pwm0.setPWM(7,  4095 - r, 4095);
45
  pwm0.setPWM(6,  4095 - g, 4095);
46
  pwm0.setPWM(8,  4095 - b, 4095);
47
}
48
void led_04(int r, int g, int b) {
49
  pwm0.setPWM(4,  4095 - r, 4095);
50
  pwm0.setPWM(3,  4095 - g, 4095);
51
  pwm0.setPWM(5,  4095 - b, 4095);
52
}
53
void led_05(int r, int g, int b) {
54
  pwm0.setPWM(1,  4095 - r, 4095);
55
  pwm0.setPWM(0,  4095 - g, 4095);
56
  pwm0.setPWM(2,  4095 - b, 4095);
57
}
58
void led_06(int r, int g, int b) {
59
  pwm1.setPWM(14, 4095 - r, 4095);
60
  pwm1.setPWM(13, 4095 - g, 4095);
61
  pwm1.setPWM(15, 4095 - b, 4095);
62
}
63
void led_07(int r, int g, int b) {
64
  pwm1.setPWM(11, 4095 - r, 4095);
65
  pwm1.setPWM(10, 4095 - g, 4095);
66
  pwm1.setPWM(12, 4095 - b, 4095);
67
}
68
void led_08(int r, int g, int b) {
69
  pwm1.setPWM(8,  4095 - r, 4095);
70
  pwm1.setPWM(7,  4095 - g, 4095);
71
  pwm1.setPWM(9,  4095 - b, 4095);
72
}
73
void led_09(int r, int g, int b) {
74
  pwm1.setPWM(5,  4095 - r, 4095);
75
  pwm1.setPWM(4,  4095 - g, 4095);
76
  pwm1.setPWM(6,  4095 - b, 4095);
77
}
78
void led_10(int r, int g, int b) {
79
  pwm1.setPWM(2,  4095 - r, 4095);
80
  pwm1.setPWM(1,  4095 - g, 4095);
81
  pwm1.setPWM(3,  4095 - b, 4095);
82
}
83
void led_11(int r, int g, int b) {
84
  pwm2.setPWM(1,  4095 - r, 4095);
85
  pwm2.setPWM(2,  4095 - g, 4095);
86
  pwm2.setPWM(0,  4095 - b, 4095);
87
}
88
void led_12(int r, int g, int b) {
89
  pwm2.setPWM(5,  4095 - r, 4095);
90
  pwm2.setPWM(6,  4095 - g, 4095);
91
  pwm2.setPWM(4,  4095 - b, 4095);
92
}
93
void led_13(int r, int g, int b) {
94
  pwm2.setPWM(8,  4095 - r, 4095);
95
  pwm2.setPWM(9,  4095 - g, 4095);
96
  pwm2.setPWM(7,  4095 - b, 4095);
97
}
98
void led_14(int r, int g, int b) {
99
  pwm2.setPWM(11, 4095 - r, 4095);
100
  pwm2.setPWM(12, 4095 - g, 4095);
101
  pwm2.setPWM(10, 4095 - b, 4095);
102
}
103
void led_15(int r, int g, int b) {
104
  pwm2.setPWM(14, 4095 - r, 4095);
105
  pwm2.setPWM(15, 4095 - g, 4095);
106
  pwm2.setPWM(13, 4095 - b, 4095);
107
}
108
void led_16(int r, int g, int b) {
109
  pwm3.setPWM(1,  4095 - r, 4095);
110
  pwm3.setPWM(2,  4095 - g, 4095);
111
  pwm3.setPWM(0,  4095 - b, 4095);
112
}
113
void led_17(int r, int g, int b) {
114
  pwm3.setPWM(4,  4095 - r, 4095);
115
  pwm3.setPWM(5,  4095 - g, 4095);
116
  pwm3.setPWM(3,  4095 - b, 4095);
117
}
118
void led_18(int r, int g, int b) {
119
  pwm3.setPWM(7,  4095 - r, 4095);
120
  pwm3.setPWM(8,  4095 - g, 4095);
121
  pwm3.setPWM(6,  4095 - b, 4095);
122
}

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.

: Bearbeitet durch User
von Joe F. (easylife)


Lesenswert?

Na dann eben so:
1
Adafruit_PWMServoDriver pwm_driver[4] = 
2
{
3
  Adafruit_PWMServoDriver(0x41),
4
  Adafruit_PWMServoDriver(0x40),
5
  Adafruit_PWMServoDriver(0x44),
6
  Adafruit_PWMServoDriver(0x42)
7
};
8
9
10
void set_led_color(uint8_t led, uint16_t r, uint16_t g, uint16_t b)
11
{
12
  const uint8_t led_lut[18][4] = {
13
    { 0, 14, 13, 15 }, // LED 1
14
    { 0, 10,  9, 11 }, // LED 2
15
    { 0,  7,  6,  8 }, // LED 3
16
    
17
    // ...
18
    
19
    { 3,  7,  8,  6 }  // LED 18
20
  }
21
  
22
  if (r==0)
23
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][1], 0, 4096)
24
  else
25
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][1], 4095-r, 4095)
26
27
  if (g==0)
28
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][2], 0, 4096)
29
  else
30
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][2], 4095-g, 4095)
31
32
  if (b==0)
33
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][3], 0, 4096)
34
  else
35
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][3], 4095-b, 4095)
36
}

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

So gehts noch etwas einfacher/schöner:
1
Adafruit_PWMServoDriver pwm_driver[4] { { 0x41 }, {0x40}, {0x44}, {0x42}};
2
3
uint16_t procColor (uint16_t clr) {
4
  return clr == 0 ? 0 : 4095 - clr;
5
  // Evtl schneller:
6
//  return (4096-clr) & 0xFFF;
7
}
8
9
void set_led_color(uint8_t led, uint16_t r, uint16_t g, uint16_t b)
10
{
11
  const uint8_t led_lut[18][4] = {
12
    { 0, 14, 13, 15 }, // LED 1
13
    { 0, 10,  9, 11 }, // LED 2
14
    { 0,  7,  6,  8 }, // LED 3
15
    
16
    // ...
17
    
18
    { 3,  7,  8,  6 }  // LED 18
19
  }
20
  
21
  pwm_driver[led_lut[led][0]].setPWM(led_lut[led][1], procColor(r), 4096)
22
  pwm_driver[led_lut[led][0]].setPWM(led_lut[led][2], procColor(g), 4096)
23
  pwm_driver[led_lut[led][0]].setPWM(led_lut[led][3], procColor(b), 4096)
24
}

von Dr. Sommer (Gast)


Lesenswert?

Ach verflixt, die auskommentierte Formel ist Quatsch. Einfach ignorieren 
;-)

von Kolja L. (kolja82)


Lesenswert?

Joe F. schrieb:
> Na dann eben so:

Danke Joe!

Ich habe den Code vervollständigt und hochgeladen:
1
#include <Wire.h>
2
#include <Adafruit_PWMServoDriver.h>
3
4
Adafruit_PWMServoDriver pwm_driver[4] =
5
{
6
  Adafruit_PWMServoDriver(0x41),
7
  Adafruit_PWMServoDriver(0x40),
8
  Adafruit_PWMServoDriver(0x44),
9
  Adafruit_PWMServoDriver(0x42)
10
};
11
12
void setup() {
13
  Wire.pins(13, 12);                      // Wire.pins(13, 12);
14
  Serial.begin(115200);
15
  Serial.println("RJ_Lauflicht_I2C");
16
17
  for (int j = 1; j <= 4; j++) {
18
    pwm_driver[j].begin();
19
    pwm_driver[j].setPWMFreq(800);
20
  }
21
22
#ifdef TWBR
23
  uint8_t twbrbackup = TWBR;
24
  TWBR = 12;
25
#endif
26
27
  for (int i = 1; i <= 4; i++) {       //Alle Pins aus
28
    for (int j = 0; j <= 15; j++) {
29
      pwm_driver[i].setPWM(j, 0, 4096);
30
    }
31
  }
32
} // setup
33
34
35
void loop() {
36
setPWM(1,4000,0,0);
37
delay(1000);
38
setPWM(1,0,0,0);
39
delay(1000);
40
} // loop
41
42
43
void setPWM(uint8_t led, uint16_t r, uint16_t g, uint16_t b)
44
{
45
  const uint8_t led_lut[18][4] = {
46
    {0, 14,  13,  15},
47
    {0, 10,  9,   11},
48
    {0, 7,   6,   8},
49
    {0, 4,   3,   5},
50
    {0, 1,   0,   2},
51
    {1, 14,  13,  15},
52
    {1, 11,  10,  12},
53
    {1, 8,   7,   9},
54
    {1, 5,   4,   6},
55
    {1, 2,   1,   3},
56
    {2, 1,   2,   0},
57
    {2, 5,   6,   4},
58
    {2, 8,   9,   7},
59
    {2, 11,  12,  10},
60
    {2, 14,  15,  13},
61
    {3, 1,   2,   0},
62
    {3, 4,   5,   3},
63
    {3, 7,   8,   6}
64
  };
65
66
  if (r == 0)
67
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][1], 0, 4096);
68
  else
69
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][1], 4095 - r, 4095);
70
71
  if (g == 0)
72
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][2], 0, 4096);
73
  else
74
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][2], 4095 - g, 4095);
75
76
  if (b == 0)
77
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][3], 0, 4096);
78
  else
79
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][3], 4095 - b, 4095);
80
}

Doch leider blinkt keine LED.
Es sollte die erste LED im Sekundentakt rot blinken.

Was mache ich noch falsch?

von Kolja L. (kolja82)


Lesenswert?

Oh, der serielle Monitor gibt Fehler aus:

Exception (28):
epc1=0x40202404 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 
depc=0x00000000

ctx: cont
sp: 3ffef2e0 end: 3ffef4e0 offset: 01a0

>>>stack>>>
3ffef480:  4020153a 00000005 00000000 40202404
3ffef490:  3ffee350 401c0000 3ffee358 40202439
3ffef4a0:  3ffee360 3ffee340 3ffee350 40202733
3ffef4b0:  3ffee360 3ffee340 3ffee358 402020c6
3ffef4c0:  3fffdad0 00000000 3ffee4a4 40202c18
3ffef4d0:  feefeffe feefeffe 3ffee4c0 40100114
<<<stack<<<

 ets Jan  8 2013,rst cause:2, boot mode:(1,6)


Aber damit kann ich leider nichts anfangen,
jemand von euch?

Danke und Gruß

von Dr. Sommer (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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".

von Einer K. (Gast)


Lesenswert?

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.
1
#include <Wire.h>
2
#include <Adafruit_PWMServoDriver.h>
3
4
using PWM = Adafruit_PWMServoDriver;
5
6
PWM pwms[] ={0x41,0x40,0x44,0x42};
7
8
struct RgbLed
9
{
10
  PWM pwm;
11
  byte r; // pin
12
  byte g; // pin
13
  byte b; // pin
14
  
15
  RgbLed(PWM & pwm,byte r,byte g, byte b):pwm(pwm),r(r),g(g),b(b){}
16
  
17
  void set(int _r, int _g, int _b)
18
  {
19
     pwm.setPWM(4095 - r, _r, 4095);  
20
     pwm.setPWM(4095 - g, _g, 4095);  
21
     pwm.setPWM(4095 - b, _b, 4095);
22
  }
23
};
24
25
RgbLed leds[] =  {  {pwms[0], 14,  13,  15},
26
                    {pwms[0], 10,  9,   11},
27
                    {pwms[0], 7,   6,   8},
28
                    {pwms[0], 4,   3,   5},
29
                    {pwms[0], 1,   0,   2},
30
                    {pwms[1], 14,  13,  15},
31
                    {pwms[1], 11,  10,  12},
32
                    {pwms[1], 8,   7,   9},
33
                    {pwms[1], 5,   4,   6},
34
                    {pwms[1], 2,   1,   3},
35
                    {pwms[2], 1,   2,   0},
36
                    {pwms[2], 5,   6,   4},
37
                    {pwms[2], 8,   9,   7},
38
                    {pwms[2], 11,  12,  10},
39
                    {pwms[2], 14,  15,  13},
40
                    {pwms[3], 1,   2,   0},
41
                    {pwms[3], 4,   5,   3},
42
                    {pwms[3], 7,   8,   6}
43
                  };
44
                
45
46
void setup() 
47
{
48
  // init
49
  for(PWM & pwm:pwms)
50
  {
51
    pwm.begin();
52
    pwm.setPWMFreq(800);
53
  }
54
  
55
  // alle weiß
56
  for(RgbLed & led:leds) led.set(4095,4095,4095);
57
  
58
  delay(1000);
59
  
60
  // erste rot
61
  leds[0].set(4095,0,0);
62
}
63
64
void loop() {}

von Dr. Sommer (Gast)


Lesenswert?

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!

von Einer K. (Gast)


Lesenswert?

Arduino F. schrieb:
> void set(int _r, int _g, int _b)
>   {
>      pwm.setPWM(4095 - r, _r, 4095);
>      pwm.setPWM(4095 - g, _g, 4095);
>      pwm.setPWM(4095 - b, _b, 4095);
>   }
Das ist falsch!

Besser:
1
  void set(int _r, int _g, int _b)
2
  {
3
     pwm.setPWM(r, 4095 - _r, 4095);  
4
     pwm.setPWM(g, 4095 - _g, 4095);  
5
     pwm.setPWM(b, 4095 - _b, 4095);
6
  }

von Karl (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

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.

von Kolja L. (kolja82)


Lesenswert?

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:
1
#include <Wire.h>
2
#include <Adafruit_PWMServoDriver.h>
3
4
Adafruit_PWMServoDriver pwm_driver[4] { { 0x41 }, {0x40}, {0x44}, {0x42}};
5
6
void setup() {
7
  Wire.pins(13, 12);                      // Wire.pins(13, 12);
8
  Serial.begin(115200);
9
10
  for (int j = 0; j <= 3; j++) {
11
    pwm_driver[j].begin();
12
    pwm_driver[j].setPWMFreq(800);
13
  }
14
15
#ifdef TWBR
16
  uint8_t twbrbackup = TWBR;
17
  TWBR = 12;
18
#endif
19
20
  for (int j = 0; j <= 17; j++) {
21
    RGB_LED(j, 1400, 1400, 1400);
22
  }
23
  delay(500);
24
  for (int j = 0; j <= 17; j++) {
25
    RGB_LED(j, 0, 0, 0);
26
  }
27
} // setup
28
29
void loop() {
30
31
  for (int j = 0; j <= 17; j++) {
32
    RGB_LED(j, 400, 0, 400);
33
    delay(50);
34
  }
35
  for (int j = 0; j <= 17; j++) {
36
    RGB_LED(j, 400, 0, 0);
37
    delay(50);
38
  }
39
  for (int j = 0; j <= 17; j++) {
40
    RGB_LED(j, 0, 400, 0);
41
    delay(50);
42
  }
43
  for (int j = 0; j <= 17; j++) {
44
    RGB_LED(j, 0, 0, 400);
45
    delay(50);
46
  }
47
  for (int j = 0; j <= 17; j++) {
48
    RGB_LED(j, 400, 400, 0);
49
    delay(50);
50
  }
51
52
} // loop
53
54
55
void RGB_LED(uint8_t led, uint16_t r, uint16_t g, uint16_t b)
56
{
57
  const uint8_t led_lut[18][4] = {
58
    {0, 14,  13,  15},
59
    {0, 10,  9,   11},
60
    {0, 7,   6,   8},
61
    {0, 4,   3,   5},
62
    {0, 1,   0,   2},
63
    {1, 14,  13,  15},
64
    {1, 11,  10,  12},
65
    {1, 8,   7,   9},
66
    {1, 5,   4,   6},
67
    {1, 2,   1,   3},
68
    {2, 1,   2,   0},
69
    {2, 5,   6,   4},
70
    {2, 8,   9,   7},
71
    {2, 11,  12,  10},
72
    {2, 14,  15,  13},
73
    {3, 1,   2,   0},
74
    {3, 4,   5,   3},
75
    {3, 7,   8,   6}
76
  };
77
78
  if (r == 0)
79
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][1], 0, 4096);
80
  else
81
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][1], 4095 - r, 4095);
82
83
  if (g == 0)
84
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][2], 0, 4096);
85
  else
86
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][2], 4095 - g, 4095);
87
88
  if (b == 0)
89
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][3], 0, 4096);
90
  else
91
    pwm_driver[led_lut[led][0]].setPWM(led_lut[led][3], 4095 - b, 4095);
92
}

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)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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
int read_memx (const __memx int *mem, long i)
2
{
3
    return mem[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".

von Dr. Sommer (Gast)


Lesenswert?

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...

von Einer K. (Gast)


Lesenswert?

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.
1
const size_t anzahlLED = sizeof(led_lut)/sizeof(led_lut[0]);

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.

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
Noch kein Account? Hier anmelden.