Forum: Mikrocontroller und Digitale Elektronik Sinusfunktion, LED Dimmen


von alxy (Gast)


Lesenswert?

Hallo,

ich habe vor, mittels Avr-gcc (Das Tutorial hab ich gelesen) und C eine 
entsprechend dimmbare LED zu programmieren. (Auf Pollin Eval Board) 
Funktioniert auch soweit, allerdings versuche ich das ganze, als das Aus 
und Einschalten (Dimmen) jetzt als Sinuskurve zu verwirklichen. Dazu 
habe ich folgenden Code:
1
 while(1)
2
 {
3
  
4
  uint8_t k;
5
  for(k=1; k < 360; k++)
6
  {
7
   i_ct = 511*(sin(k/180*M_PI)+1);
8
   
9
   
10
   if (i_ct<500) { // for debugging
11
   OUTPT |= (1<<LED2);
12
   }
13
   
14
   _delay_ms(2); // time between two increments of OCR1A (brightness increments)
15
   
16
  }
17
   
18
 }

Leider funktioniert das nicht ganz. Die LED leuchtet einfach die gannze 
Zeit. (Der entsprechende PIn wird vorher auf 1 gestellt)

Wäre für einen Tip dankbar,

alxy

von Karl H. (kbuchegg)


Lesenswert?

Und wo in dem Beispiel setzt du OCR1A auf den gewünschten 
Helligkeitswert?

Lass uns mal einfacher anfangen: Wie genau dimmst du eigentlich die LED? 
Mittels Timer oder mittels Software?

von alexxk (Gast)


Lesenswert?

Es wäre wohl besser die Werte des Sinus in einer Tabelle zu speichern in 
der genauigkeit in der du es haben willst!
Dann das Array durchlaufen (Zeitabstände mit Timer(besser) oder delay) 
und am ende wieder bei 0 anfangen...
In abhängigkeit von dem Wert den du da hast musst du die Led per PWM 
dimmen...das geht wohl am besten mit einem (Deutlich schnelleren Timer, 
wahrscheinlich auch mit der eingebauten PWM (da kenn ich mich nicht 
aus)).

LG Alexx

von gaast (Gast)


Lesenswert?

alxy schrieb:
> Dazu
> habe ich folgenden Code:

Mit Sicherheit nicht. Ohne den Rest des Programmes ist das von dir 
gelieferte ziemlich witzlos. Über den Unsinn der Nutzung von 
Floatingpointarithmetik, insbesondere Winkelfunktionen aus math.h auf 
einem AVR lasse ich mich lieber nicht aus.

von Sam .. (sam1994)


Lesenswert?

alxy schrieb:
> i_ct = 511*(sin(k/180*M_PI)+1);

Das kann ja nichts werden: k/180 ergibt entweder 0 oder 1. Sin 0/PI = 0. 
Also ist dein Ergebnis immer 511.

k kann übrigens nie 360 erreichen.

von gaast (Gast)


Lesenswert?

Gut, wenn k als int deklariert ist, sieht es wieder anders aus. Stellt 
sich noch die Frage, warum er das in der Hauptschleife macht.

von Wolfgang (Gast)


Lesenswert?

alxy schrieb:
>  sin(..)

und
>   _delay_ms(2)

passen zeitlich nicht so richtig zusammen. Wenn du den Prozessor 
unbedingt beschäftigen willst, muß der PWM-Takt per Timer erzeugt werden 
und langsamer als die längste Berechnung des neuen Wertes sein.

Abgesehen davon eignet sich die Sinusfunktion wegen der logarithmischen 
Helligkeitswahrnehmung nicht wirklich als Modulation. Im positiven 
Bereich des Sinus werden die Helligkeitsänderungen kaum wahrnehmbar 
sein.

von Sam .. (sam1994)


Lesenswert?

Grundsätzlich immer erst multiplizieren und dann dividieren (und 
aufpassen das dabei die Variable dabei nicht überläuft).

von Falk B. (falk)


Lesenswert?

Siehe LED-Fading

von alxy (Gast)


Lesenswert?

Hallo,

natürlich wäre eine Tabelle das einfachste, aber ich möchte es gerne so 
lösen...
1
 while(1)
2
 {
3
  
4
  uint8_t k;
5
  //for(k=1; k < 360; k++)
6
  //{
7
   k = 45;
8
   i_ct = 511.0*(sin(0.785)+1.0);
9
   
10
   
11
   if ((i_ct<530)  && (i_ct>500)) { // for debugging
12
   OUTPT |= (1<<LED2);
13
   //}
14
   
15
   _delay_ms(2); // time between two increments of OCR1A (brightness increments)
16
   
17
  }
18
   
19
 }
k ist also typ int. Habe den sinuswert als bogenmaß mal direkt 
eingegeben... So funktinoiert es, aber warum anders (wie oben) nicht?

alxy

von alxy (Gast)


Lesenswert?

i_ct ist übrigens typ double...

von Karl H. (kbuchegg)


Lesenswert?

alxy schrieb:
> i_ct ist übrigens typ double...

i_ct ist ziemlich uninterressant.

k ist interessant

  uint8_t k;

   k/180


k nimmt Werte von 1 bis 359 an. Damit ergibt k / 180 entweder 0 (für 
alle Werte von k von 1 bis 179) bzw. 1 (für k gleich 180 bis 359). Damit 
wird der komplette Ausdruck

  k/180*M_PI

entweder 0 oder M_PI und für beide ist der Sinus jeweils 0.

FAQ - Der Abschnitt 2, über "Datentypen in Operationen"

von Karl H. (kbuchegg)


Lesenswert?

Im Übrigen:
Du schaltest die LED nie wieder aus.
Im Laufe einer Schwingung wird (wenn du die Berechnung korrigierst) die 
LED irgendwann mal eingeschaltet, und ab da brennt sie dann dauernd.

von alxy (Gast)


Lesenswert?

Danke. Habs jetzt geändert, den Datentyp un es funkltioniert (fast)
1
 while(1)
2
 {
3
  
4
  uint8_t k;
5
  double n;
6
  for(k=1; k < 361; k++)
7
  {
8
   n = k*0.01745;
9
   i_ct = 511.0*(sin(n)+1.0);
10
   
11
   
12
   /*if ((i_ct<530)  && (i_ct>500)) { // for debugging
13
   OUTPT |= (1<<LED2);
14
   }*/
15
   
16
   _delay_ms(2); // time between two increments of OCR1A (brightness increments)
17
   
18
  }
19
   
20
 }

Sie geht von "halban" (511) auf ganz an(1022) und dann langsam bis 
aus(0) (natürlich nicht ganz aus, aber annähernd), aber dann springt sie 
wieder auf halban (511). Das wiederholt sdich dann natürlich.... sieht 
man auch auf dem oszilloskop

alxy

von alxy (Gast)


Lesenswert?

Edit: Dummer Fehler von mir!

uint16_t k; ist die Lösung, uint8 kann ja nur bis 255.

Danke an alle Antworter hier :)

alxy

von alxy (Gast)


Lesenswert?

Mh, eine Frage habe ich doch noch. Ließe sich die performance der 
berechnung noch optimieren, wenn ich zB einen Ton erzeugen will?

alxy

von Lehrmann M. (ubimbo)


Lesenswert?

alxy schrieb:
> Mh, eine Frage habe ich doch noch. Ließe sich die performance der
> berechnung noch optimieren, wenn ich zB einen Ton erzeugen will?
>
> alxy

Sorry aber liest du eigentlich auch manchmal was man dir schreibt? Es 
tut mir leid aber dein Programm ist absoluter Blödsinn. Funktionieren 
mag es in Ansätzen aber das ist nicht nach den Regeln der Kunst. Nicht 
umsonsnt gibt es hier Artikel zum LED-Fading. Das was du machst ist 
Arbeitsbeschaffungsmaßnahme für deinen Mikrocontroller. Wenn du 
optimieren möchtest, dann solltest du mal entsprechende Artikel lesen. 
Zum Thema Sound - andere Baustelle aber sicherlich nicht auf diesem 
Wege. Sorry für die harten Worte. Muss aber sein.

von alxy (Gast)


Lesenswert?

Harte worte müssen sein ... ;)

Aber ich will es eben nicht mit einer Tabelle machen, sondern so. Wenns 
nicht geht, auch oaky. Hätte ja sein können, dass man durch ausnutzung 
bestimmter Modi da noch etwas optimeiren kann und so die Frequenz 
erhöhen kann. Dann würde das mit dem Ton auch klappen ;)

alxy

von Karl H. (kbuchegg)


Lesenswert?

alxy schrieb:
> Harte worte müssen sein ... ;)
>
> Aber ich will es eben nicht mit einer Tabelle machen, sondern so.

Du kannst noch so fest mit dem Fuss aufstampfen und "Ich will aber" 
schreien. Davon wird die Arbeit, die der µC mit Floating Point 
Arithmetik hat auch nicht weniger.
Wenn du optimieren willst, dann musst du dort ansetzen, wo optimieren 
etwas bringt. In deinem Fall ist das die Floating Point Arithmetik und 
ganz speziell die Berechnung des Sinus zur Laufzeit. Du willst 
optimieren? Dann werde diese Berechnung los.

"Wasch mir den Pelz aber mach mich nicht nass" funktioniert nun mal in 
der Realität nicht.

von Ralf D. (dreilira)


Angehängte Dateien:

Lesenswert?

wieso?? Geht doch!

(Quelle: 
http://www.amazon.de/Frottee-Trockenshampoo-fresh-200ml/dp/B0012S7IXG)

Duckundwech

Scherz beiseite: SIN auf dem uC ist ein absolutes nogo. Nur weil's der 
Compiler unterstützt, muß das noch lange nicht sinnvoll sein. Ich würde 
an Deiner Stelle nicht mal ansatzweise drüber nachdenken.

Ralf

von alxy (Gast)


Lesenswert?

Mit einem externen Quartz und den entsprechenden Fusebits ließ sichd as 
ganze noch um den Faktor 16 optimeiren...

Trotzdem habe ich am Ende dann trotzdem zur Tabelle gegriffen :P Damit 
war der Ton wenigstens zu hören.

alxy

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.