Forum: Mikrocontroller und Digitale Elektronik Bresenham-Algorithmus mit Zeit als x-Achse


von Alexander Willer (Gast)


Angehängte Dateien:

Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Alexander W. (alexander_w)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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?

von Falk B. (falk)


Lesenswert?

@  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

von Falk B. (falk)


Lesenswert?

Hmm, stimmt nicht ganz, ist nur ein Fragment aus dem Hippothalamus.

von Falk B. (falk)


Lesenswert?

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
}

von Alexander W. (alexander_w)


Lesenswert?

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.

von Simon K. (simon) Benutzerseite


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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

von Simon K. (simon) Benutzerseite


Lesenswert?

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