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
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.
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.
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.
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.
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.
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
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
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 ;-)
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
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 ;)
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.
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!
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 ...
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.
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.
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? :-)
Ralf X. schrieb: > Müsste es dann nicht die Arduino heissen? :-) Wenn schon, dann doch Arduina - oder?
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! ;-)
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.
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.
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.
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 | }
|
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
|
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
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.
EAF schrieb: > Denn delay() blockiert nur eine Task auf einem Core. Und wieviel Cores hast du auf deinen Mikrocontrollern? W.S.
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.
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.
Schlaumaier schrieb: > Man muss nur die Eigenschaften des ESP32 berücksichtigen. Nicht nur berücksichtigen sondern auch ausnutzen.
Tobi schrieb: > wo ich in der Main Loop einfach nur > eine Funktion Aufrufe und als Parameter den GPIO und die Blinkfrequenz > übergebe. IRQ
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.