bei meinem aktuellen Projekt muss/ soll der Arduino einen kompletten HEX-String ausgeben.
Zum Beispiel: 01 10 F0 07 1F C7
Meine aktuelle Lösung sieht so aus:
char string[6] = { 0x01, 0x10, 0xF0, 0x07, 0x1F, 0xC7 };
for (int i = 0; i < 6; i++){
Serial.write(string[i]);
}
Dieser Code liefert auch das Ergebnis, welches ich haben möchte. Kann man dies auch anders lösen (Einzeiler?)? Wenn ja, wie müsste der Code aussehen?
Natürlich sendet der Arduino nicht nur einen HEX-String sondern soll auch HEX-Daten empfangen und auswerten. Leider stehe ich da momentan komplett auf dem Schlauch!
Ich habe in einem char-Array die Einzelteile von einem HEX-Wert.
char pieces[4] = { "00", "00", "B4", "41" };
Diese Einzelteile müssen zum HEX-Wert 41B40000 zusammengesetzt werden. Danach muss dieser Wert zum float-Wert 22.5 konvertiert werden. Leider habe ich momentan keine Ahnung, welche Funktionen sich da anbieten...
Der Code oben ist für ein Integer Array nach Float. Wenn du einen String hast, musst du den String erst mal nach Integer wandeln.
Das habe ich weggelassen weil es da verschiedene Optionen gibt wie man das macht und dein Code nicht lauffähig war. Das einfachste wäre wenn du den String gleich so hast:
char str[] = "41B40000";
Also in einem Stück und in der richtigen Reihenfolge
Dann kann man direkt das machen:
char str[] = "41B40000";
unsigned long i = strtoul(str, NULL, 16);
float f = *(float*)&i;
Serial.println(f);
Der Code von Serenifly in Post #2 würde mich sehr interessieren, da die Einzelteile in einem großen Buffer stehen. Der Beispielcode funktioniert bei mir leider nicht und ich bin auch nicht in der Lage ihn zu verbessern.. Woran kann es liegen, dass der Code nicht richtig funktioniert?
Du hast bisher noch nicht klar gemacht in welchem Format deine Daten überhaupt genau vorliegen.
Liest du die Daten wirklich als String ein, oder als Integer? Das sind zwei völlig verschiedene Dinge.
Wenn es sich tatsächlich um einen C String handelt, d.h. ein null-terminiertes Array aus ASCII Zeichen, könnte man es so in einem einzigen char Array haben:
char str[] = "41B40000";
Dann hast du hier mal angedeutet dass die Reihenfolge anders herum wäre:
Ich muss gestehen, dass ich das Programm für den Arduino gerade nur theoretisch entwickeln kann, da ich das Gerät, welches angeschlossen werden soll, noch nicht habe.
Das Gerät hat ein eigenes Binäres-Protokoll. So wie ich das jetzt verstanden habe, müssten die Werte als int vorliegen, aber nicht als HEX-Werte sondern DEC-Werte. Wenn das Gerät z.B. 2F (HEX) sendet, entspricht dies '/' (ASCII) bzw. 47 (DEC). Im Buffer-Array müsste dann 47 stehen (da buffer[index++] = Serial.read();).
Genau, die Reihenfolge im Array ist anders herum. Also 00 00 B4 41 (HEX) bzw. 000 000 180 065 (DEC). Jeder der "Einzelwerte" hat einen eigenen Index im Array!
Dann geht das in #Reply 2 eigentlich. Du musst das nur richtig einlesen. Die Reihenfolge im Array ist da erst mal egal. Du kannst das dann bei der Wandlung in einen Integer herumdrehen wenn nötig
Wenn es so im Array steht kommt tatsächlich 22.5 heraus:
Wenn jetzt die 0x41 als letztes kommt, dreht man bei der Wandlung in einen Integer einfach die Indizes herum:
unsigned long i = pieces[3] << 24 | pieces[2] << 16 | pieces[1] << 8 | pieces[0];
EDIT:
Fehler gefunden. Man kann natürlich einen 16-Bit int (der Shift wird in int gerechnet, auch wenn es ein char ist) nicht um 24 oder 16 nach links schieben. So ist es korrekt (hoffentlich)
Nachtrag:
Die Lösung mit der Union genaugenommen ist besser. Der Trick mit dem Zeiger funktioniert zwar, aber verletzt den C Standard, da man eigentlich Speicher nur durch einen Zeiger mit einem anderen Datentyp ansprechen darf (Ausnahme: char*). Produziert auch eine Warnung. Stichwort: strict aliasing, type punning
Wenn man bei sowas übertreibt kann der Compiler den Code nicht mehr richtig optimieren
Der Compiler kann das eh nicht richtig optimieren, da er nicht weiss was wie über die Leitung kommt.
Bei atmel avr Prozessoren und beim PC werden integer mit dem LSB (least significant byte) auf der niedrigsten Adresse gespeichert, Texte mit dem ersten Zeichen, und floats mit der niederwertigsten Mantisse-Byte. Der Exponent (0x41) ist im höchstwertigen Byte auf der Adresse +3.
michael_x:
Der Compiler kann das eh nicht richtig optimieren, da er nicht weiss was wie über die Leitung kommt.
Das war auch noch nicht auf diese Anwendung hier bezogen. Ich habe das auch schon so gemacht.
Auf einem 8 Bit System ist es meistens egal. Es funktioniert sogar auf dem PC mit 32 Bit ints. Bei komplexeren Sachen und wenn es um Dinge wie endianess, alignment und padding geht (z.B. wenn man structs oder Klassen castet) wird es richtig problematisch (wobei letztere zwei auf einem 8 Bit System wieder irrelevant sind).
Aber auch sonst kann es wohl manchmal vorkommen, dass der Compiler da Fehler produziert was man so liest, da er bestimmte Annahmen trifft und man diese umgeht.
beim PC werden integer mit dem LSB (least significant byte) auf der niedrigsten Adresse gespeichert
Das ist nicht universell. Das ist System an sich ist zwar Little Endian, aber Java z.B. ist Big Endian!