Forum: Mikrocontroller und Digitale Elektronik Wie rechnet der uc?


von Der Jens (Gast)


Lesenswert?

Hallo Leute,

ich sitze momentan vor einem kleinen Problem.

Ich möchte zwei LEDs über einen bestimmten Zeitraum automatisch faden 
und dabei manuell dimmen können. Dabei können beide LEDs einen 
unterschiedlichen Wert haben; z.B. LED1 = 52 und LED2 = 220.

Wenn ich jetzt BEIDE heller oder dunkler machen möchte, kommt 
automatisch eine vor der anderen an die Grenze. Den Helligkeitswert 
(0...255) muß ich über eine Geradengleichung ausrechnen, da ein 
Lookuptable bei meiner Aufgabe zu umfangreich wäre.

Die Gleichung sieht aus wie folgt:

Ergebnis = ( ( m * x ) / 100 ) + n + Verschiebung

Dabei sind m (-200...+200) und n (0...255) fix ;x ist die Zeit.
Die Verschiebung stellt nun meine Helligkeit höher oder tiefer WÄHREND 
des fadens. Das Problem ist, dass ich jedes mal über die Grenze 
hinausschiesse und der uc alles macht; nur nie das Richtige ;-).

Für meine Grenzen habe ich

if ( Ergebnis > 255 ) OCR1A = pgm_read_word( &pwmtable_16 [255] );
if ( Ergebnis < 0 ) OCR1A = pgm_read_word( &pwmtable_16 [0] );

if ( Ergebnis > 255 ) OCR1B = pgm_read_word( &pwmtable_16 [255] );
if ( Ergebnis < 0 ) OCR1B = pgm_read_word( &pwmtable_16 [0] );

Kann mir einer erklären, warum die Grenzen NICHT beachtet werden und der 
uc jedes mal son Mist macht?

Wäre schön, wenn einer ne Idee hat.

LG

Jens

von Karl H. (kbuchegg)


Lesenswert?

Der Jens schrieb:

> Kann mir einer erklären, warum die Grenzen NICHT beachtet werden und der
> uc jedes mal son Mist macht?

Ohne komplettes Program: Nein

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Je nach Datentyp kann dein Ergebnis nie größer als 255 und nie 
kleiner als 0 werden, was deine Abfragen natürlich ad absurdum führt.

von Der Jens (Gast)


Lesenswert?

OK. Hier mal die wesentlichen Teile . Zur Zeit sei noch dazu gesagt. Sie 
wird in einer ISR von 0...100 gezählt
1
int main (void) {
2
3
int16_t Verschiebung = 0;
4
uint8_t Ergebnis;
5
6
if (!(PINB & (1 << PB0))) {  // dunkler    
7
Verschiebung--;
8
long_delay(20);  // 20 * 1ms
9
}
10
11
if (!(PINB & (1 << PB1))) {  // heller
12
Verschiebung++;
13
long_delay(20);  // 20 * 1ms
14
}
15
16
Ergebnis = ( ( 100 * Zeit) / 100 ) + (50 + Verschiebung);
17
if ( Ergebnis > 255 ) OCR1A = pgm_read_word( &pwmtable_16 [255] );
18
if ( Ergebnis < 0 ) OCR1A = pgm_read_word( &pwmtable_16 [0] );
19
OCR1A = pgm_read_word( &pwmtable_16 [Ergebnis] );
20
21
Ergebnis = ( ( -100 * Zeit) / 100 ) + (50 + Verschiebung);
22
if ( Ergebnis > 255 ) OCR1B = pgm_read_word( &pwmtable_16 [255] );
23
if ( Ergebnis < 0 ) OCR1B = pgm_read_word( &pwmtable_16 [0] );
24
OCR1B = pgm_read_word( &pwmtable_16 [Ergebnis] );
25
26
}

von Sven T. (svent)


Lesenswert?

Hallo,
was passiert denn wenn eine 8 bit Variable (uint8_t) den Wert 255 hat 
und ich 1 addiere ?
Sie wird 0 ;-)

Umgekehrt passiert ägnliches.

IMO kann ein uint8 NIE größer 255 oder kleiner 0 werden.
Und das ist das Problem bei den Abgragen.

S.

von weene (Gast)


Lesenswert?

Hallo,

OCR1B wird überschrieben:

if ( Ergebnis > 255 ) OCR1B = pgm_read_word( &pwmtable_16 [255] );
if ( Ergebnis < 0 ) OCR1B = pgm_read_word( &pwmtable_16 [0] );
OCR1B = pgm_read_word( &pwmtable_16 [Ergebnis] );

besser:
if ( Ergebnis > 255 ) Ergebnis = 255;
if ( Ergebnis < 0 ) Ergebnis = 0;
OCR1B = pgm_read_word( &pwmtable_16 [Ergebnis] );

aber warum nimmst du nicht gleich eine 8 bit Variable für das Ergebnis?
Dann kannst du die Prüfung weglassen.

(Achtung: bei den Berechnung in größeren Variablen bzw. float rechnen)


MFG
weene

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Der Jens schrieb:

> uint8_t Ergebnis;
Das heißt "unsigned int mit 8 bit". Der Wertebereich ist 0 bis 255.

Das kann also nie zutreffen:
1
> if ( Ergebnis > 255 ) OCR1A = pgm_read_word( &pwmtable_16 [255] );
2
> if ( Ergebnis < 0 ) OCR1A = pgm_read_word( &pwmtable_16 [0] );
3
> if ( Ergebnis > 255 ) OCR1B = pgm_read_word( &pwmtable_16 [255] );
4
> if ( Ergebnis < 0 ) OCR1B = pgm_read_word( &pwmtable_16 [0] );
5
> OCR1B = pgm_read_word( &pwmtable_16 [Ergebnis] );

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

weene schrieb:
> aber warum nimmst du nicht gleich eine 8 bit Variable für das Ergebnis?
> Dann kannst du die Prüfung weglassen.

Das ist eine 8 bit Variable.

von weene (Gast)


Lesenswert?

Ok mein Fehler...

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Christian H. schrieb:
> Das kann also nie zutreffen:

Ich meinte nur die If-Anweisungen, nicht die OCR1B-Zuweisung.

von Karl H. (kbuchegg)


Lesenswert?

Der Jens schrieb:
> OK. Hier mal die wesentlichen Teile . Zur Zeit sei noch dazu gesagt. Sie
> wird in einer ISR von 0...100 gezählt
>
1
> Ergebnis = ( ( 100 * Zeit) / 100 ) + (50 + Verschiebung);
2
> if ( Ergebnis > 255 ) OCR1A = pgm_read_word( &pwmtable_16 [255] );
3
> if ( Ergebnis < 0 ) OCR1A = pgm_read_word( &pwmtable_16 [0] );
4
> OCR1A = pgm_read_word( &pwmtable_16 [Ergebnis] );
5
6
>

Selbst wenn Ergebnis ein int16_t wäre (was es sein müssen wird):

Gehs durch.
Du rechnest dir ein Ergebnis aus.
Ist das Ergebnis zu groß setzt du einen Wert
Wenn das Ergebnis zu klein ist setzt du einen anderen Wert
Und dann: Dann setzt du auf jeden Fall noch den Wert, den du durch die 
Rechnerei erhalten hast.

D.h. Deine if sind völlig für die Katz, weil du danach immer auf jeden 
Fall noch dein Rechenergebnis benutzt.

Wenn schon, dann so
1
  Ergebnis = ( ( 100 * Zeit) / 100 ) + (50 + Verschiebung);
2
  if ( Ergebnis > 255 )
3
    Ergebnis = 255;
4
  else if ( Ergebnis < 0 )
5
    Ergebis = 0;
6
7
  OCR1A = pgm_read_word( &pwmtable_16 [Ergebnis] );

Dazu muss aber Ergebnis überhaupt in der Lage sein, Werte größer 255 
bzw. kleiner 0 annehmen zu können. Ein uint8_t kann das per Definiton 
schon mal nicht.

von Udo. R. S. (Gast)


Lesenswert?

>uint8_t Ergebnis;
>if (Ergebnis > 255)
>if ( Ergebnis < 0 )

beide Bedingungen können nie vorkommen, da der Wertebereich der uint8 
von 0 - 255 geht.

Auch die Berechnung
>( 100 * Zeit) / 100 )
ist ziemlich sinnfrei, da sich das zu Zeit kürzt.

Wenn ich Dich richtig verstehe willst Du daß beim Fading deiner LEDs es 
bei einer LED die auf dem Helligkeitswert 200 steht genau so lange 
dauert wie wenn die Diode den Helligkeitswert 50 hat.

Dann ist die Steigung deiner Geraden eben nicht konstant, sondern die 
ist abhängig von dem Startwert.

Bei der Diode mit dem Startwert 200 muss die Änderung der Helligkeit pro 
Zeit viermal höher ausfallen als bei der mit dem Wert 50.

von Der Jens (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> D.h. Deine if sind völlig für die Katz, weil du danach immer auf jeden
>
> Fall noch dein Rechenergebnis benutzt.

genau DAS war mein Problem!! Das mit uint8_t <-> int16_t ist mir vorhin 
dann doch noch selber aufgefallen.

Krass; wie seht ihr sowas nur immer?! wunderbar! :-)

Danke nochmal.

Eine kleine Formfrage hätte ich aber noch. Du schreibst die Abfrage so:

> if ( Ergebnis > 255 )
>
>     Ergebnis = 255;
>
>   else if ( Ergebnis < 0 )
>
>     Ergebis = 0;


ich würde sie so schreiben:

if ( Ergebnis > 255 )
  Ergebnis = 255;
if ( Ergebnis < 0 )
  Ergebnis = 0;

Also warum benutzt du ein else if? Gibt es 
Geschwindwigkeits-/Codegrößenvorteile oder ist es so nur besser zu 
sehen, dass beide if's zusammen gehören?

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Der Jens schrieb:
> Krass; wie seht ihr sowas nur immer?! wunderbar! :-)
z.B. in dem wir nicht versuchen maximal viel Befehle in eine Zeile zu 
quetschen... Ich weiß gar nicht wo so was herkommt wird das als 
besonders 'cool' angesehen?

Und ich persönlich gehe sogar soweit das ich immer Klammern setze auch 
wenn die Bedingung/Schleife nur eine Anweisung umfasst...

von Karl H. (kbuchegg)


Lesenswert?

Der Jens schrieb:

> ich würde sie so schreiben:
>
> if ( Ergebnis > 255 )
>   Ergebnis = 255;
> if ( Ergebnis < 0 )
>   Ergebnis = 0;
>
> Also warum benutzt du ein else if?

Weil, wenn schon feststeht das Ergebnis größer als 255 ist, es nicht 
mehr sein kann, das Ergebnis kleiner als 0 ist.
Wozu etwas abtesten, von dem ich den Ausgang sowieso schon kenne?

von MagIO (Gast)


Lesenswert?

Die Zeile finde ich auch noch fragwürdig:
Ergebnis = ( ( -100 * Zeit) / 100 ) + (50 + Verschiebung);

Wenn Zeit von 0 - 100 geht, dann kann Ergebnis je nach Verschiebung auch 
negativ werden. Durch die 8 bit Variable liegt ne negative Variable dann 
im Bereich 128-255. Beim Übergang von einem positiven Ergebnis zum 
negativen Ergebnis springt also der PWM-Wert von z.B. &pwmtable_16[0] um 
auf @pwmtable_16[255]. Ob das so gewollt ist?

von Besucher (Gast)


Lesenswert?

Und um die Frage zu beantworten: Eigentlich kann er nur addieren... 
(duck, und wech)

von Klaus (Gast)


Lesenswert?

MagIO schrieb:
> Beim Übergang von einem positiven Ergebnis zum
> negativen Ergebnis springt also der PWM-Wert von z.B. &pwmtable_16[0] um
> auf @pwmtable_16[255]. Ob das so gewollt ist?

Was meinst du wohl, was diese Zeile hier bewirken soll?  ;-)

Der Jens schrieb:
> if ( Ergebnis < 0 )
>   Ergebnis = 0;

von Karl H. (kbuchegg)


Lesenswert?

MagIO schrieb:
> Die Zeile finde ich auch noch fragwürdig:
> Ergebnis = ( ( -100 * Zeit) / 100 ) + (50 + Verschiebung);
>
> Wenn Zeit von 0 - 100 geht, dann kann Ergebnis je nach Verschiebung auch
> negativ werden.


Er hat aber auch im Eröffnungspoting geschrieben, dass die erste 100 
hier

> Ergebnis = ( ( -100 * Zeit) / 100 ) + (50 + Verschiebung);
                 ****

eigentlich ein m ist mit einem Wertebereich von -200 .. 200. Fass diese 
100 und die 50 und die Verschiebung einfach nur als x-beliebige Werte 
auf, mit denen zur Zeit einfach nur getestet wird. Die werden sich 
sicherlich noch ändern.

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.