Forum: Mikrocontroller und Digitale Elektronik Lookup Table sinnvoll


von TGMartin (Gast)


Lesenswert?

Hallo,

ich bin momentan dabei eine LED von einem Wert auf einen anderen faden 
zu lassen und das ganze in einer bestimmten Zeit.

Ich möchte beispielsweise eine LED um 50 Helligkeitswerte heller machen 
in 30min. Bedeutet bei einer Schrittweite von 1min. 1,67 Schritte pro 
Minute. Nun weiß ich nicht wie ich das machen soll, da ich ja nur ganze 
Zahlen für meine Helligkeitswerte nehmen kann.

Kann man sowas umgehen und wenn ja wie?!

Ne andere Möglichkeit wäre ein Lookup Table, welcher denn aber 
schlechtestenfalls 2800 char Werte haben müßte und somit ~2,7kByte 
hätte. Wär also schon recht viel Speicher der da verloren gehen würde.

Wär schön, wenn mir einer mal nen Rat geben könnte.

Danke schonmal

Martin

von Karl H. (kbuchegg)


Lesenswert?

TGMartin schrieb:

> Wär schön, wenn mir einer mal nen Rat geben könnte.

Nicht über Schrittweite und aufaddieren rechnen, sonden immer vom 
Grundzustand ausgehen und

   y = k * x + d

anwenden

Deine Helligkeit y berechnet sich zum Zeitpunkt x durch diese Formel. k 
und d berechnest du dir, wenn du den Helligkeitssprung und die dazu 
vorgesehene Zeitdauer kennst.

von Falk B. (falk)


Lesenswert?

@  TGMartin (Gast)

>ich bin momentan dabei eine LED von einem Wert auf einen anderen faden
>zu lassen und das ganze in einer bestimmten Zeit.

Siehe LED-Fading

>Minute. Nun weiß ich nicht wie ich das machen soll, da ich ja nur ganze
>Zahlen für meine Helligkeitswerte nehmen kann.

Siehe Festkommaarithmetik

>Ne andere Möglichkeit wäre ein Lookup Table, welcher denn aber
>schlechtestenfalls 2800 char Werte haben müßte und somit ~2,7kByte
>hätte. Wär also schon recht viel Speicher der da verloren gehen würde.

Wäre unsinnig, weil du alle Zeit der Welt hast, den neuen Wert zu 
berechnen. Tabellen nimmt man nur bei komplexen oder sehr schnellen 
Berechnungen.

MfG
Falk

von TGMartin (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> y = k * x + d

Genial einfach; einfach genial!

Nun müsste ich aber wieder mit Kommas rechnen. Und damit habe ich leider 
noch keine Erfahrung. Ich weiß aber, dass bei der Ganzzahl Division die 
Nachkommastellen einfach gelöscht werden. Dabei würde aber eine zu große 
Ungenauigkeit beim k rauskommen. Wie kann man also mit meinetheim 2 
Nachkommastellen k ausrechnen und dann das Ganze wieder als char 
zurückwandeln ?

Meine Idee wäre jetzt den ganzen Ausdruck mal 100 zu nehmen und denn am 
Ende alles wieder durch 100 zu teilen. Also :

100k*x+100d=100y

Klappt das so?

Gruß,

Martin

von Johnny B. (johnnyb)


Lesenswert?

Ja genau, floats sind unnötig für solche Anwendungen.
Am besten machst Du Deine Versuche erst mal auf dem PC, z.B. in Excel. 
Wenns dort funktioniert, bildest Du es auf dem uC nach.

von Karl H. (kbuchegg)


Lesenswert?

TGMartin schrieb:

> 100k*x+100d=100y
>
> Klappt das so?

Wenn du mit dem Zahlenbereich auskommst, gibt es keinen Grund warum das 
nicht klappen sollte.

von Karl H. (kbuchegg)


Lesenswert?

TGMartin schrieb:
> Karl heinz Buchegger schrieb:
>> y = k * x + d
>

> noch keine Erfahrung. Ich weiß aber, dass bei der Ganzzahl Division die
> Nachkommastellen einfach gelöscht werden.

Wenn du das durchrechnest wirst du draufkommen, dass du die Division 
eigentlich nur bei der Berechnung von k benötigst. Da kommt dann ein 
Bruch raus, also Zähler und Nenner. Bei d können zwar auch Kommastellen 
auftreten, die sind aber nicht so das grosse Problem, weil sie sich im 
Ergebnis nicht besonders auswirken, wenn man sie einfach weglässt.

Nichts und niemand hindert dich jetzt aber daran, das k nicht bei der 
Bestimmung auszurechnen, sondern dir Zähler und Nenner getrennt zu 
speichern.

Dann rechnest du eben nicht

   y = k * x + d

sondern

  y = k_Zähler * x / k_Nenner  + d

:-)  Viele Wege führen nach Rom

von TGMartin (Gast)


Lesenswert?

deiner is aber schneller.. mit Abkürzung..hehe..

Eine kleine Unsicherheit habe ich dann noch bei den Zahlenbereichen.

Meine Werte sind alle vom Typ Char.

Wenn ich jetzt den Ausdruck "k_Zähler * x / k_Nenner" berechnen möchte 
muß ich meine Werte von unsigned Char nach (signed) Short konvertieren. 
Wie stelle ich das am besten an?
1
unsigned char  d = 10, y, k_x;
2
short z = 5, n = 3, x = 2;
3
4
k_x = (z*100*x)/(100*n);
5
y = k_x + d;
geht das prinzipiell ??

von Karl H. (kbuchegg)


Lesenswert?

TGMartin schrieb:

> Meine Werte sind alle vom Typ Char.

Das ist schon mal ein Fehler.
Den Datentyp char verwendest du ausschliesslich nur dann, wenn du es mit 
Charactern im Sinne von 'Zeichen in einem Text' zu tun hast.
In den anderen Fällen, wenn du es mit einem 'kleinen Integer' zu tun 
hast, verendest du immer entweder 'signed char' oder 'unsigned char' 
(oder int8_t bzw. uint8_t, was hier auf dasselbe rausläuft)

Nichtbeachtung dieser Regel wird mit seltsamen Berechnungsergebnissen 
belohnt :-)


Edit: Seh gerade: Du warst in der Beziehung ohnehin brav :-)

> Wenn ich jetzt den Ausdruck "k_Zähler * x / k_Nenner" berechnen möchte
> muß ich meine Werte von unsigned Char nach (signed) Short konvertieren.
> Wie stelle ich das am besten an?

Brauchst du nicht.
In C gilt die Regel:
Gerechnet wird grundsätzlich mindestens im Datentyp int. Kleiner wird 
nicht gerechnet, es sei denn der Optimizer kann beweisen, dass es keinen 
Unterschied macht. Das wird ihm aber bei dir schwer fallen :-)

von TGMartin (Gast)


Lesenswert?

Also int im Sinne von int16_t oder int32_t? Und wie konvertier ich dann 
von int16/32_t nach int8_t? Einfach durch Zuweisen? Weil der 
Helligkeitswert MUSS ja ein (u)int8_t sein...

von Karl H. (kbuchegg)


Lesenswert?

TGMartin schrieb:
> Also int im Sinne von int16_t oder int32_t?

int

(wenn auf deinem System ein int äquivalent ist zu einem int16_t, dann 
ist es auch gleich einem int16_t.
Auf dem AVR ist ein int synonym zu einem int16_t. Auf einem PC wäre es 
heutzutage meistens ein int32_t)

int ist der Datentyp, der der 'natürliche' für eine CPU ist, mindestens 
aber 16 Bit.
Auf einer 8 Bit CPU sind das 16 Bit
Auf einer 16 Bit CPU sind das 16 Bit
Auf einer 32 Bit CPU sind das 32 Bit
....


> Und wie konvertier ich dann
> von int16/32_t nach int8_t? Einfach durch Zuweisen?

Ja.
Wenn dich der Compiler darauf hinweist, dass da aber unter Umständen 
etwas verloren geht, kann man ihn mit einem Cast mitteilen, dass das 
schon in Ordnung ist

   i = (unsigned char)j;
   i = (uint8_t)j;

von TGMartin (Gast)


Lesenswert?

cool.. wieder was schlauer geworden.

Ich danke dir.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Karl heinz Buchegger schrieb:
> int ist der Datentyp, der der 'natürliche' für eine CPU ist, mindestens
> aber 16 Bit.
> Auf einer 8 Bit CPU sind das 16 Bit
> Auf einer 16 Bit CPU sind das 16 Bit
> Auf einer 32 Bit CPU sind das 32 Bit

Ich meine, der Wertebereich und die Größe ist in irgend einer 
Header-Datei abgelegt (types.h oder so - bitte nicht drauf festnageln).

von Karl H. (kbuchegg)


Lesenswert?

Christian H. schrieb:
> Karl heinz Buchegger schrieb:
>> int ist der Datentyp, der der 'natürliche' für eine CPU ist, mindestens
>> aber 16 Bit.
>> Auf einer 8 Bit CPU sind das 16 Bit
>> Auf einer 16 Bit CPU sind das 16 Bit
>> Auf einer 32 Bit CPU sind das 32 Bit
>
> Ich meine, der Wertebereich und die Größe ist in irgend einer
> Header-Datei abgelegt (types.h oder so - bitte nicht drauf festnageln).

Stimmt schon.
Aber ausser informellen Character kann man mit diesen Konstanten nicht 
so wahnsinnig viel anfangen. Am ehesten noch einen assert, der einem 
beim Programmstart mitteilt, dass die C-Runtime gewisse Voraussetzungen 
des Programms nicht erfüllt.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Ich möchte beispielsweise eine LED um 50 Helligkeitswerte heller
> machen in 30min. Bedeutet bei einer Schrittweite von 1min.
> 1,67 Schritte pro Minute.

Du könntest das Problem ganz anders aufziehen.

30 Minuten sind 1800 Sekunden lang. Damit ist die Dauer eines Schrittes 
36 Sekunden lang.

In einem Timerinterrupt o.ä. im Sekundentakt zählst Du die 
verstreichenden Sekunden und erhöhst den Ausgangswert alle 36 Sekunden 
um einen Schritt.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Karl heinz Buchegger schrieb:
> Aber ausser informellen Character kann man mit diesen Konstanten nicht
> so wahnsinnig viel anfangen.

Genauso meinte ich das auch. Wenn man nicht genau weiß wie groß ein INT 
ist, kann man dort schön nachschauen.

von noname (Gast)


Lesenswert?

50 Helligkeitsschritte sind etwas grob. Man kann feiner auflösen, wenn 
man schnell zwischen zwei PWM-Werten wechselt. Will man 40,2 haben gibt 
man einfach 41, 40, 40, 40, 40, 41, 40 ... als PWM aus. 
Helligkeitssprünge werden so vermieden.

von Falk B. (falk)


Lesenswert?

Oder man macht gleich eine 16 Bit PWM.

MFG
Falk

von Rolf Magnus (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> int ist der Datentyp, der der 'natürliche' für eine CPU ist, mindestens
> aber 16 Bit.

Es ist eine Empfehlung in der ISO-Norm, daß es so sein sollte (das mit 
der natürlichen Breite).

> Auf einer 8 Bit CPU sind das 16 Bit
> Auf einer 16 Bit CPU sind das 16 Bit
> Auf einer 32 Bit CPU sind das 32 Bit
> ....

Hihi, gerade da hast du aufgehört, denn bei 64-Bit-Architekturen gilt 
das in der Regel nicht mehr. Da ist int meistens trotzdem 32 Bit breit, 
einfach weil es in C nicht genügend Typen gibt, die kleiner als int 
sind. Man will üblicherweise 8-, 16- und 32-Bit-Typen haben, aber nur 
char und short dürfen kleiner als int sein.

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.