Forum: Mikrocontroller und Digitale Elektronik AVR GCC uint16_t letzte Ziffer runden ?


von Marco S. (Gast)


Lesenswert?

Hallo zusammen,

ich habe mir eine Routine geschrieben, mit der ich das Summensignal 
eines RC-Empfängers in ein Array (uint16) lesen kann. Die Werte werden 
in µs erfasst und so auch in das Array geschrieben.

Da die Servos so eine Genauigkeit nicht abbilden können, würde ich gerne 
die letzte Stelle des Messwertes (uint16) runden, also nur 0 oder 5 am 
Ende. Da ich mit der Arithmethik völlig auf Kriegsfuß stehe, würde ich 
mich über Vorschläge zur Umsetzung freuen.

Vielen Dank schon einmal im voraus.
Marco

: Verschoben durch Moderator
von Rene (Gast)


Lesenswert?

z.B.

rundet allerdings immer ab.
1
uint16_t zahl = zahl - (zahl%5);
1
uint16_t zahl;
2
uint8_t diff = zahl%5;
3
4
diff > 2 ? zahl = zahl - diff : zahl = zahl + (5-diff);

Das lässt sich natürlich wesentlich schöner und lesbarer schreiben. Das 
sollte nur als Beispiel dienen.
Getestet ist es auch nicht, kann also noch Fehler haben ;-).


Grüsse,
R.

von Georg G. (df2au)


Lesenswert?

Mit uint16_t kannst du Zahlen zwischen 0 und 65535 darstellen. Die 
letzten Stellen haben dabei die Wertigkeit 1 - 2 - 4 - 8. Da ist es 
ungeschickt, auf 0 oder 5 runden zu wollen. Am nächsten dran wäre die 4.

Also addierst du 2 und streichst dann die letzten beiden Stellen weg 
(setzt sie auf 0).

von Rene (Gast)


Lesenswert?

sorry:
1
diff < 3 ? zahl = zahl - diff : zahl = zahl + (5-diff);

von Stefan (Gast)


Lesenswert?

Addiere 0,5 und teile die Zahl dann durch 10.

Divisionen und Fließkomma-Berechnungen sind für Mikrocontroller 
allerdings Schwerstarbeit.

Viel schneller ist es, einfach die unteren drei Bit abzuschneiden:

neu=alt/8  oder neu=alt>>3   (erzeugt beiden den gleichen 
Maschinen-Code).

Das entspricht einer Division durch 8 und es wird immer abgerundet. 
Prüfe nach, ob diese einfachere Variante für Deine Anwendung genügt.

von Marco S. (Gast)


Lesenswert?

Hallo und Danke für die schnellen Antworten.

Leider verstehe ich diesen Part nicht ganz :
1
uint16_t zahl = zahl - (zahl%5);

Was bedeutet das %5 ? Auf der Suche nach einer Übersichtsseite mit den 
ganzen Operatoren bin ich leider noch nicht fündig geworden.

Viele Grüße aus dem verschneiten Norden.

Marco

von (prx) A. K. (prx)


Lesenswert?


von J.-u. G. (juwe)


Lesenswert?

Marco S. schrieb:
> Was bedeutet das %5 ? Auf der Suche nach einer Übersichtsseite mit den
> ganzen Operatoren bin ich leider noch nicht fündig geworden

Echt? Kann ich mir eigentlich nicht vorstellen. Siehe:
http://de.wikibooks.org/wiki/C-Programmierung:_Ausdr%C3%BCcke_und_Operatoren

von Marco S. (Gast)


Lesenswert?

Ihr wart zu schnell ;-)

Ich habe es in der Zwischenzeit gefunden (Modulus).

Danke nochmal !!!

Marco

von Fabian O. (xfr)


Lesenswert?

Wenn abrunden reicht, genügt einfach:
1
zahl = zahl / 5 * 5;

Ansonsten:
1
zahl = (2 * zahl + 5) / 10 * 5;

Dann aber auf die Wertebereiche aufpassen. 2 * zahl + 5 darf maximal 
65535 ergeben. zahl darf also maximal 32765 sein. Ansonsten zuerst auf 
uint32_t casten.

von Falk B. (falk)


Lesenswert?

@ Fabian O. (xfr)

Die erste sinnvolle und verständliche Antwort im Thread.

von Falk B. (falk)


Lesenswert?

Man könnte es auch etwas perfomanter über modul machen, damit hat man 
auch kein Problem mit Überläufen, aber das ist eher akademisch.
1
rest = zahl % 5;
2
if (rest<3) zahl -= rest; else zahl+=(5-rest);

von Rene (Gast)


Lesenswert?

Hallo Marco,

das % bedeutet Module.

12%5 ergibt dann 2.

Grüsse,
R.

von Oliver (Gast)


Lesenswert?

Georg G. schrieb:
> ist es
> ungeschickt, auf 0 oder 5 runden zu wollen.

Der einzige wahre Satz bisher.
Denn die wirkliche Frage lautet: WARUM?

Was genau versprichst du dir davon, die Werte auf- oder abzurunden? Den 
Servos ist das herzlich egal, dem Prozessor auch. Solange du bei 
16-Bit-Werten bleibst, verbrauchst du auch nicht weniger Speicher. Du 
verbrauchst nur Rechenzeit für die Umrechnung.

Also: Entweder reduzierst du die Auflösung um 2 oder ein vielfaches 
davon, dann aber richtig per Rechtsschift, oder du lässt die Werte, wie 
sie sind.

Nur so als Hinweis: Aktuelle "hochwertige" RC-Anlagen arbeiten mit 11 
bit, andere mit 10, und ein preiswertes Servo löst vielleicht mit viel 
Glück auf 7 bit auf...

Oliver

von tobi (Gast)


Lesenswert?

Rene schrieb:
> z.B.
>
> rundet allerdings immer ab.
> uint16_t zahl = zahl - (zahl%5);

Einfach davor 5 addieren dann rundet es auch auf

von Yalu X. (yalu) (Moderator)


Lesenswert?

Oliver schrieb:
> Georg G. schrieb:
>> ist es
>> ungeschickt, auf 0 oder 5 runden zu wollen.
>
> Der einzige wahre Satz bisher.
> Denn die wirkliche Frage lautet: WARUM?

Diese Frage ist genau die richtige Antwort auf die Anfrage.

Klar wird ein Servo das Steuersignal nicht auf die µs genau auswerten.
Wird der Wert aber vorher gerundet, kommt zum Fehler des Servos noch der
Rundungsfehler hinzu. Man verschwendet also Rechenaufwand und Flash-
Speicher dafür, das Gesamtsystem ungenauer zu machen.

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.