Forum: Compiler & IDEs 2er Komplement und C


von Marian (Gast)


Lesenswert?

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

von Εrnst B. (ernst)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Rolf Magnus (Gast)


Lesenswert?

> Könnte mir jemand einen Tip geben, wie ich das im GCC realisiere

sprintf.

von Marian (Gast)


Lesenswert?

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

von Εrnst B. (ernst)


Lesenswert?

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...

von johnny.m (Gast)


Lesenswert?

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...

von peter dannegger (Gast)


Lesenswert?

Also 0..1023 -> -512..511

Wo ist das Problem ?


Y = X - 512;

fertich


Peter

von Εrnst B. (ernst)


Lesenswert?

@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

von peter dannegger (Gast)


Lesenswert?

@Ernst,

dann aber so:
1
if (val & (1<<9))
2
  val |= (1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(1<<10);


Peter

von Εrnst B. (ernst)


Lesenswert?

@Peter

Da hast Du völlig recht... Zahlen über 5 waren noch nie meine Stärke
;)

/Ernst

von Detlef _. (detlef_a)


Lesenswert?

oder so: if(val > 511) val -= 1024;

Cheers
Detlef

von m@u (Gast)


Lesenswert?

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?

von Marian (Gast)


Lesenswert?

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

von Εrnst B. (ernst)


Lesenswert?

@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

von m@u (Gast)


Lesenswert?

@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
Noch kein Account? Hier anmelden.