Forum: Mikrocontroller und Digitale Elektronik 20 LEDs unterschiedlich blinken lassen


von Tobi (Gast)


Lesenswert?

Hallo,

ich möchte gerne an meinem ESP32 20 LEDs in unterschiedlichen Frequenzen 
blinken lassen.

Mir ist bewusst, dass das nur mit der "millis()" Methode funktioniert, 
also nicht mit delays, da ja sonst mein ganzes Programm pausiert.
Nun ist der millis Code für 20 LEDs extrem lang. Daher suche ich 
irgendeine elegante Möglichkeit, wo ich in der Main Loop einfach nur 
eine Funktion Aufrufe und als Parameter den GPIO und die Blinkfrequenz 
übergebe.

Ich suche schon ziemlich lange, jedoch finde ich immer nur Beispiele mit 
nur einer bzw. zwei LEDs, wo natürlich der Standardansatz noch 
problemlos (mit relativ wenig Zeilen Code) möglich ist.

Habt ihr ein Tipp wie ich anders suchen kann bzw. habt ihr Links?
Sowas muss doch schonmal jemand vor mir gemacht haben!

VG
Tobi

von Helge (Gast)


Lesenswert?

Vorschlag

Dispatcher ruft LED-Funktion alle 1ms auf.
Diese hat 2 Tabellen. 1. Tabelle enthält die Zeiten. 2. Tabelle enthält 
aktuelle Zeitwerte, da werden bei 0 die Werte der 1. Tabelle eingetragen 
und bei >0 runtergezählt.

von MaWin (Gast)


Lesenswert?

Tobi schrieb:
> Sowas muss doch schonmal jemand vor mir gemacht haben!

Es gibt Leute, die ganze Landkarten mit Leuchttürmen erstellt haben, und 
die so blinken liessen wie in echt, alle verschieden.

Ist nicht schwer. Man muss halt die Blinkmuster definieren, z.B. mit AN 
und AUS Zeiten in einer Tabelle. Blinken ist ja eher langsam aus Sicht 
eines uC.

von Old P. (Firma: nix) (Gast)


Lesenswert?

Warum nimmt du nicht einfach 20 Arduinos?

von Karl (Gast)


Lesenswert?

Auf dem ESP läuft, en ich das richtig im Kopf habe, freeRTOS. Also mach 
doch einfach 20 Threads auf und in denen kannst du dann deine millis 
Funktion nutzen.

von EAF (Gast)


Lesenswert?

Ja!

von Hannes J. (Firma: _⌨_) (pnuebergang)


Lesenswert?

Da nirgendwo steht das die LEDs kontrolliert blinken sollen 
selbstblinkende LEDs nehmen. Die kommen nach ein paar Minuten aus dem 
Takt und blinken unterschiedlich vor sich hin.

Wenn's kontrolliert sein einfach anständig programmieren. Ein 
Timer-Interrupt der gleich dem kleinsten gewünschte Zeitunterschied 
zwischen den LEDs ist. Für jede unabhängig steuerbare LED ein Bitmuster 
in einem Array und einen Index haben. Bei jedem Interrupt für jede LED 
das nächste Bit aus dem Bitmuster in den jeweiligen LED-Pin takten.

Optimierungen sind natürlich möglich (Ports auf einmal ansteuern, im 
Interrupt nur Zähler weiter setzen und in der Mainloop die LEDs steuern,
WS28xx LEDs, Algorithmus statt Array, ...).

Wer's mag und kann, kann auch mit einem variablen Timer arbeiten. Dann 
steht in einem Arrays eine (relative) Zeit zu der die nächste Änderung 
stattfinden soll und welche.

von DoS (Gast)


Lesenswert?

Vielleicht hilft Dir der Sourcecode in dem Artikel weiter:
http://mostfun.de/index.php/modellbau/alles-moegliche/281-beleuchtungsmodul

Ist aber Laufzeitoptimiert. Der Code ist in "C" und für Atmel 8MHz, 
8Bit-Prozessoren und kann bis zu 26 LED (CPU-Last). Ein ESP sollte das 
x-Fache können.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Tobi schrieb:
> "millis()" Methode
Also Arduino?

> Daher suche ich irgendeine elegante Möglichkeit
> ...
> Ich suche schon ziemlich lange
Irgendwann wirst du mal deine erste eigene Zeile Code programmieren 
müssen, weil du auf ein Problem stößt, das keiner vor dir gehabt, gelöst 
und ins Netz gestellt hat.

> Nun ist der millis Code für 20 LEDs extrem lang.
Was stört dich daran, dass der Code "extrem lang" ist? Hast du eine zu 
kleine Festplatte?

Aber probiers doch einfach mal so: wenn du 1 Code für 1 LED geschrieben 
hast und den dann für die nächste(n) LED(s) kopierst, dann kannst du dir 
nebenher Gedanken um Gemeinsamkeiten machen und überlegen, ob du die 
Arbeit nicht auch mit einer for-Schleife und passenden Arrays mit 20 
Elementen für die 20 Zeiten und die 20 Pins erledigen kannst.

Seis drum...
> ESP32 20 LEDs in unterschiedlichen Frequenzen blinken lassen.
Wie/wo sind denn diese 20 LEDs an den ESP32 angeschlossen? Hast du einen 
Schaltplan davon?

: Bearbeitet durch Moderator
von Falk B. (falk)


Lesenswert?

Tobi schrieb:
> Hallo,
>
> ich möchte gerne an meinem ESP32 20 LEDs in unterschiedlichen Frequenzen
> blinken lassen.
>
> Mir ist bewusst, dass das nur mit der "millis()" Methode funktioniert,
> also nicht mit delays, da ja sonst mein ganzes Programm pausiert.

Richtig!

> Nun ist der millis Code für 20 LEDs extrem lang.

Nö.

> Daher suche ich
> irgendeine elegante Möglichkeit, wo ich in der Main Loop einfach nur
> eine Funktion Aufrufe und als Parameter den GPIO und die Blinkfrequenz
> übergebe.

Richtig.

Beitrag "Re: mehrere Millis()"

Hmm, das Beispiel ist nicht so ganz übersichtlich. Dann eher siehe 
Multitasking, wenn gleich man beim Arduino eher mit millis() 
arbeitet.

: Bearbeitet durch User
von Gerald B. (gerald_b)


Lesenswert?

Wenn's besonders "ducheinander" aussehen soll, dann verwende für die An- 
und Auszeiten der jeweiligen LEDs unterschiedliche Primzahlen. 
Primzahlen haben die Besonderheit, nur durch 1 und durch sich selbst 
teilbar zu sein. Gleichtakt zwischen 2 Kanälen gibt es dann alle A mal B 
mal C mal D Durchläufe, wobei A Kanal 1 an, B Kanal 1 aus, C Kanal 2 an, 
D Kanal 2 aus ist. Das mal Anzahl der LEDs ist schon ordentlich. 
Tabellen mit Primzahlen sollten sich ebenfalls im Internet finden 
lassen. 4 stellige Primzahlen eignen sich z.B. für millis Zeiten ;-)

von Oliver S. (phetty)


Lesenswert?

Nimm 20 WS2812B-LEDs und steuer diese an. Braucht man nur einen GPIO und 
es gibt fertige Libraries dafür mit unterschiedlichsten Effekten.

Oder installier gleich WLED, da gibt es auch einen Random-Effekt.

: Bearbeitet durch User
von sooderso (Gast)


Lesenswert?

Hi, so wie ich das lese suchst du sowas ?
1
int led_pins[20] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
2
3
unsigned long warte_zeit[20] = [10,20,30,40,50,60,70,80,90,100,110,120,130,140,150,160,170,180,190,200};
4
// warten in miliSekunden
5
6
// Speichert letzten Zeitstempel
7
unsigned long last_time[20];
8
9
void setup(){
10
  for(int i=0; i<20 ; i++){
11
    pinMode(led_pins[i], OUTPUT);
12
  }
13
14
void loop(){
15
  for(int i=0; i<20; i++){
16
    check_led(led_pins[i],warte_zeit[i],i);
17
  }
18
}
19
20
void check_led(int pin, unsigned long interval, int position){
21
22
  if(millis() - last_time[position] >= interval){
23
    digitalWrite(pin, digitalRead()^1);
24
    last_time[position] = millis();
25
  }
26
}

habs mal einfach so runter geschrieben, falls du Fehler findest darfst 
du die behalten ;)

von Schlaumaier (Gast)


Lesenswert?

Du solltest dir auch Gedanken über die Ansteuerung machen.

Die üblichen 2 Methoden die ich anwenden würde sind, entweder über ein 
Portexpander o. einfach WS2812 LED's zu nehmen.

Beide haben vor und Nachteile.

Das blinken selbst ist danach nur noch eine Frage der Software.

Wobei ich das am einfachsten über eine Schleife mit Milli-Zähler machen 
würde. Dann kann ich vorher die LED's über ein Array festlegen und mit 
den Daten den Zeittakt bestimmen.

Durch das Array lade ich dann einfach neue Programmdaten für die 
Blink-Freq. und das war's.

von Falk B. (falk)


Lesenswert?

Schlaumaier schrieb:
> Das blinken selbst ist danach nur noch eine Frage der Software.

Aber eben DIESE Frage steht im Raum! Da nützt der Hinweis auf 
Portexpander und intelligente LEDs gar nichts!

von HildeK (Gast)


Angehängte Dateien:

Lesenswert?

Ich hab mir mal eine Zusammenstellung gemacht, die mit einem Timer 
mehrere (1-viele) unabhängige Zeiten verwalten lässt.
Nicht für Arduino, das kann ich nicht, nur in C.

Vielleicht hilft es ...

von W.S. (Gast)


Lesenswert?

Old P. (Firma: nix) schrieb:
> Warum nimmt du nicht einfach 20 Arduinos?

Das erinnert mich an den Witz von der Mutter, die ihrem Nachwuchs 
Nachhilfe bei den Hausaufgaben gibt: "Also Fritzchen, stell dir mal vor, 
du hast 7 Taschenrechner und nimmst dann 3 davon weg. Wieviele 
Taschenrechner bleiben da übrig?"

Tobi schrieb:
> Mir ist bewusst, dass das nur mit der "millis()" Methode funktioniert,...

Sei dir lieber bewußt, daß du noch nicht programmieren kannst, sondern 
nur mit quasi Bauklötzchen spielst. Was du brauchst, ist eine Strategie, 
wie dein Vorhaben zu machen wäre. Das ist etwas anderes, als das Tippen 
auf der Tastatur zwecks Erzeugen einer Quellcode-Datei.

Also, du hast eine Funktion, die dir anzeigt, wie der momentane Stand 
irgend eines Zählers ist, der jede Millisekunde um eins weiter zählt. 
Nun, sowas ist doch schon mal eine Zeitbasis. Und da deine LEDs blinken 
und nicht flimmern sollen, braucht es für jede Leucht- und jede 
Dunkel-Zeit wenigstens so etwa 100 Millisekunden, also recht viel Zeit 
aus Sicht des µC.

Jetzt ist es deine Angelegenheit, dir da eine dir gefallende Strategie 
zu Ein- oder Ausschalten deiner LEDs einfallen zu lassen. Ich würde 
sowas mittels "delayed Events" machen, weil bei meinem Zeugs (meinem 
Portfolio) sowas bereits vorhanden ist. Aber da du mein Zeugs nicht hast 
und auch der ESP32 eine ganz andere Plattform ist als meine Controller, 
mußt du schon selber ran, dir etwas auszudenken. Aber im Prinzip wird 
das ähnlich werden, also Zeitpunkte (aus Intervallen) zu bestimmen, bei 
denen Ein- und Ausschalt-Aktionen stattfinden sollen und Vergleiche 
zwischen millis und den bestimmten Zeitpunkten zu tun, um 
herauszufinden, ob grad eine Aktion stattfinden soll oder nicht. Denke 
jetzt mal selber.

W.S.

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Hier mal ein Entwurf. Man kann alle LEDs mit verschiedenen Frequenzen 
und Tastverhältnissen blinken lassen. Sogar die Phasenverschiebung kann 
man dynamisch anpassen, wenn man das will! Und das Beste von Allem, der 
Arduino kann nebenbei noch SEHR viel machen. Siehe Multitasking.

von Ralf X. (ralf0815)


Lesenswert?

Falk B. schrieb:
> Und das Beste von Allem, der
> Arduino kann nebenbei noch SEHR viel machen. Siehe Multitasking.

Müsste es dann nicht die Arduino heissen? :-)

von HildeK (Gast)


Lesenswert?

Ralf X. schrieb:
> Müsste es dann nicht die Arduino heissen? :-)

Wenn schon, dann doch Arduina - oder?

von Falk B. (falk)


Lesenswert?

Ralf X. schrieb:
>> Und das Beste von Allem, der
>> Arduino kann nebenbei noch SEHR viel machen. Siehe Multitasking.
>
> Müsste es dann nicht die Arduino heissen? :-)

Mein Italienisch liegt zwischen nicht vorhanden und 0,xppm. KATZO! ;-)

von Schlaumaier (Gast)


Lesenswert?

Falk B. schrieb:
> Aber eben DIESE Frage steht im Raum! Da nützt der Hinweis auf
> Portexpander und intelligente LEDs gar nichts!

Richtig und Falsch gleichzeitig.

DENN. Die Hardware bestimmt die Software nicht anders herum.

Und je nachdem was ich ansteuere, ist der Code total anders.

Bei 20 LED's ohne ein Arduino-Mega habe ich ein Problem. Also brauch ich 
ein Portexpander.

Ansonsten ist das Programm-Technisch eh nur eine Frage der IF-THEN 
abfragen.

Wie der TO schon richtig erkannt hat, würde ich das auch über Millis 
machen.

Allerdings benutzte ich Millis nur als TAKTGEBEN und zwar so.

akt_millis = millis()
led_1_millis = akt_millis + 500 ' init den Status und schaltet alle 
LED's sync.

led_1_status = low



do loop
akt_millis = millis()

if Led_1_millis < akt_millis then
  if led_1_status = low then LED_1_status = high else led_1_status_=low
  led_1_millis = led_1_millis + schalt_zeit
end if

'*** hier dann schalten nach Status und Hardware ****

loop


Das bisschen da in C Syntax übersetzen und das war's. Ist ja im Prinzip 
ein Ablaufdiagramm ;)


Das ist für 1 LED.  Ich persönlich würde ein Array aufbauen, und eine 
For_next Schleife das macht das Leben einfacher.

Aber das soll der TO selbst machen.

von MaWin (Gast)


Lesenswert?

Schlaumaier schrieb:
> Die üblichen 2 Methoden die ich anwenden würde sind, entweder über ein
> Portexpander o. einfach WS2812 LED's zu nehmen.

Der ESP32 hat üblicherweise mehr als 20 GPIO, braucht also die teure 
Methoden nicht sondern kann billige LED direkt ansteuern - was sich auch 
am einfachsten programmieren lässt.

von Schlaumaier (Gast)


Lesenswert?

MaWin schrieb:
> Der ESP32 hat üblicherweise mehr als 20 GPIO, braucht also die teure
> Methoden nicht sondern kann billige LED direkt ansteuern - was sich auch
> am einfachsten programmieren lässt.

Grundsätzlich gebe ich dir Recht.

Aber nur wenn der TO KEIN Komfort will. Weil ich würde das mit einer 
Klebe-Membranen-Tastatur, Display (1602) + IR-Empfangsdiode ausstatten. 
Was ich nebenbei bei fast allen meiner Projekte mache. Materialwert : 
ca. 5-6 Euro.

Dann hat er die Möglichkeit (falls er brauchbar programmieren kann) sich 
unterschiedliche Blink-Programme zu erstellen. Das gewünschte Programm 
zu modifizieren und via IR-Fernbedienung zu Starten/wechseln.

Und dann wird es mit den Pins verdammt eng. Weshalb ich meist die 
PCF-8574 einsetze, weil Preiswert  und einfach anzusteuern und bei mir 
war der noch nie zickig. Macht für den TO 2-3 Euro (a ca. 1 Euro)

Was unter dem Strich heißt. Opfert der TO ca. 10-12 Euro extra hat ein 
eine Beleuchtung die Mega Flexibel ist.

Davon abgesehen 4-5 Zeilen mehr in den Code und er hat sogar noch eine 
UNGENAUEN Zeittimer drin. 2 Euro mehr (dcf-77-Modul) und er hat eine 
Top-Genaue-Timersteuerung die er mit der Tastatur dann Problemlos nach 
programmieren kann.

Was alles in allen meine Aussage erklärt : Die Hardware bestimmt die 
Software.

Und ein ESP32 ist fast das selbe wie ein Arduino. Die IDE ist die selbe, 
der Code fast auch. Man muss nur die Eigenschaften des ESP32 
berücksichtigen.

von EAF (Gast)


Lesenswert?

Falk B. schrieb:
> Hier mal ein Entwurf.

Den habe ich mal durch die Mühle gedreht und daraus einen Gegenentwurf 
gemacht.

Allerdings ungetestet, da kein ESP32 erreichbar.
1
#define TIME_STEP 10    // Millisekunden
2
3
struct Led
4
{
5
  unsigned int pin;
6
  unsigned int onTime;
7
  unsigned int offTime;
8
  unsigned long zeitMerker;
9
10
  void init()
11
  {
12
    pinMode(pin, OUTPUT);
13
    zeitMerker = 0;
14
  }
15
16
  void run()
17
  {
18
    bool state = digitalRead(pin);
19
    unsigned long interval = state?onTime:offTime;
20
    if(millis() - zeitMerker > interval)
21
    {
22
      zeitMerker += interval;
23
      digitalWrite(pin,!state);
24
    }
25
  }
26
};
27
28
Led leds[] =
29
{
30
  // IO-Pin, onTime, offTime alle in millisec
31
  {1, 200, 100},
32
  {2, 300, 50},
33
  {3, 400, 30},
34
  {4, 990, 50},
35
  {5, 770, 600},
36
  {6, 660, 600},
37
  {7, 880, 50},
38
  {9, 1010, 500},
39
  {10, 2000, 1000},
40
  {11, 3000, 100},
41
  {12, 4000, 3500},
42
  {13, 5000, 2500},
43
  {14, 10000, 1000},
44
  {15, 9990, 1000},
45
  {16, 7770, 1000},
46
  {17, 8880, 1000},
47
  {18, 4440, 1000},
48
  {19, 3330, 1000},
49
  {20, 1110, 1000}
50
};
51
52
53
void ledTask(void *pvParameter)
54
{
55
  while(1)
56
  {
57
    for(Led &led : leds) led.run();
58
    vTaskDelay(TIME_STEP / portTICK_RATE_MS);
59
  }
60
}
61
62
void setup()
63
{
64
  for(Led &led : leds) led.init();
65
  xTaskCreate(ledTask, "ledTask", 2048, NULL, 5, NULL);
66
}
67
68
void loop()
69
{
70
}

von EAF (Gast)


Lesenswert?

Nachtrag:
kleine Anpassung noch...
1
struct Led
2
{
3
  byte pin;
4
  unsigned long onTime;
5
  unsigned long offTime;
6
  unsigned long zeitMerker;
7
8
// und weiter wie gehabt

von Stefan F. (Gast)


Lesenswert?

Tobi schrieb:
> Mir ist bewusst, dass das nur mit der "millis()" Methode funktioniert
> also nicht mit delays, da ja sonst mein ganzes Programm pausiert.

Wenn du das ohne Mithilfe eines Betriebssystems machen willst, stimme 
ich dir zu. Dein ESP hat allerdings ein solches (RTOS). Du kannst also 
durchaus dessen Threads oder Timer nutzen. Oder du machst es ohne - geht 
auch.

Tobi schrieb:
> Habt ihr ein Tipp wie ich anders suchen kann bzw. habt ihr Links?

http://stefanfrings.de/multithreading_arduino/index.html

von EAF (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> stimme ich dir zu.

Ich stimme nicht zu.
Denn delay() blockiert nur eine Task auf einem Core. Der Rest läuft 
ungetrübt weiter. Was ja durchaus erwünscht sein kann.

von W.S. (Gast)


Lesenswert?

EAF schrieb:
> Denn delay() blockiert nur eine Task auf einem Core.

Und wieviel Cores hast du auf deinen Mikrocontrollern?

W.S.

von Cartman (Gast)


Lesenswert?

Nur der Arduinofickler gibt sich mit "Blinken" zufrieden.

In den fortgeschritteneren Regionen der Welt, erwartet man eine
an das Helligkeitsempfinden des Auges angepasste sinusodiale
Schwingung der Helligkeiten.

Geblinkt wurde da gestern...

Seblst mein uraltes Dummfon signalisiert seinen Standbymodus
mi angenehmen Sinusabschnitten.

von EAF (Gast)


Lesenswert?

W.S. schrieb:
> ....(eine Provokation)....
Falls du es noch nicht bemerkt hast, wir reden hier über einen ESP.

Was dir auch evtl. durch die Lappen gegangen ist:
Der von mit gezeigte Umbau funktioniert auch neben einem delay(), und 
auf den kleinen AVRs

Beispiel: (für einen Arduino UNO)
1
struct Led
2
{
3
  byte pin;
4
  unsigned long onTime;
5
  unsigned long offTime;
6
  unsigned long zeitMerker;
7
8
  void init()
9
  {
10
    pinMode(pin, OUTPUT);
11
    zeitMerker = 0;
12
  }
13
14
  void run()
15
  {
16
    bool state = digitalRead(pin);
17
    unsigned long interval = state ? onTime : offTime;
18
    if(millis() - zeitMerker > interval)
19
    {
20
      zeitMerker += interval;
21
      digitalWrite(pin, !state);
22
    }
23
  }
24
};
25
26
Led leds[] =
27
{
28
  // IO-Pin, onTime, offTime alle in millisec
29
  //  {1, 200, 100},
30
  {2, 300, 50},
31
  {3, 400, 30},
32
  {4, 990, 50},
33
  {5, 770, 600},
34
  {6, 660, 600},
35
  {7, 880, 50},
36
  {9, 1010, 500},
37
  {10, 2000, 1000},
38
  {11, 3000, 100},
39
  {12, 4000, 3500},
40
  {13, 5000, 2500},
41
  {14, 10000, 1000},
42
  {15, 9990, 1000},
43
  {16, 7770, 1000},
44
  {17, 8880, 1000},
45
  {18, 4440, 1000},
46
  {19, 3330, 1000},
47
  //  {20, 1110, 1000},
48
};
49
50
51
void yield()
52
{
53
  for(Led &led : leds) led.run();
54
}
55
56
void setup()
57
{
58
  for(Led &led : leds) led.init();
59
}
60
61
void loop()
62
{
63
  delay(4711);
64
}

Du siehst, nur ein minimaler Umbau.

Offensichtlich hast du zu wenig Ahnung von Arduino um substantielle 
Kritik zu üben.

von Oliver S. (phetty)


Lesenswert?

Schlaumaier schrieb:
> Man muss nur die Eigenschaften des ESP32 berücksichtigen.

Nicht nur berücksichtigen sondern auch ausnutzen.

von Dieter (Gast)


Lesenswert?

Tobi schrieb:
> wo ich in der Main Loop einfach nur
> eine Funktion Aufrufe und als Parameter den GPIO und die Blinkfrequenz
> übergebe.

IRQ

von Jobst M. (jobstens-de)


Lesenswert?

Für die Simulation einer Diskothek auf der Eisenbahnanlage habe ich in 
einem tiny13 5 32 Bit Zufallsgeneratoren (Rückgekoppelte 
Schieberegister) laufen. Das rückgekoppelte Bit zählt bei 3 Kanälen 
zusätzlich einen Zähler rauf bzw. runter, mit dem die Helligkeit einer 
LED gesteuert wird. (Über PDM, einer Art einfachem noise shaping)
Die beiden anderen steuern zwei weiße LEDs als Blitzer an.
http://jobstens.mooo.com/elektronik/bahn/disco/

Gruß
Jobst

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.