Hallo Leute, ich habe mal wieder ein Problem. Diesesmal geht es um das 2er Komplement. Ich möchte gerne, eine 2er Komplementzahl in eine Dezimalzahl umwandeln aber ich weiß nicht wie ich das machen soll. Das ganze soll im AVR-Studio geschehen und ein µC soll es mir nachher auf dem Bildschirm ausgeben. Das 2er Komplement erhalte ich von einem Beschleunigungssensor und ich würde diese Werte halt gerne Dezimal ausgeben, so wie es unten kurz beschrieben ist: Dez Bin Hex +511 01 1111 1111 0x1FF +510 01 1111 1110 0x1FE ... +1 00 0000 0001 0x001 0 00 0000 0000 0x000 -1 11 1111 1111 0x3FF ... -511 10 0000 0001 0x201 -512 10 0000 0000 0x200 Könnte mir jemand einen Tip geben, wie ich das im GCC realisiere oder mir sogar einen kleinen Beispielcode dazu geben? Ich komme einfach nicht weiter. Schonmal danke und Gruß, Marian
Liess die 10 Bit? von deinem Sensor ein (in ein 16bit int), teste ob das 10te gesetzt ist (=> negative Zahl) und setze dann bits 11-15 auf eins. dann hast du einen 16bit int, der vorzeichenrichtig deinen Sensorwert enthält. /Ernst
1 | #include <stdlib.h> |
2 | |
3 | uint16_t val; |
4 | char b[20]; |
5 | ...
|
6 | val = ...; |
7 | itoa(val, b, 10); |
Oder halt sprintf() benutzen, wenn du die nötigen Resourcen dafür hast.
> Könnte mir jemand einen Tip geben, wie ich das im GCC realisiere
sprintf.
Erstmal Danke an alle! @Jörg: Leider funktioniert dein Vorschlag mit itoa nicht. Ich bekommen immernoch Werte von 0 bis 1023 aber leider nicht die negativen die ich haben möchte (also von -512 bis 511). Hat noch jemand ne andere Idee oder muss ich an deinem Vorschlag nur noch etwas ändern, denn was die 10 in itoa bedeutet weiß ich noch nicht. Leider kann ich sprintf nicht nutzen, weil ich wenig Ressourcen habe und diese Funktion auch noch nicht ganz verstanden habe. Gruß, Marian
Du musst auf jeden Fall die Vorzeichenbits wie ich geschrieben habe erweitern, sonst kann itoa, sprintf etc. garnicht wissen, dass es eine negative zahl ist. also
1 | int16_t val; |
2 | val=read_from_sensor(); |
3 | if (val & (1<<10)) { |
4 | val |= (1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<10); |
5 | }
|
6 | ...itoa(val... |
7 | ...sprintf(...val... |
Der dritte Parameter im Aufruf von itoa ist die Basis für die ausgegebene Zahl (also 10 -> dezimal). Wenn man eine 16 eingibt, ist die Ausgabe hexadezimal usw...
@peter: das stimmt so nicht: der chip sendet -512, als bits: 0000 0010 0000 0000 nach deiner umrechnung kommt da 0 raus, nicht -512... Beim kopieren eines 2er-Komplement werts in eine variable mit mehr bits, muss man immer das Vorzeichenbit auf die neu hinzugekommenen Bits kopieren, also: 1o bit eingelesen: 0000 0010 0000 0000 10er bit umkopiert in die "neuen" bits: 1111 1110 0000 0000 und voila, eine 16bit signed int variable, die den richtigen wert enthält. /Ernst
@Ernst, dann aber so:
1 | if (val & (1<<9)) |
2 | val |= (1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(1<<10); |
Peter
@Peter Da hast Du völlig recht... Zahlen über 5 waren noch nie meine Stärke ;) /Ernst
oder so: if(val&0x100){ // val & 0000 0010 0000 0000 val|=0xFC00; // val |= 1111 1100 0000 0000 } Dann hast du doch einen signed int, oder nicht?
Nur mal so zur Info: Beide Varianten funktionieren! Die mit Y=X-1024 und die mit dem einfügen der Einsen. Danke nochmals an alle für eure Bemühungen. Gruß, Marian
@m@u: das ist genau, was der compiler aus dem obigen code macht, die einzelnen bitshifts+or-Verknüpfungen werden zur compilezeit aufgelöst, und durch eine Konstante ersetzt. Hat den Vorteil, dass man sich in einem Jahr nicht fragt, was die magische "0xFC00" Konstante macht. /Ernst
@Ernst Dass das der Compiler bereits zur Compilierzeit auflöst habe ich nicht gewusst, danke!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.