Forum: Mikrocontroller und Digitale Elektronik Umformung hex->dec mit 14 bit


von Ben _. (burning_silicon)


Lesenswert?

ich muß mich jetzt endlich mal mit der korrekten umwandlung von zahlen 
im hexadezimalen format ins dezimale format beschäftigen.

das problem ist, daß es diesmal 16 bit zahlen sind (mindestens 14 davon 
auch genutzt). das mag ich nicht über einen murks wie eine wiederholte 
addition machen, sondern ich möchte wissen wie es die profis auf dem 
gebiet anstellen.

anwendung soll eine spannungsmessung auf einem atmega32 sein, 9-16V 
messbar. das grundprinzip ist mir klar, die 7V messbereich mit dem ADC 
messen ergibt einen 10 bit wert, auf diesen die 9V offset aufaddiert - 
fertig. kein problem, kann man alles hexadezimal machen. aber wie bekomm 
ich das ergebnis möglichst effizient nach dezimal gewandelt um es 
auszugeben? und wie gehts auch in die andere richtung? "auflösung" 
wollte ich drei stellen nach dem komma, d.h. aus 16V werden 16000 
dezimal. zwei stellen wären immer noch 1600... zwei stellen nach dem 
komma wären auch noch in ordnung, aber nur eine stelle wäre zu wenig.

wenn einer ideen oder codeschnipsel für sowas hat wäre ich echt dankbar 
dafür.

von Er (Gast)


Lesenswert?

fprintf, sprintf etc. "%d.%d" falls integer oder %f fslls flot resp. 
double
Alles weitere in einem C Buch Deines Vertrauens.

>kann man alles hexadezimal machen
Diese Ausdrucksweise zeigt ein hier und anderswo unter Laien weit 
verbreitetes Missverständnis. Zahlen und Symbole werden im Computer 
"binär" und nicht etwa hexadezimal, dezimal, als Zeichen oder ähnliches 
repräsentiert.
Hexadezimal, dezimal Zeichen etc. sind Repräsentationen die wir Menschen 
benutzen. Computer sind nur so gnädig sie uns an passenden Stellen zu 
präsentieren. Dazu rechnen sie die binäre Darstellung in andere 
Repräsentationen um.

Rechnungen werden also nicht hexadezimal oder anders ausgeführt, sondern 
immer nur binär (mit evtl. einem Vorzeichen oder Infos zur Stellung des 
Kommas, bzw. Unterscheidung von Exponent, Mantisse, etc.)

Da wir Menschen dem Computer allerdings nicht Binärzahlen geben wollen 
sondern irgendwie einfacher handhabbare Grössen muss es sogenannte 
"Literale" geben. Das sind dann 0x89 oder 'a' etc. Diese werden wieder 
vom Computer in binäre Darstellungen umgewandelt.

von Ben _. (burning_silicon)


Lesenswert?

oops... ich vergaß das wichtigste. ich brauch das in assembler. sorry! 
aber dafür reichen integer-werte, floating point brauche ich nicht.

beim PC wär's auch etwas einfacher, die x86 prozessoren haben befehle 
für solche umwandlungen, die AVRs leider nicht.

mit "in hexadezimal rechnen" meine ich daß für die eigentlichen 
berechnungen und kontrollaufgaben keine derartige umformung erforderlich 
ist (wahrscheinlich haben diese µCs genau deswegen keine befehle für die 
umformung). wie das ding intern arbeitet ist mir schon klar, braucht man 
hier aber nicht aufzuschlüsseln weil es für das problem nicht sonderlich 
relevant ist.

von Er (Gast)


Lesenswert?

>mit "in hexadezimal rechnen" meine ich daß für die eigentlichen
>berechnungen und kontrollaufgaben keine derartige umformung erforderlich
>ist

;-) Das mag sein, das Du das damit meinst, aber das was Du schreibst 
bedeutet nicht was es heisst.
Es gibt keinen Vorgang oder eine Tätigkeit die man sinnvoll mit "in 
hexadezimal rechnen" bezeichnen kann.

In Assembler jedenfalls bleibt Dir die übliche Methode mit Division 
durch zehn bzw. 2 und 5 und Ausgabe des Restes.

von Horst H. (horha)


Lesenswert?

Hallo,

Im Prinzip ist es ja nur eine Basisumwandlung
Für Ganzzahlen in einer Schleife:
<c>
Falls Zahl = 0 dann
  Zeichenkette = '0'
sonst
  Vorzeichen merken
  Zahl positiv machen

  Wiederhole:
    Rest %= 10
    Zahl /= 10
    /* Alternativ mit temp Variable
    temp = Zahl / 10
    Rest = Zahl - 10*temp
    Zahl = temp
    */
    Zeichenkette = char(Rest+'0')+ Zeichenkette
  Bis Zahl = 0
  IF Vorzeichen = Minus dann
    Zeichenkette = '-'TZeichenkette
</c>

Mist, da kommt ein oops... ;-)
http://www.avr-asm-tutorial.net/avr_de/quellen/konvert.asm

von Er (Gast)


Lesenswert?

>Im Prinzip ist es ja nur eine Basisumwandlung

Ach, was!

von Ben _. (burning_silicon)


Lesenswert?

> In Assembler jedenfalls bleibt Dir die übliche Methode mit Division
> durch zehn bzw. 2 und 5 und Ausgabe des Restes.
wäre schön wenn mir genau das einmal jemand erklären könnte... :) 
division hat der AVR auch nicht on-chip. division durch 2/4/8/16/32 usw. 
ist durch bit-shifts noch einfach und schnell machbar, aber 5 und 10 ist 
doof. ;)

edit: das tutorial ist gut, da arbeite ich mich mal durch! danke!

von Er (Gast)


Lesenswert?

>wäre schön wenn mir genau das einmal jemand erklären könnte... :)

Es gibt da so eine App-Note von Atmel mit einem Code für die Division.
http://www.atmel.com/dyn/resources/prod_documents/doc0936.pdf
mit Code:http://www.atmel.com/dyn/resources/prod_documents/AVR200.zip

>division hat der AVR auch nicht on-chip. division durch 2/4/8/16/32 usw.
>ist durch bit-shifts noch einfach und schnell machbar, aber 5 und 10 ist
>doof. ;)
Ja, das ist wirklich ein Problem. Lässt sich leider nicht änder.

von Peter R. (pnu)


Angehängte Dateien:

Lesenswert?

Im Anhang eine Routine, abgeleitet von einer Atmel-AN, das Erweitern von 
10 aif 14 Bit müsstest Du selbst machen.

von Ben _. (burning_silicon)


Lesenswert?

hmmm mal schauen, der umweg über BCD könnte was bringen. bleibt halt die 
fragen was dann letztendlich am schnellsten ist. oder eben wirklich 
jedes gesetzte bit einzeln aufaddieren. sind erstens 11MHz, nur zwei 
werte die zu wandeln sind und auch maximal zwei abfragen je sekunde.

auf jeden fall danke für eure anregungen!

von Rolf Magnus (Gast)


Lesenswert?

> mmm mal schauen, der umweg über BCD könnte was bringen.

Was heißt "Umweg"?

> bleibt halt die fragen was dann letztendlich am schnellsten ist. oder
> eben wirklich jedes gesetzte bit einzeln aufaddieren. sind erstens
> 11MHz, nur zwei werte die zu wandeln sind und auch maximal zwei abfragen
> je sekunde.

Bei 11 Mhz kannst du locker ein paar Hunderttausend davon pro Sekunde 
machen, auch wenn's nicht ganz optimal programmiert ist.

PS: Deine Shift-Taste klemmt anscheinend.

von Ben _. (burning_silicon)


Lesenswert?

negativ. die ist defekt! ;)

okay kommt halt drauf an ob man BCD mit einer oder zwei ziffern je 8bit 
register verwendet. der x86 könnte beides. ich meine den weg über eine 
ziffer je register, sonst wird bei der ausgabe eine weitere umformung 
erforderlich, um das addieren von 30h kommt man sowieso nicht drumrum.

von Er (Gast)


Lesenswert?

>negativ. die ist defekt! ;)

Sage mal, was ist los mit Dir? Einerseits will man Dir nicht gleich 
verbal eine reinwürgen, aber die zarte Tour verstehst Du auch nicht.
Den Respekt hier, wie in einem Brief auch, die Regeln der Gross- und 
Kleinschreibung einzuhalten hast Du nicht, aber Hilfe willst Du?
Guten Tag sagen, Türen aufhalten und sowas machst Du auch nur wenn Du 
bezahlt wirst, oder was?

Bauer!

von Ben _. (burning_silicon)


Lesenswert?

klar, für jeden beitrag hier wo ich anderen helfe schicke ich hinterher 
eine angemessene rechnung raus wenn ich selbst keine hilfe brauche... 
**grummel**

sorry ich bin nunmal verfechter der 
ist-doch-egal-ob-groß-oder-kleinschreib-fraktion. und ich stehe dazu. 
ich denke damit schade ich niemandem.

von Er (Gast)


Lesenswert?

>ich denke damit schade ich niemandem.
Nun, wenn der Schaden auch nicht gross ist, aber doch: Du schadest mir 
und jedem der Deinen Text liest. Es kostet nämlich mehr Zeit, wenn 
Hauptworte und Eigennamen nicht auf einen Blick erkennbar sind. Das 
gliedert den Satz und macht ihn leichter lesbar.

Aber gut. Wenn Du es mir unnötig erschwerst Dir zu helfen, helfe ich Dir 
nicht mehr.

von Peter D. (peda)


Lesenswert?


von Ben _. (burning_silicon)


Lesenswert?

danke peda! genau sowas hab ich gesucht. ich hoffe nur ich verstehe auch 
irgendwann wie es funktioniert.

> Aber gut. Wenn Du es mir unnötig erschwerst Dir zu helfen, helfe ich Dir
> nicht mehr.
das steht dir frei. aber soll ich nun deiner wegen niemandem mehr helfen 
der hier "großschreibt"? ooch komm das ist doch babyka**a sowas! für 
mich liest sich beides absolut identisch schnell.

von Er (Gast)


Lesenswert?

>aber soll ich nun deiner wegen niemandem mehr helfen der hier >"großschreibt"?
Das wiederrum steht Dir frei. Es geht hier nicht um Rache oder sowas. 
Sondern darum, das Du Dich weigerst es anderen leichter zu machen Dir zu 
helfen. Wenn auch der Nachteil der mir dadurch entsteht minimal ist, so 
zeigt Deine Reaktion, das Dir die Tatsache das überhaupt ein Nachteil 
entsteht völlig gleichgültig ist. Und das ist mein Motiv, Dir nicht mehr 
zu helfen.

>für mich liest sich beides absolut identisch schnell.
Du irrst Dich.

von Anja (Gast)


Lesenswert?

Hallo,

für Deinen Fall (Assembler) folgende Idee:
(Divisionsfreies Verfahren mit 16*16 Bit Multiplikation)
das mit möglichst wenigen Takten zum Ergebnis kommt

Multiplikation mit einem Umrechnungsfaktor:
in Deinem Fall 9-16V Meßbereich mit 10 Bit
Als Zielwert sollte eine möglichst große 32 Bit-Zahl herauskommen
deren 1. Digit deiner 1. Zehnerzahl entspricht
also z.B. 0x1XXX XXXX für maximalen Endwert 16
(die übrigen Ziffern XXXXXXX berechnen sich bei 16 als 0.6 *0x10000000)
also Gesamtzielwert für 16V = 0x1999 999A
9V entsprechend 9/16*0x1999999A = 0x0E666666 abgezogen ergibt
0x0B333334 als Zielwert für die Multiplikation.
geteilt durch 1024 Maximalwert vom ADC ergibt sich 0x0002CCCC als 
Faktor.
(ist leider größer als 16 Bit also muß die Multiplikation aufgeteilt 
werden
als 0x02CCCC = 0x4 * 0xB333

also folgende Rechnung
Beispiel für 14000 mV = ADC-Wert (14-9) /(16-9V) * 1024 = 731 dez = 
0x2DB

ADC-Wert * 4 (2* links-Shift)
0x2DB << 2 = 0x0B6C
Multiplikation mit Faktor 0xB333
0x0B6C * B333 = 0x07FECA84
Offset 0x0E666666 + Rundungsoffset (0.0005V * 0x10000000/10V = 0x00346)
also insgesamt 0x0E6669AC addieren ergibt:
0x07FECA84 + 0x0E6669AC = 0x16653430

Im höchsten Nibble steht als BCD-Zahl bereits die 1. Ziffer des 
Ergebnisses
diese wird entfernt, der Rest mit 10 multipliziert R = ((R<<2) + R) << 1
1. Ziffer = 1
0x06653430 * 0x0A = 0x3FF409E0
2. Ziffer = 3
0x0FF409E0 * 0x0A = 0x9F8862C0
3. Ziffer = 9
0x0F8862C0 * 0x0A = 0x9B53DB80
4. Ziffer = 9
0x0B53DB80 * 0x0A = 0x71469300
5. Ziffer = 7

Dieses Verfahren hat den Vorteil daß die Ziffern in der Reihenfolge 
anfallen wie sie auch üblicherweise ausgegeben werden.

von Ben _. (burning_silicon)


Lesenswert?

> das Dir die Tatsache das überhaupt ein Nachteil entsteht völlig
> gleichgültig ist.
das ist das problem was ich damit habe - ich sehe da keine nachteile. 
für niemanden. zumal sich das im IRC/chat allgemein und (fast) allen 
foren mehr als eingebürgert hat. sogar schon in emails. nur offizielle 
dinge werden da noch groß/klein geschrieben um etwas form reinzubringen. 
vielleicht ein generationskonflikt?

weißt du was ich viel schlimmer finde was ich auch überhaupt nur sehr 
schwer lesen kann und nicht weiß ob dir das besser gefällt oder auch 
nicht weil du es gar nicht mehr entziffern kannst was mir eigentlich 
auch egal sein kann aber ich sags dir trotzdem ist wenn einer keinen 
punkt und kein komma über seinen gesamten absatz setzen kann und wenn 
ich das jetzt gerade mal mit absicht mache hoffe ich daß du keine 
herzattacke davon bekommst sondern einfach nur verstehst was ich dir 
damit sagen möchte

> Und das ist mein Motiv, Dir nicht mehr zu helfen.
wenn du das brauchst betrachte es als mein weihnachtsgeschenk für dich. 
ich finds arm, aber das sind halt getrennte meinungen.

>> für mich liest sich beides absolut identisch schnell.
> Du irrst Dich.
**lol** wie willst du das denn beurteilen wie ich was lesen kann?

von Ben _. (burning_silicon)


Lesenswert?

wow das ist mal eine erklärung anja... alle achtung und danke dir dafür!

von Peter D. (peda)


Lesenswert?

Ben _ schrieb:
> danke peda! genau sowas hab ich gesucht. ich hoffe nur ich verstehe auch
> irgendwann wie es funktioniert.

Das ist die Subtraktionsmethode.
Man zieht Zenerpotenzen ab, angefangen von der höchsten und zählt mit.
D.h. pro Digit sind es nur maximal 10 Schritte und damit ist diese 
Methode sehr schnell (auf MCs ohne Division die schnellste).

Um nicht nach jedem Digit wieder den zuviel abgezogenen Wert addieren zu 
müssen, wird abwechselnd subtrahiert und addiert.
Dadurch ist auch der Code sehr klein im Vergleich zu anderen Methoden.
Wenn man sich Zahl als Ganzzahl im Zweierkomplement denkt, versteht man, 
warum das funktioniert.


Peter

von Er (Gast)


Lesenswert?

>> Und das ist mein Motiv, Dir nicht mehr zu helfen.
>wenn du das brauchst betrachte es als mein weihnachtsgeschenk für dich.
Wie kann eine Entscheidung die ich gegen Dich treffen muss, um mich zu 
schützen, ein Geschenk von Dir an mich sein? Es wäre mir lieber zu 
kooperieren. Du bist es der die Kooperation verweigert und 
kontraproduktiv handelt.

>ich finds arm, aber das sind halt getrennte meinungen.
Es geht hier nicht um Meinungen sondern um Naturwissenschaften, 
insbesondere um Psychologie und Physiologie.

>>> für mich liest sich beides absolut identisch schnell.
>> Du irrst Dich.
>**lol** wie willst du das denn beurteilen wie ich was lesen kann?

Wenn Du im selben Kulturkreis wie ich aufgewachsen bist, dann ist Dir in 
der Schule eine bestimmte Schreibweise als "korrekt" beigebracht worden. 
Abweichungen davon sind Dir als Fehler von den Lehrern und Eltern 
rückgemeldet worden. Psychologisch gesehen ein negativer Reiz, den Du 
gelernt hast zu vermeiden.
Dies hielt über mehrere Jahre an. Daher ist das Vermeidungsverhalten, 
vor allem weil es in sehr frühem Alter eingeprägt wurde, nicht mehr 
bewusst zu kontrollieren.

Wenn Du also jetzt einen Text liest, dann gibt es jedesmal eine kurze 
Verzögerung, weil Dein Gehirn einen Fehler meldet, den es erstmal 
korrigieren muss.

von Ohne Aufwand (Gast)


Lesenswert?

Ihr macht das für mich alles viel zu kompliziert.
Man braucht doch nur eine Routine, die 1 zu einer BCD-Bytefolge addiert.
Erst die Summe löschen und dann sooft aufrufen, bis die Binarzahl auf 0 
heruntergezählt ist.
Diese Lösung versteht jeder und arbeitet schneller, als man das Ergebnis 
lesen kann :-)

von Horst H. (horha)


Lesenswert?

Hallo,

@peda:
witziges Verfahren, aber es bleibt bei dem +- addieren.
Aber es ist extrem schnell:
"55555" sind 5*5 2-Byte Additionen geschätzte 5*(2+5*3)=  85 Takte
Es müsste sogar in etwa die gleiche Laufzeit für "12345" oder "77777" 
haben.
Leider werden viele Register belegt.

@anja:
Seit der Atmega den MUL-Befehl hat, ist Multiplikation ja nicht mehr 
Rechenzeit mordende Angelegenheit.
R = ((R<<2) + R) << 1 kostet dank MUL viel zuviel Zeit.
Du skalierst ja gleichzeitig das Ergebnis, was ja ohnehin noch gemacht 
werden muß.
Sehr praktisch und sehr genau.

@Ohne Aufwand:
Das dauert ja eine Ewigkeit bis 16000 in BCD zu zählen bei geratenen 10 
Takten pro Durchgang.O.K. es ist sehr kompakt ;-)


Es geht sogar ganz ohne Shift/Mul und Div, aber das ist etwas langsam:
Man erzeugt nacheinander alle Zweier-Potenzen zu der gewünschten Basis.
Und wenn das entsprechende Bit in der AusgangsZahl gesetzt ist, wird die
Zweier-Potenz auf das Ergennis addiert, wieder unter Berücksichtigung
der Basis.
<c>
AusgangsZahl = ???
Ergebnis = 0
ZweierPotenz = 1
wiederhole für alle Stellen aufsteigend:
  Maske = 1
  wiederhole für alle Bits der Stelle
    Falls AusgangsZahl[Stelle] AND Maske <> 0 dann
       AddiereZurBasis(Ergebnis,ZweierPotenz,Basis)
    AddiereSichSelbstZurBasis(ZweierPotenz,Basis)
    Maske = Maske+Maske
</c>
Das braucht aber noch mehr Speicher für Zweierpotenz, ist aber für 
beliebige
Stellenzahlen und doch etwas scheller als immer 1 zu addieren

von Peter D. (peda)


Lesenswert?

Horst Hahn schrieb:
> Aber es ist extrem schnell:
> "55555" sind 5*5 2-Byte Additionen geschätzte 5*(2+5*3)=  85 Takte
> Es müsste sogar in etwa die gleiche Laufzeit für "12345" oder "77777"
> haben.

Am längsten dauert 50900.


> Leider werden viele Register belegt.

Nö, man muß ja nicht alle Digits in Registern speichern. Du kannst die 
Digits einzeln ausgeben oder im SRAM ablegen. Dann wird nur ein Register 
mehr, als die Zahl benötigt.


Peter

von Ben _. (burning_silicon)


Lesenswert?

die register kann man ja vorher auch einfach auf den stack schmeißen.

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.