Hallo Leute,
ich beschäftige mich seit kurzem mit dem AVR Assembler und bin da auf
ein Problem gestoßen, bei dem ich nicht so recht weiß, wie ich es lösen
soll.
Ich versuche mein Problem mal anhand eines Minimalbeispiels zu
erläutern.
Über den USART bekomme ich einen vorzeichenbehafteten 8bit Wert, den ich
durch eine Zweierpotenz teilen und das Ergebnis aufrunden möchte. Da ich
nur durch Zweierpotenzen teile, hab ich mir gedacht, ich verwende den
Shift Operator (arithmetical right shift), um Zyklen zu sparen. Also
angenommen, ich habe den Wert 9 im Register r16 stehen und möchte diesen
durch 4 dividieren. Dann würde ich schreiben:
1
;in r16 steht der Wert 9
2
asr r16
3
asr r16
4
;nach den beiden Shift Befehlen steht in r16 der Wert 2
Nun möchte ich aber, dass der Wert der Division ( 9/4 = 2.25) immer
aufgerundet wird. In meinem Fall sollte also auf 3 aufgerundet werden.
Die Frage ist nur, wie mach ich das? Ich hab schon versucht, auf ein
gesetztes Carry Flag zu überprüfen und dieses dann zu meinem Ergebnis zu
addieren, doch das klappt leider auch nicht so ganz. Hat da jemand einen
Tipp wie man das elegant lösen könnte? Ich glaub, ich steh da gerade
etwas auf dem Schlauch...
Hi
>asr r16
Mit asr solltest vorsichtig sein. Das ist für vorzeichenbehaftete
Zahlen. Für Zahlen >127 könnte es unangenehme Überraschungen geben.
>Nun möchte ich aber, dass der Wert der Division ( 9/4 = 2.25) immer>aufgerundet wird. In meinem Fall sollte also auf 3 aufgerundet werden.
[avrasm]
subi r16,-3
lsr r16
lsr r16
[{avrasm]
sollte dein Problem lösen.
MfG Spess
Hallo,
spess53 schrieb:> Mit asr solltest vorsichtig sein. Das ist für vorzeichenbehaftete> Zahlen. Für Zahlen >127 könnte es unangenehme Überraschungen geben.
Da ich vom USART einen vorzeichenbehafteten 8bit Wert bekomme, wäre das
dann doch genau das richtige, oder? Es gibt übrigens eine Routine, die
überprüft, dass sich die Zahl x in folgendem Bereich befindet: -127 <= x
<= 127
spess53 schrieb:> Sollte so aussehen:> subi r16,-3 ; +3> lsr r16> lsr r16
Das funktioniert für positive Zahlen wunderbar, doch wenn im Register
r16 eine negative Zahl steht, dann funktioniert es nicht mehr. Das war
auch der Grund, warum ich zu asr tendiert habe. Man könnte das jetzt
natürlich so lösen, dass man für positive Zahlen lsr und für negative
Zahlen asr verwendet, doch das wäre ja ziemlich ineffizient, oder?
PS: Könntest du vielleicht auch noch erklären, warum du -3 subtrahierst?
Es funktioniert zwar, aber mir ist irgendwie nicht ganz klar, warum das
so ist.
Neuling schrieb:> Das funktioniert für positive Zahlen wunderbar, doch wenn im Register> r16 eine negative Zahl steht, dann funktioniert es nicht mehr. Das war> auch der Grund, warum ich zu asr tendiert habe.
Was verstehst du im Negativen genau unter "aufrunden"? Soll -3/2 nun -1
sein (mathematisch aufgerundet) oder -2 (betragsmässig aufgerundet)?
Die 3 (Nenner - 1) werden vorher addiert, weil ASR stets mathematisch
abrundet. Mit dieser Addition wird aufgerundet.
Man subtrahiert -3, weil der AVR keine Konstante addieren kann, nur
subtrahieren.
Hi
>Da ich vom USART einen vorzeichenbehafteten 8bit Wert bekomme, wäre das>dann doch genau das richtige, oder?
In dem Fall ja.
>PS: Könntest du vielleicht auch noch erklären, warum du -3 subtrahierst?>Es funktioniert zwar, aber mir ist irgendwie nicht ganz klar, warum das>so ist.
Weil es keinen Befehl gibt, der eine Konstante zu einem Register
addiert. Nur Subtraktion. Und ein subi rxy, -x entspricht einem (nicht
vorhandenem) addi rxy, x.
MfG Spess
A. K. schrieb:> Was verstehst du im Negativen genau unter "aufrunden"? Soll -3/2 nun -1> sein (mathematisch aufgerundet) oder -2 (betragsmässig aufgerundet)?
Oh, stimmt, das hätte ich besser spezifizieren sollen.
Ich meine mathematisch aufrunden. Also -3/2 soll zu -1 werden.
A. K. schrieb:> Die 3 (Nenner - 1) werden vorher addiert, weil ASR stets mathematisch> abrundet. Mit dieser Addition wird aufgerundet.
Kann ich mir das folgendermaßen vorstellen:
Die Zahl 9 wird in Binärdarstellung durch 00001001 repräsentiert.
Wenn ich die Zahl 9 nun um 2 nach rechts shifte (also durch 4
dividiere), dann erhalte ich 00000010, was 2 im Dezimalsystem
entspricht. Wie man sieht, wird hier das letzte Bit rausgeschoben und
hat keinen Einfluss auf das Ergebnis. Wenn ich aber vorher 3 addiere,
dann hat das letzte Bit noch einen Einfluss auf das Ergebnis (es wird
also aufgerundet). Ist das korrekt?
Wenn ich also statt 2x nach rechts, 3x mal nach rechts shiften würde,
dann müsste ich vorher 6 addieren. Also:
subi r16,-6
Stimmt das?
Neuling schrieb:> Wenn ich also statt 2x nach rechts, 3x mal nach rechts shiften würde,> dann müsste ich vorher 6 addieren. Also:> subi r16,-6>> Stimmt das?
Fast.
Du musst immer (Divisor - 1) addieren, im geschilderten Fall also 7.
Neuling schrieb:> Oh, stimmt, das hätte ich besser spezifizieren sollen.> Ich meine mathematisch aufrunden. Also -3/2 soll zu -1 werden.
Dann passt der Vorschlag von spess53, wenn du die LSR durch ASR ersetzt.
Eine Fallunterscheidung zwischen positiven und negativen Zahlen brauchst
du nicht.
Dieter Werner schrieb:> Du musst immer (Divisor - 1) addieren, im geschilderten Fall also 7.
Danke, hab mir das ganze jetzt nochmal im ausgeschlafenen Zustand
durchgedacht und ich versteh's jetzt :)
Danke auch an spess53, A.K. und Yalu X.!