Forum: Mikrocontroller und Digitale Elektronik 10bit signed in 16bit signed wandeln


von Thomas (Gast)


Lesenswert?

Hallo,
ich bekomme von einem Sensor ein 10bit signed Wert, gespeichert in 2 
Bytes, wobei das eine Byte die oberen 8 Bit darstellt und das andere 
Byte die 2 niederwertigsten Bit enthält zusätzlich sind in diesem Byte 
noch Flags.
Ich habe nun durch ausblenden und verschieben die 10Bit signed in einer 
16bit signed Integer-Variablen abgelegt. Nun meine Frage reicht es, wenn 
das 10. Bit gesetzt ist (Vorzeichen-Bit) dass ich die führenden Bits zu 
Einsen mache? So dass z.b. aus
10Bit signed: xxxx xx10 0000 0000
16Bit signed: 1111 1110 0000 0000
werden.

von Oliver (Gast)


Lesenswert?

Ja

Oliver

von Mark B. (markbrandis)


Lesenswert?

Bei der Zweier-Komplement-Darstellung haben negative Zahlen immer 
führende Einsen.

von Raimund R. (corvuscorax)


Lesenswert?

Das wäre die Methode um einen 10-Bit-Wert 'right-aligned' in einen 
16-Bit-Wert unterzubringen.
In Hinsicht auf mögliche spätere Erweiterungen (ein Sensor mit mehr als 
10 Bit) würde ich eher dazu tendieren, den 10-Bit-Wert 'left-aligned' in 
den 16-Bit-Wert zu packen. Dazu müsstest Du dann einfach die 10 Bits um 
6 Bits nach links schieben. Damit würden Dir sämtliche 
Anpassungsarbeiten erspart bleiben (abgesehen davon die Anzahl der 
Shifts zu ändern), falls mal ein Sensor mit höherer Auflösung zum 
Einsatz kommen könnte - Du arbeitest damit also immer mit 'echten' 
16-Bit-Werten, egal ob der Sensor tatsächlich diese Auflösung beherrscht 
oder nicht.
Anmerkung: Von rechts reingeschoben werden dann übrigens Nullen.

von Thomas (Gast)


Lesenswert?

@Raimund:
Dann funktionieren aber die ganzen Operationen (Addition, Subtraktion, 
usw.)aus der AVR-Libc nicht mehr, die müsste ich dann alle speziell für 
diese Darstellung neu schreiben, oder verstehe ich dich da nicht 
richtig?

von Ahem (Gast)


Lesenswert?

>Dann funktionieren aber die ganzen Operationen (Addition, Subtraktion,
>usw.)aus der AVR-Libc nicht mehr
Wie kommst Du darauf?

von Raimund R. (corvuscorax)


Lesenswert?

16-Bit-Arithmetik bleibt 16-Bit-Arithmetik! Egal ob die Werte darin nun 
'left-' oder 'right-aligned' sind! Bei 'right-aligned' muß man lediglich 
den Wert vorzeichenrichtig erweitern.

Der Vorteil von 'left-aligned' ist, daß alle (weiterführenden) 
Berechnungen unangetastet bleiben können. Der Wertebereich der 
16-Bit-Zahlen geht immer (vorzeichenbehaftet) von -32768 über 0 bis 
+32767. Wenn, wie von mir angedeutet, Deine 10-Bit-Werte um sechs Bits 
nach links verschoben werden und die unteren 6 Bits damit stets Null 
sind, so wird der 16-Bit Wertebereich auch hier komplet überstrichen - 
aber nun in Intervallen von 64 - also von -32768, -32704, -32640, ..., 
32576, 32640 bis hin zu 32704.

Oder mal anders erklärt:
Dein 10-Bit-Wertebereich geht von -512 über 0 bis +511. Bei allen 
folgenden Berechnungen gehst Du ja dann von diesem Wertebereich aus.
Nun kommt aber (dem Fortschritt sei dank) ein besserer Sensor mit einer 
höheren Auflösung, sagen wir z.B. 12 Bit, zum Einsatz. Nun geht der 
Wertebereich aber dummerweise von -2048 bis +2047. Jetzt stimmen also 
sämtliche weiterführende Berechnungen nicht mehr, da sich die Auflösung 
vervierfacht hat - die weiterführenden Berechnungen müssen also folglich 
(alle) angepaßt werden.
Wären die Werte 'left-aligned' gewesen, bräuchte an den Berechnungen 
absolut nichts geändert werden.

Ein simples links-Schieben für's 'left-aligned' ist außerdem noch 
wesentlich einfacher als ein vorzeichenrichtiges Erweitern bei 
'right-aligned'. Warum also sollte man sich das Leben (in diesem Fall 
Programmieren) unnötig schwer machen?

von Oliver (Gast)


Lesenswert?

Und wenn es dann mal den noch besseren Sensor mit 18 bit Auflösung gibt, 
was dann?

Oliver

von Gast (Gast)


Lesenswert?

>Und wenn es dann mal den noch besseren Sensor mit 18 bit Auflösung gibt,
>was dann?

Dann schmeißt man die letzen beiden Bits weg, da diese sowieso nichts 
zur Genauigkeit beitragen, oder man erweitert gleich alle Meßwerte auf 
32 Bit.
Oder noch besser - auch wenn das Geschreie gleich wieder losgeht - nimmt 
man einfach den Datentyp float.

von Raimund R. (corvuscorax)


Lesenswert?

Jau, gutes Argument Oliver, aber ich sehe das genauso wie 'Gast'.

Ich arbeite selbst in einer Firma, die intelligente Regel-, Steuer- und 
Messelektronik herstellt und kenne daher das 'Geschrei' der Kunden nach 
immer besser werdender Auflösung, Geschwindigkeit, usw.
Dumm nur, daß in industriellen Umgebungen soviel verseuchende 
Komponenten existieren, die die Messsignale derart 'versauen', daß an 
eine präzise Messung mit utopischen Auflösungen (manchmal sogar schon 
größer 12-Bit) völlig illusorisch ist. Aber versuch das mal den Kunden 
klar zu machen.

von Thomas (Gast)


Lesenswert?

@Raimund:
Danke für die ausführliche Erklärung, allerdings hat die Sache mit dem 
"left-aligned" einen Haken, sobald ich multipliziere, bekomme ich in 
diesem Fall schneller einen Überlauf.
Außerdem muss ich, wenn ich die Daten dann (dezimal lesbar) ausgeben 
will (seriell) auch wieder um 6 Bit nach links schieben, d.h. ich muss 
im Falle einer Auflösungserweiterung auch hier wieder meinen Code 
anpassen, das ist auch nicht optimal, da so etwas leicht vergessen wird.

Zitat: "Nun geht der Wertebereich aber dummerweise von -2048 bis +2047. 
Jetzt stimmen also sämtliche weiterführende Berechnungen nicht mehr, da 
sich die Auflösung vervierfacht hat - die weiterführenden Berechnungen 
müssen also folglich (alle) angepaßt werden."

Dem kann ich so nicht zu stimmen oder ich sehe das Problem noch nicht.

Wenn ich 10Bit (oder 12Bit) in einer Integer-Variablen richtig ablege, 
dann haben folgende Berechnungen mit der Variablen keinen Einfluss, 
außer evtl. Überläufe, aber das Problem habe ich mit "left-aligned" auch 
siehe oben.

von Raimund R. (corvuscorax)


Lesenswert?

Thomas schrieb:
> @Raimund:
> Danke für die ausführliche Erklärung, allerdings hat die Sache mit dem
> "left-aligned" einen Haken, sobald ich multipliziere, bekomme ich in
> diesem Fall schneller einen Überlauf.

Das schon, aber einen Überlauf mußt Du so oder so einplanen und dann 
entsprechend weiterverarbeiten. Bei 16-Bit x 16-Bit kommt (eigentlich) 
immer ein 32-Bit-Wert bei raus, kann also Deine Argumentation hier nicht 
unterstützen.

> Außerdem muss ich, wenn ich die Daten dann (dezimal lesbar) ausgeben
> will (seriell) auch wieder um 6 Bit nach links schieben, d.h. ich muss
> im Falle einer Auflösungserweiterung auch hier wieder meinen Code
> anpassen, das ist auch nicht optimal, da so etwas leicht vergessen wird.

Häh, dies kann ich nun nicht nachvollziehen.
Wenn Du mit "dezimal lesbar" eine Konvertierung in BCD meinst, ist der 
'Mehraufwand' nur zwei Dezimalstellen oder ein lächerliches Byte.
Warum sollte man hier etwas um 6 Bits nach links schieben wollen?

> Zitat: "Nun geht der Wertebereich aber dummerweise von -2048 bis +2047.
> Jetzt stimmen also sämtliche weiterführende Berechnungen nicht mehr, da
> sich die Auflösung vervierfacht hat - die weiterführenden Berechnungen
> müssen also folglich (alle) angepaßt werden."
>
> Dem kann ich so nicht zu stimmen oder ich sehe das Problem noch nicht.
>
> Wenn ich 10Bit (oder 12Bit) in einer Integer-Variablen richtig ablege,

Ein 'richtig' gibt es nicht immer. Ein 'praktischer' oder 'geschickter' 
ist aber, vmtl. nicht nur meiner Meinung nach, die 
'left-aligned'-Methode.

> dann haben folgende Berechnungen mit der Variablen keinen Einfluss,
> außer evtl. Überläufe, aber das Problem habe ich mit "left-aligned" auch
> siehe oben.

Uff, muß ich jetzt tatsächlich ein praktisches Beispiel bringen?
Laß uns also mal annehmen der 10-Bit-Sensorwert käme von einem ADC. Laß 
uns weiter annehmen, das -512 einer Spannung von -1V entspräche und 511 
einer Spannung von +0,998...V. Damit hätte ein Bit die Wertigkeit von 
etwa 2mV. Wenn man nun den ADC-Wert zur Anzeige auf einem Display in 
"Volt" umrechnen müßte, muß man wohl oder übel den Wert mit einer 
Konstanten (in diesem Fall: 0,001953125) multiplizieren.
Nun kommt der Knackpunkt. Wenn die Werte, unabhängig von der Auflösung, 
immer 'left-aligned' wären, so wäre der Muliplikator stets 0,0000305...! 
Im Falle der Verwendung eines Sensors mit nun 12 Bit, würde sich der 
Multiplikator zu 0,000488... ändern. Diesen Multiplikator müßtest Du 
eben, nach Deiner 'right-aligned'-Methode, immer wieder an die Auflösung 
des Sensors anpassen. Das meinte ich damit, daß weiterführende 
Berechnungen bei der 'left-aligned'-Methode unangetastet bleiben 
(können). Jetzt alles klar?

Resumée:
Wenn Du Dir um spätere Erweiterungen (ein Sensor mit höherer Auflösung) 
nicht scheren mußt, dann vergiss das bisher gesagte, und schreib Dein 
Programm so wie Du es gewohnt bist - eben ganz speziell auf die eine 
einzige Anwendung orientiert, ohne der Einplanung von späteren 
Änderungen oder Erweiterungen.
Für den Fall, das Du aber Code schreiben willst, den man evtl. auch 
später noch einmal verwenden will (das Rad muß man ja nicht ständig neu 
entwickeln), dann schreibt man ihn üblicherweise so, das er universell 
ist und z.B. mit (mehr oder weniger) 'genormten' Eingangsgrößen arbeiten 
kann.

Jeder möge aber letztendlich seiner eigenen Philospophie folgen.

von Thomas (Gast)


Lesenswert?

> Häh, dies kann ich nun nicht nachvollziehen.
> Wenn Du mit "dezimal lesbar" eine Konvertierung in BCD meinst, ist der
> 'Mehraufwand' nur zwei Dezimalstellen oder ein lächerliches Byte.
> Warum sollte man hier etwas um 6 Bits nach links schieben wollen?

In meinem Fall muss ich nur den Wert an der seriellen Schnittstelle 
ausgeben, dazu benutze ich die Funktion itoa(), diese gibt mir den 
Integer als String zurück den ich dann als "lesbare" Zahl an die 
serielle Schnittstelle gebe.

Würde ich deine Methode benutzen müsste ich erst wieder 6 mal rechts 
schieben, damit das "left aligned" zu einem "right aligned" wird das die 
itoa()-Funktion richtig interpretiert.
Würde ich das nicht machen müsste ich ein PC-Programm schreiben das mir 
die übertragenen Werte wieder in den "original" Zahlenbereich 
transformiert (rechts schieben). Damit müsste ich ein µC-Program und ein 
Programm für den PC schreiben.
Was jetzt weniger Arbeit ist kannst du dir sicher denken.

Danke trotzdem für die ausführliche Diskussion.

von Raimund R. (corvuscorax)


Lesenswert?

Thomas schrieb:
>> Häh, dies kann ich nun nicht nachvollziehen.
>> Wenn Du mit "dezimal lesbar" eine Konvertierung in BCD meinst, ist der
>> 'Mehraufwand' nur zwei Dezimalstellen oder ein lächerliches Byte.
>> Warum sollte man hier etwas um 6 Bits nach links schieben wollen?
>
> In meinem Fall muss ich nur den Wert an der seriellen Schnittstelle
> ausgeben, dazu benutze ich die Funktion itoa(), diese gibt mir den
> Integer als String zurück den ich dann als "lesbare" Zahl an die
> serielle Schnittstelle gebe.

Yip, kann man so machen.

> Würde ich deine Methode benutzen müsste ich erst wieder 6 mal rechts
> schieben, damit das "left aligned" zu einem "right aligned" wird das die
> itoa()-Funktion richtig interpretiert.

Ein rechtsschieben ist sicher nicht nötig. Es kommt lediglich ein 
anderer String bei raus.

> Würde ich das nicht machen müsste ich ein PC-Programm schreiben das mir
> die übertragenen Werte wieder in den "original" Zahlenbereich
> transformiert (rechts schieben). Damit müsste ich ein µC-Program und ein
> Programm für den PC schreiben.
> Was jetzt weniger Arbeit ist kannst du dir sicher denken.

Dazu kann ich nur folgendes sagen:
Es ist immer eine Frage, wie ich meine String-Werte interpretiere. 
Bisher hast Du ja den übertragenen String als 10-Bit-Wert interpretiert. 
Wo ist jetzt das Problem ihn als 16-Bit-Wert zu interpretieren??? Es 
gibt hier nicht mehr oder weniger Arbeit. Wenn Du den Wert auf dem PC in 
z.B. SI-Einheiten anzeigen willst, mußt Du den String doch so oder so 
'anfassen'. Das kann ja nun nicht das Problem sein!?!

> Danke trotzdem für die ausführliche Diskussion.

Gern geschehen.

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.