Hallo Liebe Leute,
ich habe ein kleines Problem mit der Umwandlung von hex asciizeichen in
eine Variable.
Ich habe einen String mit zB. folgendem Inhalt:
"010ff00a3001". Das sind 12 Zeichen, also 6 Byte. Die möchte ich in eine
Variable packen. Dazu brauche ich eine long long int, die ist dann 8
Byte lang.
Ich habe schon eine Funktion, die mir aus 2 Zeichen eine Zahl macht.
hier die Funktion:
1
// Umwandlung von 2 Zeichen eines strings in ein Byte
2
unsignedcharhex(unsignedchara,unsignedcharb)
3
{
4
unsignedcharc=0;
5
6
if(a<59){
7
c=16*(a-48);// wenn a eine zahl ist
8
}else{
9
c=16*(a-87);// wenn a eine zeichen ist
10
}
11
if(b<59){
12
c+=(b-48);// wenn b eine zahl ist
13
}else{
14
c+=(b-87);// wenn b eine zeichen ist
15
}
16
returnc;
17
}
Jetzt hole ich mir die ganzen Zeichen aus dem String und schiebe sie in
meine Variable:
if(frequenz==0xa000000000000000ULL)TCCR1B=0x04;// Timer1 starten
Erst dachte ich es Funktioniert. Aber nach eingehender Prüfung habe ich
feststellen müssen, dass es mit dem höchsten Byte, also die ersten
beiden Zechen, nicht geht. Wenn also mein String so aussieht, wie in dem
obigen Vergleich, wird der Timer nicht gestartet. Ich weiss nicht mehr
weiter, woran kann das liegen ?
Gibt es vielleicht eine Möglichkeit das Problem anders zu lösen ?
Danke schon im voraus.
Grüße Mattias
Das hat mehrere Vorteile
* man kann im Code ablesen, was da eigentlich passiert
* Du musst dir keine ASCII Codes merken
* Es ist nicht so verwirrend warum du den ASCII Code von 'W' abziehst
Und warum nimmst du nicht einfach ein Byte Array? Dann könnte man die
Funktion universell und unabhängig von der Länge des Hex Strings
implementieren, ausserdem sind shifts von 32, 40 (oder noch mehr) nicht
unbedingt performant zumal je nachdem was der Prozessor in Hardware kann
bei so grossen Variablen entsprechende overflow Überprüfungen per
software gemacht werden müssen.
Udo
Hallo,
ja das mit der 48 ist natürlich Banane. Jetzt sollte es Funktionieren.
@Udo S
wie meinst Du das mit dem Byte Array ?
Könntest Du mal ein Beispiel geben ?
Wenn ich nicht shifte, wie soll ich die Werte sonnst dort hin bekommen.
Ich denke mal multiplizieren ist schlimmer.
Gruß Mattias
@Klaus Wachtler
Der Poster hat nur gesagt er möchte den Hex String ein eine Variable
packen. Das hiess für mich, daß der String nicht einen bestimmten
numerischen Wert beinhaltet, sondern er nur Hex in numerische Werte
wandeln will.
Wenn der String genau eine Zahl darstellt hast Du natürlich recht, dann
müsstest Du wirklich berücksichtigen wie diese Zahl gespeichert wird.
Trotzdem sind diese Shift Operationen abhängig von Prozessor und
Compiler nicht unbedingt effizient, ein Mul ist bei modernen Prozessoren
oft schneller, wobei aber mancher Compiler das wieder optimiert.
udo
Hallo,
es handelt sich um einen Mega8 und als Compiler den Winavr.
Es ist wirklich so, dass der String eine einzige Zahl darstellt.
Wenn jemand eine Idee hat, wie man das effizienter macht, dann bitte
melden.
@Klaus Wachtler
Was sind Endianness ?
Gruß Mattias
Mattias schrieb:
> Hallo,> es handelt sich um einen Mega8 und als Compiler den Winavr.> Es ist wirklich so, dass der String eine einzige Zahl darstellt.
Die Frage ist: muss die Zahl so dermassen gross sein?
Da deine Variable Frequenz heisst, rate ich mal, dass du einen
Frequenzgenerator baust.
Dazu nimmst du einen Timer her.
Jetzt die Gretchenfrage: Ist die mit dieser Zahl einstellbare Frequenz
wirklich realistisch? Kannst du mit dem Timer speziell die grossen
Frequenzen wirklich aufs Herz genau einstellen? Oder gaukelst du mit
diesen großen Zahlen und den vielen Stellen nicht eine Genauigkeit vor,
die du nicht hast.
Es kann natürlich schon sein, dass ich falsch geraten habe. Allerdings
kommt ein long long schon sehr selten vor, dass man sich automatisch
frägt: Was will er machen? Will er die Atome im Universum zählen?
Mattias schrieb:
> es handelt sich um einen Mega8 und als Compiler den Winavr.
Dann ist 64Bit nur mit der Kneifzange anzufassen.
Die 64Bit-Lib ist extrem groß (~5kB) und extrem langsam, also noch
deutlich schlechter als float.
> Wenn jemand eine Idee hat, wie man das effizienter macht, dann bitte> melden.
Wurde schon gesagt, nimm ein Byte-Array.
Die Zahl liegt ja schon als HEX vor, also muß Du nix rechnen:
- wandle ein Zeichen in ein Nibble
- füge 2 Nibble zu einem Byte zusammen
- usw. bis alle Bytes fertig sind
Peter
Hallo,
@Karl heinz Buchegger
ja, ich brauche so große Zahlen. Das ist für ein DDS, 48bit Auflösung.
@Peter Dannegger
wie geht das mit dem Byte-Array ?
Habe sowas noch nicht gemacht.
Gruß Mattias
Mattias schrieb:
> Hallo,> @Karl heinz Buchegger> ja, ich brauche so große Zahlen. Das ist für ein DDS, 48bit Auflösung.
OK.
Du musst aber nicht damit selber rechnen, oder?
D.h. du kriegst die 'Zahl' und gibst sie einfach nur weiter.
(Denk gut nach: Wenn du eine Anzeige hast auf die die Zahl rauf muss,
musst du rechnen)
> @Peter Dannegger> wie geht das mit dem Byte-Array ?> Habe sowas noch nicht gemacht.
wo liegt das Problem?
uint8_t Bytes[6];
Im Grunde hast du das ja schon fast mit deinem String :-)
Mattias schrieb:
> ...> @Klaus Wachtler> Was sind Endianness ?
Das ist dann relevant, wenn man die Zahl nicht mit shift-Operatoren
zusammenschrauben will, sondern direkt Byte für Byte im Speicher
ablegt.
Dann muß man nämlich wissen, ob das niederwertige Byte der
long long an der Adresse der Variablen liegt und die höherwertigen
oberhalb (little endian), oder die höherwertigen unten und
die niederwertigen oben (big endian).
Grob gesagt sind Intel+AMD littele endian, der Rest (inkl. AVR)
big endian.
Siehe http://de.wikipedia.org/wiki/Endianness
Wenn man weiß, wie es auf dem aktuellen Rechner aussieht und man
in Kauf nimmt, den Quelltext für einen anderen Fall entsprechend
ändern muß, könnte man die Umwandlung deutlich effizienter
machen.
Mein Vorschlag:
PS: Diese Version funktioniert bei allen Stringlängen (bei mehr
als 16 Zeichen werden die führenden ignoriert) ebenso wie
für ungerade Stringlängen.
Ungültige Ziffern (also nicht 0-9 oder a-f oder A-F) werden
zu 0 angenommen.
Klaus Wachtler schrieb:
> Grob gesagt sind Intel+AMD littele endian, der Rest (inkl. AVR)> big endian.
Das mit dem AVR = big endian war nicht so wirklich ernst gemeint, oder?
;-)
Vermutlich werden die Bytes per SPI an den DDS-Chip gesendet.
Dann ist die Byteorder des Compilers egal, wenn er den Wert in ein Array
ablegt und dieses Array sendet.
Nur beim Umweg über uint64_t muß man die Byteorder wissen.
Peter
Stefan Ernst schrieb:
> Klaus Wachtler schrieb:>>> Grob gesagt sind Intel+AMD littele endian, der Rest (inkl. AVR)>> big endian.>> Das mit dem AVR = big endian war nicht so wirklich ernst gemeint, oder?> ;-)
ok, war ein Scherz.
Wobei genau genommen das ja eigentlich nicht mal vom AVR vorgegeben
wird, wenn ich das richtig sehe. Oder kennt der AVR überhaupt
2 Byte oder mehr? Wenn nicht, hat der Compiler ja eigentlich freie
Auswahl, wie er es macht.
Aber tatsächlich: zumindest die Kombination AVR+gcc ist little endian.
Klaus Wachtler schrieb:
> Wobei genau genommen das ja eigentlich nicht mal vom AVR vorgegeben> wird, wenn ich das richtig sehe. Oder kennt der AVR überhaupt> 2 Byte oder mehr? Wenn nicht, hat der Compiler ja eigentlich freie> Auswahl, wie er es macht.
Die 16-Bit-Register sind Little-Endian, und die Opcodes liegen auch
Little-Endian im Flash. So gesehen ist der AVR Little-Endian. Aber es
gibt ausschließlich 8-Bit Speicherzugriffe, also hätte der Compiler
theoretisch die freie Wahl.
Der AVR kennt insofern 2 Byte Werte, als er die z.B. beim Timer in zwei
Register hat. Wenn das HighByte in dem Register mit der höheren Adresse
ist (ich kenn den AVR nicht so gut) benutzt er Big Endian.
Aber im 8 Bit Controllerbereich ist das eh egal, weil du die Werte
Byteweise in ein Display oder eine weiterverarbeitende Peripherie
steckst, und da musst Du eh die Doku bemühen ober LSB oder HSB zuerst
kommt. Und für das zuammenbauen oder Multiplizieren der Werte musst du
es eh von Hand machen.
Also insofern wäre ein Byte Array wesentlich schneller zumal Du sonst
diese LongLong Bibliothek brauchst.
Ich persönlich mag bei so kleinen Controllern eher Assembler, da weiss
man wenigstens was passiert und hats beim Debuggen viel einfacher, ist
aber Geschmackssache.
Nochmal zu langsam / schnell: Moderne Prozessoren brauchen für eine
Multiplikation nur einen Takt, genausolange wie für einen Shift um 1
Bit. Das heisst im Extremfall für eine Multiplikation einer Tahl mit
2^24 brauchst Du nur einen Takt (32Bit Prozessor), für das Schieben von
24 Bit 24 Takte.
Früher zur Zeit des 8088 brauchte eine Multiplikation zweier 16 Bit
Zahlen zu einem 32 Bit Ergebnis bis zu 100 Takte, da waren
Schiebeoperationen deutlich schneller. Aber das ist hochgradig
Prozessorabhängig und im Falle einer Hochsprache wie C auch noch
Compilerabgängig.
Gruß, Udo
> Autor: Udo S (Gast)> Datum: 20.11.2009 16:15> Der AVR kennt insofern 2 Byte Werte, als er die z.B. beim Timer in zwei> Register hat. Wenn das HighByte in dem Register mit der höheren Adresse> ist (ich kenn den AVR nicht so gut) benutzt er Big Endian.> Aber im 8 Bit Controllerbereich ist das eh egal, weil du die Werte> Byteweise in ein Display oder eine weiterverarbeitende Peripherie> steckst, und da musst Du eh die Doku bemühen ober LSB oder HSB zuerst> kommt. Und für das zuammenbauen oder Multiplizieren der Werte musst du> es eh von Hand machen.> Also insofern wäre ein Byte Array wesentlich schneller zumal Du sonst> diese LongLong Bibliothek brauchst.> Ich persönlich mag bei so kleinen Controllern eher Assembler, da weiss> man wenigstens was passiert und hats beim Debuggen viel einfacher, ist> aber Geschmackssache.> Nochmal zu langsam / schnell: Moderne Prozessoren brauchen für eine> Multiplikation nur einen Takt, genausolange wie für einen Shift um 1> Bit. Das heisst im Extremfall für eine Multiplikation einer Tahl mit> 2^24 brauchst Du nur einen Takt (32Bit Prozessor), für das Schieben von> 24 Bit 24 Takte.> Früher zur Zeit des 8088 brauchte eine Multiplikation zweier 16 Bit> Zahlen zu einem 32 Bit Ergebnis bis zu 100 Takte, da waren> Schiebeoperationen deutlich schneller. Aber das ist hochgradig> Prozessorabhängig und im Falle einer Hochsprache wie C auch noch> Compilerabgängig.> Gruß, Udo
Auch hier möchte ich Festellen, dass nicht ich diesen Beitrag
geschrieben habe.
@ Gast (Udo S)
Schaff dir bitte einen anderen Nick an.
Gruß
Udo
Udo S schrieb:
> Der AVR kennt insofern 2 Byte Werte, als er die z.B. beim Timer in zwei> Register hat. Wenn das HighByte in dem Register mit der höheren Adresse> ist (ich kenn den AVR nicht so gut) benutzt er Big Endian.
High-Byte in höherer Adresse ist Little-Endian, nicht Big-Endian.