Forum: Mikrocontroller und Digitale Elektronik Schrittweise Ausgabe


von Newbie (Gast)


Lesenswert?

Seid gegrüßt,

ich rechne nun schon seit Stunden herum, komme aber auf keine 
funktionierende Lösung.

Ich versuche ein Fading für eine LED (über PWM) hinzubekommen...

int16_t nFadeCount = 0;     // Zähler für das Überblenden(Fading)
int16_t nFadingTime = 200;
int16_t nSavedPWM = 100;    // Variable zur Speicherung des letzten 
Helligkeitswertes

nFadeCount++;
if(nFadeCount <= nFadingTime)
    OCR1A += nSavedPWM/nFadingTime;

... steh aber irgendwie auf dem Schlauch. Der hier gezeigte Ansatz geht 
zwar 'irgendwie', aber nur, solang nSavedPWM>nFadingTime ist.

Wichtig: OCR1A kann nur int-Werte annehmen und das Fading soll relativ 
gleichmäßig gehen

Wenn also z.B. nFadingTime=1000 und nSavedPWM=100 wäre, sollte OCR1A in 
jedem 10sten Schritt um 1 erhöht werden.
Wie kann man das umsetzen?
Würde mich über jeden Ansatz freuen.

Viele Grüße

von Matthias (Gast)


Lesenswert?

Newbie schrieb:
> Wenn also z.B. nFadingTime=1000 und nSavedPWM=100 wäre, sollte OCR1A in
> jedem 10sten Schritt um 1 erhöht werden.

Das ist der falsche Ansatz. Wenn das Fading gleichmäßig gehen soll, muß 
die LED logarithmisch angesteuert werden (-> Weber-Fechner-Gesetz)

von Karl H. (kbuchegg)


Lesenswert?

Newbie schrieb:

Abgesehen von der logarithmischen Verteilung von der Matthias gesprochen 
hat.

> Wenn also z.B. nFadingTime=1000 und nSavedPWM=100 wäre, sollte OCR1A in
> jedem 10sten Schritt um 1 erhöht werden.
> Wie kann man das umsetzen?

Was hindert dich daran, auszurechnen, wieviele Schritte notwendig sind, 
ehe OCR1A wieder um 1 erhöht werden soll? Wenn ein Computer etwas ganz 
gut kann, dann ist das Berechnungen ausführen.

von Newbie (Gast)


Lesenswert?

Hi Matthias,

ich glaub, du beziehst dich auf die LED-Kennlinie.
Ähm... jepp, ich hab mich da wohl falsch ausgedrückt. Ich meinte 
eigentlich 'gleichmäßiges Abarbeiten des nSavedPWM-Wertes'.

(Für die Ansteuerung der LED-Helligkeit werd' ich mir später eine 
Tabelle anlegen.)

LG

von Matthias (Gast)


Lesenswert?

Newbie schrieb:
> ich glaub, du beziehst dich auf die LED-Kennlinie.

Nein, auf die Helligkeitswahrnehmung. Bei PWM spielt die Kennlinie keine 
Rolle, weil immer der volle Strom fließt.

von Newbie (Gast)


Lesenswert?

Hallo Karl,

bei z.B. nFadingTime=1000 und nSavedPWM=100 ist das leicht. Da hab ich 
int-Werte und vielfache von einander.

Was ist aber bei z.B. nFadingTime=133 und nSavedPWM=633?
Dann müßte bei jedem 133/633sten Schritt weitergezählt werden. Und dann 
WIE den Faktor einbauen - es kann ja nur in int-Werten weitergezählt 
werden?

Von Mathe versteh ich schon was, aber ich verzweifle langsam echt an der 
Umsetzung.:(

Viele Grüße

von Newbie (Gast)


Lesenswert?

Niemand einen Rat?

Viele Grüße

von Kein Name (Gast)


Lesenswert?

> es kann ja nur in int-Werten weitergezählt werden?

Nö - auch mit Festkommazahlen.
int32_t nSavedPWM_32 = (int32_t)nSavedPWM << 16;
OCR1A += (nSavedPWM_32/nFadingTime) >> 16;

Einfach mal drüber schlafen. Morgen löst sich der Knoten von alleine 
auf.
-- Grüße.

von Kein Name (Gast)


Lesenswert?

Alles zurück.

Natürlich muss OCR1A eine Festkommazahl sein.

int32_t nSavedPWM_32 = (int32_t)nSavedPWM << 16;
int32_t OCR1A_32 = (int32_t)OCR1A << 16;

OCR1A_32 += (nSavedPWM_32/nFadingTime);
OCR1A = OCR1A_32 >> 16;

von Newbie (Gast)


Lesenswert?

Hi,

ich bekomme für die erste Zeile eine Fehlermeldung:
initializer element is not constant

?

Viele Grüße

von Karl H. (kbuchegg)


Lesenswert?

Newbie schrieb:
> Hi,
>
> ich bekomme für die erste Zeile eine Fehlermeldung:
> initializer element is not constant
>
> ?

Na, ja. Was ist dein ein 'Initializer'?

Das womit eine Variable initialisiert wird.

Und der muss an bestimmten Stellen (zb globale Variablen) konstant sein. 
Bei dir ist er das nicht.

Mach halt eine normale Zuweisung draus, und dann passt es wieder


anstelle
1
int32_t nSavedPWM_32 = (int32_t)nSavedPWM << 16;

dann eben
1
int32_t nSavedPWM_32;
2
3
4
int main()
5
{
6
  nSavedPWM = ....;
7
  nSavedPWM_32 = (int32_t)nSavedPWM << 16;
8
}

oder wie es dann eben bei dir passt.


Im übrigen ist es doch einfach. Was tust du denn, wenn du in Euros 
rechnen sollst, aber keine Kommazahlen haben darfst. Du sollstz 2.80 
Euro + 3.40 Euro rechnen, ohne Kommazahlen. Dann rechnest du eben in 
Cent! 280 Cent + 340 Cent. Und schon kannst du das rechnen, ohne 
Kommazahlen benutzen zu müssen.

So auch hier

Wenn du 133/633 rechnen musst, dir aber nur das Ganzzahlige Ergebnis zu 
wenig ist (weil 0), dann rechnest du eben 1330/633, das macht 2. Du 
merkst dir einfach, dass die 2 (oder allgemeiner: die Einer deines 
Ergebnisses) eigentlich schon die erste Kommastelle sind. Und wenn die 1 
Kommastelle nicht reicht, dann rechnest du eben 13300/633, das mach 21 
und du merkst dir, dass die Zehner und die Einer die ersten beiden 
Kommastellen sind. Wenn du ans OCR zuweist, musst du die beiden Stellen 
loswerden, das sollte aber einfach sein: dividieren durch 100 reicht.
Addierst du also
    21
    21
    21
    21
    21
    21
  ----
   126

dann hast du laut deiner Systematik eigentlich 5 * 0.21 = 1.26 
errechnet. Bei dir dann eben 126 / 100 -> 1, die ins OCR kommt. Und 
schon hast du mit 2 Nachkommastellen gerechnet ohne Kommazahlen benutzen 
zu müssen.

In einem Computerprogramm wird man natürlich sinnvollerweise nicht 
Vielfache von 10 nehmen (so wie bei den Cent) sondern Vielfache von 2, 
weil man die dann wieder leicht loswerden kann (anstelle von Dividieren 
verschiebt man einfach die Bits), aber das Prinzip ist völlig identisch.

von Werner (Gast)


Lesenswert?

Kein Name schrieb:
> Natürlich muss OCR1A eine Festkommazahl sein.

Wohl eher eine Ganze Zahl.

von Newbie (Gast)


Lesenswert?

Hallo Karl,

sooooooooooooooooooooo, jetzt raucht mir der Kopf.;-)))

Ich glaube, diese etwas längere Übung mit der 0,21... hab' ich nicht so 
wirklich verstanden - auch nach zwei Stunden Brainstorming!:(

ABER... nachdem ich mir nochmal ganz intensiv eure zwei Beiträge (u.a. 
mein C-Buch zu Operatoren) durchlas, und zudem sah, dass mein ATMega88 
bei Verwendung einer einzigen float-Variable gleich 400% meiner 
ursprünglichen Speicherkapazität verbraucht (65% Speicherauslastung bei 
etwa 200 Zeilen Programmcode^^), hab ich endlich die Shiftoperation 
kappiert - da ich auch scheinbar gar nicht mehr daran vorbei komme. 
Jippiiieieee, Schweinebacke;-)

DANKE!^^

Gott, ich hab's mir ja vorher so unglaublich schwer mit dem Basteln 
einer passenden Gleichung gemacht. So sieht das jetzt schon mal aus:

OCR1A = nFadeCount*((nSavedPWM<<2)/(nFadingTime<<2));

Nun hab' ich nur noch ein ganz ein kleines Problem. Der 
nSavedPWM-Maximalwert wird so niemals erreicht, da mit dieser Zeile ja 
stets zumindest ein ganz ein kleines Stückerl abgeschnitten wird.

Mal guggn, wie lang ich brauche, um draufzukommen. ODER ein "Wissender" 
schaut vl. mal kurz drüber und gibt mir einen 'Wink'.;-))

Liebe Grüße

von Newbie (Gast)


Lesenswert?

EDIT:

... nehm alles zurück......... groooooooooooooooßer Denkfehler drin:(

LG

von Newbie (Gast)


Lesenswert?

Ok, jetzt scheint's zu gehen. Wie "Kein Name" schon aufzeigte:

int32_t nSavedPWM_32 = (int32_t)nSavedPWM << 16;
int32_t OCR1A_32 = (int32_t)OCR1A << 16;

OCR1A_32 = nFadeCount*(nSavedPWM_32/nFadingTime);
OCR1A = OCR1A_32 >> 16;

Ich muß die Bitmanipulation wohl doch noch mal gründlich studieren.;-)))

Danke!

LG

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.