Frage:
13-Bit-2-Komplement auf .Net MF
Gineer
2011-07-13 15:06:40 UTC
view on stackexchange narkive permalink

Ich verwende einen ADXL345-Dreiachsen-Beschleunigungsmesser über eine FEZmini1.3 .Net Micro Framework-Karte in einem Projekt, mit dem ich beschäftigt bin.

Der ADXL345 liefert Daten im 13-Bit-2-Komplement.

Wie dekodiert man dies in Dezimalzahlen?

Ich habe einen BitConverter ( wie von Ravenheart (Toshko) bereitgestellt) in das Projekt implementiert, aber dies setzt sicherlich eine vollständige voraus Daten im Wert von 16 Bit (oder zwei Bytes), wobei das höchstwertige Bit immer das Vorzeichenbit ist?

In einer 13-Bit-Zahl ist das 16. Bit immer 0, nicht wahr?

  ------------ Byte 1 ------------ ------------ Byte 2-- --------- Bit #: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 016 Bit: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 = -3276713 Bit : 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 = -4095  

aber wenn die 13-Bit-Nummer von einem Algorithmus konvertiert wird, der volle 16 Bit annimmt, ist die Nummer wird gleich 8192 sein.

Ist mein Verständnis korrekt? Wenn ja, wie gehe ich vor, um die Komplementzahl einer 13-Bit-2 in eine Dezimalzahl umzuwandeln?

Bearbeiten (nachdem ich unten Hilfe von meinen Freunden erhalten habe): Also dank der Antworten, die ich Jetzt wissen Sie, dass meine Annahmen über das Kompliment von 2 falsch waren. Aus Gründen der Klarheit wollte ich meine ursprüngliche Aussage korrigieren, wenn jemand diesen Thread liest:

  ------------ Byte 1 ------------ ------------ Byte 2 ----------- Bit #: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 016 Bit: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 = -113 Bit: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 = -1  

In 2's Compliment zählen die Zahlen bis zur Hälfte und beginnen dann mit dem Countdown.

  00000000 = 000000001 = 200000010 = 300000011 = 4 .. .01111110 = 12601111111 = 12710000000 = -12810000001 = -12710000010 = -126 ... 11111100 = -411111101 = -311111110 = -211111111 = -1  
Warum brauchst du eine Dezimalstelle?
Fünf antworten:
Olin Lathrop
2011-07-13 16:32:51 UTC
view on stackexchange narkive permalink

Um die Zahl in eine Dezimalzahl zu dekodieren, konvertieren Sie sie in etwas, das Ihr Prozessor nativ versteht, und verwenden Sie dann die vorhandenen Konvertierungsfunktionen für Binär- in Dezimalzahlen, um sie in Dezimalzahlen zu konvertieren. Um in eine native Ganzzahldarstellung zu konvertieren, müssen Sie lediglich das Vorzeichen erweitern:

 II ist ein nativ vorzeichenbehafteter Ganzzahl-< - 13-Bit-A / D-Wert mit Vorzeichen (erhalten Sie das A / D-Ergebnis) II < - II & 1FFFh ( Stellen Sie sicher, dass Sie auf 13 Bit begrenzt sind.) Wenn II> = 1000h (negativer Wert?), dann II <-- II - 2000h (in natives Negativ konvertieren) 
Beachten Sie, dass dies unabhängig davon ist, wie breit die native vorzeichenbehaftete Ganzzahl ist. solange es mehr als 13 Bit ist. Dies bedeutet, dass diese Technik sowohl für 16-Bit- als auch für 32-Bit-Ganzzahlen mit Vorzeichen funktioniert.

Bearbeiten: Feste Details des Vorzeichens, die sich oben erstrecken. Ich habe es direkt auf das Scribble-Papier neben meiner Tastatur geschrieben und es dann falsch in den Post kopiert. Es wurde auch ein Hinweis hinzugefügt, dass es unabhängig von der nativen Ganzzahlgröße ist.

Huh? - Als "Int13" bedeutet 1001h -4095d, aber das Subtrahieren von 1000h würde zu 1 führen. 1000h repräsentiert auch -4096 als "Int13", aber wenn es nicht modifiziert wird, repräsentiert es +4096 als "Int16"
@Mikej: Ich habe meine Skizzen falsch kopiert, und Sie beziehen sich möglicherweise darauf, bevor ich sie bearbeitet habe, um das zu beheben. Angenommen, der A / D-Wert ist 1FFFh. Das A / D bedeutet damit -1, wird aber 8191 sein, wenn es direkt in eine größere native Ganzzahl kopiert wird. Das Subtrahieren von 2000h (8192) davon ergibt das gewünschte -1. Dies funktioniert für alle negativen Zahlen. -2 kommt aus dem A / D als 1FFEh = 8190. 8190 - 8192 = -2 wie gewünscht.
Das ist besser, aber der bedingte Test sollte `> =` sein. Die Bitbreitenunabhängigkeit ist jedoch ein Plus.
@Mikej: Yup, hat das> = gefunden und behoben, bevor Sie Ihren Kommentar sehen. Argh, ich frage mich, wie viele kleine Dinge ich in zwei Codezeilen noch falsch machen kann!?
stevenvh
2011-07-13 15:20:25 UTC
view on stackexchange narkive permalink

Der 6809 Mikroprozessor (der schönste 8-Bitter aller Zeiten!) hatte eine SEX -Anweisung, kurz für "Sign EXtend", die die Komplementzahl einer 8-Bit-2 in konvertierte 16-Bit (der 6809 könnte seine zwei 8-Bit-Akkumulatoren zu einem 16-Bit-Akkumulator kombinieren). Wenn das höchste Bit 1 (negativ) wäre, würde das höherwertige Byte 0xFF werden, andernfalls 0x00 . Eine Vorzeichenerweiterung kopiert also tatsächlich das Vorzeichenbit in alle vorherigen Bits. Sie können ODER mit 0xE000 setzen, wenn Bit 12 gesetzt ist:

  if (adxl & 0x1000) {adxl | = 0xE000};  

Um in Dezimalzahl (BCD) zu konvertieren, hat Atmel diese interessante Appnote, die Algorithmen für BCD-zu-Binär und umgekehrt enthält:

16-Bit-Konvertierung von Binärdaten in 5-stellige BCD
Konvertierung von 8-Bit-Binärdaten in 2-stellige BCDs
Konvertierung von 5-stelligen BCDs in 16-Bit-Binärdaten
2-stellige Konvertierung von BCD in 8-Bit-Binärdateien Konvertierung
2-stellige gepackte BCD-Addition
2-stellige gepackte BCD-Subtraktion

Die Algorithmen sind prozessorunabhängig, obwohl Atmel Quellcode für bereitstellt der AVR.

Majenko
2011-07-13 16:08:41 UTC
view on stackexchange narkive permalink

Dreimal nach links verschieben? Das würde Ihnen dann eine 16-Bit-Ganzzahl mit Vorzeichen geben, die mit dem Bereich der anderen Zahlen übereinstimmt, mit denen Sie arbeiten.

Sie haben nicht die Auflösung niedriger Ordnung Ihrer anderen Sensoren, aber die Werte Die Arbeit ist viel einfacher.

  00011111 11111111Shift Left00111111 11111110Shift Left01111111 11111100Shift Left11111111 11111000  

In C können Sie

  val = val << 3;  

In ASM gibt es entsprechende Linksverschiebungsbefehle. Möglicherweise müssen Sie einzelne Bytes verschieben und das Übertragsflag verwenden, um Bits von den niedrigen zu den hohen Bits zu übergeben.

Möglicherweise müssen Sie die Übertragsflagge löschen, bevor Sie wechseln.
Yup - Clear Carry, Shift Low, Store Carry, Shift High, Set / Clear Low Bit von High, abhängig vom gespeicherten Carry.
Oder - hoch verschieben, Übertrag löschen, niedrig verschieben, Übertrag prüfen, niedriges Bit des hohen Bytes setzen / zurücksetzen.
Sieht für einen 16-Bit- oder 32-Bit-Controller in Ordnung aus, für 8-Bit teuer. In diesem Fall ist der OP, den ich in meiner Antwort erwähne, weniger involviert. Nur drei Anweisungen: Bittest, bedingter Sprung, ODER.
Aber dann müssen Sie sich fragen, ob die zusätzliche Effizienz der Zeichenerweiterung Ihre Mathematik später komplexer macht, oder ob es besser ist, ein paar weitere Unterrichtszyklen mit der Zeichenmanipulation zu verbringen, um sich dann mit Zahlenbereichen zu belassen, die Ihren entsprechen andere Daten, wodurch Ihre anderen Berechnungen einfacher werden? Wer kann sagen, ohne den Rest des OP-Programms zu kennen?
@Matt Jenkins - Huh? Sicherlich wird die Zeichenerweiterung die Mathematik einfacher machen, da das Ergebnis als "Int16" korrekt ist und nicht als 8-mal größer.
@Mike Wie ich schon sagte, hängt alles vom Rest des Programms ab. Möchte das OP dann das Ergebnis multiplizieren, um es trotzdem mit den Werten der anderen Sensoren in Einklang zu bringen? Wer weiß? Nur das OP kann entscheiden, welches für dieses Programm effizienter ist.
@Matt - das ist eine seltsame Argumentation. Das ist wie ein Fehler in einem Algorithmus, der eine überschüssige 1 ergibt und sagt: "Nun, hängt davon ab, was er danach tun möchte. Vielleicht möchte er 1 hinzufügen." :-)
@stevenvh Das Ersetzen von 2 Algorithmen durch 1 ist eine gute Argumentation. Mein Verständnis davon, was er mit den absoluten Werten tut, ist bedeutungslos. Die relativen Werte (Versatz von 0) werden zusammen in einen Algorithmus eingespeist, um einen einzelnen Ausgabevektor zu erzeugen. Wahrscheinlich muss er den einen oder anderen Wert ändern, um sie in den gleichen Bereich zu bringen, damit der zweite Algorithmus etwas Sinnvolles tut.
starblue
2011-07-13 18:53:14 UTC
view on stackexchange narkive permalink

Sie müssen die Zeichenerweiterung durchführen, wie die anderen sagten.

Es gibt verschiedene Methoden, siehe Hacker's Delight in Kapitel 2 Grundlagen auf Seite 18.

Bearbeiten: Ich mag die zweite Methode, die an Ihren Fall angepasst ist und zu

  (x ^) wird 0x1000) - 0x1000  

unter der Annahme, dass die drei höchstwertigen Bits immer Null sind ( ^ ist exklusiv oder).

Es wäre schön, wenn Sie die Methode hier zitieren würden.
Der ganze Abschnitt war etwas lang, aber ich habe jetzt meine Lieblingsmethode angepasst.
vicatcu
2011-07-13 22:23:30 UTC
view on stackexchange narkive permalink

Wenn Sie den Komplementwert einer 13-Bit-2 haben, lesen Sie ihn in eine vorzeichenbehaftete 16-Bit-Variable ein, verschieben Sie ihn um 16-13 = 3 Bit nach links und dann um drei Bit nach rechts.

  int16_t value = readValue (); // readValue gibt das Komplement numbervalue einer 13-Bit-2 zurück = (Wert << 3) >> 3; // Vorzeichen erweitern den Wert  

Die Variable value enthält jetzt den tatsächlichen Dezimalwert.


Bearbeiten Angesichts des Kommentars von @ Olin möchte ich in meiner Antwort klar sein. Hier wird ausführlicher beschrieben, wie aus 0001 1111 1111 1111 explizit 1111 1111 1111 1111 wird (gemäß dem Beispiel des OP), wenn ich die Frage richtig verstehe. Das Folgende ist ein repräsentativer C-Code.

  uint8_t byte1 = 0x1F; // 0b00011111uint8_t byte2 = 0xFF; // 0b11111111int16_t value = (((uint16_t) byte1) * 256) + (byte2); // Wert enthält jetzt 0b0001111111111111value = (Wert << 3) >> 3; // Wert enthält jetzt 0b1111111111111111  
Nein, tut es nicht. Die Variable enthält jetzt den Zweierkomplementwert * binär *, vorausgesetzt, Ihre Sprache führt beim Signieren der Zahl eine arithmetische Rechtsverschiebung durch. Moderne Mainstream-Computer halten Zahlen binär und nicht dezimal, und Ihre Verschiebungsstrategie hängt sogar davon ab!
@Olin Ich nahm C an. Ich ging weiter davon aus, dass das OP eine vernünftige Ausgabe von etwas wie "printf ("% d ", Wert);" anstrebte
Das ist alles vernünftig, aber Ihre Aussage "Variable enthält jetzt den tatsächlichen * Dezimal * -Wert" ist immer noch falsch.
@Olin Ich glaube, Sie spalten jetzt die Haare. Letztendlich bezieht sich die Variable auf einen Speicherort, der eine Reihe von Bits enthält. Der Wert dieser Bits ist das, was Sie interpretieren. Durch die Zuweisung zu einem "int16_t" gebe ich ihm eine Bedeutung, d. H. Eine 16-Bit-Ganzzahl mit Vorzeichen. Der Wert dieser Ganzzahl entspricht dem, was das OP für seine Interpretation der 13-Bit-Ganzzahl mit Vorzeichen erwarten würde (was meiner Meinung nach mit dem 2er-Komplement mit der Vorzeichenerweiterung übereinstimmt). C sieht eine Vorzeichenerweiterung vor, wenn der Operator ">>" für signierte Datentypen verwendet wird.
Ja, das ist alles in Ordnung. Ich widerspreche nur Ihrer Aussage, dass die Variable einen * Dezimal * -Wert enthält. Das tut es nicht. Es enthält einen * binären * Wert.
@Olin wunderbar pedantisch :-p, ja, SRAM besteht aus binären Zustandselementen, die Sie gewinnen ... lol


Diese Fragen und Antworten wurden automatisch aus der englischen Sprache übersetzt.Der ursprüngliche Inhalt ist auf stackexchange verfügbar. Wir danken ihm für die cc by-sa 3.0-Lizenz, unter der er vertrieben wird.
Loading...