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.
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.
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.
>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.
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
> 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!
>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.
Im Anhang eine Routine, abgeleitet von einer Atmel-AN, das Erweitern von 10 aif 14 Bit müsstest Du selbst machen.
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!
> 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.
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.
>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!
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.
>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.
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.
>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.
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.
> 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?
wow das ist mal eine erklärung anja... alle achtung und danke dir dafür!
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
>> 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.
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 :-)
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.