Hallo zusammen, für einen RGB-Controller möchte ich eine Funktion schreiben, welche es ermöglicht die LEDs vom aktuellen Wert yAlt (uint16_t, 0 - 1023) zu einem anderen, beliebigen Wert yNeu im gleichen Bereich zu faden. Dies soll in einem bestimmten Zeitraum passieren. Damit das Fading unabhängig von der Hauptschleife funktioniert, habe ich einen Timer so eingestellt, dass eine ISR alle 1 ms aufgerufen wird. Im nächsten Schritt habe ich versucht, die C-Implementierung des Bresenham-Algorithmus so umzubauen, dass die Funktion der Schleife von der ISR übernommen wird. Die x-Achse ist dabei die Zeit, bzw. die Zahl der ISR-Aufrufe. Dabei ist allerdings ein Problem aufgetaucht, aufgrund der Vertauschung von x- und y-Achse bei Steigungen größer 1 ist nicht gewährleistet, dass jeder ISR-Aufruf die y-Achse um 1 inkrementiert (mehrere "Pixel"/y-Werte auf einem x-Wert), so dass die Zeit nicht eingehalten wird. Im Anhang ist der bisherige Stand zu finden (Zu Testzwecken erstmal in C#, so kann ich es auf dem Rechner testen + plotten). Habt Ihr eine Idee, wie ich einen Wert yAlt zu yNeu in einer festgelegten Schrittzahl inkrementieren/dekrementieren kann? Viele Grüße, Alex
Zu viel Aufwand. Nimm einfach ein paar Bits mehr und implementiere dir eine Festkommaarithmetik. Neuer_Wert = Alter_Wert + Inkrement Den Aufsummierfehler vermeidest du, indem du bei der letzten Summierung den Zielwert setzt. Solange man keine Vergleichsmöglichkeiten hat (wie zb bei einer Linie am Schirm, wo man immer auch das Pixel 'davor' sieht), merkt kein Mensch wenn sich dein Farbwert mal um einen klitzekleinen Sprung zuviel ändert.
Ich hab gerade noch einmal gezielt gesucht und noch das hier gefunden: Beitrag "Lineare Pulsweitenänderung PWM von a nach b in vorgegebener Zeit (wie?)" Im Prinzip das gleiche Problem, aber auch ohne konkretere Lösung. Mit der Geradengleichung möchte ich nur ungerne arbeiten, da bei den angestrebten Auflösungen die Werte recht groß werden und die Berechnung halbwegs zeitkritisch ist. Der Bresenham-Algorithmus müsste ja auch nur für den ersten Quadranten implementiert werden, ich denke, dass man dieses Beispiel dafür verwenden kann: http://de.wikipedia.org/wiki/Bresenham-Algorithmus#C-Implementierung Lediglich die Umschaltung für den Fall, dass dy > dx ist, bereitet bei der Verwendung Probleme.
Alexander W. schrieb: > Mit der Geradengleichung möchte ich nur ungerne arbeiten, da bei den > angestrebten Auflösungen die Werte recht groß werden und die Berechnung > halbwegs zeitkritisch ist. Jetzt hast du mich neugierig gemacht. Was bitte ist an einem LED Fading zeitkritisch?
@ Alexander Willer (Gast) >ermöglicht die LEDs vom aktuellen Wert yAlt (uint16_t, 0 - 1023) zu >einem anderen, beliebigen Wert yNeu im gleichen Bereich zu faden. Das sollte eher einfach sein. du willst N PWM-Schritte in M 1ms Takten machen. Mr Bresenham machte das so.
1 | N = pwm_max-pmw_min; |
2 | M = 100; |
3 | |
4 | void(1mstimer) { |
5 | static fehler=0; |
6 | |
7 | fehler += N; |
8 | if (fehler >=M) { |
9 | fehler -= M; |
10 | pwm++; |
11 | }
|
12 | }
|
Ähhh vola, oder so ähnlich. MFG Falk http://de.wikipedia.org/wiki/Bresenham-Algorithmus
Hmm, stimmt nicht ganz, ist nur ein Fragment aus dem Hippothalamus.
Eher so, dann passen auch steile Rampen mit N>M und beide Richtungen.
1 | M = 100; // Zeitschritte für Übergang |
2 | if (pwm_max>=pwm_min) { |
3 | dir = 1; |
4 | N = pwm_max-pmw_min; |
5 | } else { |
6 | dir = -1; |
7 | N = pwm_min-pmw_max; |
8 | }
|
9 | |
10 | void(1mstimer) { |
11 | static fehler=0; |
12 | |
13 | fehler += N; |
14 | while (fehler >=M) { |
15 | fehler -= M; |
16 | pwm += dir; |
17 | }
|
18 | }
|
Zeitkritisch ist das ganze, weil ich auch bei niedrigen Helligkeiten einen stufenlosen Farbwechsel und gleichzeitige Bedienung von diversen anderen Funktionen sicherstellen möchte. Da ich nicht einschätzen kann, was 32-Bit-Divisionen und Multiplikationen für RGB+W an Zeit benötigen, verzichte ich lieber drauf. @Falk: Danke, das werde ich gleich mal ausprobieren, ich müsste bitte noch wissen, was ich mit pwm/pmw_min/max machen soll? Zwei der Werte sind vermutlich Start und Ziel des Fadings, aber so ganz klar ist mir das noch nicht.
Also wenns um Programmkonzepte geht: Ich würde einfach eine Istwert- und Zielwert-Variable für jede LED einbauen. Dann zyklisch aufrufen:
1 | if (Zielwert > Istwert) { |
2 | Istwert++; |
3 | /* Ausgabe von Istwert */
|
4 | } else if (Zielwert < Istwert) { |
5 | Istwert--; |
6 | /* Ausgabe von Istwert */
|
7 | }
|
Das als Basic. Um das ganze Zeitvariabel zu machen würde ich einfach etwas DDS-ähnliches benutzen:
1 | if (Zielwert > Istwert) { |
2 | Istwert += Inkrement; |
3 | /* Ausgabe von Istwert */
|
4 | } else if (Zielwert < Istwert) { |
5 | Istwert -= Inkrement; |
6 | /* Ausgabe von Istwert */
|
7 | }
|
Um dabei hohe Zeitauflösungen zu garantieren, verweise ich auf Karl Heinz Post: Festkommaarithmetik. Verwendet man bspw. eine PWM mit 16 Bit, so legt man für Istwert und Zielwert einfach 32 Bit Werte an. Die PWM wird dann aus den oberen 16 Bit davon gebildet. Völlig analog zum DDS Prinzip. EDIT: Das ganze ist jetzt übrigens eine I-Strecke. Also es wird linear angefahren, und der Zielwert erreicht. Man könnte auch andere Strecken implementieren.
@ Alexander W. (alexander_w) >Zeitkritisch ist das ganze, weil ich auch bei niedrigen Helligkeiten >einen stufenlosen Farbwechsel und gleichzeitige Bedienung von diversen >anderen Funktionen sicherstellen möchte. Bei 1ms Zeitauflösung langeweilt sich der AVR. > Da ich nicht einschätzen kann, >was 32-Bit-Divisionen und Multiplikationen für RGB+W an Zeit benötigen, >verzichte ich lieber drauf. Bresenham braucht sowas nicht, nur Addition und Substraktion, der Vergleich ist effektiv eine Subtraktion. >noch wissen, was ich mit pwm/pmw_min/max machen soll? Zwei der Werte >sind vermutlich Start und Ziel des Fadings, sicher. > aber so ganz klar ist mir das noch nicht. Hmmmm . . .
Einfach mal ein wenig drüber nachdenken. Mach den Monitor aus, nimm dir ein Blatt Papier und überlege wie du nur mit einem konstanten Takt das von dir gewünschte Verhalten hinkriegst. Anregungen sind hier ja genug. Das Problem ist fast zu trivial, als dass man da irgendwo eine fertige Lösung für findet.
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.