Forum: Compiler & IDEs Umwandlung von langen Dezimalzahlen als String in Hex


von Bernhard (Gast)


Lesenswert?

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

von PittyJ (Gast)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Mike (Gast)


Lesenswert?

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>

von Bernhard (Gast)


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

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?

von Bernhard (Gast)


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

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.

von Mike (Gast)


Lesenswert?

>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!

von Bernhard (Gast)


Lesenswert?

Das Datenblatt tut nichts zur Sache.

von Peter II (Gast)


Lesenswert?

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.

von Mike (Gast)


Lesenswert?

>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?

von Peter II (Gast)


Lesenswert?

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.

von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von Mike (Gast)


Lesenswert?

>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.

von Mike (Gast)


Lesenswert?

>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.

von Ralf G. (ralg)


Lesenswert?

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.

von Bernhard (Gast)


Lesenswert?

@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.

von Bernhard (Gast)


Lesenswert?

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.

von Bernhard (Gast)


Lesenswert?

@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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Bernhard (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@ 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.

von Falk B. (falk)


Lesenswert?

@ 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.

von Peter II (Gast)


Lesenswert?

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.

von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von Bernhard (Gast)


Lesenswert?

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 ;)

von Yalu X. (yalu) (Moderator)


Lesenswert?

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
Noch kein Account? Hier anmelden.