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