Guten Morgen! In einem AVR empfange ich per UART eine lange Dezimalzahl die mir dann als Zeichenkette vorliegt, z.B. "3117396039019" Diese möchte ich in eine Binärzahl umwandeln, sodass das Ergebnis in einem Array vorliegt. Im Falle der obigen Zahl sollte das Ergebnis 02 D5 D3 48 95 6B sein. Gibt es einen Trick das in einem AVR mit GCC zu realisieren ohne bigints mit 64 oder 128 Bit verwenden zu müssen? Grüße, Bernhard
Meiner Meinung nach geht das nicht ohne bigint oder "long long"s. Kann man das evtl auf dem Gerät vor dem Uart schon erledigen?
Seh ich genauso. Was ist denn das für eine Zahl. Wofür steht sie? Muss mit der gerechnet werden? Nicht alles was wir umgangssprachlich eine Zahl oder eine Nummer nennen ist in Wirklichkeit auch eine. Beispielsweise ist eine "Telefonnummer" keine Nummer im Sinne der Informatik sondern ein Text, der meistens (aber nicht immer) nur aus Ziffern besteht.
Der Wert ist zu gross für 32 Bit, also müssen 64 Bit her. Man kann auch etwas selber gestricktes basteln, z.B. 48 Bit Zahlen, aber der Aufwand lohnt sich mit grosser Wahrscheinlichkeit nicht! Ansonsten siehe strtol() oder atol() aus <stdlib.h>
Es geht um einen vorgefertigten Sensor der seine Register über eine 5-Bit Schnittstelle übermittelt, die nur Zeichen von 0-9 übermitteln kann. Dazu wandelt dieser sein Registerset in dezimal um und schickt dann die Ziffern über die Schnittstelle an mich. Jetzt möchte ich aber wieder auf die einzelnen Register zugreifen und muss daher die lange Dezimalzahl in Binär umwandeln. Mir ist auch nichts besseres eingefallen als mit "long long" Variablen zu arbeiten und dann so die Zahl zu konvertieren. Gibt es nicht irgendeine arithmetische Lösung für das Problem? Grüße, Bernhard
Bernhard schrieb: > Dazu wandelt dieser sein Registerset in dezimal um und schickt dann die > Ziffern über die Schnittstelle an mich. sicher das er es so macht? dann müsste er ja intern das gleiche Problem haben und mit mindestens 48bit rechnen. Kann ich mir aber kaum vorstellen. Gib es ein Datenblatt vom Sensor?
Wenn ich die empfangene Dezimalzahl mit dem Taschenrechner in Hex umwandle, dann habe ich alle Register vor mir wie sie sein sollen und im Datenblatt stehen. Die Kernfrage ist ob es eine arithmetische Möglichkeit gibt die Aufgabe zu erledigt oder ob dafür der AVG mit 64-Bit Zahlen rechnen muss. Grüße, Bernhard
Bernhard schrieb: > Wenn ich die empfangene Dezimalzahl mit dem Taschenrechner in Hex > umwandle, dann habe ich alle Register vor mir wie sie sein sollen und im > Datenblatt stehen. möchte immer noch gerne das Datenblatt sehen.
>Wenn ich die empfangene Dezimalzahl mit dem Taschenrechner in Hex >umwandle, dann habe ich alle Register vor mir wie sie sein sollen und im >Datenblatt stehen. Ich habe da meine Zweifel! Wie viele Register gibt es und wie viele Bits haben diese Register? Adressierung? Poste doch einfach mal das Datenblatt!
Bernhard schrieb: > Das Datenblatt tut nichts zur Sache. für uns schon, eventuell steht ja was drin was du übersehen hast. Soetwas ist halt verdammt ungewöhnlich, das es fast nicht sein kann.
>Die Kernfrage ist ob es eine arithmetische Möglichkeit gibt die Aufgabe >zu erledigt Ja, mit 64 Bit! >oder ob dafür der AVG mit 64-Bit Zahlen rechnen muss. Ja, doch das macht der AVRGCC mit links! Nimm doch einfach die 64 Bit und gut is! Oder wovor hast Du Angst?
Mike schrieb: > Ja, doch das macht der AVRGCC mit links! leider nicht, diese code ist extrem ineffizent und überhaupt nicht für die AVRs optimiert.
Folgendes sollte für bis zu 255 Binärbytes (das sind über 600 Dezimalstellen) funktionieren (für größere Zahlen müssen nur die Datentypen geändert werden):
1 | #include <stdio.h> |
2 | #include <stdint.h> |
3 | |
4 | /* dec: ASCII-String mit Dezimalzahl
|
5 | * bin: Puffer für Binärzahl
|
6 | * maxbin: Puffergröße in Bytes
|
7 | * return: Anzahl der Binärbytes, die Binärzahl steht in bin im Little-Endian-Format
|
8 | */
|
9 | uint8_t dec2bin(const char *dec, uint8_t *bin, uint8_t maxbin) { |
10 | uint8_t i, nbin = 0; |
11 | uint16_t p; |
12 | char d; |
13 | |
14 | while ((d = *dec++)) { |
15 | p = d - '0'; |
16 | for (i=0; i<nbin; i++) { |
17 | p += 10 * bin[i]; |
18 | bin[i] = p & 0xff; |
19 | p >>= 8; |
20 | }
|
21 | if (p && nbin < maxbin) |
22 | bin[nbin++] = p; |
23 | }
|
24 | return nbin; |
25 | }
|
26 | |
27 | int main(int argc, char *argv[]) { |
28 | static uint8_t bin[100]; |
29 | uint8_t i, nbin; |
30 | |
31 | nbin = dec2bin(argv[1], bin, sizeof bin); |
32 | |
33 | for (i=0; i<nbin; i++) |
34 | printf("%02x ", bin[i]); |
35 | printf("\n"); |
36 | |
37 | return 0; |
38 | }
|
Das Ergebnis wird – entsprechend der AVR-Konvention – im Little-Endian-Format gespeichert. Aber auch das kann bei Bedarf geändert werden. Beispiel:
1 | $ dec2bin 3117396039019 |
2 | 6b 95 48 d3 d5 02 |
Eine Null liefert übrigens eine Bytefolge mit der Länge 0, also nicht wundern.
>Das Datenblatt tut nichts zur Sache.
Ist es derart streng geheim?
Ich denke ebenfalls, dass Du das Datenblatt falsch interpretierst. Ich
kann mir nicht verstellen, dass ein Sensor seine Register in einer
13-Stellige Dezimalzahl konvertiert, nur um 2..3 IO-Leitungen zu sparen!
Da gibt es viel bessere Möglichkeiten.
>leider nicht, diese code ist extrem ineffizent und überhaupt nicht für >die AVRs optimiert. Es steht nirgends, dass es ein zeitkritisches Problem gibt. Es bringt nichts, eine Aufgabe in 1uS zu erledigen um dann 1000000us (=1s) auf die nächste Aufgabe zu warten.
Mike schrieb: > Es bringt > nichts, eine Aufgabe in 1uS zu erledigen um dann 1000000us (=1s) auf die > nächste Aufgabe zu warten. Bernhard schrieb: > [...] tut nichts zur Sache.
@Yalu X.: Vielen Dank für den konstruktiven Beitrag! Ich werde die Routine gleich mal testen. @Mike: @Peter II: Es ist mir bekannt dass der AVR mit großen Zahlen nicht sonderlich gut umgehen kann und der GCC dafür nicht optimiert ist. Genau deswegen wollte ich die Variante vermeiden. Zu dem Datenblatt: Das Datenblatt ist nicht öffentlich verfügbar Die Schnittstelle ist schon zig Jahre alt und es war damals einfach nicht dafür vorgesehen. Dieser Sensor ist für den Betrieb an dieser Schnittstelle vorgesehen und muss nun schauen wie er seine Daten konform übermittelt. Die Entwickler haben sich halt dann für die Variante mit der Dezimalzahl entschieden da die Übertragung der einzelnen Nibbles nicht möglich war. Heute würde man das natürlich ganz anders machen.
Der Code ist eigentich nicht zeitkritisch, jedoch achte ich persönlich immer besonders drauf dass der Code nicht unnötig aufgeblasen wird. Wenn es eine andere bzw. elegantere Lösung für ein Problem gibt, dann bevorzuge ich einfach diese. In Zeiten wo Rechenleistung und Speicher quasi ohne Limit verfügbar ist, macht man sich über solche Sachen leider nicht mehr so viel Gedanken.
@Yalu X.: Code funktioniert einwandfrei und belegt nur knapp 44 Words. Perfekt! :) Vielen Dank nochmal! Hast Du die Änderungen für die Ausgabe in Big-Endian zur Hand?
Bernhard schrieb: > Das Datenblatt ist nicht öffentlich verfügbar > Die Schnittstelle ist schon zig Jahre alt und es war damals einfach > nicht dafür vorgesehen. Gerade deshalb denke ich ebenfalls, das du den falschen Baum anbellst. Auch vor zig Jahren hätte man sich nicht sinn- und grundlos und schon gar nicht bei der von dir beschriebenen Anwendung dafür entschieden, sich in 64 Bit Arithmetik reintreiben zu lassen. Noch nicht mal mit vorgehaltener Waffe.
Das eine hat doch mit dem anderen nichts zu tun. Ich will hier doch nur sitzen... nein, nur eine lange Dezimalzahl in Binär wandeln. Ok, vielleicht war ich selbst Schuld überhaupt den Sensor erwähnt zu haben. Aber dann heißt es wieder "ja aber warum willst Du das denn überhaupt so machen, erklär doch mal Dein Setup" Der Sensor bietet keine Möglichkeit etwas zu konfigurieren (keine Jumper oder Dip-Schalter) und darüberhinaus bekomme ich nur Daten automatisch geschickt, ich kann also nicht aktiv auf das Teil einwirken. Da kann im Datenblatt stehen was will, wenn ich nur Zahlen von 0-9 über diese doofe Schnittstelle bekomme und die auch korrekt empfange, dann muss man sich eben drum kümmern.
@ Bernhard (Gast) >Die Schnittstelle ist schon zig Jahre alt und es war damals einfach >nicht dafür vorgesehen. >Dieser Sensor ist für den Betrieb an dieser Schnittstelle vorgesehen und >muss nun schauen wie er seine Daten konform übermittelt. >Die Entwickler haben sich halt dann für die Variante mit der Dezimalzahl >entschieden da die Übertragung der einzelnen Nibbles nicht möglich war. Ich wette 1 Kasten Bier, dass das KEINE Zahl ist sondern eine Folge von Registern, die man einzelen bearbeitet. Also ist es sinnlos, das in eine Binärzahl zu wandeln. Vielmehr muss man wahrscheinlich die ASCII-zeichen ind die entsprechenden HEX-Zahlen wandeln und in Nibbles packen. 2x ASCII -> 1x 8 Bit. DAS ist geradezu trivial.
@ Bernhard (Gast) >Der Sensor bietet keine Möglichkeit etwas zu konfigurieren (keine Jumper >oder Dip-Schalter) und darüberhinaus bekomme ich nur Daten automatisch >geschickt, ich kann also nicht aktiv auf das Teil einwirken. Das ist egal. >Da kann im Datenblatt stehen was will, wenn ich nur Zahlen von 0-9 über >diese doofe Schnittstelle bekomme und die auch korrekt empfange, dann >muss man sich eben drum kümmern. Aber wie man die Daten interpretiert und danach handhabet, ist NICHT egal. UNd die Wahrscheinlichkeit, dass 1ß Leute hier im Forum in Summe mehr Idden und Durchblick haben als du allein mit deinem Tunnelblick, ist eher hoch. Aber wer nicht will, der hat.
Falk Brunner schrieb: > Ich wette 1 Kasten Bier, naja er hat aber extra geschrieben: > Wenn ich die empfangene Dezimalzahl mit dem Taschenrechner in Hex > umwandle, dann habe ich alle Register vor mir wie sie sein sollen und im > Datenblatt stehen. und > Die Entwickler haben sich halt dann für die Variante mit der Dezimalzahl > entschieden da die Übertragung der einzelnen Nibbles nicht möglich war. und > Da kann im Datenblatt stehen was will, wenn ich nur Zahlen von 0-9 über > diese doofe Schnittstelle bekomme und die auch korrekt empfange, dann > muss man sich eben drum kümmern. damit steht es schlecht um den Kasten Bier. Leider werden wir wohl nie den Grund erfahren warum der Sensor es so macht.
Bernhard schrieb: > Hast Du die Änderungen für die Ausgabe in Big-Endian zur Hand? Dazu musst du im Prinzip nur die innere Schleife ander herum (also von oben nach unten) laufen lassen. Allerdings liegt die Binärzahl dann am oberen Ende des übergebenen Puffers und der Anfang der Zahl (das höchstwertige Byte) an einer variablen Adresse. Das ist an sich kein Problem, nur muss der Programmteil, der die Zahl weiterverarbeitet, darauf abgestimmt sein. Du kannst aber auch die Routine so nehmen, wie sie ist, und am Schluss in einer weiteren Schleife die Reihenfolge der Bytes umkehren. Dann liegt der Anfang der Zahl auch bei Big-Endian am Anfang des Puffers. Bernhard schrieb: > Wenn ich die empfangene Dezimalzahl mit dem Taschenrechner in Hex > umwandle, dann habe ich alle Register vor mir wie sie sein sollen und im > Datenblatt stehen. Ah, dann hat die Binärzahl wahrscheinlich eine feste Länge. Wenn das so ist, kann man die obige Routine sogar noch etwas vereinfachen.
Yalu X. schrieb: > Du kannst aber auch die Routine so nehmen, wie sie ist, und am Schluss > in einer weiteren Schleife die Reihenfolge der Bytes umkehren. Dann > liegt der Anfang der Zahl auch bei Big-Endian am Anfang des Puffers. So habe ich das gerade auch realisiert. Ich werde mir die Routine aber trotzdem nochmal genauer ansehen und versuchen das ohne die letzte Schleife zu realisieren. Falk Brunner schrieb: > Vielmehr muss man wahrscheinlich die ASCII-zeichen > ind die entsprechenden HEX-Zahlen wandeln und in Nibbles packen. > > 2x ASCII -> 1x 8 Bit. > > DAS ist geradezu trivial. Wie bereits geschrieben erfolgt die Übertragung in 5-Bit Zeichen. Abzüglich Parity und Steuerzeichen (0xA-0xF) bleiben nur noch 0-9 übrig. Vorschlag: Jeder von uns bekommt einen halben Kasten Bier ;)
Bernhard schrieb: > Ich werde mir die Routine aber trotzdem nochmal genauer ansehen und > versuchen das ohne die letzte Schleife zu realisieren. Wie gesagt, wenn die Länge der resultierenden Bytefolge vorab bekannt ist (was ich vermute, wenn es sich dabei um einen Registersatz handelt), kannst du den Puffer problemlos von hinten nach vorne mit den berechneten Bytes befüllen. Dann brauchst du keine zusätzlich Schleife. Ich habe übrigens in obigem Code noch zwei kleine Änderungen vorgenommen: maxbin ist nun vom gleichen Typ wie nbin, nämlich uint8_t. Außerdem war die Zeile *bin=0 überflüssig. Das spart noch das eine oder andere Code-Byte.
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.